允许.SDcols随data.table中的分组变量而变化

时间:2016-02-19 08:49:25

标签: r data.table

是否允许.SDcolsby分组变量而异?我有以下情况,我希望每年将.SDcols更改为不同的列。 .SDcols的值在一个data.table中,而我正在尝试使用这些值将函数应用于另一个表中的.SD

很可能我错过了明显的做法并做错了,但这就是我的尝试,

## Contains the .SDcols applicable to each year
dat1 <- data.table(
  year = 1:4,
  vals = lapply(1:4, function(i) letters[1:i])
)

## Make the sample data (with NAs)
set.seed(1775)
dat2 <- data.table( year = sample(1:4, 10, TRUE) )
dat2[, letters[1:4] := replicate(4, sample(c(NA, 1:5), 10, TRUE), simplify=FALSE)]

## Goal: Sum up the columns in the corresponding .SDcols for each year
## Attempt, doesn't work -- I think b/c .SDcols must be fixed?
dat2[, SUM := rowSums(.SD, na.rm=TRUE), by=year, 
  .SDcols=unlist(dat1[year == .BY[[1]], vals])]

## Desired result, by simply iterating through each possible year
for (i in 1:4) {
  dat2[year==i, SUM := rowSums(.SD, na.rm=TRUE), 
    .SDcols=unlist(dat1[year == i, vals])]
}

dat2[]
#     year  a  b c  d SUM
#  1:    1  3  1 5  1   3
#  2:    2  1  3 3  1   4
#  3:    1  5  4 3 NA   5
#  4:    4  1 NA 4  5  10
#  5:    2  2  2 2 NA   4
#  6:    2 NA  3 3 NA   3
#  7:    4  2  3 2 NA   7
#  8:    1  2 NA 5  4   2
#  9:    2  3  3 5  1   6
# 10:    3 NA  4 2 NA   6

1 个答案:

答案 0 :(得分:6)

在我看来,您只是在dat1 by = .EACHI)中的每个值更新值(按引用)时寻找简单连接。无论哪种方式,rowSums都是在这个解决方案和你的尝试(由于矩阵转换)瓶颈。如果我是你,我会将所有NA转换为零并运行Reduce(`+`,...)而不是(不确定,如果你想要的话)更改原始数据中的值)

dat2[dat1, 
      SUM := rowSums(.SD[, unlist(i.vals), with = FALSE], na.rm = TRUE), 
      on = "year", 
     by = .EACHI]
dat2
#     year  a  b c  d SUM
#  1:    1  3  1 5  1   3
#  2:    2  1  3 3  1   4
#  3:    1  5  4 3 NA   5
#  4:    4  1 NA 4  5  10
#  5:    2  2  2 2 NA   4
#  6:    2 NA  3 3 NA   3
#  7:    4  2  3 2 NA   7
#  8:    1  2 NA 5  4   2
#  9:    2  3  3 5  1   6
# 10:    3 NA  4 2 NA   6

如果我是你,如上所述,我会将NA转换为零并使用Reduce代替

for(j in 2:ncol(dat2)) set(dat2, i = which(is.na(dat2[[j]])), j = j, value = 0L)
dat2[dat1,
       SUM := Reduce(`+`, .SD[, unlist(i.vals), with = FALSE]), 
       on = "year", 
    by = .EACHI]
dat2
#     year a b c d SUM
#  1:    1 3 1 5 1   3
#  2:    2 1 3 3 1   4
#  3:    1 5 4 3 0   5
#  4:    4 1 0 4 5  10
#  5:    2 2 2 2 0   4
#  6:    2 0 3 3 0   3
#  7:    4 2 3 2 0   7
#  8:    1 2 0 5 4   2
#  9:    2 3 3 5 1   6
# 10:    3 0 4 2 0   6