如何在data.table中对列的子集应用函数,同时按其他列进行分组?

时间:2018-06-16 15:54:23

标签: r data.table

举一个例子来看看这个data.table:

foo <- data.table(id = letters[1:5], group = c('a', 'a', 'a', 'b', 'b'), x=1:5, y = (-4):0, z = 2:6)

   id group x  y z
1:  a     a 1 -4 2
2:  b     a 2 -3 3
3:  c     a 3 -2 4
4:  d     b 4 -1 5
5:  e     b 5  0 6

我想按组归一化列向量x,y和z(x/sum(x)),即按列group定义的那些组。我还想保留所有其他剩余的列。

我正在尝试这些方面:

foo[, lapply(.SD[, -1], function(x) {x/sum(x)}), by = group]

   group         x         y         z
1:     a 0.1666667 0.4444444 0.2222222
2:     a 0.3333333 0.3333333 0.3333333
3:     a 0.5000000 0.2222222 0.4444444
4:     b 0.4444444 1.0000000 0.4545455
5:     b 0.5555556 0.0000000 0.5454545

但由于id而删除了列.SD[, -1],但是我不知道如何只应用数字列而不删除它...

1 个答案:

答案 0 :(得分:3)

我们可以指定.SDcols并将输出分配回相同的列。

foo[, names(foo)[3:5]  := lapply(.SD, function(x) x/sum(x)),
                 by = group, .SDcols = x:z]

请注意,输出和输入的类型应相同。如果输入为integer且输出为numeric则会出现问题。因此,首先将class更改为numeric,然后执行作业

nm1 <- names(foo)[3:5]
#or programmatically based on checking whether column is numeric
#nm1 <- foo[, which(unlist(lapply(.SD, is.numeric)))]
foo[, (nm1) := lapply(.SD, as.numeric), .SDcols = nm1
      ][, (nm1) := lapply(.SD, function(x) x/sum(x)), 
                by = group, .SDcols = nm1][]

上述tidyverse方法

library(dplyr)
foo %>% 
     group_by(group) %>%
     mutate_if(is.numeric, funs(./sum(.)))