多组具有不同功能的列上的mutate_at

时间:2019-11-12 06:14:30

标签: r dplyr mutate

我定义了必须应用于不同组数据框列的函数。例如,mtcars我想将as.integer()函数应用于列c("mpg", "cyl")as.logical()c("vs", "am")

library(dplyr)

mtcars %>% 
  mutate_at(c("mpg", "cyl"), as.integer) %>% 
  mutate_at(c("vs", "am"), as.logical)

最好使用tidyverse来保存此列集以及相应功能并应用它们而无需多次使用mutate_at的做法。

2 个答案:

答案 0 :(得分:3)

这就是我要处理的方式。结果是一个矩阵列表,可用于进一步覆盖现有列或创建新列,或用作独立数据对象。

vars <- list(van = c("mpg", "cyl"),
             tu = c("vs", "am"))
funk <- list(van = as.integer,
             tu = as.logical)

mapply(FUN = function(v, f) {
  sapply(mtcars[, v], FUN = f)
}, v = vars, f = funk, SIMPLIFY = FALSE)

$van
      mpg cyl
 [1,]  21   6
 [2,]  21   6
 [3,]  22   4
 [4,]  21   6
 [5,]  18   8
 ...
$tu
         vs    am
 [1,] FALSE  TRUE
 [2,] FALSE  TRUE
 [3,]  TRUE  TRUE
 [4,]  TRUE FALSE
 [5,] FALSE FALSE
 ...

要覆盖现有的列,可以使用“可怕的” for循环。 :)

mtcars[colnames(out$van)] <- out$van
mtcars[colnames(out$tu)] <- out$tu
# in generalized form
for (i in seq_along(out)) {
  mtcars[colnames(out[[i]])] <- out[[i]]
}

> head(mtcars)
                  mpg cyl disp  hp drat    wt  qsec    vs    am gear carb
Mazda RX4          21   6  160 110 3.90 2.620 16.46 FALSE  TRUE    4    4
Mazda RX4 Wag      21   6  160 110 3.90 2.875 17.02 FALSE  TRUE    4    4
Datsun 710         22   4  108  93 3.85 2.320 18.61  TRUE  TRUE    4    1
Hornet 4 Drive     21   6  258 110 3.08 3.215 19.44  TRUE FALSE    3    1
Hornet Sportabout  18   8  360 175 3.15 3.440 17.02 FALSE FALSE    3    2
Valiant            18   6  225 105 2.76 3.460 20.22  TRUE FALSE    3    1

或者一站式地完成所有操作(更短)。

for (i in seq_along(vars)) {
  cls <- vars[[i]]
  f <- funk[[i]]

  mtcars[, cls] <- sapply(mtcars[, cls], FUN = f)
}

> head(mtcars)
                  mpg cyl disp  hp drat    wt  qsec    vs    am gear carb
Mazda RX4          21   6  160 110 3.90 2.620 16.46 FALSE  TRUE    4    4
Mazda RX4 Wag      21   6  160 110 3.90 2.875 17.02 FALSE  TRUE    4    4
Datsun 710         22   4  108  93 3.85 2.320 18.61  TRUE  TRUE    4    1
Hornet 4 Drive     21   6  258 110 3.08 3.215 19.44  TRUE FALSE    3    1
Hornet Sportabout  18   8  360 175 3.15 3.440 17.02 FALSE FALSE    3    2
Valiant            18   6  225 105 2.76 3.460 20.22  TRUE FALSE    3    1

答案 1 :(得分:2)

我将在@Roman Lustrik的答案的最后部分中提出与@Roman Lustrik相同的方法,但这是在我打字之间完成的:)。当我在这里的时候,我想我可以对R的switch()函数有所帮助。

for (i in colnames(mtcars)) {
    mtcars[, i] = switch(i,
                         mpg = as.integer(mtcars[, i]),
                         cyl = as.integer(mtcars[, i]),
                         vs = as.logical(mtcars[, i]),
                         am = as.logical(mtcars[, i]))
}

> head(mtcars)
                  mpg cyl    vs    am
Mazda RX4          21   6 FALSE  TRUE
Mazda RX4 Wag      21   6 FALSE  TRUE
Datsun 710         22   4  TRUE  TRUE
Hornet 4 Drive     21   6  TRUE FALSE
Hornet Sportabout  18   8 FALSE FALSE
Valiant            18   6  TRUE FALSE

编辑:

由于switch()函数具有在未提供默认值的情况下删除列的副作用,并且OP要求保留所有列...这是解决方案:

for (i in colnames(mtcars)) {
    mtcars[, i] = switch(i,
                         mpg = as.integer(mtcars[, i]),
                         cyl = as.integer(mtcars[, i]),
                         vs = as.logical(mtcars[, i]),
                         am = as.logical(mtcars[, i]),
                         mtcars[, i]) # just add a default option
}

> head(mtcars)
                  mpg cyl disp  hp drat    wt  qsec    vs    am gear carb
Mazda RX4          21   6  160 110 3.90 2.620 16.46 FALSE  TRUE    4    4
Mazda RX4 Wag      21   6  160 110 3.90 2.875 17.02 FALSE  TRUE    4    4
Datsun 710         22   4  108  93 3.85 2.320 18.61  TRUE  TRUE    4    1
Hornet 4 Drive     21   6  258 110 3.08 3.215 19.44  TRUE FALSE    3    1
Hornet Sportabout  18   8  360 175 3.15 3.440 17.02 FALSE FALSE    3    2
Valiant            18   6  225 105 2.76 3.460 20.22  TRUE FALSE    3    1