r - 在调节特定行的同时动态改变多列

标签 r dplyr data.table

我知道这里有几个类似的问题,但它们似乎都没有解决我遇到的确切问题。

set.seed(4)
df = data.frame(
  Key = c("A", "B", "A", "D", "A"),
  Val1 = rnorm(5),
  Val2 = runif(5),
  Val3 = 1:5
)

我想将 Key == "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))

但是,这在我的真实数据上似乎非常慢。我希望找到一个更优雅,更重要的是更快的解决方案。

我使用 map 尝试了很多组合, 使用 !! 取消引用, 使用 get:= (烦人地可能会被 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 正确指出的一种更干净、更好的方法(见下面的评论)是使用函数替换,同时向它传递额外的参数:
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

关于r - 在调节特定行的同时动态改变多列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58917643/

相关文章:

r - 从数值向量中提取多个范围

r - 将数据框转换为列表,具有应用系列的功能

r - 如何使用saveRDS(...,refhook =)参数?

r - dplyr summarise_each 标准误差函数

python - 创建一个基于 Python 中的另一列递增的列

r - 星星包 : how to define additional dimensions based on an attribute (filename)?

r - if_else 或替代的向量输出

r - 在 R 中,发现与另一个数据框中的行部分匹配的行

r - 按组计算具有某些值的数据表中的行

r - 在 r 中使用带有替换函数的 data.table