【问题标题】:mutate multiple columns elegantly优雅地改变多个列
【发布时间】:2019-07-22 17:05:14
【问题描述】:

如下图所示 df

df <- read.table(text="name id_final    id1 id2 id3
sample1 10.96311    4.767571    3.692556    2.966773
sample2 10.83782    11.61998    11.402257   10.301068
sample3 13.98669    12.123346   10.299306   8.85533
sample4 13.97313    12.200774   11.874366   11.013115
sample5 13.89532    10.712515   9.102278    9.832699
sample6 13.86255    11.808834   9.180613    8.813621", header=T, sep='\t')
head(df)
> head(df)
     name id_final       id1       id2       id3
1 sample1 10.96311  4.767571  3.692556  2.966773
2 sample2 10.83782 11.619980 11.402257 10.301068
3 sample3 13.98669 12.123346 10.299306  8.855330
4 sample4 13.97313 12.200774 11.874366 11.013115
5 sample5 13.89532 10.712515  9.102278  9.832699
6 sample6 13.86255 11.808834  9.180613  8.813621

需要做一些基本的数学运算,将每一列除以 id_final 列 并以_log 作为后缀创建新列,这可以通过简单的变异来完成,如下所示。

df <- df %>%
  mutate(id1_log = log2(id1/id_final),
         id2_log = log2(id2/id_final),
         id3_log = log2(id3/id_final))
head(df)
> head(df)
     name id_final       id1       id2       id3    id1_log     id2_log     id3_log
1 sample1 10.96311  4.767571  3.692556  2.966773 -1.2013308 -1.56996541 -1.88569067
2 sample2 10.83782 11.619980 11.402257 10.301068  0.1005330  0.07324483 -0.07328067
3 sample3 13.98669 12.123346 10.299306  8.855330 -0.2062667 -0.44150746 -0.65943661
4 sample4 13.97313 12.200774 11.874366 11.013115 -0.1956825 -0.23480474 -0.34343264
5 sample5 13.89532 10.712515  9.102278  9.832699 -0.3753018 -0.61029950 -0.49893967
6 sample6 13.86255 11.808834  9.180613  8.813621 -0.2313261 -0.59453027 -0.65338590

在给定的示例中,如果只有 3 列,这很容易,如果我有超过 3 列,我将如何自动执行此操作,每次输入都不优雅。

mutate(id1_log = log2(id1/id_final),
          id2_log = log2(id2/id_final),
          id3_log = log2(id3/id_final))

为了给出更大的图景,我正在尝试编写一个函数,我可以在具有多个 id1...n 列的多个文件上使用该函数

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    可以:

    library(dplyr)
    
    df %>% mutate_at(vars(matches("id\\d+$")), list(log = ~ log2(. / id_final)))
    

    我们改变(与mutate_at 一起)所需的列 - 这些都与正则表达式 id\\d+$ 匹配,它基本上匹配以数字结尾并以 id 开头的列名(例如,为了避免捕获 @ 987654325@ 或任何其他id_.. 列。

    之后,我们会提供一个包含所需转换的列表。您可以为转换提供一个名称,然后此名称会自动附加到列名称中。我们说log,所以列最后会自动得到_log;你可以在那里写任何东西。

    如果您不提供名称,则会修改已存在的列;如果你这样做了,你会得到像我们这样的额外的。

    输出:

         name id_final       id1       id2       id3    id1_log     id2_log     id3_log
    1 sample1 10.96311  4.767571  3.692556  2.966773 -1.2013308 -1.56996541 -1.88569067
    2 sample2 10.83782 11.619980 11.402257 10.301068  0.1005330  0.07324483 -0.07328067
    3 sample3 13.98669 12.123346 10.299306  8.855330 -0.2062667 -0.44150746 -0.65943661
    4 sample4 13.97313 12.200774 11.874366 11.013115 -0.1956825 -0.23480474 -0.34343264
    5 sample5 13.89532 10.712515  9.102278  9.832699 -0.3753018 -0.61029950 -0.49893967
    6 sample6 13.86255 11.808834  9.180613  8.813621 -0.2313261 -0.59453027 -0.65338590
    

    【讨论】:

    • 甜蜜!你能解释一下发生了什么吗?
    • 已添加简短说明 - 如果您有任何其他问题,请告诉我。我还建议您查看?mutate_atdplyr 动词的其他范围变体(selectrename、或summarisedistinct 最近等)。可能非常有用。
    • 完美!!这有助于我了解正在发生的事情
    【解决方案2】:

    这里有一个data.table 选项:

    library(data.table)
    cols <- names(df)[3:5] # first, select columns you are interested in (or names(df)[grepl("id\\d+$", names(df))])
    setDT(df)[, paste(cols, "log", sep = "_") :=  lapply(.SD, function(x) log2(x/id_final)),
              .SDcols = cols][] # apply { function(x) log2(x/id_final) } to selected columns
    # output
          name id_final       id1       id2       id3    id1_log     id2_log     id3_log
    1: sample1 10.96311  4.767571  3.692556  2.966773 -1.2013308 -1.56996541 -1.88569067
    2: sample2 10.83782 11.619980 11.402257 10.301068  0.1005330  0.07324483 -0.07328067
    3: sample3 13.98669 12.123346 10.299306  8.855330 -0.2062667 -0.44150746 -0.65943661
    4: sample4 13.97313 12.200774 11.874366 11.013115 -0.1956825 -0.23480474 -0.34343264
    5: sample5 13.89532 10.712515  9.102278  9.832699 -0.3753018 -0.61029950 -0.49893967
    6: sample6 13.86255 11.808834  9.180613  8.813621 -0.2313261 -0.59453027 -0.65338590
    

    【讨论】:

    • 这很好,但是有数千列,第一部分变得令人厌烦。也许一些“自动”的方式来提取目标列?
    • 当然,你是对的。根据 OP 数据,选择目标列或多或少会让人厌烦,但 there are many ways to do that。这里的重点是看到有一个必要的步骤是选择目标列,无论列名是否一致
    猜你喜欢
    • 2021-07-08
    • 2016-10-09
    • 1970-01-01
    • 2015-12-05
    • 1970-01-01
    • 2013-06-01
    • 2021-02-19
    • 2015-11-27
    • 1970-01-01
    相关资源
    最近更新 更多