2017-10-19 70 views
1

我正试图找到一种更好的方法,以基于列名部分的列组合来运行mutate()dplyr - 根据列名中的相似性改变公式

例如,一种方式,以简化在以下代码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

@bouncyball将变量更改为'df' – waealu

回答

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_quosurerlang然后用于解析表达式到quosure。因此,expr_listquosure的命名列表,然后我可以使用!!!将参数取出并将参数拼接到mutate中的单独表达式中。

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

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

1

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

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