2016-11-02 5 views
2

У меня есть набор данных 20000 * 5. В настоящее время он обрабатывается итеративно, и набор данных постоянно обновляется на каждой итерации.Каков самый быстрый способ обновления набора данных в R?

Ячейки в data.frame обновляются на каждой итерации и ищут некоторую помощь в быстром выполнении этих задач. Поскольку это небольшой data.frame, я не уверен, что data.table будет работать нормально.

Вот ориентиры для data.frame subassignment:

sessionInfo() 
R version 3.2.4 Revised (2016-03-16 r70336) 
Platform: x86_64-w64-mingw32/x64 (64-bit) 
Running under: Windows Server >= 2012 x64 (build 9200) 
set.seed(1234) 
test <- data.frame(A = rep(LETTERS , 800), B = rep(1:26, 800), C=runif(20800), D=runif(20800) , E =rnorm(20800)) 
microbenchmark::microbenchmark(test[765,"C"] <- test[765,"C"] + 25) 
Unit: microseconds 
            expr  min  lq  mean median  uq  max neval 
test[765, "C"] <- test[765, "C"] + 25 112.306 130.8485 979.4584 186.3025 197.7565 44556.15 100} 

Есть ли способ для достижения указанной выше функции быстрее, чем то, что я писал?

+2

Самый быстрый способ - это функция 'set' в package data.table. Очевидно, еще быстрее избежать этого. – Roland

+0

Добро пожаловать в StackOverflow! Пожалуйста, прочитайте информацию о [как задать хороший вопрос] (http://stackoverflow.com/help/how-to-ask) и как дать [воспроизводимый пример] (http://stackoverflow.com/questions/ 5963269). Это облегчит вам помощь другим людям. – Jaap

+0

microbenchmark :: microbenchmark (тест [765, «C»] <- test [[765, «C»]] + 25) это быстрее, чем в моем посте, но есть ли альтернативы? – sak88

ответ

4

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

library(data.table) 
library(microbenchmark) 
dt <- data.table(test) 

# Accessing the entry 
dt[765, "C", with = FALSE] 

# Replacing the value with the new one 
# Basic data.table syntax 
dt[i =765, C := C + 25 ] 

# Replacing the value with the new one 
# using set() from data.table 
set(dt, i = 765L, j = "C", value = dt[765L,C] + 25) 

microbenchmark(
     a = set(dt, i = 765L, j = "C", value = dt[765L,C] + 25) 
    , b = dt[i =765, C := C + 25 ] 
    , c = test[765, "C"] <- test[765, "C"] + 25 
    , times = 1000  
) 

Результаты microbenchmark:

            expr  min  lq  mean median  uq  max neval 
a = set(dt, i = 765L, j = "C", value = dt[765L, C] + 25) 236.357 46.621 266.4188 250.847 260.2050 572.630 1000 
b = dt[i = 765, `:=`(C, C + 25)]       333.556 345.329 375.8690 351.668 362.6860 1603.482 1000 
c = test[765, "C"] <- test[765, "C"] + 25    73.051 81.805 129.1665 84.220 87.6915 1749.281 1000 
+2

Используйте 'a =' вместо 'a <-'. Интересные и удивительные тесты. По-видимому, '[<-. Data.frame' был улучшен и теперь больше не копирует data.frame? – Roland

+0

Может стоить добавить тест с использованием строки 20k (почти весь пример df), так как результаты действительно отличаются. – Tensibai

2

Вы можете начать только с руководством по ?set функции. В примере вы найдете код, который вы можете использовать для сравнения. Я просто перезапустил его и получил следующие тайминги.

library(data.table) 
m = matrix(1, nrow = 2e6L, ncol = 100L) 
DF = as.data.frame(m) 
DT = as.data.table(m)  

system.time(for (i in 1:1000) DF[i, 1] = i) 
# user system elapsed 
# 3.048 1.512 24.854 
system.time(for (i in 1:1000) DT[i, V1 := i]) 
# user system elapsed 
# 0.232 0.000 0.259 
system.time(for (i in 1:1000) set(DT, i, 1L, i)) 
# user system elapsed 
# 0.000 0.000 0.002 

В идеале вы должны проверить сценарий обновления данных о ваших данных и масштаба, чтобы правильно измерить, который является «самым быстрым». Также не забудьте проверить использование памяти, используя [<- на матрице, похоже, использует больше памяти, чем data.table, если вы закончите замену, это будет медленнее.

+0

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

+0

@ sak88 Хорошо, вы приводите воспроизводимый пример, так как для меня это наиболее важно после сообщения вопроса :) Помните, что вы можете обновлять _slices_ of data.table, предоставляя векторный (не скалярный) аргумент 'i'. – jangorecki

+0

@ sak88 метод data.frame работает быстрее для крошечного набора данных, а разница в микросекундах. Чем больше набор данных, тем больше производительность будет отличаться в зависимости от 'set' –

Смежные вопросы