在具有多个元素的数据表中执行逐行操作

Perform row-wise operation in datatable with multiple elements

我有以下数据table:

library(data.table)
set.seed(1)
DT <- data.table(ind=1:100,x=sample(100),y=sample(100),group=c(rep("A",50),rep("B",50)))

现在我遇到的问题是我需要获取“x”列中的每个值(即每个给定的 ID),并将“y”列中的所有现有值添加到它。我还需要按“组”列单独进行。假设我们从 ID = 1 开始。此元素的值为:x_1 = 68 和 y_1 = 76。我们还看到 y_2 = 39,y_3 = 24等。所以我想计算的是 x_1 + y_1、x_1 + y2、x_1 + y_3 等的总和。但不仅限于x_1,还有 x_2、x_3 等。所以对于 x_2,它看起来像:x_2 + y_1、x_2 + y_2, x_2 + y_3, 等等。这也应该按“组”列单独完成(在这方面,数据集应该简单地按组拆分)。

编辑:仅针对 X_1 和 A 组执行此操作的示例代码:

current_X <- DT[1,x] # not needed, just to illustrate
vector_current_X <- rep(DT[1,x],nrow(DT[group == "A"]))
DT[group == "A",copy_current_X := vector_current_X]
DT[,sum_current_X_Y := copy_current_X + y]
DT

这种方法的一个明显问题是,如果它应用于所有 x,那么最终的 DT 中会添加很多列。所以我不确定这是否是最好的方法。最后,我只是在寻找每个元素 y 和每个组的最低总和(每个元素 x)。

我知道如何按组进行运算,我也知道lapply函数。问题是,根据我的理解,我需要包含一个按行循环。接下来,结果的结构将不同于原始数据 table,因为我们有很多额外的观察结果。我之前看到您可以将列表保存在 data.table 中,但我不确定这是否是最佳方法。我的数据集要大得多,所以效率很重要。

感谢您提供解决此问题的任何提示。

你可以这样做:

DT[, .(.BY$x+DT[group==.BY$group,y]), by=.(x,group)]

每个 x returns N 行,其中 N 是 x 所在组的大小。我们利用特殊的 (.BY),它在使用 by 时在 j 中可用。基本上,.BY 是一个命名列表,包含分组变量的值。在这里,我将 x (.BY$x) 的值添加到 DT 子集中的 y 值向量,其中 group 等于当前组值(.BY$group)

输出:

          x  group    V1
      <int> <char> <int>
   1:    68      A   144
   2:    68      A   107
   3:    68      A    92
   4:    68      A   121
   5:    68      A   160
  ---                   
4996:     4      B    25
4997:     4      B    66
4998:     4      B    83
4999:     4      B    27
5000:     4      B    68

您也可以通过连接完成此操作:

DT[,!c("y")][DT[, .(y,group)], on=.(group), allow.cartesian=T][, total:=x+y][order(ind)]

输出:

        ind     x  group     y total
      <int> <int> <char> <int> <int>
   1:     1    68      A    76   144
   2:     1    68      A    39   107
   3:     1    68      A    24    92
   4:     1    68      A    53   121
   5:     1    68      A    92   160
  ---                               
4996:   100     4      B    21    25
4997:   100     4      B    62    66
4998:   100     4      B    79    83
4999:   100     4      B    23    27
5000:   100     4      B    64    68

如果我理解正确,请求的结果需要一个 cross join,其中 x 的每个元素与 y 的每个元素组合(在每个group).

这可以使用 CJ() 函数轻松完成:

DT[, CJ(x, y, sorted = FALSE), by = group][, sum_x_y := x + y][]
      group  x  y sum_x_y
   1:     A 68 76     144
   2:     A 68 39     107
   3:     A 68 24      92
   4:     A 68 53     121
   5:     A 68 92     160
  ---                    
4996:     B  4 21      25
4997:     B  4 62      66
4998:     B  4 79      83
4999:     B  4 23      27
5000:     B  4 64      68