如何在dplyr中对许多列进行突变而不重复多次?

时间:2019-01-16 20:59:00

标签: r dplyr

我正在用R编写非常干燥的dplyr链。我需要在数据框中的很多列上调用dplyr::mutate() and dplyr::percent_rank()函数,对于我每个电话没有一行代码很有帮助。我需要为其计算百分位数的数据框列具有以下模式:

regions <- c("atr2", "sht2", "mid2", "lng2", "all2", "sht3", "lng3", "all3")
suffixes <- c("Made", "Att", "AttFreq", "Pct")
for(i in regions) {
  for(j in suffixes) {
    print(paste0(i, j))
  }
}

在上面的示例中,我需要8 * 4 == 32个不同的百分位数列。所有32个初始列atr2Madeatr2Att等都已经在我的数据框中。为了计算百分位数,我一直在做以下事情:

pctile.lineup.data <- pctile.lineup.data %>%
    dplyr::group_by(season) %>%
    # dplyr::group_by(season, homeConfId) %>%
    dplyr::mutate(atr2MadeRankNcaa = round(100 * dplyr::percent_rank(atr2Made))) %>%
    dplyr::mutate(atrAttRankNcaa = round(100 * dplyr::percent_rank(atr2Att))) %>%
    dplyr::mutate(atr2AttFreqRankNcaa = round(100 * dplyr::percent_rank(atr2AttFreq))) %>%
    dplyr::mutate(atr2PctRankNcaa = round(100 * dplyr::percent_rank(atr2Pct))) %>%
    dplyr::mutate(sht2MadeRankNcaa = round(100 * dplyr::percent_rank(sht2Made))) %>%
    dplyr::mutate(shtAttRankNcaa = round(100 * dplyr::percent_rank(sht2Att))) %>%
    dplyr::mutate(sht2AttFreqRankNcaa = round(100 * dplyr::percent_rank(sht2AttFreq))) %>%
    dplyr::mutate(sht2PctRankNcaa = round(100 * dplyr::percent_rank(sht2Pct))) %>%
    dplyr::mutate(mid2MadeRankNcaa = round(100 * dplyr::percent_rank(mid2Made))) %>%
    dplyr::mutate(midAttRankNcaa = round(100 * dplyr::percent_rank(mid2Att))) %>%
    dplyr::mutate(mid2AttFreqRankNcaa = round(100 * dplyr::percent_rank(mid2AttFreq))) %>%
    dplyr::mutate(mid2PctRankNcaa = round(100 * dplyr::percent_rank(mid2Pct))) %>%
    ... %>%
    dplyr::ungroup()

我不仅需要32个不同的mutate()函数,还需要为2个不同的group_by()运行两次此代码(请参阅第二个注释掉)。有没有比64行代码更好的方法?我有一个单独的dataram,它具有21个区域而不是8个区域,具有相同的4个后缀和相同的2个group_by()s,因此计算这些百分位数需要21 * 4 * 2 == 168行代码。这不是DRY-请帮忙!

编辑:显然,我正在研究mutate_at,但是对mutate的_at版本不是很熟悉/不熟悉。我的数据框中除了这32列之外还有其他列,因此我认为mutate_all不起作用。

1 个答案:

答案 0 :(得分:2)

这正是dplyr::mutate_at的用途。从一些示例数据开始:

df <- data.frame(name = LETTERS[1:5],
                 item1 = rnorm(5, mean=2),
                 item2 = rnorm(5, mean=5),
                 item3 = rnorm(5, mean=7))

*_at函数接受2个参数:

  • 一个.vars参数,它接受dplyr::select使用的选择器功能。在这种情况下,我们使用one_of提供变量列表,但是如果变量有模式,可以使用containsstarts_with简化此过程
  • 一个.funs参数,我们将函数应用于这些列中的每列。

请注意,为了使这些参数正常工作,必须将这些参数分别包装在varsfuns函数中:

df %>%
    mutate_at(.vars = vars(one_of('item1', 'item2')),
              .funs = funs(rounded = round(100 * percent_rank(.)))   

  name    item1    item2    item3 item1_rounded item2_rounded
1    A 3.801373 5.701111 9.871991           100            75
2    B 2.264733 5.730916 8.558700            25           100
3    C 3.432726 5.623918 7.359317            75            50
4    D 2.137491 5.286736 7.996114             0            25
5    E 3.227416 5.269252 6.588257            50             0

由于.funs中的函数被命名为(rounded = ...,所以该操作的结果被制成新变量,后缀为。如果未命名,则所选变量将被自己修改(即item1item2将被四舍五入)