【问题标题】:How to simplify a case_when() inside a mutate()如何在 mutate() 中简化 case_when()
【发布时间】:2019-11-06 11:38:12
【问题描述】:

我有一个数据框,我想添加一列。为此,我使用 dplyr::mutate。但是,我要添加的列的值取决于其他列的值。我使用 case_when() 并解决了问题,但是如果有很多情况,代码编写起来不舒服(我在下面显示一个示例),所以我想知道是否有另一个选项(可能是循环)来简化这个。

以下代码有效:

NewTable <- Table %>% 
  dplyr::mutate(ColumnB = case_when(
               ColumnA=="2000" ~ 0,
               ColumnA=="2001" ~ 4,
               ColumnA=="2002" ~ 8,
               ColumnA=="2003" ~ 12,
               ColumnA=="2004" ~ 16,
               ColumnA=="2005" ~ 20,
               ColumnA=="2006" ~ 24,
               ColumnA=="2007" ~ 28,
               ColumnA=="2008" ~ 32,
               ColumnA=="2009" ~ 36,
               ColumnA=="2010" ~ 40,
               ColumnA=="2011" ~ 44))

我该如何改进它?非常感谢。

【问题讨论】:

  • 可能是查找表,see here,可能重复。
  • 由于没有简单、直接的函数/逻辑可以将 a 映射到 0、b 到 4、...、l 到 345,因此您必须在某处指定它们的映射。当然,您可以编写一个 lokk-up 表格,将映射包装在一个函数中,等等,但这不会减少整体代码。还是我错过了你的愿望?
  • @wusel 假设映射更简单:a 到 0,b 到 2,c 到 4,d 到 6,...我可以简化它吗?我的问题是我需要添加更多分配,并且假设要在我的代码中添加很多行。
  • 这会将 2000 映射到 0,将 2001 映射到 4,等等。4 * (as.numeric(as.character(ColumnA)) - 2000)。如果ColumnA 已经是字符而不是因子,则可以省略as.character。请在您的帖子中发布可重复的输入。请参阅r 顶部的说明。
  • 你在计算三个月吗?

标签: r dplyr


【解决方案1】:

由于您已更改数据,您可能想试试这个:

Table<-data.frame(A = c("2000", "2001", "2002", "2003", "2004"))
Table$B = (as.numeric(as.character(Table$A))-2000)*4 

如果你没有这样的模式,你可以生成一个匹配 A 和 B 的值列表,并将它们合并:

match_list<-data.frame(A = c("2000", "2001", "2002", "2003", "2004"),
                       B = c(0, 4, 8, 16, 20))
merge(Table, match_list, by = "A")  # Table itself does not have B at this stage

这只能节省一些打字。

【讨论】:

    【解决方案2】:

    我会这样做:

    lkp <- setNames(c(0, 4, 8, 16, 20),
                    c("2000", "2001", "2002", "2003", "2004"))
    df <- data.frame(ColumnA = c("2004","2002"),stringsAsFactors = FALSE)
    dplyr::mutate(df, ColumnB = lkp[ColumnA])
    #>   ColumnA ColumnB
    #> 1    2004      20
    #> 2    2002       8
    

    reprex package (v0.3.0) 于 2019 年 11 月 6 日创建

    【讨论】:

      【解决方案3】:

      由于您正在编写 B 列,我假设它在 Table 中不存在,因此连接可以解决问题。

      library(dplyr)
      NewTable <- left_join( Table,
      tibble( A = c("2000", "2001", "2002", "2003", "2004"),
              B = seq(from = 0, to = 32, by = 4) )
      

      【讨论】:

        【解决方案4】:

        这是使用plyr 包中的mapvalues 的解决方案。我经常使用它。

        library(dplyr)
        #> 
        #> Attaching package: 'dplyr'
        #> The following objects are masked from 'package:stats':
        #> 
        #>     filter, lag
        #> The following objects are masked from 'package:base':
        #> 
        #>     intersect, setdiff, setequal, union
        # Create a simulated data frame
        
        set.seed(9049)
        
        Table <- data.frame(columnA = as.character(sample(2000:2011, 
                                                          size = 100, 
                                                          replace = TRUE)),
                            stringsAsFactors = FALSE)
        
        # Extract unique levels from column A
        colA_levels <- unique(Table$columnA)
        
        # Create unique levels of column B to map to
        colB_levels <- (as.numeric(colA_levels) - 2000) * 4
        
        # Use `mapvalues` from `plyr` package
        # 
        NewTable <- Table %>% 
          mutate(columnB = plyr::mapvalues(columnA,
                                           from = colA_levels,
                                           to = colB_levels))
        
        head(NewTable, 10)
        #>    columnA columnB
        #> 1     2008      32
        #> 2     2011      44
        #> 3     2007      28
        #> 4     2011      44
        #> 5     2001       4
        #> 6     2010      40
        #> 7     2000       0
        #> 8     2007      28
        #> 9     2000       0
        #> 10    2002       8
        

        reprex package (v0.3.0) 于 2019 年 11 月 6 日创建

        【讨论】:

          【解决方案5】:

          考虑到 OP 的评论,您可以编写一个函数(this answer 的问题):

          library(tidyverse)
          letter2num <- function(x) {(utf8ToInt(x) - utf8ToInt("a")) * 2}
          tibble(x = letters) %>% 
            rowwise() %>% 
            mutate(y = letter2num(x))
          

          【讨论】:

          • 这个答案没有用,我们需要知道重新编码的逻辑。我怀疑他们在真实数据中有 ABC 字母。
          • 问题是如果有一个esay映射,OP是否会简化它。回答:是的,有,这就是它在指定情况下的工作方式。在不同的环境中,OP 必须调整代码。
          猜你喜欢
          • 1970-01-01
          • 2020-01-11
          • 1970-01-01
          • 2022-11-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-05
          • 2020-03-29
          相关资源
          最近更新 更多