gpt4 book ai didi

使用 dplyr 中的数字索引替换变量的部分内容。我需要创建索引列并使用 ifelse 吗?

转载 作者:行者123 更新时间:2023-12-02 19:14:17 25 4
gpt4 key购买 nike

dplyr 较长链的一个阶段函数中,我需要使用数字索引替换变量的一部分来指定要替换的元素。

我的数据如下所示:

df1 <- data.frame(grp = rep(1:2, each = 3),
a = 1:6,
b = rep(c(10, 20), each = 3))
df1
# grp a b
# 1 1 1 10
# 2 1 2 10
# 3 1 3 10
# 4 2 4 20
# 5 2 5 20
# 6 2 6 20

假设我们在每个组中希望替换变量 a 中的元素与 b 中的相应元素,在一个或多个位置。在这个简单的示例中,我使用单个索引( id ),但这可能是索引向量。首先,我将如何使用 ddply 来做到这一点:

library(plyr)
id <- 2
ddply(.data = df1, .variables = .(grp), function(x){
x$a[id] <- x$b[id]
x
})

# grp a b
# 1 1 1 10
# 2 1 10 10
# 3 1 3 10
# 4 2 4 20
# 5 2 20 20
# 6 2 6 20

dplyr我可以想出一些不同的方法来执行替换。 (1)使用do使用匿名函数,类似于 ddply 中使用的函数。 (2)使用mutate :使用数字索引连接一个向量,其中替换是“插入”的。这可能只对单个索引有效。 (3)使用mutate :创建索引向量并使用 ifelse 进行条件替换(例如,参见 herehereherehere )。

detach("package:plyr", unload = TRUE)
library(dplyr)

# (1)
fun_do <- function(df){
l <- df %.%
group_by(grp) %.%
do(function(dat){
dat$a[id] <- dat$b[id]
dat
})
do.call(rbind, l)
}

# (2)
fun_mut <- function(df){
df %.%
group_by(grp) %.%
mutate(
a = c(a[1:(id - 1)], b[id], a[(id + 1):length(a)])
)
}

# (3)
fun_mut_ifelse <- function(df){
df %.%
group_by(grp) %.%
mutate(
idx = 1:n(),
a = ifelse(idx %in% id, b, a)) %.%
select(-idx)
}

fun_do(df1)
fun_mut(df1)
fun_mut_ifelse(df1)

在数据集稍大的基准测试中,“拼图插入”速度最快,但同样,此方法可能只适合单个替换。而且看起来不太干净......

set.seed(123)
df2 <- data.frame(grp = rep(1:200, each = 3),
a = rnorm(600),
b = rnorm(600))

library(microbenchmark)
microbenchmark(fun_do(df2),
fun_mut(df2),
fun_mut_ifelse(df2),
times = 10)

# Unit: microseconds
# expr min lq median uq max neval
# fun_do(df2) 48443.075 49912.682 51356.631 53369.644 55108.769 10
# fun_mut(df2) 891.420 933.996 1019.906 1066.663 1155.235 10
# fun_mut_ifelse(df2) 2503.579 2667.798 2869.270 3027.407 3138.787 10

只是为了检查 do.call(rbind 的影响力参与do函数,尝试不使用它:

fun_do2 <- function(df){
df %.%
group_by(grp) %.%
do(function(dat){
dat$a[2] <- dat$b[2]
dat
})
}
fun_do2(df1)

然后是更大数据集上的新基准:

df3 <- data.frame(grp = rep(1:2000, each = 3),
a = rnorm(6000),
b = rnorm(6000))

microbenchmark(fun_do(df3),
fun_do2(df3),
fun_mut(df3),
fun_mut_ifelse(df3),
times = 10)

同样,简单的“插入”速度最快,而 do功能正在失势。在帮助文本中do被描述为另一个 dplyr 的“通用补充”功能。对我来说,这似乎是匿名函数的自然选择。然而,令我惊讶的是do速度慢得多,当非 dplyr 时也是如此。 rbind ing 部分被跳过。目前,do文档相当稀缺,所以我想知道我是否滥用了该功能,并且可能有更合适的(未记录的?)方法 do它?

当我搜索 dplyr help text 时,我没有找到任何索引。或vignette 。所以现在我想知道:
还有其他的dplyr使用我忽略的数字索引替换变量部分的方法?具体来说就是结合ifelse创建索引列该怎么走,或者有没有更直接的a[i] <- b[i] -类似的替代品?

<小时/>

编辑以下来自 @G.Grothendieck 的评论(谢谢!)。已添加replace替代方案(?[ 中“另请参阅”的候选者)。

fun_replace <- function(df){
df %.%
group_by(grp) %.%
mutate(
a = replace(a, id, b[id]))
}
fun_replace(df1)

microbenchmark(fun_do(df3),
fun_do2(df3),
fun_mut(df3),
fun_mut_ifelse(df3),
fun_replace(df3),
times = 10)

# Unit: milliseconds
# expr min lq median uq max neval
# fun_do(df3) 685.154605 693.327160 706.055271 712.180410 851.757790 10
# fun_do2(df3) 291.787455 294.047747 297.753888 299.624730 302.368554 10
# fun_mut(df3) 5.736640 5.883753 6.206679 6.353222 7.381871 10
# fun_mut_ifelse(df3) 24.321894 26.091049 29.361553 32.649924 52.981525 10
# fun_replace(df3) 4.616757 4.748665 4.981689 5.279716 5.911503 10

replace函数速度最快,而且肯定比 fun_mut 更容易使用当有多个索引时。

编辑 2 fun_dofun_do2不再适用于 dplyr 0.2 ; Error: Results are not data frames at positions:

最佳答案

这是一种更快的就地修改方法:

library(data.table)

# select rows we want, then assign b to a for those rows, in place
fun_dt = function(dt) dt[dt[, .I[id], by = grp]$V1, a := b]

# benchmark
df4 = data.frame(grp = rep(1:20000, each = 3),
a = rnorm(60000),
b = rnorm(60000))
dt4 = as.data.table(df4)

library(microbenchmark)

# using fastest function from OP
microbenchmark(fun_dt(dt4), fun_replace(df4), times = 10)
#Unit: milliseconds
# expr min lq median uq max neval
# fun_dt(dt4) 15.62325 17.22828 18.42445 20.83768 21.25371 10
# fun_replace(df4) 99.03505 107.31529 116.74830 188.89134 286.50199 10

关于使用 dplyr 中的数字索引替换变量的部分内容。我需要创建索引列并使用 ifelse 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23642811/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com