gpt4 book ai didi

r - 使用 `dplyr` 创建仅为数据子集定义的新变量

转载 作者:行者123 更新时间:2023-12-04 06:33:51 25 4
gpt4 key购买 nike

考虑这个示例数据:

set.seed(1234567)
mydf <- data.frame(var1 = runif(10), var2 = c(runif(5), rep(NA, 5)))

这个示例向量化函数,不幸的是,只要参数之一是 NA 就会触发错误
myfn <- function(x, y){
sum(x:y)
}
myfn <- Vectorize(myfn)

现在,在 dplyr 链的中间,我需要使用 myfn 创建一个新变量。这个新的 var ( var3 ) 仅在 var1var2 不是 NA 时定义。

所以类似情况最常见的解决方案是使用 ifelse 。像这样的东西。
mydf %>%
mutate(var3 = ifelse(
test = is.na(var2),
yes = NA,
no = myfn(var1, var2)))

但这在我的情况下不起作用,因为 ifelse 无论如何实际上将整个向量 var1var2 传递给 myfn 而不仅仅是当 testFALSE 时的子向量。这一切都会中断,因为 myfn 每当收到 NA 时就会中断。

那么,对此有什么巧妙的 dplyr 解决方案呢? (我可以在不使用 dplyr 的情况下想到很多解决方案,但我只对 dplyr 友好的解决方案感兴趣)

我突然想到 filter 可以提供帮助,并且确实可以使用非常易读的 dplyr y 代码
mydf %>%
filter(!is.na(var2)) %>%
mutate(var3 = myfn(var1, var2))

var1 var2 var3
1 0.56226084 0.62588794 0.56226084
2 0.72649850 0.24145251 0.72649850
3 0.91524985 0.03768974 0.91524985
4 0.02969437 0.51659297 0.02969437
5 0.76750970 0.81845788 0.76750970

但是随后我必须将其保存在一个临时对象中,然后使用 var3 在原始数据中创建 NA 并将所有数据放回相同的数据中(因为据我所知,某些具有 suggestedunfilter 不存在, ..., 然而)。

所以只是为了说明我想要的输出,这段代码产生了它(根本不使用 dplyr):
mydf$var3 <- NA
index <- !is.na(mydf$var2)
mydf$var3[index] <- myfn(mydf$var1[index], mydf$var2[index])
mydf

> mydf
var1 var2 var3
1 0.56226084 0.62588794 0.56226084
2 0.72649850 0.24145251 0.72649850
3 0.91524985 0.03768974 0.91524985
4 0.02969437 0.51659297 0.02969437
5 0.76750970 0.81845788 0.76750970
6 0.48005398 NA NA
7 0.08837960 NA NA
8 0.86294587 NA NA
9 0.49660306 NA NA
10 0.85350403 NA NA

编辑:

我接受了@krlmlr 的解决方案,因为它正是我所寻找的:清晰、易读且简洁的代码,可以毫不费力地集成到 dplyr 链中。对于我的示例,此解决方案如下所示。
mydf %>%
rowwise %>%
mutate(var3 = if(is.na(var2)) NA else myfn(var1, var2))

然而,正如@krlmlr 在他的回答中指出的那样,逐行操作在性能方面是有代价的。对于小数据集或单次操作可能意义不大,但对于较大的数据集或重复操作数百万次,则可能相当可观。为了说明这一点,这里是使用 microbenchmark 和三个解决方案(base、dyplr 和 data.table)的比较,它们应用于更大的数据集(不是大量的或任何东西,只有 1000 行,而不是我原来的例子中的 10 行)。
library(data.table)
library(dplyr)

set.seed(1234567)
mydf <- data.frame(var1 = runif(1000), var2 = c(runif(500), rep(NA, 500)))

myfn <- function(x, y){
sum(x:y)
}
myfn <- Vectorize(myfn)

using_base <- function(){
mydf$var3 <- NA
index <- !is.na(mydf$var2)
mydf$var3[index] <- myfn(mydf$var1[index], mydf$var2[index])
}

using_dplyr <- function(){
mydf <- mydf %>%
rowwise %>%
mutate(var3 = if(is.na(var2)) NA else myfn(var1, var2))
}

using_datatable <- function(){
setDT(mydf)[!is.na(var2), var3 := myfn(var1, var2)]
}

library(microbenchmark)
mbm <- microbenchmark(
using_base(), using_dplyr(), using_datatable(),
times = 1000)

library(ggplot2)
autoplot(mbm)

enter image description here

如您所见,使用 dplyrrowwise 解决方案比其 basedata.table 竞争对手慢得多。

最佳答案

如果您的原始函数未矢量化并且无法处理某些输入,则使用 Vectorize() 对其进行矢量化没有性能优势。 .相反,使用 dplyr::rowwise()逐行操作:

iris %>%
rowwise %>%
mutate(x = if (Sepal.Length < 5) 1 else NA) %>%
ungroup

请注意,使用 if这里是完全安全的,因为输入的长度为 1。

关于r - 使用 `dplyr` 创建仅为数据子集定义的新变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36392134/

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