我有一个值如下所示的数据表:
Score ID
1.2 1
2.4 1
1.1 1
1.9 1
2.4 2
3.5 2
2.2 2
1.1 3
1.1 3
1.7 3
3.1 3
2.2 3
Run Code Online (Sandbox Code Playgroud)
我真正需要的是在单独的列中计算每个ID的更改分数,使其看起来像这样:
Score ID Changes
1.2 1
2.4 1 1.2
1.1 1 -1.3
1.9 1 0.8
2.4 2
3.5 2 1.1
2.2 2 -1.3
1.1 3
1.1 3 0
1.7 3 0.6
3.1 3 1.4
2.2 3 -0.9
Run Code Online (Sandbox Code Playgroud)
注意每个"变化"是如何通过取得前一个分数并从当前分数中减去来计算的:例如,在第一个变化中,你得到1.2乘1.2 = 2.4(当前分数) - 1.2(前一个分数)
问题是这些分数只能仅与ID范围内的分数有关.你不能只是迭代并取得分数的差异.我该怎么做?我可以使用什么逻辑来测试在同一ID中包含"更改"?我熟悉R或python(或BASH)来做到这一点.
在R可能:
transform(
df,
Changes = ave(df$Score, df$ID, FUN = function(x) c(NA, diff(x)))
)
# Score ID Changes
# 1 1.2 1 NA
# 2 2.4 1 1.2
# 3 1.1 1 -1.3
# 4 1.9 1 0.8
# 5 2.4 2 NA
# 6 3.5 2 1.1
# 7 2.2 2 -1.3
# 8 1.1 3 NA
# 9 1.1 3 0.0
# 10 1.7 3 0.6
# 11 3.1 3 1.4
# 12 2.2 3 -0.9
Run Code Online (Sandbox Code Playgroud)
df 保存您的原始数据框.
关于@Bulat的评论:
id<- c(1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3)
score <- c(1.2, 2.4, 1.1, 1.9, 2.4, 3.5, 2.2, 1.1, 1.1, 1.7, 3.1, 2.2)
library(data.table)
df <- data.frame(id, score)
dt = data.table(id, score)
library(microbenchmark)
microbenchmark(
dt = dt[ , diff := c(NA, diff(score)), by = id],
df = df$diff <- ave(df$score, df$id, FUN = function(x) c(NA, diff(x))),
times = 1000
)
# Unit: microseconds
# expr min lq mean median uq max neval cld
# dt 1121.931 1225.2660 1342.4626 1269.5530 1321.2210 5908.411 1000 b
# df 397.175 488.2085 547.8198 525.8175 586.7995 7784.270 1000 a
Run Code Online (Sandbox Code Playgroud)