使用滑动 window 对数据框中的计数求和
Summing the counts in a data frame using sliding window
我是 R 的新手。我在 R 中有一个数据框,如下所示
df <- data.frame(ID=c(rep("A1",10),rep("A2",13),rep("A3",12)),
Values=c(10,2,4,23,10,5,20,15,13,21,15,9,19,5,14,25,18,19,31,26,4,21,4,6,7,12,15,18,25,20,16,29,21,19,10))
对于每个 ID,我想对每 3 个位置的滑动 windows 列 "Values" 中的计数求和。以下数据框是 df
的摘录,其中仅包含对应于 A1
:
的记录
ID Values
A1 10
A1 2
A1 4
A1 23
A1 10
A1 5
A1 20
A1 15
A1 13
A1 21
我想一次取 3 个条目,求和并移至下 3 个条目。当滑动 windows 不能容纳 3 个条目时,我会跳过这些值。
例如,Window_1
从第一个值 (10
) 开始,而 window_2
从第二个值 (2
) 开始,window_3 从第三个值(4
)。
window_1 = [10+2+4] + [23+10+5] + [20+15+13] = 102
window_2 = [2+4+23] + [10+5+20] + [15+13+21] = 113
window_3 = [4+23+10] + [5+20+15] = 77
并在如下数据框中报告:
ID Window_1 Window_2 Window_3
A1 102 113 77
同样,我想对数据框 "df" 中每个 ID 列 Values
中的计数求和,并在 data.frmae 中报告如下:
ID window_1 window_2 window_3
A1 102 113 77
A2 206 195 161
A3 198 163 175
我试过下面的代码
sum_win_3=0
sum_win_2=0
sum_win_1=0
win_1_counts=0
win_2_counts=0
win_3_counts=0
for (i in seq(1,length(df$Values),3))
{
if((i+i+1+i+2) %% 3 == 0)
{
win_1_counts=df$Values[i]+df$Values[i+1]+df$Values[i+2]
win_1_counts[is.na(win_1_counts)]=0
#print(win_1_counts)
}
sum_win_1=sum_win_1+win_1_counts
}
#print(sum_win_1)
for (j in seq(2,length(df$Values),3))
{
if((j+j+1+j+2) %% 3 == 0)
{
win_2_counts=df$Values[j]+df$Values[j+1]+df$Values[j+2]
win_2_counts[is.na(win_2_counts)]=0
#print(win_2_counts)
}
sum_win_2=sum_win_2+win_2_counts
}
#print(sum_win_2)
for (k in seq(3,length(df$Values),3))
{
if((k+k+1+k+2) %% 3 == 0)
{
win_3_counts=df$Values[k]+df$Values[k+1]+df$Values[k+2]
win_3_counts[is.na(win_3_counts)]=0
#print(win_3_counts)
}
#sum_win_3=sum_win_3+win_3_counts
}
print(sum_win_3)
output=data.frame(ID=df[1],Window_1=sum_win_1,Window_2=sum_win_2,Window_3=sum_win_3)
以上代码通过将所有 ID 放在一起而不是分别处理每个 ID,对 window_1、windows_2 和 window_3 的计数求和。
请指导我以上述所需格式获取输出。
提前致谢
使用 data.table 包,我会按如下方式处理它:
library(data.table)
setDT(df)[, .(w1 = sum(Values[1:(3*(.N%/%3))]),
w2 = sum(Values[2:(3*((.N-1)%/%3)+1)]),
w3 = sum(Values[3:(3*((.N-2)%/%3)+2)]))
, by = ID]
给出:
ID w1 w2 w3
1: A1 102 113 77
2: A2 206 195 161
3: A3 198 163 175
或者为了避免重复(感谢@Cath):
setDT(df)[, lapply(1:3, function(i) {sum(Values[i:(3*((.N-i+1)%/%3)+(i-1))])})
, by = ID]
如果要重命名 V1、V2 和 V3 变量,可以在之后进行,但也可以:
cols <- c("w1","w2","w3")
setDT(df)[, (cols) := lapply(1:3, function(i) {sum(Values[i:(3*((.N-i+1)%/%3)+(i-1))])})
, by = ID]
这似乎有效:
library(zoo)
wins = function(x, w)
rollapply(x, width = w*((length(x)-seq(w)+1) %/% w), align = "left", sum)
aggregate(Values ~ ID, df, wins, 3)
# ID Values.1 Values.2 Values.3
# 1 A1 102 113 77
# 2 A2 206 195 161
# 3 A3 198 163 175
这是迄今为止唯一的滚动计算的答案,通常效率更高。
这可以使用 tapply
和 aggregate
来完成
sumf <- function(x1){
sum(tapply(x1,
(seq_along(x1) -1) %/%3,
function(x) ifelse(length(x) == 3, sum(x), 0)))
}
aggregate(Values ~ ID, data = df,
FUN = function(y){
cbind(sumf(y), sumf(y[-1]), sumf(y[-c(1,2)]))
})
# Group.1 x.1 x.2 x.3
#1 A1 102 113 77
#2 A2 206 195 161
#3 A3 198 163 175
这也可以使用 filter
来完成
sum.filter <- function(z) tapply(head(tail(as.numeric(
filter(z, c(1,1,1))),-1), -1),
0:(length(z)-3) %% 3 +1, sum)
aggregate(Values ~ ID, data = df, FUN = function(y){ cbind(sum.filter(y) )})
我是 R 的新手。我在 R 中有一个数据框,如下所示
df <- data.frame(ID=c(rep("A1",10),rep("A2",13),rep("A3",12)),
Values=c(10,2,4,23,10,5,20,15,13,21,15,9,19,5,14,25,18,19,31,26,4,21,4,6,7,12,15,18,25,20,16,29,21,19,10))
对于每个 ID,我想对每 3 个位置的滑动 windows 列 "Values" 中的计数求和。以下数据框是 df
的摘录,其中仅包含对应于 A1
:
ID Values
A1 10
A1 2
A1 4
A1 23
A1 10
A1 5
A1 20
A1 15
A1 13
A1 21
我想一次取 3 个条目,求和并移至下 3 个条目。当滑动 windows 不能容纳 3 个条目时,我会跳过这些值。
例如,Window_1
从第一个值 (10
) 开始,而 window_2
从第二个值 (2
) 开始,window_3 从第三个值(4
)。
window_1 = [10+2+4] + [23+10+5] + [20+15+13] = 102
window_2 = [2+4+23] + [10+5+20] + [15+13+21] = 113
window_3 = [4+23+10] + [5+20+15] = 77
并在如下数据框中报告:
ID Window_1 Window_2 Window_3
A1 102 113 77
同样,我想对数据框 "df" 中每个 ID 列 Values
中的计数求和,并在 data.frmae 中报告如下:
ID window_1 window_2 window_3
A1 102 113 77
A2 206 195 161
A3 198 163 175
我试过下面的代码
sum_win_3=0
sum_win_2=0
sum_win_1=0
win_1_counts=0
win_2_counts=0
win_3_counts=0
for (i in seq(1,length(df$Values),3))
{
if((i+i+1+i+2) %% 3 == 0)
{
win_1_counts=df$Values[i]+df$Values[i+1]+df$Values[i+2]
win_1_counts[is.na(win_1_counts)]=0
#print(win_1_counts)
}
sum_win_1=sum_win_1+win_1_counts
}
#print(sum_win_1)
for (j in seq(2,length(df$Values),3))
{
if((j+j+1+j+2) %% 3 == 0)
{
win_2_counts=df$Values[j]+df$Values[j+1]+df$Values[j+2]
win_2_counts[is.na(win_2_counts)]=0
#print(win_2_counts)
}
sum_win_2=sum_win_2+win_2_counts
}
#print(sum_win_2)
for (k in seq(3,length(df$Values),3))
{
if((k+k+1+k+2) %% 3 == 0)
{
win_3_counts=df$Values[k]+df$Values[k+1]+df$Values[k+2]
win_3_counts[is.na(win_3_counts)]=0
#print(win_3_counts)
}
#sum_win_3=sum_win_3+win_3_counts
}
print(sum_win_3)
output=data.frame(ID=df[1],Window_1=sum_win_1,Window_2=sum_win_2,Window_3=sum_win_3)
以上代码通过将所有 ID 放在一起而不是分别处理每个 ID,对 window_1、windows_2 和 window_3 的计数求和。
请指导我以上述所需格式获取输出。
提前致谢
使用 data.table 包,我会按如下方式处理它:
library(data.table)
setDT(df)[, .(w1 = sum(Values[1:(3*(.N%/%3))]),
w2 = sum(Values[2:(3*((.N-1)%/%3)+1)]),
w3 = sum(Values[3:(3*((.N-2)%/%3)+2)]))
, by = ID]
给出:
ID w1 w2 w3 1: A1 102 113 77 2: A2 206 195 161 3: A3 198 163 175
或者为了避免重复(感谢@Cath):
setDT(df)[, lapply(1:3, function(i) {sum(Values[i:(3*((.N-i+1)%/%3)+(i-1))])})
, by = ID]
如果要重命名 V1、V2 和 V3 变量,可以在之后进行,但也可以:
cols <- c("w1","w2","w3")
setDT(df)[, (cols) := lapply(1:3, function(i) {sum(Values[i:(3*((.N-i+1)%/%3)+(i-1))])})
, by = ID]
这似乎有效:
library(zoo)
wins = function(x, w)
rollapply(x, width = w*((length(x)-seq(w)+1) %/% w), align = "left", sum)
aggregate(Values ~ ID, df, wins, 3)
# ID Values.1 Values.2 Values.3
# 1 A1 102 113 77
# 2 A2 206 195 161
# 3 A3 198 163 175
这是迄今为止唯一的滚动计算的答案,通常效率更高。
这可以使用 tapply
和 aggregate
sumf <- function(x1){
sum(tapply(x1,
(seq_along(x1) -1) %/%3,
function(x) ifelse(length(x) == 3, sum(x), 0)))
}
aggregate(Values ~ ID, data = df,
FUN = function(y){
cbind(sumf(y), sumf(y[-1]), sumf(y[-c(1,2)]))
})
# Group.1 x.1 x.2 x.3
#1 A1 102 113 77
#2 A2 206 195 161
#3 A3 198 163 175
这也可以使用 filter
sum.filter <- function(z) tapply(head(tail(as.numeric(
filter(z, c(1,1,1))),-1), -1),
0:(length(z)-3) %% 3 +1, sum)
aggregate(Values ~ ID, data = df, FUN = function(y){ cbind(sum.filter(y) )})