【问题标题】:Multiplication of different subsets with different data in RR中不同数据与不同子集的乘法
【发布时间】:2016-06-06 15:17:50
【问题描述】:

我有一个大型数据集,我将其拆分为子集。对于每个子集,我必须使用不同的数字进行相同的计算。示例:

Main Table
x a b c d
A 1 2 4 5 
A 4 5 1 7
A 3 5 6 2
B 4 5 2 9
B 3 5 2 8
C 4 2 5 2
C 1 9 6 9
C 1 2 3 4
C 6 3 6 2

 Additional Table for A
  a b c d
A 5 1 6 1

Additional Table for B
  a b c d
B 1 5 2 6

Additional Table for C
  a c c d
C 8 2 4 1

我需要将主表中的所有行 A 与附加表中 A 的值相乘,主表中的所有行 B 与 B 中的值相乘,主表中的所有行 B 与 C 中的值相乘。它是如果这使解决方案更容易,那么将其他表合并到一个组合中是完全可以的。

我考虑了一个 for 循环,但我无法将不同的乘数(来自附加表)放入代码中。由于存在大量子组,因此应避免手动编码每个乘法。我该如何做这个乘法?

【问题讨论】:

  • 分享您的一些数据以使用:dput(your_data) 将其粘贴到您的问题中。
  • 我刚刚注意到您在我的帖子上评论了一些内容并将其删除。抓不住。

标签: r subset matrix-multiplication multiplication


【解决方案1】:

如果我们以 addDf 开头的加法表和 df 的主表开始:

addDf
  x a b c d
A A 5 1 6 1
B B 1 5 2 6
C C 8 2 4 1

我们可以使用矩阵的合并和逐元素乘法,

df[-1] <- merge(addDf, data.frame(x = df[1]), by = "x")[-1] * df[order(df[1]), -1]
df
  x  a  b  c  d
1 A  5  2 24  5
2 A 20  5  6  7
3 A 15  5 36  2
4 B  4 25  4 54
5 B  3 25  4 48
6 C 32  4 20  2
7 C  8 18 24  9
8 C  8  4 12  4
9 C 48  6 24  2

注意:从@akrun 借用一点语法糖作为df[-1] 赋值。

【讨论】:

  • merge 似乎对两个“data.frame”的“by”列进行了排序;即* df[-1] 不适用于未订购的df$x。类似的merge-y 替代方案可能是addDf[match(df$x, addDf$x), -1] * df[-1] 或类似的东西
  • @alexis_laz。是的,感谢您指出这一点。刚刚更新了一个排序的版本,我同意你的方法甚至很短。
  • @Psidom 这很好用。不幸的是,我的 data.frame df 要大得多,并且包含数百个与乘法无关的列。在对真实数据使用计算时,我收到消息“*”是为相同大小的数据帧定义的。解决方案是什么?
  • 您可以明确指定要修改的列。例如,如果您只想将列从 2 修改为 5,您可以使用 df[2:5] &lt;- merge(addDf, data.frame(x = df[1]), by = "x")[-1] * df[order(df[1]), 2:5]。这样,您只需提取与附加表具有相同维度的数字列,将它们相乘并相应地修改它们。
【解决方案2】:

我们可以在splitting主数据'df'之后使用Map(假设所有数据集都是data.frames。

df[-1] <- unsplit(Map(function(x,y) x*y[col(x)], 
                     split(df[-1], df$x),
                     list(unlist(dfA), unlist(dfB), unlist(dfC))), df$x)
df
#  x  a  b  c  d
#1 A  5  2 24  5
#2 A 20  5  6  7
#3 A 15  5 36  2
#4 B  4 25  4 54
#5 B  3 25  4 48
#6 C 32  4 20  2
#7 C  8 18 24  9
#8 C  8  4 12  4
#9 C 48  6 24  2

或者我们可以使用更快的选项data.table

library(data.table)
setnames(setDT(do.call(rbind, list(dfA, dfB, dfC)), keep.rownames=TRUE)[df, 
 .(a= a*i.a, b= b*i.b, c = c*i.c, d= d*i.d),  on = c('rn' = 'x'), by = .EACHI], 1, 'x')[]
#   x  a  b  c  d
#1: A  5  2 24  5
#2: A 20  5  6  7
#3: A 15  5 36  2
#4: B  4 25  4 54
#5: B  3 25  4 48
#6: C 32  4 20  2
#7: C  8 18 24  9
#8: C  8  4 12  4
#9: C 48  6 24  2

如果有很多列,上面会很困难,在这种情况下,我们可以使用mget 来检索列,并在i. 列上使用Map 执行*

setDT(do.call(rbind, list(dfA, dfB, dfC)), keep.rownames=TRUE)[df,  
     Map(`*`, mget(names(df)[-1]), mget(paste0("i.", names(df)[-1]))) ,
          on = c('rn' = 'x'), by = .EACHI]

【讨论】:

  • @akrun:非常感谢,但我也得到了不同的结果。似乎 addDF 表是从最后一个值读取(并因此相乘)到第一个值。
  • @nous.calc 看起来我得到的结果与另一篇文章相同(其中我的 id 在上下文中也提到了一些糖)。在这里,我假设所有数据集都是data.frame
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-03
  • 2011-10-16
  • 1970-01-01
  • 2016-09-04
相关资源
最近更新 更多