обновление data.table присоединиться к группе - PullRequest
1 голос
/ 30 января 2020

У меня есть конкретный c data.table вопрос: есть ли способ выполнить обновление, кроме как по группе? Позвольте мне привести пример:

df1 <- data.table(ID = rep(letters[1:3],each = 3),x = c(runif(3,0,1),runif(3,1,2),runif(3,2,3)))
df2 <- data.table(ID = c(letters[1],letters[1:5]))

> df2
   ID
1:  a
2:  a
3:  b
4:  c
5:  d
6:  e

> df1
   ID         x
1:  a 0.9719153
2:  a 0.8897171
3:  a 0.7067390
4:  b 1.2122764
5:  b 1.7441528
6:  b 1.3389710
7:  c 2.8898255
8:  c 2.0388562
9:  c 2.3025064

Я хотел бы сделать что-то вроде

df2[df1,plouf := sample(i.x),on ="ID"]

Но для каждой группы ID это означает, что plouf будет образцом x значения для каждого соответствующего ID. Приведенная выше строка кода не работает таким образом, она выполняет выборку всего вектора x:

> df2

   ID     plouf
1:  a 1.3099715
2:  a 0.8540039
3:  b 2.0767138
4:  c 0.6530148
5:  d        NA
6:  e        NA

Вы видите, что значения plouf не являются x, соответствующими ID группа df1. Мне бы хотелось, чтобы значение plouf было от 0 до 1 для a, от 1 до 2 для b и от 2 до 3 для c. Я хочу попробовать без замены. Я пытался:

df2[df1,plouf := as.numeric(sample(i.x,.N)),on ="ID",by = .EACHI]

, который не работает:

Error in sample.int(length(x), size, replace, prob) : 
  cannot take a sample larger than the population when 'replace = FALSE'

Эта другая попытка, кажется, работает:

df2$plouf <- df2[df1,on ="ID"][,sample(x,df2[ID == ID2,.N]),by = .(ID2 = ID)]$V1

Но мне трудно читать или понять, это может быть проблематично c для более чем одной переменной группировки, и я не уверен, что это достаточно эффективно. Я уверен, что есть хороший простой способ написать это, но у меня его нет. Есть идеи?

Ответы [ 2 ]

3 голосов
/ 30 января 2020

Другой вариант:

df1[df2[, .N, ID], on=.(ID), sample(x, N), by=.EACHI]

вывод:

   ID        V1
1:  a 0.2655087
2:  a 0.3721239
3:  b 1.2016819
4:  c 2.6607978
5:  d        NA
6:  e        NA

данные:

library(data.table)
set.seed(0L)
df1 <- data.table(ID = rep(letters[1:3],each = 3),x = c(runif(3,0,1),runif(3,1,2),runif(3,2,3)))
df2 <- data.table(ID = c(letters[1],letters[1:5]))

Адресация комментария:

library(data.table)
set.seed(0L)
df1 <- data.table(ID = rep(letters[1:3],each = 3),
    NAME = rep(LETTERS[1:3],each = 3),
    x = c(runif(3,0,1),runif(3,1,2),runif(3,2,3)))
df2 <- data.table(ID = c(letters[1],letters[1:5]),
    NAME = c(LETTERS[1],LETTERS[1:5]))

df2[, ri := rowid(ID, NAME)][
    df1[df2[, .N, .(ID, NAME)], on=.(ID, NAME), .(ri=1L:N, VAL=sample(x, N)), by=.EACHI],
    on=.(ri, ID, NAME), VAL := VAL]
df2

Если это слишком многократно для ввода ID, NAME, вы можете использовать

cols <- c("ID", "NAME")
df2[, ri := rowidv(.SD, cols)][
    df1[df2[, .N, cols], on=cols, .(ri=1L:N, VAL=sample(x, N)), by=.EACHI],
    on=c("ri", cols), VAL := VAL]
df2
1 голос
/ 30 января 2020

Образец с заменой

Вы можете сделать это следующим образом:

df2[, plouf := df1[df2, on = .(ID),
                        sample(x, size = 1),
                        by=.EACHI]$V1]

Вы можете присоединиться к переменной ID, но вы должны указать by=.EACHI как вы возвращаете несколько значений. $V1 говорит ему вернуть первый столбец результатов.

Результат:

   ID      sample
1:  a 0.042188292
2:  a 0.002502247
3:  b 1.145714600
4:  c 2.541768627
5:  d          NA
6:  e          NA

Образец без замены

Это не красиво но это работает:

df2$plouf = as.numeric(NA)

# create temporary table of number of sample required for each group
temp = df2[, .N, by = ID]

for(i in temp$ID){
  # create a temporary sample
  temp_sample = sample(df1[i==ID]$x, size = temp[ID==i]$n, replace = FALSE)

  # assign sample
  for(j in seq(1, length(temp_sample))){
    df2[ID==i][j]$plouf = temp_sample[j] 
  }
}

Спасибо @David Arenburg за помощь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...