使用 purrr 一次将函数应用于两列

Apply function to two columns at a time with purrr

我有一个简化的 tibble,其中我 select 两列(手动)并将它们传递给自定义函数,但在这种情况下仅使用 sum。关于如何扩展它以容纳任意数量的 ko 的任何想法。在这种情况下只有 2 个,但假设有 5 个?

library(dplyr)
library(purrr)

df <- tibble(l2fc_ko1 = rnorm(1:10), l2fc_ko2 = rnorm(1:10), ctrl_ko1 = rnorm(1:10), ctrl_ko2 = rnorm(1:10))

df %>% mutate(ko1_sum = map2_dbl(ctrl_ko1, l2fc_ko1, sum),
           ko2_sum = map2_dbl(ctrl_ko2, l2fc_ko2, sum))

我们可以使用 pivot_longer 重塑数据,为 ko 的每个级别创建一列。计算总和,然后 pivot_wider 返回原来的格式:

library(tidyverse)

df %>% 
  mutate(idx = row_number()) %>% 
  pivot_longer(-idx, names_sep = '_', names_to = c('group', 'ko')) %>% 
  pivot_wider(names_from = group, values_from = value) %>% 
  mutate(sum = l2fc + ctrl) %>% 
  pivot_wider(names_from = ko, values_from = c(l2fc, ctrl, sum))

     idx l2fc_ko1 l2fc_ko2 ctrl_ko1 ctrl_ko2 sum_ko1 sum_ko2
   <int>    <dbl>    <dbl>    <dbl>    <dbl>   <dbl>   <dbl>
 1     1  -1.04    -0.710    -0.288   -1.65   -1.33   -2.36 
 2     2   0.0338   0.400    -0.850    0.319  -0.816   0.719
 3     3   2.08     0.723     0.325    0.314   2.40    1.04 
 4     4   0.740   -0.411    -0.307    1.77    0.433   1.36 
 5     5   0.347   -1.57     -0.153    0.657   0.195  -0.915
 6     6  -0.998   -0.145     0.265   -1.95   -0.733  -2.09 
 7     7   2.05    -0.0876   -0.909   -0.190   1.14   -0.278
 8     8   0.0735  -0.134    -2.04    -0.832  -1.96   -0.966
 9     9   1.52     2.37      1.53    -0.596   3.05    1.78 
10    10   1.42    -0.753    -1.61     1.84   -0.194   1.09

rowwise怎么样?您可以使用 cc_across.

指定所需的列
df %>%
  rowwise() %>% 
  mutate(total = sum(c_across(ends_with("ko1"))))

# A tibble: 10 x 5
# Rowwise: 
   l2fc_ko1 l2fc_ko2 ctrl_ko1 ctrl_ko2  total
      <dbl>    <dbl>    <dbl>    <dbl>  <dbl>
 1  -0.179   0.496     -1.10   -0.375  -1.27 
 2  -0.0887 -0.873      0.613  -0.348   0.525
 3  -2.33   -0.322     -0.515   3.03   -2.84 
 4  -0.602  -0.0387     0.704  -0.118   0.102
 5  -0.389  -0.00801    0.276   0.500  -0.113
 6  -2.18    0.648     -0.485  -0.243  -2.66 
 7   0.0529  0.237     -0.371  -0.0382 -0.318
 8   0.818  -0.181      1.11   -1.25    1.93 
 9  -0.271  -0.883      0.480  -0.296   0.209
10  -0.208  -1.11       1.09   -0.528   0.882

如果你有一个动态数量的配对 ctrl_/l2fc_ 列,那么试试这个:

  1. 确保我们拥有所有具有相应 l2fc_ctrl_(反之亦然):

    ctrls <- grep("^ctrl_ko", names(df), value = TRUE)
    l2fcs <- gsub("^ctrl", "l2fc", ctrls)
    ctrls <- ctrls[ l2fcs %in% names(df) ]
    l2fcs <- l2fcs[ l2fcs %in% names(df) ] # or intersect(l2fcs, names(df))
    
  2. 将这些组合成一个向量(稍后我们将对其进行拆分)并将其转换为我们需要的新 _sum 名称。

    nms <- c(l2fcs, ctrls)
    nms
    # [1] "l2fc_ko1" "l2fc_ko2" "ctrl_ko1" "ctrl_ko2"
    newnms <- gsub("ctrl_(.*)", "\1_sum", ctrls)
    newnms
    # [1] "ko1_sum" "ko2_sum"
    
  3. 使用 split.default(它将 df 分成几组列)和 rowSums,我们可以设计两个 _sum 列:

    setNames(as.data.frame(lapply(split.default(df[nms], gsub(".*_ko", "", nms)), rowSums)), newnms)
    #       ko1_sum    ko2_sum
    # 1   1.0643199  1.7603198
    # 2  -2.3460066  2.9914827
    # 3   0.1912111 -0.3537572
    # 4   1.8475373 -0.8877151
    # 5   2.2994618  0.3716338
    # 6  -0.5365936 -1.0810583
    # 7   1.2542526 -1.0687119
    # 8  -1.8578221 -3.5073630
    # 9   2.4785211 -4.8546746
    # 10 -0.7027090  1.3562360
    
  4. 我们可以 cbind/bind_cols 那些,或者我们也可以 mutate 他们。对于后者,我们将在 mutate 环境中将 df 替换为 cur_data(),并且我们需要添加 as.data.frame)

    选择以下一个,所有这些都有效地产生相同的结果:

    cbind(df, setNames(lapply(split.default(df[nms], gsub(".*_ko", "", nms)), rowSums), newnms))
    bind_cols(df, setNames(lapply(split.default(df[nms], gsub(".*_ko", "", nms)), rowSums), newnms))
    df %>% 
      mutate(
        setNames(
          as.data.frame(
            lapply(split.default(cur_data()[nms], gsub(".*_ko", "", nms)), rowSums)),
          newnms)
      )
    # # A tibble: 10 x 6
    #    l2fc_ko1 l2fc_ko2 ctrl_ko1 ctrl_ko2 ko1_sum ko2_sum
    #       <dbl>    <dbl>    <dbl>    <dbl>   <dbl>   <dbl>
    #  1   1.37      1.30    -0.307   0.455    1.06    1.76 
    #  2  -0.565     2.29    -1.78    0.705   -2.35    2.99 
    #  3   0.363    -1.39    -0.172   1.04     0.191  -0.354
    #  4   0.633    -0.279    1.21   -0.609    1.85   -0.888
    #  5   0.404    -0.133    1.90    0.505    2.30    0.372
    #  6  -0.106     0.636   -0.430  -1.72    -0.537  -1.08 
    #  7   1.51     -0.284   -0.257  -0.784    1.25   -1.07 
    #  8  -0.0947   -2.66    -1.76   -0.851   -1.86   -3.51 
    #  9   2.02     -2.44     0.460  -2.41     2.48   -4.85 
    # 10  -0.0627    1.32    -0.640   0.0361  -0.703   1.36