【问题标题】:mutate_at on multiple sets of columns with different functionsmutate_at 在具有不同功能的多组列上
【发布时间】:2020-03-07 19:53:20
【问题描述】:

我定义了必须应用于不同数据框列集的函数。例如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

【问题讨论】:

  • 不太确定您想要的方法是什么样的。您想创建一个包含变量和相应函数的列表吗?
  • 我不确定你想要什么。您是否只是在寻找一种方法来保存具有这些更改的 mtcars 数据集(即,无需应用 mutate_at 函数),以便您可以继续使用例如“mpg”和“cyl”和“vs”和“am”分别作为整数和逻辑值?
  • @TimTeaFan 可以是包含变量和对应函数的列表或其他东西(列表看起来最适合我)。重点是最后我不需要写多个mutate_at
  • @larsoevlisen 我想要与上面代码相​​同的输出,但不多次使用mutate_at - 我将不得不在我的真实代码中编写近 20 个这样的语句(这只是一个示例)。我希望我很清楚,否则请告诉我。

标签: r dplyr


【解决方案1】:

我正要提出@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

【讨论】:

    【解决方案2】:

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

    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
    

    【讨论】:

    • 您能否补充一下您将如何覆盖现有列?谢谢。
    • @Miha 完成。还添加了另一个跳过mapply 部分的解决方案。
    猜你喜欢
    • 2013-12-18
    • 1970-01-01
    • 2021-12-14
    • 2011-10-22
    • 1970-01-01
    • 1970-01-01
    • 2020-06-12
    • 1970-01-01
    • 2019-10-01
    相关资源
    最近更新 更多