将函数应用于 R data.frame 中另一列的一系列值以使其保持矢量化的最佳方法是什么?
What is the best way to apply a function to a range of values from another column in R data.frame so it remains vectorized?
我在 R data.frame 中有几个列,我想根据一些已经存在的列的值范围创建一个新列。这些范围不是规则的,由写在前两列中的起始值和结束值决定。我希望计算保持矢量化。我不想要下面的 for 循环。
所需结果,通过 for 循环实现:
df = data.frame(start=c(2,1,4,4,1), end=c(3,3,5,4,2), values=c(1:5))
for (i in 1:nrow(df)) {
df[i, 'new'] <- sum(df[df[i, 'start']:df[i, 'end'], 'values'])
}
df
这里有一个选项map2
library(purrr)
library(dplyr)
df %>%
mutate(new = map2_dbl(start, end, ~ sum(values[.x:.y])))
-输出
# start end values new
#1 2 3 1 5
#2 1 3 2 6
#3 4 5 3 9
#4 4 4 4 4
#5 1 2 5 3
或 rowwise
df %>%
rowwise %>%
mutate(new =sum(.$values[start:end])) %>%
ungroup
-输出
# A tibble: 5 x 4
# start end values new
# <dbl> <dbl> <int> <int>
#1 2 3 1 5
#2 1 3 2 6
#3 4 5 3 9
#4 4 4 4 4
#5 1 2 5 3
或使用data.table
library(data.table)
setDT(df)[, new := sum(df$values[start:end]), seq_len(nrow(df))]
这是一个基数 R one-liner。
mapply(function(x1, x2, y){sum(y[x1:x2])}, df[['start']], df[['end']], MoreArgs = list(y = df[['values']]))
#[1] 5 6 9 4 3
还有一个。
sapply(seq_len(nrow(df)), function(i) sum(df[['values']][df[i, 'start']:df[i, 'end']]))
#[1] 5 6 9 4 3
我在 R data.frame 中有几个列,我想根据一些已经存在的列的值范围创建一个新列。这些范围不是规则的,由写在前两列中的起始值和结束值决定。我希望计算保持矢量化。我不想要下面的 for 循环。
所需结果,通过 for 循环实现:
df = data.frame(start=c(2,1,4,4,1), end=c(3,3,5,4,2), values=c(1:5))
for (i in 1:nrow(df)) {
df[i, 'new'] <- sum(df[df[i, 'start']:df[i, 'end'], 'values'])
}
df
这里有一个选项map2
library(purrr)
library(dplyr)
df %>%
mutate(new = map2_dbl(start, end, ~ sum(values[.x:.y])))
-输出
# start end values new
#1 2 3 1 5
#2 1 3 2 6
#3 4 5 3 9
#4 4 4 4 4
#5 1 2 5 3
或 rowwise
df %>%
rowwise %>%
mutate(new =sum(.$values[start:end])) %>%
ungroup
-输出
# A tibble: 5 x 4
# start end values new
# <dbl> <dbl> <int> <int>
#1 2 3 1 5
#2 1 3 2 6
#3 4 5 3 9
#4 4 4 4 4
#5 1 2 5 3
或使用data.table
library(data.table)
setDT(df)[, new := sum(df$values[start:end]), seq_len(nrow(df))]
这是一个基数 R one-liner。
mapply(function(x1, x2, y){sum(y[x1:x2])}, df[['start']], df[['end']], MoreArgs = list(y = df[['values']]))
#[1] 5 6 9 4 3
还有一个。
sapply(seq_len(nrow(df)), function(i) sum(df[['values']][df[i, 'start']:df[i, 'end']]))
#[1] 5 6 9 4 3