【问题标题】:Normalization with apply使用 apply 进行标准化
【发布时间】:2020-03-08 08:58:59
【问题描述】:

我正在为一位同事开展一个项目,以标准化 GC 数据并将从 mol% 转换为 mass%。

编辑:我正在进行逐行标准化。即每次norm1 中的物种总和应该是 100(尽管每个都乘以质量,因此不再总和为 100。在 for 循环中,它相当于一个非常繁重的:

for (time in Nmass[,1]){
   for species in norm1{
      Nmass[time,species] = Fmolwt[species,] = Nmass[time,species] / rowSums(Nmass[time,norm1])
                       }
                       }

我导入了 CSV 文件,它们被排列为物种名称列和注入时间行(处理虚拟数据,因此目前全为零)。

> Nmass[1:5,c("Time",norm1)]
# A tibble: 5 x 13
  Time                HTFeed_Methane HTFeed_Ethane HTFeed_Ethylene HTFeed_Propane HTFeed_Propylene `HTFeed_iso-butane` `HTFee~ `HTFeed~ `HTFe~ HTFee~ `HTFee~ `HTFee~
  <dttm>                       <dbl>         <dbl>           <dbl>          <dbl>            <dbl>               <dbl>   <dbl>    <dbl>  <dbl>  <dbl>   <dbl>   <dbl>
1 2019-10-06 13:02:00              0             0               0              0                0                   0       0        0      0      0       0       0
2 2019-10-06 13:17:00              0             0               0              0                0                   0       0        0      0      0       0       0
3 2019-10-06 13:32:00              0             0               0              0                0                   0       0        0      0      0       0       0
4 2019-10-06 13:47:00              0             0               0              0                0                   0       0        0      0      0       0       0
5 2019-10-06 14:02:00              0             0               0              0                0                   0       0        0      0      0       0       0

我有一个正常的正常化例程:

norm1 = c('HTFeed_Methane','HTFeed_Ethane','HTFeed_Ethylene','HTFeed_Propane','HTFeed_Propylene','HTFeed_iso-butane','HTFeed_n-Butane',
        'HTFeed_trans-2-butene','HTFeed_1-Butene','HTFeed_Isobutylene','HTFeed_cis-2-butene','HTFeed_1,3-Butadiene')

Nmass[,norm1] = as.data.frame(apply(Nmass[,norm1], 2, function(x) x/sum(x)))

但是当我尝试使用预先构建的物种质量列表来实现质量转换时:

Fmolwt = data.frame(c(16.04,30.07,28.05,44.9,42.08,58.12,58.12,56.11,56.11,56.11,56.11,54.1))
colnames(Fmolwt)[1] = 'weight'
rownames(Fmolwt) = c('HTFeed_Methane','HTFeed_Ethane','HTFeed_Ethylene','HTFeed_Propane','HTFeed_Propylene','HTFeed_iso-butane',
                    'HTFeed_n-Butane','HTFeed_trans-2-butene','HTFeed_1-Butene','HTFeed_Isobutylene','HTFeed_cis-2-butene','HTFeed_1,3-Butadiene')

套路变成(我认为):

Nmass[,norm1] = as.data.frame(apply(Nmass[,norm1], 2, function(x) x*Fmolwt[x,]/sum(x)))

我收到关于尺寸不同的错误。

Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE,  : 
  arguments imply differing number of rows: 0, 3696
In addition: Warning messages:
1: In x * Fmolwt[x, ] :
  longer object length is not a multiple of shorter object length
2: In x * Fmolwt[x, ] :
  longer object length is not a multiple of shorter object length
3: In x * Fmolwt[x, ] :
  longer object length is not a multiple of shorter object length
4: In x * Fmolwt[x, ] :
  longer object length is not a multiple of shorter object length
5: In x * Fmolwt[x, ] :
  longer object length is not a multiple of shorter object length
6: In x * Fmolwt[x, ] :
  longer object length is not a multiple of shorter object length
7: In x * Fmolwt[x, ] :

我预计这是由于 apply 语句试图同时提取 norm1 中命名的所有内容的分子量。

我可以按照我尝试的方式完成这项工作吗,还是我需要编写一个 for 循环?

【问题讨论】:

  • 不要使用 apply 循环遍历 data.frame 列。使用lapply。无论如何,如果你想同时迭代两个向量/列表/data.frames,你可以使用mapply
  • @Roland 在这种情况下,您能否为我指出正确的 mapply 方向?
  • 嗨@BenA,我查看了您的解释并更正了答案。希望这次是正确的

标签: r


【解决方案1】:

你这里有一个错误:

Nmass[,norm1] = as.data.frame(apply(Nmass[,norm1], 2, function(x) x*Fmolwt[x,]/sum(x)))

使用 apply(..,2,..),您可以使用 x 调用列条目,据我所知,您需要执行逐行操作。其次,Fmolwt[x,] 给出了一个错误,因为您正在调用与 Fmolwt 的行名匹配的值(而不是列名)。

为了说明,我模拟了一些如下所示的数据:

set.seed(1234)

norm1 = c('HTFeed_Methane','HTFeed_Ethane','HTFeed_Ethylene',
'HTFeed_Propane','HTFeed_Propylene','HTFeed_iso-butane',
'HTFeed_n-Butane','HTFeed_trans-2-butene',
'HTFeed_1-Butene','HTFeed_Isobutylene','HTFeed_cis-2-butene',
'HTFeed_1,3-Butadiene')

values <- matrix(abs(rnorm(120,1000,100)),ncol=12)
colnames(values) = norm1

ts <- seq(as.POSIXct("2017-01-01", tz = "UTC"),
    as.POSIXct("2017-01-02", tz = "UTC"),
    length.out = 100)

Nmass = data.frame(Time=ts,values,check.names=F)

Fmolwt = data.frame(c(16.04,30.07,28.05,44.9,42.08,58.12,58.12,
56.11,56.11,56.11,56.11,54.1))
colnames(Fmolwt)[1] = 'weight'
rownames(Fmolwt) = c('HTFeed_Methane','HTFeed_Ethane','HTFeed_Ethylene',
'HTFeed_Propane','HTFeed_Propylene',
'HTFeed_iso-butane','HTFeed_n-Butane','HTFeed_trans-2-butene',
'HTFeed_1-Butene','HTFeed_Isobutylene','HTFeed_cis-2-butene',
'HTFeed_1,3-Butadiene')

模拟数据的样子:

> head(Nmass,2)
                 Time HTFeed_Methane HTFeed_Ethane HTFeed_Ethylene
1 2017-01-01 00:00:00       879.2934      952.2807       1013.4088
2 2017-01-01 00:14:32      1027.7429      900.1614        950.9314
  HTFeed_Propane HTFeed_Propylene HTFeed_iso-butane HTFeed_n-Butane
1      1110.2298        1144.9496          819.3969        1065.659
2       952.4407         893.1357          941.7924        1254.899
  HTFeed_trans-2-butene HTFeed_1-Butene HTFeed_Isobutylene HTFeed_cis-2-butene
1             1000.6893        982.2210           994.6841           1041.4524
2              954.4531        983.0006          1025.5196            952.5282
  HTFeed_1,3-Butadiene
1             980.4065
2             935.0930

第一步,我们以第一行为例,对其进行归一化(按其总数),然后乘以相应的质量,例如第1行,这样做:

Fmolwt[norm1,]*Nmass[1,norm1]/sum(Nmass[1,norm1])

为您提供以下结果:

  HTFeed_Methane HTFeed_Ethane HTFeed_Ethylene HTFeed_Propane HTFeed_Propylene
1       1.176825      2.389309        2.371873       4.159423         4.020092
  HTFeed_iso-butane HTFeed_n-Butane HTFeed_trans-2-butene HTFeed_1-Butene
1          3.973688        5.167942              4.685041        4.598576
  HTFeed_Isobutylene HTFeed_cis-2-butene HTFeed_1,3-Butadiene
1           4.656926            4.875886             4.425653

如果你想使用内置的 r 函数,最简单的是 apply,你已经使用过:

results = t(apply(Nmass[,norm1],1,function(x){
      Fmolwt[norm1,]*x/sum(x)
    }))

所以按照我们之前的做法,x 是来自 Nmass[,norm1] 的一行,所以我们用 x/sum(x) 进行归一化,然后乘以 Fmolwt[norm1,]。这些值匹配,因为我们从 Nmass[,norm1] 开始。现在我们需要转置结果以获得与 Nmass 相同的维度,因此需要 t(apply(..))。

如果我们查看第一行,它会给出与上面示例相同的输出:

> results[1,]
       HTFeed_Methane         HTFeed_Ethane       HTFeed_Ethylene 
             1.176825              2.389309              2.371873 
       HTFeed_Propane      HTFeed_Propylene     HTFeed_iso-butane 
             4.159423              4.020092              3.973688 
      HTFeed_n-Butane HTFeed_trans-2-butene       HTFeed_1-Butene 
             5.167942              4.685041              4.598576 
   HTFeed_Isobutylene   HTFeed_cis-2-butene  HTFeed_1,3-Butadiene 
             4.656926              4.875886              4.425653

所以如果你想把结果放回去,做

Nmass[,norm] = results

【讨论】:

  • 我实际上是按行规范化,我需要在规范化时间戳的同时将 GC 值。所以 2 让它在那里正常工作,对吧?但我看到它打破了质量乘法。
  • 好吧,如果我让你正确的话,对于每一行,你想乘以匹配的质量值并除以行的总和吗?我已经编辑了我的答案
  • 在 tmp 中,当您调用 Fmolwt*Nmass[,norm1] 时,它会神奇地知道将匹配的 Fmolwt 条目与 norm1 条目相乘吗?如果我有 Methane/(Methane+Ethane) 作为一个简单的案例,我需要质量版本相当于 Fmolwt$methane * Methane/(Methane+Ethane)
  • 我更新了我在 OP 中的编辑,以展示我将如何循环遍历结构。我不想要 for 循环的负担,我想利用 R 中的内置功能使其变得更好。谢谢!
  • 感谢 Ben 编辑帖子,是的,它更清晰了。对不起,我对什么是什么有点困惑。我现在已经编辑了我的帖子,它应该给你你想要的。以后,为了防止混淆,最好放一些示例数据,例如 dput(head(Nmass,5)) ,并显示预期结果
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-27
  • 2013-05-02
  • 1970-01-01
  • 1970-01-01
  • 2017-11-01
  • 2015-07-20
  • 2021-06-30
相关资源
最近更新 更多