R:数据表中按行的条件总和
R: Conditional Sum by Row in DataTable
我有一个非常大的数据集(数百万行,我需要循环数千次),在循环期间我必须做一个条件求和,这似乎需要很长时间。有没有办法提高效率?
数据table格式如下:
DT <- data.table('A' = c(1,1,1,2,2,3,3,3,3,4),
'B' = c(500,510,540,500,540,500,510,519,540,500),
'C' = c(10,20,10,20,10,50,20,50,20,10))
一个
B
C
1
500
10
1
510
20
1
540
10
2
500
20
2
540
10
3
500
50
3
510
20
3
519
50
3
540
20
4
500
10
我需要 C 列(在新列 D 中)的总和,A == A,并且 B >= B & B < B + 20(按行)。所以输出 table 将如下所示:
一个
B
C
D
1
500
10
30
1
510
20
30
1
540
10
10
2
500
20
20
2
540
10
10
3
500
50
120
3
510
20
120
3
519
50
120
3
540
20
20
4
500
10
10
我目前使用的代码:
DT[,D:= sum(DT$C[A == DT$A & ((B >= DT$B) & (B < DT$B + 20))]), by=c('A', 'B')]
这需要很长时间才能真正 运行,并且给了我错误的答案。我得到的输出如下所示:
一个
B
C
D
1
500
10
10
1
510
20
30
1
540
10
10
2
500
20
20
2
540
10
10
3
500
50
50
3
510
20
70
3
519
50
120
3
540
20
20
4
500
10
10
(即 D 似乎只是累积增加)。
我不太关心累积的事情,更关心速度。最终我想要得到的是 A 的 C 的最大总和,前提是 B 在彼此的 20 以内。我真的很感激任何帮助!提前致谢。
# logic for B
DT[, g := B >= shift(B) & B < shift(B, 1) + 20, by = A]
# creating index column
DT[, gi := !g]
DT[is.na(gi), gi := T]
DT[, gi := cumsum(gi)]
DT[, D := sum(C), by = gi] # summing by new groups
DT
# A B C g gi D
# 1: 1 500 10 NA 1 30
# 2: 1 510 20 TRUE 1 30
# 3: 1 540 10 FALSE 2 10
# 4: 2 500 20 NA 3 20
# 5: 2 540 10 FALSE 4 10
# 6: 3 500 50 NA 5 120
# 7: 3 510 20 TRUE 5 120
# 8: 3 519 50 TRUE 5 120
# 9: 3 540 20 FALSE 6 20
# 10: 4 500 10 NA 7 10
您可能需要调整 B
的逻辑,因为问题中的所有边缘情况都不清楚...如果对于一个 A
值,我们有 c(30, 40, 50, 60)
,所有这些行中的一组?
如果我没理解错的话,这可以通过非equi自连接来解决:
DT[, Bp20 := B + 20][
DT, on = .(A, B >= B, B < Bp20), mult = "last"][
, .(B, C = i.C, D = sum(i.C)), by = .(A, Bp20)][
, Bp20 := NULL][]
A B C D
1: 1 500 10 30
2: 1 510 20 30
3: 1 540 10 10
4: 2 500 20 20
5: 2 540 10 10
6: 3 500 50 120
7: 3 510 20 120
8: 3 519 50 120
9: 3 540 20 20
10: 4 500 10 10
我有一个非常大的数据集(数百万行,我需要循环数千次),在循环期间我必须做一个条件求和,这似乎需要很长时间。有没有办法提高效率?
数据table格式如下:
DT <- data.table('A' = c(1,1,1,2,2,3,3,3,3,4),
'B' = c(500,510,540,500,540,500,510,519,540,500),
'C' = c(10,20,10,20,10,50,20,50,20,10))
一个 | B | C |
---|---|---|
1 | 500 | 10 |
1 | 510 | 20 |
1 | 540 | 10 |
2 | 500 | 20 |
2 | 540 | 10 |
3 | 500 | 50 |
3 | 510 | 20 |
3 | 519 | 50 |
3 | 540 | 20 |
4 | 500 | 10 |
我需要 C 列(在新列 D 中)的总和,A == A,并且 B >= B & B < B + 20(按行)。所以输出 table 将如下所示:
一个 | B | C | D |
---|---|---|---|
1 | 500 | 10 | 30 |
1 | 510 | 20 | 30 |
1 | 540 | 10 | 10 |
2 | 500 | 20 | 20 |
2 | 540 | 10 | 10 |
3 | 500 | 50 | 120 |
3 | 510 | 20 | 120 |
3 | 519 | 50 | 120 |
3 | 540 | 20 | 20 |
4 | 500 | 10 | 10 |
我目前使用的代码:
DT[,D:= sum(DT$C[A == DT$A & ((B >= DT$B) & (B < DT$B + 20))]), by=c('A', 'B')]
这需要很长时间才能真正 运行,并且给了我错误的答案。我得到的输出如下所示:
一个 | B | C | D |
---|---|---|---|
1 | 500 | 10 | 10 |
1 | 510 | 20 | 30 |
1 | 540 | 10 | 10 |
2 | 500 | 20 | 20 |
2 | 540 | 10 | 10 |
3 | 500 | 50 | 50 |
3 | 510 | 20 | 70 |
3 | 519 | 50 | 120 |
3 | 540 | 20 | 20 |
4 | 500 | 10 | 10 |
(即 D 似乎只是累积增加)。
我不太关心累积的事情,更关心速度。最终我想要得到的是 A 的 C 的最大总和,前提是 B 在彼此的 20 以内。我真的很感激任何帮助!提前致谢。
# logic for B
DT[, g := B >= shift(B) & B < shift(B, 1) + 20, by = A]
# creating index column
DT[, gi := !g]
DT[is.na(gi), gi := T]
DT[, gi := cumsum(gi)]
DT[, D := sum(C), by = gi] # summing by new groups
DT
# A B C g gi D
# 1: 1 500 10 NA 1 30
# 2: 1 510 20 TRUE 1 30
# 3: 1 540 10 FALSE 2 10
# 4: 2 500 20 NA 3 20
# 5: 2 540 10 FALSE 4 10
# 6: 3 500 50 NA 5 120
# 7: 3 510 20 TRUE 5 120
# 8: 3 519 50 TRUE 5 120
# 9: 3 540 20 FALSE 6 20
# 10: 4 500 10 NA 7 10
您可能需要调整 B
的逻辑,因为问题中的所有边缘情况都不清楚...如果对于一个 A
值,我们有 c(30, 40, 50, 60)
,所有这些行中的一组?
如果我没理解错的话,这可以通过非equi自连接来解决:
DT[, Bp20 := B + 20][
DT, on = .(A, B >= B, B < Bp20), mult = "last"][
, .(B, C = i.C, D = sum(i.C)), by = .(A, Bp20)][
, Bp20 := NULL][]
A B C D 1: 1 500 10 30 2: 1 510 20 30 3: 1 540 10 10 4: 2 500 20 20 5: 2 540 10 10 6: 3 500 50 120 7: 3 510 20 120 8: 3 519 50 120 9: 3 540 20 20 10: 4 500 10 10