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

标签 r dplyr

为了形象化这个问题,我们假设我有一个 R 数据集 data ,其中包含以下列:

  • 因素
  • 参数
  • 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 获取数据,同时变异?

(在实际案例中,我有更多的列和条件,因此手动输入所有可能的情况不是一个选项)

最佳答案

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
  )

但这仅在您有一个小/静态的 T* 变量列表需要修改时才有效。

如果这些T*变量的数量是动态的(或者只是“高”),一种方法包括将帧重新整形为更长的格式。 (有人可能会说,无论如何,长格式可能更适合这种情况,所以我将引导您了解 Wide-long-mutate 以及 Wide-long-mutate-wide。)

一些数据:

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

首先,第一次 reshape :

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*n 列进行转换,其中包含 T#T#_g1T#_g2 模式,仅包含 3 列,但行数是 n 倍。我们将这个n 保留为另一列(暂时)。一般来说,这可以说是一种很好的使用格式:tidyverse,尤其是 ggplot2 确实喜欢这种格式的数据,但可能还有更多我不知道的数据。

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

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

reshape 后,您最初的 mutate_at 概念被简化为单个 mutate(T = ...) 调用。其余的涉及重新水化宽度。

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

关于通过 mutate_at 中的名称片段引用其他列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53284289/

相关文章:

r - 使用 dplyr 进行管道传输时获取 lhs 对象名称

r - 根据列的每个值所属列表的类别对它们进行分组

r - "object ' ansvals ' not found"错误 - 这是什么意思?

r - 比较两个数据帧以了解 R 中变量值的变化

r - 使用 ggplot2 绘制多条正态曲线,无需硬编码均值和标准差

mysql - 用于分组变异操作的 dbplyr 窗口函数

r - 在 dplyr 中一起使用 summarize_all 和 summarize

R 圆形包计算线性平均值而不是圆形平均值,单位 = "hours"

r - 使用 Shiny 的 navbarPage 更改 sidebarPanel

用快捷方式替换 df <- df %>% ...