Генерация индикаторов в больших фреймах данных - PullRequest
5 голосов
/ 26 марта 2012

Цель состоит в том, чтобы создать индикаторы для факторной / строковой переменной во фрейме данных. Этот фрейм данных имеет> 2 мм строк и работает R на окнах, у меня нет возможности использовать plyr с .parallel = T. Поэтому я выбираю маршрут «разделяй и властвуй» с помощью plyr и reshape2.

Запуск расплавления и отливки заканчивается памятью, а

ddply( idata.frame(items) , c("ID") , function(x){
       (    colSums( model.matrix( ~ x$element - 1) ) > 0   )
} , .progress="text" )    

или

ddply( idata.frame(items) , c("ID") , function(x){
           (    elements %in% x$element   )
    } , .progress="text" )  

занимает некоторое время. Самый быстрый подход - призыв к применению ниже. Вы видите способ ускорить это? Оператор% in% выполняется быстрее, чем вызов model.matrix. Спасибо.

set.seed(123)

dd <- data.frame(
  id  = sample( 1:5, size=10 , replace=T ) ,
  prd = letters[sample( 1:5, size=10 , replace=T )]
  )

prds <- unique(dd$prd)

tapply( dd$prd , dd$id , function(x) prds %in% x )

Ответы [ 3 ]

4 голосов
/ 27 марта 2012

Для этой проблемы пакеты bigmemory и bigtabulate могут быть вашими друзьями.Вот немного более амбициозный пример:

library(bigmemory)
library(bigtabulate)

set.seed(123)

dd <- data.frame(
  id = sample( 1:15, size=2e6 , replace=T ), 
  prd = letters[sample( 1:15, size=2e6 , replace=T )]
  )

prds <- unique(dd$prd)

benchmark(
bigtable(dd,c(1,2))>0,
table(dd[,1],dd[,2])>0,
xtabs(~id+prd,data=dd)>0,
tapply( dd$prd , dd$id , function(x) prds %in% x )
)

И результаты бенчмаркинга (я постоянно учусь чему-то новому):

                                            test replications elapsed relative user.self sys.self user.child sys.child
1                      bigtable(dd, c(1, 2)) > 0          100  54.401 1.000000    51.759    3.817          0         0
2                    table(dd[, 1], dd[, 2]) > 0          100 112.361 2.065422   107.526    6.614          0         0
4 tapply(dd$prd, dd$id, function(x) prds %in% x)          100 178.308 3.277660   166.544   13.275          0         0
3                xtabs(~id + prd, data = dd) > 0          100 229.435 4.217478   217.014   16.660          0         0

И это показывает bigtable выигрышна значительную сумму.Результаты в значительной степени совпадают с тем, что все prds находятся во всех идентификаторах, но подробности о формате результатов см. В ?bigtable.

2 голосов
/ 26 марта 2012

Можете ли вы сказать немного больше о том, как проблема будет масштабироваться с точки зрения количества уровней, количества идентификаторов и т. Д. (Если вы сохраните фиксированное число уровней, то для достаточного количества людей вычисляемая матрица индикатора будет приблизить все ИСТИНА / все 1 ...)? Я ожидал, что xtabs будет быстрее, но это не для примера такого размера ...

library(rbenchmark)
benchmark(
          tapply( dd$prd , dd$id , function(x) prds %in% x ),
          xtabs(~id+prd,data=dd)>0)

     test        replications elapsed relative 
1 tapply(...)             100   0.053 1.000000
2 xtabs(...) > 0          100   0.120 2.264151  
1 голос
/ 26 марта 2012

Ваше использование функции %in% кажется мне задом наперед. И если вы хотите получить значение true / false для каждой строки данных, вам следует использовать либо% in% как векторную операцию, либо ave. Хотя здесь это и не нужно, вы можете использовать его, если есть более сложная функция, которую необходимо применить к каждому элементу.

set.seed(123)

dd <- data.frame(
  id  = sample( 1:5, size=10 , replace=T ) ,
  prd = letters[sample( 1:5, size=10 , replace=T )]
  )

prds <- unique(dd$prd)
target.prds <- prds[1:2]
dd$prd.in.trgt <- with( dd, prd %in% target.prds)
...