【问题标题】:Convert column names to title case [duplicate]将列名转换为标题大小写[重复]
【发布时间】:2022-01-22 02:19:21
【问题描述】:

我正在开发一个 Rmd,它将使用 kintr 转换为 html 报告。我从 xls 导入数据,使用 clean_names() 作为列名,并完成了操作。这是数据样本:

df <- data.frame(precinct = c("a_b_c", "b_c_d", "e_f_g"), steve_alpha = c(309, 337, 294), mike_bravo = c(120, 151, 240), allan_charlie = c(379, 442, 597))

现在我想使用 kable() 在表格中以美观的方式呈现数据,但列名和“区域”列的内容需要采用标题大小写。是否有一个函数可以一次性完成所有这些操作?

【问题讨论】:

  • library(tools) colnames(df) = colnames(toTitleCase(colnames(df)) # 改变标题大小写的方法 toTitleCase("This is a test")
  • snakecase::to_title_case 这样做。我写了similar function 为我的工作包。它基本上是几个 gsub 电话的包装,请随意复制它
  • 你能澄清一下你是否想用空格替换下划线吗?这就是标题对我的暗示,但我可能错了
  • 只有现在我才能看到@camille 对类似功能的评论。啊。好吧,我会继续回答,但也许 camille 应该使用该功能发布答案。

标签: r


【解决方案1】:

这里有一些皱纹。首先,我将标题大小写解释为每个单词都以大写字母开头,并且下划线被空格替换。其次,一些解决方案将适用于数据框的名称,但不适用于区域列,因为 tools::toTitleCase 是其他一些功能的基础,包括我最初建议的 snakecase,它假定单个字母不应大写。

snakecase::to_title_case(names(df))
#> [1] "Precinct"      "Steve Alpha"   "Mike Bravo"    "Allan Charlie"
snakecase::to_title_case(df$precinct, sep_out = " ", sep_in = "_")
#> [1] "A b c" "B c d" "E f g"

对于辖区来说,这似乎不是正确的结果。知道每个区域只有单字母单词,您可以替换下划线,然后转换为全部大写,但这不适用于任何其他单词。或者,stringr::str_to_title 不会将单字母单词保持小写,因此请进行替换,然后传递给它。

stringr::str_to_title(stringr::str_replace_all(df$precinct, "_", " "))
#> [1] "A B C" "B C D" "E F G"

我在评论中提到,我为工作中的一个包创建了一个similar function,它可以处理各种情况,人们应该可以随意复制。这是一个大大简化的版本,它替换了下划线,然后将单词开头的任何小写字母转换为对应的大写字母,因此它适用于两个实例。

clean_titles <- function(x) {
  x <- gsub("_", " ", x)
  x <- gsub("\\b([a-z])", "\\U\\1", x, perl = TRUE)
  x
}

clean_titles(names(df))
#> [1] "Precinct"      "Steve Alpha"   "Mike Bravo"    "Allan Charlie"
clean_titles(df$precinct)
#> [1] "A B C" "B C D" "E F G"

最后,因为你有一个函数可以做到这一点,你可以在dplyr::mutate 中使用它来更改那一列,并在dplyr::rename_with 中使用它来更改所有列名。

library(dplyr)

df %>%
  mutate(precinct = clean_titles(precinct)) %>%
  rename_with(clean_titles)
#>   Precinct Steve Alpha Mike Bravo Allan Charlie
#> 1    A B C         309        120           379
#> 2    B C D         337        151           442
#> 3    E F G         294        240           597

【讨论】:

    【解决方案2】:

    这不能用纯正则表达式完成吗,只需将perl = TRUE 传递给gsub 并使用\U modifier

    gsub("(^|_)([[:alpha:]])", "\\1\\U\\2", names(df), perl = TRUE)
    ## [1] "Precinct"      "Steve_Alpha"   "Mike_Bravo"    "Allan_Charlie"
    

    因此:

    to_title <- function(x) {
      gsub("_", " ", gsub("(^|_)([[:alpha:]])", "\\1\\U\\2", x, perl = TRUE))
    }
    df$precinct <- to_title(df$precinct)
    names(df) <- to_title(names(df))
    df
    ##   Precinct Steve Alpha Mike Bravo Allan Charlie
    ## 1    A B C         309        120           379
    ## 2    B C D         337        151           442
    ## 3    E F G         294        240           597
    

    【讨论】:

      【解决方案3】:

      有几种方法可以做到这一点。

      tools 包中有一个名为toTitleCase 的函数。有了这个,sub 你可以像这样重命名列:

      names(df)<-tools::toTitleCase(sub("_"," ",names(df)))
      
      df
      #>   Precinct Steve Alpha Mike Bravo Allan Charlie
      #> 1        A         309        120           379
      #> 2        B         337        151           442
      #> 3        C         294        240           597
      

      使用优秀的stringr 包中的函数str_to_title 的等效方法:

      names(df)<-stringr::str_to_title(sub("_"," ",names(df)))
      df
      #>   Precinct Steve Alpha Mike Bravo Allan Charlie
      #> 1        A         309        120           379
      #> 2        B         337        151           442
      #> 3        C         294        240           597
      

      最后,如果你热衷于使用pipesdplyr

      df <- df |>
        rename_all(~ gsub("_", " ", .)) |>
        rename_all(stringr::str_to_title)
      df
      
      #>   Precinct Steve Alpha Mike Bravo Allan Charlie
      #> 1        A         309        120           379
      #> 2        B         337        151           442
      #> 3        C         294        240           597
      

      【讨论】:

        【解决方案4】:

        也许这可能是另一种解决方案:

        library(stringr)
        
        names(df) <- sapply(strsplit(names(df), "_"), \(x) {
          paste0(str_to_title(x), collapse = "_")
        })
        
        df
          Precinct Steve_Alpha Mike_Bravo Allan_Charlie
        1    a_b_c         309        120           379
        2    b_c_d         337        151           442
        3    e_f_g         294        240           597
        

        【讨论】:

          【解决方案5】:

          选项 1:gregexpr/chartr

          这里有一个使用正则表达式的技巧(只查找前面的_ 或字符串的开头),然后使用chartrtranlate characters 从小写到大写。

          nms <- colnames(df)
          gre <- gregexpr("(?<=_|^)[a-z]", nms, perl = TRUE)
          ltrs <- regmatches(nms, gre)
          regmatches(nms, gre) <- 
            lapply(ltrs, chartr, old = paste(letters, collapse = ""), new = paste(LETTERS, collapse = ""))
          colnames(df) <- nms
          df
          #   Precinct Steve_Alpha Mike_Bravo Allan_Charlie
          # 1    a_b_c         309        120           379
          # 2    b_c_d         337        151           442
          # 3    e_f_g         294        240           597
          

          形式化了一点,没有经过真正的压力测试:

          #' @param text character
          #' @param sep character, separators that will cause the next letter to
          #'   be translated to upper-case
          #' @return text, updated
          toSnakeCase <- function(text, sep = c("^", "_")) {
            ptn <- paste0("(?<=", paste(sep, collapse = "|"), ")[a-z]")
            gre <- gregexpr(ptn, text, perl = TRUE)
            ltrs <- regmatches(text, gre)
            regmatches(text, gre) <- 
              lapply(ltrs, chartr, old = paste(letters, collapse = ""), new = paste(LETTERS, collapse = ""))
            text  
          }
          
          toSnakeCase(colnames(df), sep = "_")
          # [1] "precinct"      "steve_Alpha"   "mike_Bravo"    "allan_Charlie"
          toSnakeCase(colnames(df))
          # [1] "Precinct"      "Steve_Alpha"   "Mike_Bravo"    "Allan_Charlie"
          

          选项 2:toTitleCase,已修改

          (也许我应该领导这个。)

          colnames(df) <- gsub(" ", "_", tools::toTitleCase(gsub("_", " ", colnames(df))))
          df
          #   Precinct Steve_Alpha Mike_Bravo Allan_Charlie
          # 1    a_b_c         309        120           379
          # 2    b_c_d         337        151           442
          # 3    e_f_g         294        240           597
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-10-15
            • 2016-02-24
            • 2010-11-15
            • 2022-05-24
            相关资源
            最近更新 更多