dplyr - 基于列名相似性的mutate公式

时间:2017-10-19 14:33:42

标签: r dplyr mutate

我正在尝试找到一种更好的方法,根据列名的一部分对列组合运行mutate()

例如,在以下代码中简化mutate函数的方法:

df <- data.frame(LIMITED_A = c(100,200),
                UNLIMITED_A = c(25000,50000),
                LIMITED_B = c(300,300),
                UNLIMITED_B = c(500,500),
                LIMITED_C = c(2,10),
                UNLIMITED_C = c(5,20))

df %>%
  mutate(FINAL_LIMITED = (LIMITED_A - LIMITED_B) / LIMITED_C,
         FINAL_UNLIMITED = (UNLIMITED_A - UNLIMITED_B) / UNLIMITED_C)

形式为(._A - ._B) / ._C的公式,结果名称为FINAL_.

有没有办法将此简化为mutate函数中的单行代码?

2 个答案:

答案 0 :(得分:2)

一个想法是将数据帧转换为长格式并进行计算。

library(dplyr)
library(tidyr)

df2 <- df %>%
  mutate(ID = 1:n()) %>%
  gather(Type, Value, -ID) %>%
  separate(Type, into = c("Type", "Group")) %>%
  spread(Group, Value) %>%
  mutate(Final = (A - B)/C)
df2
  ID      Type     A   B  C Final
1  1   LIMITED   100 300  2  -100
2  1 UNLIMITED 25000 500  5  4900
3  2   LIMITED   200 300 10   -10
4  2 UNLIMITED 50000 500 20  2475

您始终可以将数据帧转换回宽屏格式。

df3 <- df2 %>%
  gather(Group, Value, A:Final) %>%
  unite(Col, Type, Group) %>%
  spread(Col, Value) %>%
  select(colnames(df), 
         FINAL_LIMITED = LIMITED_Final, 
         FINAL_UNLIMITED = UNLIMITED_Final)
  LIMITED_A UNLIMITED_A LIMITED_B UNLIMITED_B LIMITED_C UNLIMITED_C FINAL_LIMITED FINAL_UNLIMITED
1       100       25000       300         500         2           5          -100            4900
2       200       50000       300         500        10          20           -10            2475

答案 1 :(得分:2)

这是一种不同的方法:

library(dplyr)
library(rlang)
library(glue)

dynamic_mutate = function(DF,  
                          col_names = gsub("(.*)_\\w+$", "\\1", names(DF)), 
                          expression = "({x}_A - {x}_B)/{x}_C",
                          prefix = "FINAL"){

  name_list = col_names %>% 
    unique() %>%
    as.list()

  expr_list = name_list %>%
    lapply(function(x) parse_quosure(glue(expression))) %>% 
    setNames(paste(prefix, name_list, sep = "_")) 

  DF %>% mutate(!!!expr_list)

}

<强>结果:

> df %>%
+   dynamic_mutate()
  LIMITED_A UNLIMITED_A LIMITED_B UNLIMITED_B LIMITED_C UNLIMITED_C FINAL_LIMITED
1       100       25000       300         500         2           5          -100
2       200       50000       300         500        10          20           -10
  FINAL_UNLIMITED
1            4900
2            2475

> df %>%
+   dynamic_mutate(c("LIMITED", "UNLIMITED"), prefix = "NEW")
  LIMITED_A UNLIMITED_A LIMITED_B UNLIMITED_B LIMITED_C UNLIMITED_C NEW_LIMITED
1       100       25000       300         500         2           5        -100
2       200       50000       300         500        10          20         -10
  NEW_UNLIMITED
1          4900
2          2475

> df %>%
+   dynamic_mutate(c("UNLIMITED"), prefix = "NEW")
  LIMITED_A UNLIMITED_A LIMITED_B UNLIMITED_B LIMITED_C UNLIMITED_C NEW_UNLIMITED
1       100       25000       300         500         2           5          4900
2       200       50000       300         500        10          20          2475

> df %>% 
+   dynamic_mutate(c("A", "B", "C"), "LIMITED_{x} + UNLIMITED_{x}")
  LIMITED_A UNLIMITED_A LIMITED_B UNLIMITED_B LIMITED_C UNLIMITED_C FINAL_A FINAL_B FINAL_C
1       100       25000       300         500         2           5   25100     800       7
2       200       50000       300         500        10          20   50200     800      30

备注:

此方法使用lapplyglue从使用gsub提取的前缀构造表达式(或者您可以提供自己的前缀/后缀)。然后使用来自parse_quosure的{​​{1}}将表达式解析为rlang。因此,quosureexpr_list的命名列表,然后我可以使用quosure取消引用并将参数拼接到!!!中的单独表达式中。

您可以通过调整mutate参数来更改公式,如上一个示例所示。

这种方法的优点是它非常快,因为我主要是操纵列名和创建字符串(表达式)。缺点是它使用多个包。