В R, как Вы циклично выполняетесь по строкам кадра данных действительно быстро?

Предположим, что у Вас есть кадр данных со многими строками и многими столбцами.

Столбцы имеют имена. Вы хотите получить доступ к строкам числом и столбцам по имени.

Например, один (возможно медленный) способ циклично выполниться по строкам

for (i in 1:nrow(df)) {
  print(df[i, "column1"])
  # do more things with the data frame...
}

Иначе должен создать "списки" для отдельных столбцов (как column1_list = df[["column1"]), и доступ списки в одном цикле. Этот подход мог бы быть быстрым, но также и неудобным, если Вы хотите получить доступ ко многим столбцам.

Существует ли быстрый способ цикличного выполнения по строкам кадра данных? Некоторая другая структура данных лучше для цикличного выполнения быстро?

30
задан smci 29 April 2016 в 11:08
поделиться

2 ответа

Думаю, мне нужно дать полный ответ, потому что мне труднее отслеживать комментарии, и я уже потерял один комментарий по этому поводу ... Есть пример от nullglob это демонстрирует различия между for и применяет семейные функции намного лучше, чем другие примеры. Если сделать функцию очень медленной, тогда будет потрачена вся скорость, и вы не найдете различий между вариациями цикла. Но когда вы сделаете функцию тривиальной, вы увидите, насколько сильно на вещи влияет цикл.

Я также хотел бы добавить, что некоторые члены семейства apply, не исследованные в других примерах, обладают интересными характеристиками производительности. Сначала я покажу репликации относительных результатов nullglob на моей машине.

n <- 1e6
system.time(for(i in 1:n) sinI[i] <- sin(i))
  user  system elapsed 
 5.721   0.028   5.712 

lapply runs much faster for the same result
system.time(sinI <- lapply(1:n,sin))
   user  system elapsed 
  1.353   0.012   1.361 

Он также обнаружил, что sapply намного медленнее. Вот некоторые другие, которые не тестировались.

Обычное старое применение к матричной версии данных ...

mat <- matrix(1:n,ncol =1),1,sin)
system.time(sinI <- apply(mat,1,sin))
   user  system elapsed 
  8.478   0.116   8.531 

Итак, сама команда apply () существенно медленнее, чем цикл for. (цикл for не замедляется заметно, если я использую sin (mat [i, 1]).

Еще один, который, похоже, не тестируется в других сообщениях, - это tapply.

system.time(sinI <- tapply(1:n, 1:n, sin))
   user  system elapsed 
 12.908   0.266  13.589 

Конечно, таким способом нельзя использовать tapply, и его полезность намного превосходит любую подобную проблему скорости в большинстве случаев.

15
ответ дан 28 November 2019 в 00:23
поделиться

Самый быстрый способ - не зацикливать (т. Е. Векторизованные операции). Один из единственных случаев, когда вам нужно выполнить цикл, - это когда есть зависимости (т.е. одна итерация зависит от другой). В противном случае постарайтесь выполнить как можно больше векторизованных вычислений вне цикла.

Если вам нужен цикл, то использование цикла for по сути так же быстро, как и все остальное ( lapply может быть немного быстрее, но другие применяют функции, как правило, имеют примерно такую ​​же скорость, как для ).

12
ответ дан 28 November 2019 в 00:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: