R dplyr:使用字符串函数重命名变量
R dplyr: rename variables using string functions
(有点相关的问题:Enter new column names as string in dplyr's rename function)
在 dplyr
链 (%>%
) 的中间,我想用它们旧名称的函数替换多个列名称(使用 tolower
或 gsub
, 等等)
library(tidyr); library(dplyr)
data(iris)
# This is what I want to do, but I'd like to use dplyr syntax
names(iris) <- tolower( gsub("\.", "_", names(iris) ) )
glimpse(iris, 60)
# Observations: 150
# Variables:
# $ sepal_length (dbl) 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6,...
# $ sepal_width (dbl) 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4,...
# $ petal_length (dbl) 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4,...
# $ petal_width (dbl) 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3,...
# $ species (fctr) setosa, setosa, setosa, setosa, s...
# the rest of the chain:
iris %>% gather(measurement, value, -species) %>%
group_by(species,measurement) %>%
summarise(avg_value = mean(value))
我看到 ?rename
将参数 replace
作为 named character vector, with new names as values, and old names as names.
所以我尝试了:
iris %>% rename(replace=c(names(iris)=tolower( gsub("\.", "_", names(iris) ) ) ))
但是这个 (a) returns Error: unexpected '=' in iris %>% ...
和 (b) 需要通过名称引用链中先前操作的数据框,在我的实际用例中我做不到.
iris %>%
rename(replace=c( )) %>% # ideally the fix would go here
gather(measurement, value, -species) %>%
group_by(species,measurement) %>%
summarise(avg_value = mean(value)) # I realize I could mutate down here
# instead, once the column names turn into values,
# but that's not the point
# ---- Desired output looks like: -------
# Source: local data frame [12 x 3]
# Groups: species
#
# species measurement avg_value
# 1 setosa sepal_length 5.006
# 2 setosa sepal_width 3.428
# 3 setosa petal_length 1.462
# 4 setosa petal_width 0.246
# 5 versicolor sepal_length 5.936
# 6 versicolor sepal_width 2.770
# ... etc ....
我认为您正在查看 plyr::rename
的文档,而不是 dplyr::rename
。你会用 dplyr::rename
:
做这样的事情
iris %>% rename_(.dots=setNames(names(.), tolower(gsub("\.", "_", names(.)))))
这里有一个绕过有点笨拙的 rename
语法的方法:
myris <- iris %>% setNames(tolower(gsub("\.","_",names(.))))
我的 eloquent 尝试使用 base、stringr 和 dplyr:
编辑:library(tidyverse) 现在包括所有三个库。
library(tidyverse)
library(maggritr) # Though in tidyverse to use %>% pipe you need to call it
# library(dplyr)
# library(stringr)
# library(maggritr)
names(iris) %<>% # pipes so that changes are apply the changes back
tolower() %>%
str_replace_all(".", "_")
我这样做是为了使用管道构建功能。
my_read_fun <- function(x) {
df <- read.csv(x) %>%
names(df) %<>%
tolower() %>%
str_replace_all("_", ".")
tempdf %<>%
select(a, b, c, g)
}
对于这种特殊的[但相当常见]的情况,函数已经写在janitor包中:
library(janitor)
iris %>% clean_names()
## sepal_length sepal_width petal_length petal_width species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
## . ... ... ... ... ...
所以一起,
iris %>%
clean_names() %>%
gather(measurement, value, -species) %>%
group_by(species,measurement) %>%
summarise(avg_value = mean(value))
## Source: local data frame [12 x 3]
## Groups: species [?]
##
## species measurement avg_value
## <fctr> <chr> <dbl>
## 1 setosa petal_length 1.462
## 2 setosa petal_width 0.246
## 3 setosa sepal_length 5.006
## 4 setosa sepal_width 3.428
## 5 versicolor petal_length 4.260
## 6 versicolor petal_width 1.326
## 7 versicolor sepal_length 5.936
## 8 versicolor sepal_width 2.770
## 9 virginica petal_length 5.552
## 10 virginica petal_width 2.026
## 11 virginica sepal_length 6.588
## 12 virginica sepal_width 2.974
这是一个很晚的答案,2017 年 5 月
从 dplyr 0.5.0.9004
开始,即将成为 0.6.0,许多重命名列的新方法,符合 maggritr
管道运算符 %>%
,已添加到包中。
这些函数是:
- rename_all
- rename_if
- rename_at
有许多不同的方法可以使用这些函数,但与您的问题相关的一种方法是使用 stringr
包,方法如下:
df <- df %>%
rename_all(
funs(
stringr::str_to_lower(.) %>%
stringr::str_replace_all(., '\.', '_')
)
)
因此,继续管道 :)(无双关语意)。
select()
和 select_all()
都可以用来重命名列。
如果您只想重命名特定的列,您可以使用 select
:
iris %>%
select(sepal_length = Sepal.Length, sepal_width = Sepal.Width, everything()) %>%
head(2)
sepal_length sepal_width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
rename
做同样的事情,只是不必包括 everything()
:
iris %>%
rename(sepal_length = Sepal.Length, sepal_width = Sepal.Width) %>%
head(2)
sepal_length sepal_width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
select_all()
适用于所有列并且可以将函数作为参数:
iris %>%
select_all(tolower)
iris %>%
select_all(~gsub("\.", "_", .))
或结合两者:
iris %>%
select_all(~gsub("\.", "_", tolower(.))) %>%
head(2)
sepal_length sepal_width petal_length petal_width species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
如果你不想自己写正则表达式,你可以使用
- 非常灵活的snakecase-pkg,
janitor::make_clean_names()
有一些不错的默认值或
janitor::clean_names()
与 make_clean_names()
的作用相同,但直接作用于数据帧。
在管道内调用它们应该很简单。
library(magrittr)
library(snakecase)
iris %>% setNames(to_snake_case(names(.)))
iris %>% tibble::as_tibble(.name_repair = to_snake_case)
iris %>% purrr::set_names(to_snake_case)
iris %>% dplyr::rename_all(to_snake_case)
iris %>% janitor::clean_names()
截至 2020 年,rename_if
、rename_at
和 rename_all
已标记为已取代。用 dplyr 方式解决这个问题的最新方法是 rename_with()
:
iris %>% rename_with(tolower)
或更复杂的版本:
iris %>%
rename_with(stringr::str_replace,
pattern = "Length", replacement = "len",
matches("Length"))
(编辑 2021-09-08)
正如@a_leemo 的评论中提到的,手册中没有逐字提及这种表示法。相反,人们会从手册中推断出以下内容:
iris %>%
rename_with(~ stringr::str_replace(.x,
pattern = "Length",
replacement = "len"),
matches("Length"))
两者做同样的事情,但是,我发现第一个解决方案更具可读性。在第一个示例中,pattern = ...
和 replacement = ...
作为 ...
点实现的一部分转发给函数。有关详细信息,请参阅 ?rename_with
和 ?dots
。
(有点相关的问题:Enter new column names as string in dplyr's rename function)
在 dplyr
链 (%>%
) 的中间,我想用它们旧名称的函数替换多个列名称(使用 tolower
或 gsub
, 等等)
library(tidyr); library(dplyr)
data(iris)
# This is what I want to do, but I'd like to use dplyr syntax
names(iris) <- tolower( gsub("\.", "_", names(iris) ) )
glimpse(iris, 60)
# Observations: 150
# Variables:
# $ sepal_length (dbl) 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6,...
# $ sepal_width (dbl) 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4,...
# $ petal_length (dbl) 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4,...
# $ petal_width (dbl) 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3,...
# $ species (fctr) setosa, setosa, setosa, setosa, s...
# the rest of the chain:
iris %>% gather(measurement, value, -species) %>%
group_by(species,measurement) %>%
summarise(avg_value = mean(value))
我看到 ?rename
将参数 replace
作为 named character vector, with new names as values, and old names as names.
所以我尝试了:
iris %>% rename(replace=c(names(iris)=tolower( gsub("\.", "_", names(iris) ) ) ))
但是这个 (a) returns Error: unexpected '=' in iris %>% ...
和 (b) 需要通过名称引用链中先前操作的数据框,在我的实际用例中我做不到.
iris %>%
rename(replace=c( )) %>% # ideally the fix would go here
gather(measurement, value, -species) %>%
group_by(species,measurement) %>%
summarise(avg_value = mean(value)) # I realize I could mutate down here
# instead, once the column names turn into values,
# but that's not the point
# ---- Desired output looks like: -------
# Source: local data frame [12 x 3]
# Groups: species
#
# species measurement avg_value
# 1 setosa sepal_length 5.006
# 2 setosa sepal_width 3.428
# 3 setosa petal_length 1.462
# 4 setosa petal_width 0.246
# 5 versicolor sepal_length 5.936
# 6 versicolor sepal_width 2.770
# ... etc ....
我认为您正在查看 plyr::rename
的文档,而不是 dplyr::rename
。你会用 dplyr::rename
:
iris %>% rename_(.dots=setNames(names(.), tolower(gsub("\.", "_", names(.)))))
这里有一个绕过有点笨拙的 rename
语法的方法:
myris <- iris %>% setNames(tolower(gsub("\.","_",names(.))))
我的 eloquent 尝试使用 base、stringr 和 dplyr:
编辑:library(tidyverse) 现在包括所有三个库。
library(tidyverse)
library(maggritr) # Though in tidyverse to use %>% pipe you need to call it
# library(dplyr)
# library(stringr)
# library(maggritr)
names(iris) %<>% # pipes so that changes are apply the changes back
tolower() %>%
str_replace_all(".", "_")
我这样做是为了使用管道构建功能。
my_read_fun <- function(x) {
df <- read.csv(x) %>%
names(df) %<>%
tolower() %>%
str_replace_all("_", ".")
tempdf %<>%
select(a, b, c, g)
}
对于这种特殊的[但相当常见]的情况,函数已经写在janitor包中:
library(janitor)
iris %>% clean_names()
## sepal_length sepal_width petal_length petal_width species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
## . ... ... ... ... ...
所以一起,
iris %>%
clean_names() %>%
gather(measurement, value, -species) %>%
group_by(species,measurement) %>%
summarise(avg_value = mean(value))
## Source: local data frame [12 x 3]
## Groups: species [?]
##
## species measurement avg_value
## <fctr> <chr> <dbl>
## 1 setosa petal_length 1.462
## 2 setosa petal_width 0.246
## 3 setosa sepal_length 5.006
## 4 setosa sepal_width 3.428
## 5 versicolor petal_length 4.260
## 6 versicolor petal_width 1.326
## 7 versicolor sepal_length 5.936
## 8 versicolor sepal_width 2.770
## 9 virginica petal_length 5.552
## 10 virginica petal_width 2.026
## 11 virginica sepal_length 6.588
## 12 virginica sepal_width 2.974
这是一个很晚的答案,2017 年 5 月
从 dplyr 0.5.0.9004
开始,即将成为 0.6.0,许多重命名列的新方法,符合 maggritr
管道运算符 %>%
,已添加到包中。
这些函数是:
- rename_all
- rename_if
- rename_at
有许多不同的方法可以使用这些函数,但与您的问题相关的一种方法是使用 stringr
包,方法如下:
df <- df %>%
rename_all(
funs(
stringr::str_to_lower(.) %>%
stringr::str_replace_all(., '\.', '_')
)
)
因此,继续管道 :)(无双关语意)。
select()
和 select_all()
都可以用来重命名列。
如果您只想重命名特定的列,您可以使用 select
:
iris %>%
select(sepal_length = Sepal.Length, sepal_width = Sepal.Width, everything()) %>%
head(2)
sepal_length sepal_width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
rename
做同样的事情,只是不必包括 everything()
:
iris %>%
rename(sepal_length = Sepal.Length, sepal_width = Sepal.Width) %>%
head(2)
sepal_length sepal_width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
select_all()
适用于所有列并且可以将函数作为参数:
iris %>%
select_all(tolower)
iris %>%
select_all(~gsub("\.", "_", .))
或结合两者:
iris %>%
select_all(~gsub("\.", "_", tolower(.))) %>%
head(2)
sepal_length sepal_width petal_length petal_width species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
如果你不想自己写正则表达式,你可以使用
- 非常灵活的snakecase-pkg,
janitor::make_clean_names()
有一些不错的默认值或janitor::clean_names()
与make_clean_names()
的作用相同,但直接作用于数据帧。
在管道内调用它们应该很简单。
library(magrittr)
library(snakecase)
iris %>% setNames(to_snake_case(names(.)))
iris %>% tibble::as_tibble(.name_repair = to_snake_case)
iris %>% purrr::set_names(to_snake_case)
iris %>% dplyr::rename_all(to_snake_case)
iris %>% janitor::clean_names()
截至 2020 年,rename_if
、rename_at
和 rename_all
已标记为已取代。用 dplyr 方式解决这个问题的最新方法是 rename_with()
:
iris %>% rename_with(tolower)
或更复杂的版本:
iris %>%
rename_with(stringr::str_replace,
pattern = "Length", replacement = "len",
matches("Length"))
(编辑 2021-09-08)
正如@a_leemo 的评论中提到的,手册中没有逐字提及这种表示法。相反,人们会从手册中推断出以下内容:
iris %>%
rename_with(~ stringr::str_replace(.x,
pattern = "Length",
replacement = "len"),
matches("Length"))
两者做同样的事情,但是,我发现第一个解决方案更具可读性。在第一个示例中,pattern = ...
和 replacement = ...
作为 ...
点实现的一部分转发给函数。有关详细信息,请参阅 ?rename_with
和 ?dots
。