使用 purrr 遍历数据框中的多个(但不是全部)列
Iterate over several (but not all) columns in a data frame with purrr
我正在寻找一种简洁的方式来在 tidyverse 管道中同时处理多个列。
问题是我不需要处理所有列:只有几个。
library(tidyverse)
mtcars <- mtcars %>% rownames_to_column(var = 'car')
str(mtcars)
'data.frame': 32 obs. of 12 variables:
$ car : chr "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
$ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
$ cyl : num 6 6 4 6 8 6 8 4 4 6 ...
$ disp: num 160 160 108 258 360 ...
$ hp : num 110 110 93 110 175 105 245 62 95 123 ...
$ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
$ wt : num 2.62 2.88 2.32 3.21 3.44 ...
$ qsec: num 16.5 17 18.6 19.4 17 ...
$ vs : num 0 0 1 1 0 1 0 1 1 1 ...
$ am : num 1 1 1 0 0 0 0 0 0 0 ...
$ gear: num 4 4 4 3 3 3 3 4 4 4 ...
$ carb: num 4 4 1 1 2 1 4 2 2 4 ...
假设我想对 drat
、qsec
和 gear
列执行一些操作。 (例如,转换为字符。谁知道为什么)
动作不写3遍怎么行?也许使用 purrr()
?
这里的 2 个关键函数是 map_at
(或 map_if
,如果我们不知道这些列,但我们对这些列有所了解,但不知道我们需要哪些)和 map_df
(其中returns一个数据框而不是一个列表)。
遗憾的是,我看不到结合了两者的函数。但我们可以解决它。查看 map_df
的内部结构,它是一个常规的 map
,最后添加了 bind_rows()
。
这就是我们所需要的:
mtcars2 <- mtcars %>%
map_at(c('drat', 'qsec', 'gear'), as.character) %>%
bind_rows()
在 dplyr 中尝试 mutate_at
:
mtcars %>% mutate_at(c("drat", "qsec", "gear"), as.character)
也可以这样写:
mtcars %>% mutate_at(vars(drat, qsec, gear), as.character)
基础 R 解决方案。我们可以使用lapply
循环遍历列名并设计一个函数将目标列转换为字符。
mtcars[] <- lapply(colnames(mtcars),
function(x) {
y <- mtcars[[x]]
if (x %in% c("drat", "qsec", "gear")){
y <- as.character(y)
}
return(y)
})
str(mtcars)
# 'data.frame': 32 obs. of 12 variables:
# $ car : chr "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
# $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
# $ cyl : num 6 6 4 6 8 6 8 4 4 6 ...
# $ disp: num 160 160 108 258 360 ...
# $ hp : num 110 110 93 110 175 105 245 62 95 123 ...
# $ drat: chr "3.9" "3.9" "3.85" "3.08" ...
# $ wt : num 2.62 2.88 2.32 3.21 3.44 ...
# $ qsec: chr "16.46" "17.02" "18.61" "19.44" ...
# $ vs : num 0 0 1 1 0 1 0 1 1 1 ...
# $ am : num 1 1 1 0 0 0 0 0 0 0 ...
# $ gear: chr "4" "4" "4" "3" ...
# $ carb: num 4 4 1 1 2 1 4 2 2 4 ...
您还可以使用 purrr
中的 modify
或 modify_at
,modify
函数与 map
类似,只是输出的格式与输入相同。
modify_at
将以与@g-grothendieck 的解决方案中的 mutate_at
相同的方式使用:
mtcars %>% modify_at(c("drat", "qsec", "gear"), as.character)
如果你使用 magrittr
你也可以这样做(这个覆盖 mtcars
):
mtcars[, c("drat", "qsec", "gear")] %<>% modify(as.character)
我正在寻找一种简洁的方式来在 tidyverse 管道中同时处理多个列。 问题是我不需要处理所有列:只有几个。
library(tidyverse)
mtcars <- mtcars %>% rownames_to_column(var = 'car')
str(mtcars)
'data.frame': 32 obs. of 12 variables:
$ car : chr "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
$ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
$ cyl : num 6 6 4 6 8 6 8 4 4 6 ...
$ disp: num 160 160 108 258 360 ...
$ hp : num 110 110 93 110 175 105 245 62 95 123 ...
$ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
$ wt : num 2.62 2.88 2.32 3.21 3.44 ...
$ qsec: num 16.5 17 18.6 19.4 17 ...
$ vs : num 0 0 1 1 0 1 0 1 1 1 ...
$ am : num 1 1 1 0 0 0 0 0 0 0 ...
$ gear: num 4 4 4 3 3 3 3 4 4 4 ...
$ carb: num 4 4 1 1 2 1 4 2 2 4 ...
假设我想对 drat
、qsec
和 gear
列执行一些操作。 (例如,转换为字符。谁知道为什么)
动作不写3遍怎么行?也许使用 purrr()
?
这里的 2 个关键函数是 map_at
(或 map_if
,如果我们不知道这些列,但我们对这些列有所了解,但不知道我们需要哪些)和 map_df
(其中returns一个数据框而不是一个列表)。
遗憾的是,我看不到结合了两者的函数。但我们可以解决它。查看 map_df
的内部结构,它是一个常规的 map
,最后添加了 bind_rows()
。
这就是我们所需要的:
mtcars2 <- mtcars %>%
map_at(c('drat', 'qsec', 'gear'), as.character) %>%
bind_rows()
在 dplyr 中尝试 mutate_at
:
mtcars %>% mutate_at(c("drat", "qsec", "gear"), as.character)
也可以这样写:
mtcars %>% mutate_at(vars(drat, qsec, gear), as.character)
基础 R 解决方案。我们可以使用lapply
循环遍历列名并设计一个函数将目标列转换为字符。
mtcars[] <- lapply(colnames(mtcars),
function(x) {
y <- mtcars[[x]]
if (x %in% c("drat", "qsec", "gear")){
y <- as.character(y)
}
return(y)
})
str(mtcars)
# 'data.frame': 32 obs. of 12 variables:
# $ car : chr "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
# $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
# $ cyl : num 6 6 4 6 8 6 8 4 4 6 ...
# $ disp: num 160 160 108 258 360 ...
# $ hp : num 110 110 93 110 175 105 245 62 95 123 ...
# $ drat: chr "3.9" "3.9" "3.85" "3.08" ...
# $ wt : num 2.62 2.88 2.32 3.21 3.44 ...
# $ qsec: chr "16.46" "17.02" "18.61" "19.44" ...
# $ vs : num 0 0 1 1 0 1 0 1 1 1 ...
# $ am : num 1 1 1 0 0 0 0 0 0 0 ...
# $ gear: chr "4" "4" "4" "3" ...
# $ carb: num 4 4 1 1 2 1 4 2 2 4 ...
您还可以使用 purrr
中的 modify
或 modify_at
,modify
函数与 map
类似,只是输出的格式与输入相同。
modify_at
将以与@g-grothendieck 的解决方案中的 mutate_at
相同的方式使用:
mtcars %>% modify_at(c("drat", "qsec", "gear"), as.character)
如果你使用 magrittr
你也可以这样做(这个覆盖 mtcars
):
mtcars[, c("drat", "qsec", "gear")] %<>% modify(as.character)