Подтвердить что ты не робот

Эффективность операций над структурами данных R

Мне интересно, есть ли какая-либо документация об эффективности операций в R, в частности, связанных с манипуляциями с данными.

Например:

  • Я считаю, что эффективно добавлять столбцы в фрейм данных, потому что я предполагаю, что вы просто добавляете элемент в связанный список.
  • Я предполагаю, что добавление строк медленнее, потому что векторы хранятся в массивах в C level, и вам нужно выделить новый массив длиной n+1 и скопировать все элементы.

Разработчики, вероятно, не хотят привязываться к конкретной реализации, но было бы неплохо иметь что-то более твердое, чем предполагалось.

Кроме того, я знаю, что основной R подсказкой производительности является использование векторных операций, когда это возможно, в отличие от loops.

  • как насчет различных ароматов apply?
  • являются только тегами hidden loops?
  • как насчет matrices vs. data frames?
4b9b3361

Ответ 1

Data IO была одной из особенностей, которую я изучил, прежде чем я посвятил себя обучению R. Для улучшения или хуже, вот мои наблюдения и решения/паллиативы по этим вопросам:

1. Что R не обрабатывает большие данные ( > 2 ГБ?) Мне это неверно. По умолчанию общие функции ввода данных загружают ваши данные в ОЗУ. Не быть glib, но для меня это особенность, а не ошибка - в любое время мои данные будут соответствовать моей доступной ОЗУ, где я хочу. Аналогично, одной из самых популярных функций SQLite является опция in-memory - у пользователя есть простой способ загрузки всего дБ в ОЗУ. Если ваши данные не будут вписываться в память, тогда R делает его удивительно простым в использовании, подключаясь к общим системам РСУБД (RODBC, RSQLite, RMySQL и т.д.), Используя опции без излишеств, такие как пакет filehash, и через системы, которые используют текущую технологию/практику (например, я могу рекомендовать ff). Другими словами, разработчики R выбрали разумный (и, вероятно, оптимальный) по умолчанию, из которого очень легко отказаться.

2. Производительность read.table (read.csv, read.delim и др.), Наиболее распространенное средство для получения данных в R, может быть улучшена 5 раз (и часто намного больше в моем опыте), просто выбрав из нескольких аргументов read.table по умолчанию - те, которые оказывают наибольшее влияние на производительность, упоминаются в справке R (? read.table). Вкратце, разработчики R сообщают нам, что если вы предоставите значения для параметров colClasses, 'nrows', 'sep' и 'comment.char' (в частности, перейдите в '', если вы знаете, что ваш файл начинается с заголовков или данные в строке 1), вы увидите значительное увеличение производительности. Я нашел это, чтобы быть правдой.

Вот фрагменты, которые я использую для этих параметров:

Чтобы получить количество строк в вашем файле данных (поставьте этот фрагмент в качестве аргумента для параметра "nrows" в вашем вызове read.table):

as.numeric((gsub("[^0-9]+", "", system(paste("wc -l ", file_name, sep=""), intern=T))))

Чтобы получить классы для каждого столбца:

function(fname){sapply(read.table(fname, header=T, nrows=5), class)}  

Примечание. Вы не можете передать этот фрагмент в качестве аргумента, вы должны сначала его вызвать, а затем передать возвращаемое значение - другими словами, вызвать функцию, связать возвращаемое значение с переменной, а затем перейдите в переменную как значение к параметру "colClasses" в вашем вызове read.table:

3. Использование Scan. С небольшим количеством проблем вы можете сделать лучше (оптимизируя "read.table" ), используя "scan" вместо "read.table" ( "read.table" на самом деле просто обертка вокруг "scan" ). Еще раз, это очень легко сделать. Я использую "сканирование" для ввода каждого столбца отдельно, а затем создаю свой файл data.frame внутри R, т.е. Df = data.frame(cbind (col1, col2,....)).

4. Используйте R Containers для сохранения на месте вместо обычных форматов файлов (например, "txt", "csv" ). R native data. '.RData' - это двоичный формат, который немного меньше сжатого (.gz ') файла данных txt. Вы создаете их, используя сохранить (,). Вы загрузите его обратно в пространство имен R с помощью load(). Разница во времени загрузки по сравнению с "read.table" является драматической. Например, с файлом размером 25 МБ (несжатый размер)

system.time(read.table("tdata01.txt.gz", sep=","))
=>  user  system elapsed 
    6.173   0.245   **6.450** 

system.time(load("tdata01.RData"))
=> user  system elapsed 
    0.912   0.006   **0.912**   

5. Обращая внимание на типы данных, вы часто можете повысить производительность и уменьшить объем памяти. Этот момент, вероятно, более полезен для получения данных из R. Ключевым моментом здесь является то, что по умолчанию числа в R-выражениях интерпретируются как плавающая точка с двойной точностью, например, > typeof (5) возвращает double. " Сравните размер объекта массива разумного размера, и вы можете увидеть его значение (используйте object.size()). Так что принуждение к целому числу, когда вы можете.

Наконец, семейство функций "apply" (среди прочих) не является "скрытыми петлями" или оберткими цикла. Они представляют собой петли, реализованные в C - большие различия в производительности. [edit: AWB правильно указал, что в то время как "sapply", "tapply" и "mapply" реализованы в C, "apply" - это просто оболочка.

Ответ 2

Эти вещи появляются в списках, в частности, на r-devel. Один довольно устоявшийся самородок - это, например, Операции matrix имеют тенденцию быть быстрее операций data.frame. Тогда есть дополнительные пакеты, которые преуспевают - Matt data.table пакет довольно быстро, и Джефф получил xts, чтобы быть быстрым.

Но это "все зависит" - так что вам обычно рекомендуется советовать профилю по вашему конкретному коду. R имеет много профилирующей поддержки, поэтому вы должны ее использовать. My Вступление к HPC с учебниками R содержит ряд примеров профилирования.

Ответ 3

Я попытаюсь вернуться и предоставить более подробную информацию. Если у вас есть вопрос об эффективности одной операции над другой, вы бы лучше всего профилировали свой собственный код (как предлагает Дирк). Функция system.time() - это самый простой способ сделать это, хотя есть много дополнительных утилит (например, Rprof, как описано здесь).

Быстрый ответ для второй части вашего вопроса:

Как насчет различных вкусов? Это просто скрытые петли?

По большей части да, функции apply являются просто циклами и могут быть медленнее, чем операторы for. Их главное преимущество - более четкий код. Основное исключение, которое я нашел, это lapply, которое может быть быстрее, потому что оно напрямую закодировано в C.

А как насчет матриц и кадров данных?

Матрицы более эффективны, чем фреймы данных, потому что они требуют меньше памяти для хранения. Это связано с тем, что кадры данных требуют дополнительных данных атрибутов. Из R Введение:

Кадр данных может использоваться во многих целях как матрица с столбцами, которые могут иметь разные моды и атрибуты.