减去成对的列

时间:2017-11-23 13:48:50

标签: r data.table lapply

我有一对包含列的数据表:

set.seed(1) 
dt <- data.table(a1 = round(runif(3),1), a2 = round(runif(3),1), a3 =round(runif(3),1),
                 b1 = round(runif(3),1), b2 = round(runif(3),1), b3 =round(runif(3),1))

它看起来像这样:

 a1  a2  a3  b1  b2  b3
0.3 0.9 0.9 0.1 0.7 0.5
0.4 0.2 0.7 0.2 0.4 0.7
0.6 0.9 0.6 0.2 0.8 1.0

现在我想定义一个列的子集:

n<-2
cols <- paste0(rep(letters[1:2], n),rep(1:n,each=2))
"a1" "b1" "a2" "b2"

并为每对添加一个新列,区别为:

dt[,.(desired_ab1=c(0.2,0.2,0.4),desired_ab2=c(0.2,-0.2,0.1))]

desired_ab1 desired_ab2
        0.2         0.2
        0.2        -0.2
        0.4         0.1

我的目标与之前的帖子类似: Sum pairs of columns by group, 所以我尝试了以下内容:

myNames <- paste0("ab_", seq(n))
dt[, (myNames):=lapply(1:(ncol(.SD)/2), 
                       function(x) (.SD[2*(x-1)+1]-.SD[2*(x-1)+2])), .SDcols=cols][]

我不知道会发生什么。有人可以给我一个暗示失败的提示吗?

2 个答案:

答案 0 :(得分:2)

.SD也是data.table。您必须使用[[对列进行子集化(或使用[, j, with = FALSE])。所以这个:function(x) (.SD[[2*(x-1)+1]]-.SD[[2*(x-1)+2]])将适合你的情况。当您使用单个[时,它实际上是对.SD中的行而不是列进行分类(就像普通data.table所发生的那样)。

答案 1 :(得分:1)

访问列的算法看起来相当复杂,如果列的排序方式不同,则会很脆弱。

通过从宽到长形式重新整形数据,可以简化计算。长形式的数据是同时熔化两个测量柱的结果

cols <- c("a", "b")
melt(dt, measure.vars = patterns(cols), value.name = cols)]
   variable   a   b
1:        1 0.3 0.1
2:        1 0.4 0.2
3:        1 0.6 0.2
4:        2 0.9 0.7
5:        2 0.2 0.4
6:        2 0.9 0.8
7:        3 0.9 0.5
8:        3 0.7 0.7
9:        3 0.6 1.0

现在,只需要计算列ab之间的差异。最后,结果可以再次变换为宽形式(在过滤所需的对之后。

如果将所有部件组合在一起,则变为

# reshape from wide to long format with two measure variables
melt(dt, measure.vars = patterns(cols), value.name = cols)[
  # calculate differences
  , ab := a - b][
    # select pairs of interest
    variable %in% 1:2, 
    # reshape from long to wide format
    dcast(.SD, rowid(variable) ~ paste0("ab", variable), value.var = "ab")][
      # drop row id
      , -"variable"]
   ab1  ab2
1: 0.2  0.2
2: 0.2 -0.2
3: 0.4  0.1