我知道这里有几个类似的问题,但是似乎没有一个问题可以解决我遇到的确切问题。
set.seed(4) df = data.frame( Key = c("A", "B", "A", "D", "A"), Val1 = rnorm(5), Val2 = runif(5), Val3 = 1:5 )
我想将其中Key ==“ A”的行的value列的值清零。通过a引用列名grep
:
cols = grep("Val", names(df), value = TRUE)
通常,在这种情况下,要实现我想要的功能,我将使用data.table
以下命令:
library(data.table) df = as.data.table(df) df[Key == "A", (cols) := 0]
所需的输出是这样的:
Key Val1 Val2 Val3 1 A 0.000000 0.00000000 0 2 B -1.383814 0.55925762 2 3 A 0.000000 0.00000000 0 4 D 1.437151 0.05632773 4 5 A 0.000000 0.00000000 0
但是这一次我需要dplyr
在每个人都在使用的团队项目中使用它。我刚刚提供的数据是说明性的,我的真实数据是> 5m行,其中有16个值列需要更新。我唯一能想到的解决方案是这样使用mutate_at
:
df %>% mutate_at(.vars = vars(cols), .funs = function(x) ifelse(df$Key == "A", 0, x))
但是,这对我的真实数据而言似乎极其缓慢。我希望找到一个更优雅,更重要的是更快的解决方案。
我已经尝试了许多组合使用using map
,unquoting using !!
,using get
和:=
(烦人的可以被:=
in data.table掩盖)等),但是我认为我对这些工作原理的理解还不足以构成一个有效的解决方案。
使用此dplyr命令,
df %>% mutate_at(.vars = vars(cols), .funs = function(x) ifelse(df$Key == "A", 0, x))
您实际上在评估语句df $ Key ==“ A”,n次,其中n =您拥有的列数。
一种解决方法是预定义要更改的行:
idx = which(DF$Key=="A") DF %>% mutate_at(.vars = vars(cols), .funs = function(x){x[idx]=0;x})
由@IceCreamToucan正确指出的一种更干净,更好的方法(请参见下面的注释)是使用replace函数,同时向其传递额外的参数:
DF %>% mutate_at(.vars = vars(cols), replace, DF$Key == 'A', 0)
我们可以对所有这些方法进行测试,我认为dplyr和data.table是可比的。
#simulate data set.seed(100) Key = sample(LETTERS[1:3],1000000,replace=TRUE) DF = as.data.frame(data.frame(Key,matrix(runif(1000000*10),nrow=1000000,ncol=10))) DT = as.data.table(DF) cols = grep("[35789]", names(DF), value = TRUE) #long method system.time(DF %>% mutate_at(.vars = vars(cols), .funs = function(x) ifelse(DF$Key == "A", 0, x))) user system elapsed 0.121 0.035 0.156 #old base R way system.time(DF[idx,cols] <- 0) user system elapsed 0.085 0.021 0.106 #dplyr # define function func = function(){ idx = which(DF$Key=="A") DF %>% mutate_at(.vars = vars(cols), .funs = function(x){x[idx]=0;x}) } system.time(func()) user system elapsed 0.020 0.006 0.026 #data.table system.time(DT[Key=="A", (cols) := 0]) user system elapsed 0.012 0.001 0.013 #replace with dplyr system.time(DF %>% mutate_at(.vars = vars(cols), replace, DF$Key == 'A', 0)) user system elapsed 0.007 0.001 0.008