如何使用高阶函数重命名我自己的函数中的列?

How to rename a column within my own function using a higher-order function?

概述

我有一些列,其中观察值全部大写,例如 "NORWALK." 但是,我编写了一个函数来转换观察值,因此它们只有首字母大写,例如 "Norwalk."

代码

library(dplyr)
capitalizeColumn <- function(dataSet, c) { # c for column
  dataSet%>%
    mutate(c = tolower({{c}}))%>%
    mutate(c = toTitleCase(c))
}
df3 <- df3 %>%
  capitalizeColumn(ResidenceCity)%>%
  rename_all(recode, c= "ResidenceCity")

但是,此代码输出名为 "c" 的列,而我希望它输出原始列的名称,在本例中为 "ResidenceCity"。现在我必须使用函数 rename_all 稍后重命名该列,但我希望它在我的 capitalizeColumn[=23= 中] 功能。我已经尝试在我的函数中使用几个不同的高阶函数,但到目前为止没有任何效果。

我们可能需要执行赋值运算符 (:=) 而不是 =,同时计算 'lhs'

上的 'c'
capitalizeColumn <- function(dataSet, c) { 
  dataSet%>%
    mutate(!! enquo(c) := tolower({{c}}) %>% tools::toTitleCase(.))

        }


capitalizeColumn(df1, ResidenceCity) 
# A tibble: 1 x 1
#  ResidenceCity
#  <chr>        
#1 Norwalk      

数据

df1 <- tibble( ResidenceCity = "NORWALK")

@akrun 的答案是基于 dplyr 的解决方案的正确答案(我赞成它),但有时 Base R 中的事情比 tidyverse 更容易,因为 tidyverse 依赖于非标准评估。这是处理数据框中多列的函数的 Base R 版本。

city <- c("CHICAGO","NEW YORK","LOS ANGELES", "DETROIT")
state <- c("ILLINOIS","NEW YORK","CALIFORNIA","MICHIGAN")
data <- data.frame(city,state,stringsAsFactors = FALSE)
capitalizeColumns <- function(df,vars){
     require(tools)
     for(v in vars) df[[v]] <- toTitleCase(tolower(df[[v]]))
     df
}
capitalizeColumns(data,c("city","state"))

...输出:

> capitalizeColumns(data,c("city","state"))
         city      state
1     Chicago   Illinois
2    New York   New York
3 Los Angeles California
4     Detroit   Michigan
> 

在 dplyr 1.0 中,我们可以使用 mutate/across 将第二个参数中指定的函数应用于第一个参数中指定的一个或多个列。

library(dplyr)
library(tools)

capitalizeColumn <- function(data, c) {
  data %>% 
    mutate(across({{c}}, . %>% tolower %>% toTitleCase))
}


df3 <- data.frame(ResidenceCity = "NORWALK")
capitalizeColumn(df3, ResidenceCity)
##   ResidenceCity
## 1       Norwalk

在 dplyr 的早期版本中(以及在 1.0 中虽然不太受欢迎)可以使用 mutate_at:

capitalizeColumn <- function(data, c) {
  data %>% 
    mutate_at(vars({{c}}), . %>% tolower %>% toTitleCase)
}