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

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

Candy
Sanitizer
Candy
Water
Cake
Candy
Ice Cream
Gum
Candy
Coffee

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

【问题讨论】:

    标签: r 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")
            )
        

        【讨论】:

          猜你喜欢
          • 2017-09-20
          • 1970-01-01
          • 2020-11-17
          • 2018-10-18
          • 2020-04-03
          • 2014-08-23
          • 2016-11-17
          • 1970-01-01
          相关资源
          最近更新 更多