使用 dplyr 有条件地替换列中的值

Posted

技术标签:

【中文标题】使用 dplyr 有条件地替换列中的值【英文标题】:Using dplyr to conditionally replace values in a column 【发布时间】:2016-06-07 05:33:57 【问题描述】:

我有一个示例数据集,其中有一列有点像这样:

Candy
Sanitizer
Candy
Water
Cake
Candy
Ice Cream
Gum
Candy
Coffee

我想做的只是将它替换为两个因素 - “糖果”和“非糖果”。我可以用 Python/Pandas 做到这一点,但似乎无法找出基于 dplyr 的解决方案。谢谢!

【问题讨论】:

【参考方案1】:

dplyrtidyr

dat %>% 
    mutate(var = replace(var, var != "Candy", "Not Candy"))

ifelse 方法快得多。 创建初始数据框的代码如下:

library(dplyr)
dat <- as_data_frame(c("Candy","Sanitizer","Candy","Water","Cake","Candy","Ice Cream","Gum","Candy","Coffee"))
colnames(dat) <- "var"

【讨论】:

【参考方案2】:

假设你的数据框是dat,你的列是var

dat = dat %>% mutate(candy.flag = factor(ifelse(var == "Candy", "Candy", "Non-Candy")))

【讨论】:

@RichardScriven 的方法(我的 cmets)严格控制了这一点【参考方案3】:

dplyr 使用case_when 的另一种解决方案:

dat %>%
    mutate(var = case_when(var == 'Candy' ~ 'Candy',
                           TRUE ~ 'Non-Candy'))

case_when 的语法是 condition ~ value to replace。文档here。

可能比使用replace 的解决方案效率低,但优点是可以在单个命令中执行多个替换,同时仍然具有良好的可读性,即替换以产生三个级别:

dat %>%
    mutate(var = case_when(var == 'Candy' ~ 'Candy',
                           var == 'Water' ~ 'Water',
                           TRUE ~ 'Neither-Water-Nor-Candy'))

【讨论】:

【参考方案4】:

不需要dplyr。假设var 已经作为一个因子存储:

non_c <- setdiff(levels(dat$var), "Candy")

levels(dat$var) <- list(Candy = "Candy", "Non-Candy" = non_c)

?levels

这比ifelse 方法(bound to be slow)更高效

library(microbenchmark)
set.seed(01239)
smp <- data.frame(sample(dat$var, 1e6, TRUE))
names(smp) <- "var"

times <- 
  replicate(50, 
            cop <- smp
            s <- get_nanotime()
            levs <- setdiff(levels(cop$var), "Candy")
            levels(cop$var) <- list(Candy = "Candy", "Non-Candy" = levs)
            d1 <- get_nanotime() - s
            cop <- smp
            s <- get_nanotime()
            cop = cop %>%
              mutate(candy.flag = factor(ifelse(var == "Candy", 
                                                "Candy", "Non-Candy")))
            d2 <- get_nanotime() - s
            cop <- smp
            s <- get_nanotime()
            cop$var <- 
              factor(cop$var == "Candy", labels = c("Non-Candy", "Candy"))
            d3 <- get_nanotime() - s
            c(levels = d1, dplyr = d2, direct = d3))

(x <- apply(times, 1, median))[2]/x[1]
#    dplyr   direct 
# 8.894303 4.962791 

也就是说,这快了 9 倍。

【讨论】:

或者factor(dat$var == "Candy", labels = c("Non-Candy", "Candy")),但我认为重置关卡是一个不错的选择。【参考方案5】:

当你只需要两个值时,我认为一个简单的 ifelse() 会更漂亮。

此外,嵌入式 ifelses 可以模拟与 PhJ 提出的 case_when 解决方案相同的情况(不过我喜欢他的可读性)!

dat %>%
    mutate(
        var = ifelse(var == "Candy", "Candy", "Non-Candy")
    )

【讨论】:

以上是关于使用 dplyr 有条件地替换列中的值的主要内容,如果未能解决你的问题,请参考以下文章

tidyverse 和 dplyr:根据其他列有条件地替换列中的值

R:dplyr 有条件地汇总并重新编码列中的值

用 D 列中的值有条件地替换 A、B、C 列中的值

使用 R 中的条件替换列中的值

R中的条件数据框突变与magrittr和dplyr

使用python替换电源查询列中的值? [关闭]