【问题标题】:R: apply function to each row of a data frame by factor, calling in the function a value (by factor)R:将函数按因子应用于数据帧的每一行,在函数中调用一个值(按因子)
【发布时间】:2014-02-15 21:04:30
【问题描述】:

我有一个像这样的大数据集:

my.df <- data.frame(Cond= rep(c("A", "B", "C", "D"), each = 4),
             Gene = rep(c("Gene1", "Gene2", "Gene3", "Gene4"), 4),
             Avg=sample(85:100, 16, replace = TRUE), 
             SE=sample(1:5, 16, replace = TRUE), 
             Val1=sample(1:50, 16),
             Val2=sample(1:50, 16))

现在,对于每个基因,我想对所有内容(将“Avg”、“SE”、“Val1”和“Val2”的每个值除以)Cond A 的 Avg 值进行归一化。

我目前的想法是做这样的事情:

by(my.df[ , 3:6], Gene,   #since I want to do my calculation on each Gene
   lapply(function(x)   #since I want to do my calculation on each value

但我不知道如何编写函数,以便它获取x 的当前值并将其除以该基因的 Cond A Avg 值。

另外,我想到制作另一个包含 Gene 和 Cond A Avg 值的数据框:

CondAavg <- my.df[Cond =="A", c("Gene","Avg")]

然后尝试使用 sapply 将函数应用于“基因”的每个值,但我也不太了解如何使其工作。

我显然对 R 还是很陌生,所以任何建议都将不胜感激。

【问题讨论】:

    标签: r apply


    【解决方案1】:

    我会分两步完成,使用merge:

    dtm = merge(subset(my.df,Cond!='A'),
         subset(my.df,Cond=='A',select=c('Gene','Avg')),by='Gene')
       Gene Cond Avg.x SE Val1 Val2 Avg.y
    1  Gene1    B    97  4    9   29    88
    2  Gene1    C    97  5   30   21    88
    3  Gene1    D    94  5   19   39    88
    4  Gene2    B    88  2   13   20    97
    5  Gene2    C    98  5   20   43    97
    6  Gene2    D    95  4   39    2    97
    7  Gene3    B    93  5   40   50    89
    8  Gene3    C    92  5   43   30    89
    9  Gene3    D    91  3   27   11    89
    10 Gene4    B    87  2   49   49    98
    11 Gene4    C    97  3    6   47    98
    12 Gene4    D    88  3   33   44    98
    

    然后我将数字列除以最后一个:

      dtm[,c(3:6)] <- dtm[,c(3:6)]/dtm[,'Avg.y']
    
       Gene Cond     Avg.x         SE       Val1       Val2 Avg.y
    1  Gene1    B 1.1022727 0.04545455 0.10227273 0.32954545    88
    2  Gene1    C 1.1022727 0.05681818 0.34090909 0.23863636    88
    3  Gene1    D 1.0681818 0.05681818 0.21590909 0.44318182    88
    4  Gene2    B 0.9072165 0.02061856 0.13402062 0.20618557    97
    5  Gene2    C 1.0103093 0.05154639 0.20618557 0.44329897    97
    6  Gene2    D 0.9793814 0.04123711 0.40206186 0.02061856    97
    7  Gene3    B 1.0449438 0.05617978 0.44943820 0.56179775    89
    8  Gene3    C 1.0337079 0.05617978 0.48314607 0.33707865    89
    9  Gene3    D 1.0224719 0.03370787 0.30337079 0.12359551    89
    10 Gene4    B 0.8877551 0.02040816 0.50000000 0.50000000    98
    11 Gene4    C 0.9897959 0.03061224 0.06122449 0.47959184    98
    12 Gene4    D 0.8979592 0.03061224 0.33673469 0.44897959    98
    

    最好使用grep 来避免数字索引:

    dtm[, !grepl('Gene|Cond',names(dtm))] = 
        dtm[, !grepl('Gene|Cond',names(dtm))] /dtm[,'Avg.y']
    > dtm
        Gene Cond     Avg.x         SE       Val1       Val2 Avg.y
    1  Gene1    B 1.1022727 0.04545455 0.10227273 0.32954545     1
    2  Gene1    C 1.1022727 0.05681818 0.34090909 0.23863636     1
    3  Gene1    D 1.0681818 0.05681818 0.21590909 0.44318182     1
    4  Gene2    B 0.9072165 0.02061856 0.13402062 0.20618557     1
    5  Gene2    C 1.0103093 0.05154639 0.20618557 0.44329897     1
    6  Gene2    D 0.9793814 0.04123711 0.40206186 0.02061856     1
    7  Gene3    B 1.0449438 0.05617978 0.44943820 0.56179775     1
    8  Gene3    C 1.0337079 0.05617978 0.48314607 0.33707865     1
    9  Gene3    D 1.0224719 0.03370787 0.30337079 0.12359551     1
    10 Gene4    B 0.8877551 0.02040816 0.50000000 0.50000000     1
    11 Gene4    C 0.9897959 0.03061224 0.06122449 0.47959184     1
    12 Gene4    D 0.8979592 0.03061224 0.33673469 0.44897959     1
    

    【讨论】:

    • 谢谢!这比我尝试的要简单得多,并且绝对可以完成工作。我确实想到了一个解决方案,但我不知道如何使用合并来制作最后一列。
    【解决方案2】:

    编辑:请注意,这是对 OP 要求的误解。这样做是通过 Cond=="A" 的平均值对数据框中的每一列进行标准化。把它留在这里以防有人在乎。谢谢 Agstudy。

    你可以试试:

    norm.vec <- colMeans(subset(my.df, Cond=="A")[-(1:2)])
    my.df[-(1:2)] <- t(t(my.df[-(1:2)]) / norm.vec)
    

    这利用了回收的优势(但我们需要转置它才能工作)。 head(df):

    #    Cond  Gene       Avg        SE       Val1      Val2
    # 1     A Gene1 0.9470752 0.6153846 0.89655172 1.6752137
    # 2     A Gene2 1.0473538 1.2307692 1.41379310 0.5811966
    # 3     A Gene3 1.0473538 1.5384615 0.44827586 1.6068376
    # 4     A Gene4 0.9582173 0.6153846 1.24137931 0.1367521
    # 5     B Gene1 1.0250696 0.3076923 0.06896552 0.6495726
    # 6     B Gene2 0.9582173 1.2307692 0.41379310 0.4444444
    

    【讨论】:

    • @Brodgie 这就是 OP 正在寻找的东西。无需使用colMeans,即使我认为这可能是一个很好的解决方案!您应该只使用Avg 列来构造norm.vec。
    • @agstudy,大声笑,感谢您为我回答未提出的问题提供道具。我完全被专栏的名字吓坏了!!考虑到实际询问的内容,除非我对基因的顺序和数量做出很多假设,否则我认为这个答案是行不通的。
    【解决方案3】:

    这是我使用 plyr 包的方法:

    library("plyr")
    
    ddply(my.df, .(Gene), transform,
          Avg.norm = Avg / Avg[Cond=="A"],
          SE.norm = SE / SE[Cond=="A"],
          Val1.norm = Val1 / Val1[Cond=="A"],
          Val2.norm = Val2 / Val2[Cond=="A"])
    

    我将标准化值放入新列中,但您也可以轻松地覆盖现有值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 2018-01-21
      • 2021-01-11
      • 1970-01-01
      • 1970-01-01
      • 2017-09-02
      相关资源
      最近更新 更多