Повышение производительности data.table при назначении новых значений столбцу - PullRequest
0 голосов
/ 08 января 2019

У меня огромный data.table, и мне нужно создавать новые столбцы на основе условий внутри существующих столбцов.

Допустим, мои данные выглядят так:

library(data.table)            
dt=data.table(ID=rep(1:3,1000000),LABEL=rep(c("A","A","B"),1000000),COND=rep(c("C","D","D"),1000000),VALUE=sample(letters,1000000,replace=T))

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

dt$WHATEVER=as.numeric(NA)
for(id in dt[,unique(ID)]){
  for(label in dt[,unique(LABEL)]){
  n=dt[which(ID==id&LABEL==label&COND=="C"),cumsum(grepl("a",VALUE))]
    set(dt,
        i=dt[,which(ID==id&LABEL==label&COND=="C")],
        j="WHATEVER",
        value=n)
  }
}

Если я system.time() это, я получаю:

   user  system elapsed 
  0.788   0.000   0.788 

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

setkey(dt,ID,LABEL,COND)
for(id in dt[,unique(ID)]){
  for(label in dt[,unique(LABEL)]){
  #setkey(dt,ID,LABEL,COND)
  n=dt[which(ID==id&LABEL==label&COND=="C"),cumsum(grepl("a",VALUE))]
    set(dt,
        i=dt[,which(ID==id&LABEL==label&COND=="C")],
        j="WHATEVER",
        value=n)
  }
}

... как видите:

   user  system elapsed 
  0.801   0.020   0.820

Есть ли что-то, что я делаю неправильно или могло быть лучше? (Я знаю, что могу изменить, чтобы применить функции. Мой вопрос - data.table wise)

По просьбе Хенрика я покажу пример моего набора данных и объясню, что я пытаюсь сделать. Мой набор данных выглядит так:

       ID                                 NAME      PROGRAM
 1:    2056                                 CE      348
 2:    2056                                 CE      348
 3:    2056                                 AE      348
 4:    2056                                 CE      348
 5:    2056                                 AE      348
 6:    2056                                 AE      348
 7:    2056                                 CE      348
 8:    2056                                 AE      348
 9:    2056                                 BC      348
10:    2056                                 CB      348

Я пытаюсь подсчитать, для каждого идентификатора, сколько раз появляется каждое ИМЯ, и назначить для NEWCOLUMN номер, который сообщает мне, какое время это (порядок имеет значение, и, возможно, setkey может испортить это, хотя Я мог бы обойти это), но только для некоторой ПРОГРАММЫ.

Позже я использую значение, назначенное новому столбцу, чтобы создать еще один, который сообщает мне, какое ИМЯ было сделано ПЕРВЫМ и ПОСЛЕДНИМ, снова для каждого идентификатора и только для определенной ПРОГРАММЫ. (Этот еще медленнее, так как он сделан каким-то другим столбцом), хотя ответ PoGibas может помочь ускорить его.

1 Ответ

0 голосов
/ 08 января 2019

Вы можете выбрать строки с значениями COND == "C" и cumsum TRUE, сгенерированными из условия VALUE == "a" (строки с COND != "C" будут заполнены NA).

# Assign cumsum to new column WHATEVER2 by ID and LABEL
dt[COND == "C", WHATEVER2 := cumsum(VALUE == "a"), .(ID, LABEL)]

# All values are equal to the ones generate by OP
dt[, all(WHATEVER == WHATEVER2, na.rm = TRUE)]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...