通过mutate_at中的名称片段引用其他列

时间:2018-11-13 15:27:49

标签: r dplyr

为可视化该问题,我们假设我在R中有一个数据集data,其中包含以下列:

  • 因素
  • param
  • T1_g1
  • T2_g1
  • T1_g2
  • T2_g2

我要对列的子集执行操作:

data_final <- data %>%
  mutate_at(vars(T1, T2), funs(if(param > 100) {
    . * T(n)_g1 
  } else {
    . * T(n)_g2
  } 

如何在表达式T(n)_g1中引用正确的列名,以便它在进行突变时分别从T1_g1T2_g1中获取数据?

(在实际情况下,我有更多的列和条件,因此,不能手动键入所有可能的情况)

1 个答案:

答案 0 :(得分:2)

if需要一个比较,但是由于这是一个向量,因此需要if_else(或ifelse)。我不知道您可以基于mutate*快速界面中要更改的名称来(轻松)动态地确定其他列的名称。一个快速的技巧可能是:

data %>%
  mutate(
    T1 = if_else(param > 100, T1_g1, T1_g2) * T1,
    T2 = if_else(param > 100, T2_g1, T2_g2) * T2
  )

但这仅在您有{/ {1}}个变量的小型/静态列表要修改的情况下有效。

如果这些T*变量有动态(或仅“高”)个数,则一种方法包括将帧重塑为更长的格式。 (有人可能会争辩说,无论如何,长格式都可能更适合此操作,所以我将带您逐步了解一下long-long-mutate以及Wide-long-mutate-wide。)

一些数据:

T*

首先,第一次重塑:

x <- data_frame(
  param = c(1L,50L,101L,150L),
  T1 = 1:4,
  T2 = 5:8,
  T1_g1 = (1:4)/10,
  T1_g2 = (1:4)*10,
  T2_g1 = (5:8)/10,
  T2_g2 = (5:8)*10
)
x
# # A tibble: 4 x 7
#   param    T1    T2 T1_g1 T1_g2 T2_g1 T2_g2
#   <int> <int> <int> <dbl> <dbl> <dbl> <dbl>
# 1     1     1     5   0.1    10   0.5    50
# 2    50     2     6   0.2    20   0.6    60
# 3   101     3     7   0.3    30   0.7    70
# 4   150     4     8   0.4    40   0.8    80

我们要做的是将x %>% gather(k, v, -param) %>% mutate( num = sub("^T([0-9]+).*", "\\1", k), k = sub("^T[0-9]+(.*)", "T\\1", k) ) %>% spread(k, v) # # A tibble: 8 x 5 # param num T T_g1 T_g2 # <int> <chr> <dbl> <dbl> <dbl> # 1 1 1 1 0.1 10 # 2 1 2 5 0.5 50 # 3 50 1 2 0.2 20 # 4 50 2 6 0.6 60 # 5 101 1 3 0.3 30 # 6 101 2 7 0.7 70 # 7 150 1 4 0.4 40 # 8 150 2 8 0.8 80 列的3*nT#T#_g1模式的四行变成三列,但{{1} }乘以行数。我们将此T#_g2保留为另一列(目前)。一般而言,这可以说是一种很好的格式:n,尤其是n确实喜欢这种格式的数据,但是我可能还不知道。

现在完整的shebang(重复代码的前几行):

tidyverse

重塑后,您最初的ggplot2概念被简化为单个x %>% gather(k, v, -param) %>% mutate( num = sub("^T([0-9]+).*", "\\1", k), k = sub("^T[0-9]+(.*)", "T\\1", k) ) %>% spread(k, v) %>% mutate(T = T * if_else(param > 100, T_g1, T_g2)) %>% gather(k, v, -param, -num) %>% mutate(k = if_else(grepl("^T", k), paste0("T", num, substr(k, 2, nchar(k))), k)) %>% select(-num) %>% spread(k, v) # # A tibble: 4 x 7 # param T1 T1_g1 T1_g2 T2 T2_g1 T2_g2 # <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> # 1 1 10 0.1 10 250 0.5 50 # 2 50 40 0.2 20 360 0.6 60 # 3 101 0.900 0.3 30 4.90 0.7 70 # 4 150 1.6 0.4 40 6.4 0.8 80 调用。其余的包括重新给宽度补水。

如果您的数据很大,可能会有点麻烦。其他解决方案可能涉及手动确定mutate_at列和手动进行mutate(T = ...)(在T#之外)。