【问题标题】:How can I multiply two tibbles by column names如何将两个小标题乘以列名
【发布时间】:2019-12-30 03:29:18
【问题描述】:

我有两个列名相同的小标题:

tb1:

   date        a     b     c     d     e
  <date>     <dbl> <dbl> <dbl> <dbl> <dbl>
1 2017-06-01  113.  182.  21.0  31.9  111.

tb2:

   date        a     b     c     d     e
  <date>     <dbl> <dbl> <dbl> <dbl> <dbl>
1 2016-05-01  122. 106.   23.9  43.7  93.5
2 2016-06-01  117. 111.   20.8  41.6  111. 
3 2016-07-01  116.  94.4  22.5  41.0  92.4

我想将 tb2 的每一行乘以 tb1 中的相应数字,有没有一种简单的方法可以用 dplyr 或其他方式做到这一点?我需要保留 tb2 中的日期,但我已将其从 tb1 中删除。

【问题讨论】:

    标签: r dplyr tibble


    【解决方案1】:

    我们可以使tb1tb2 中的行相等,然后将两个大小相等的数据帧相乘。

    cbind(tb2[1], tb1[rep(1, nrow(tb2)), -1] * tb2[-1])
    
    #       date     a       b     c       d       e
    #1 2016-05-01 13786 19292.0 501.9 1394.03 10378.5
    #2 2016-06-01 13221 20202.0 436.8 1327.04 12321.0
    #3 2016-07-01 13108 17180.8 472.5 1307.90 10256.4
    

    如果tb1tb2中的列顺序不同,我们可以先做

    tb1 <- tb1[match(names(tb2), names(tb1))]
    

    然后使用上面的。

    数据

    tb1 <- structure(list(date = structure(1L, .Label = "2017-06-01", class = "factor"),
    a = 113, b = 182, c = 21, d = 31.9, e = 111), class = "data.frame", row.names = "1")
    
    tb2 <- structure(list(date = structure(1:3, .Label = c("2016-05-01", 
    "2016-06-01", "2016-07-01"), class = "factor"), a = c(122, 117, 
    116), b = c(106, 111, 94.4), c = c(23.9, 20.8, 22.5), d = c(43.7, 
    41.6, 41), e = c(93.5, 111, 92.4)), class = "data.frame", 
    row.names = c("1", "2", "3"))
    

    【讨论】:

      【解决方案2】:

      为了很好地扩展并处理不匹配或乱序的列以及不同的行数,我会尝试重新调整数据。如果您将两个数据集都设为长格式,您将拥有 a、b、c、... 列,您可以使用这些列将数据集连接在一起。保留您需要的列并将其重新调整为宽格式。

      我选择使用左连接,以便保留 tb2 中的每一行(具有更多行的行),即使它在 tb1 中没有匹配的行。我还设置了 suffix 参数,以便更清楚每列来自哪个数据集。

      library(dplyr)
      library(tidyr)
      
      left_join(
        pivot_longer(tb2, -date),
        pivot_longer(tb1, -date),
        by = "name", suffix = c("2", "1")
      ) %>%
        mutate(value = value1 * value2) %>%
        select(date = date2, name, value) %>%
        pivot_wider()
      #> # A tibble: 3 x 6
      #>   date           a      b     c     d      e
      #>   <fct>      <dbl>  <dbl> <dbl> <dbl>  <dbl>
      #> 1 2016-05-01 13786 19292   502. 1394. 10378.
      #> 2 2016-06-01 13221 20202   437. 1327. 12321 
      #> 3 2016-07-01 13108 17181.  472. 1308. 10256.
      

      【讨论】:

      • 如何将该文本读入数据框中?谢谢!
      【解决方案3】:

      另一个选项是在 tb1tb2 的数字列上使用 base-R 的 sweep(请检查 ?sweep 的用法),假设列的顺序相同:

      ## sweep multiplication
      tb3 <- sweep(data.matrix(tb2)[, -1], MARGIN = 2, STATS = data.matrix(tb1)[, -1], FUN = "*")
      
      ## convert back to data.frame
      cbind(date = tb2[, 1], as.data.frame(tb3))
      #>         date     a       b     c       d       e
      #> 1 2016-05-01 13786 19292.0 501.9 1394.03 10378.5
      #> 2 2016-06-01 13221 20202.0 436.8 1327.04 12321.0
      #> 3 2016-07-01 13108 17180.8 472.5 1307.90 10256.4
      

      【讨论】:

        【解决方案4】:

        另一种基本 R 解决方案是使用kronecker()tb1 中的行扩展为与tb2[-1] 相同大小的矩阵,即:

        res <- cbind(tb2[1],kronecker(rep(1,nrow(tb2)),as.matrix(tb1[-1]))*tb2[-1])
        

        这样

        > res
                date     a       b     c       d       e
        1 2016-05-01 13786 19292.0 501.9 1394.03 10378.5
        2 2016-06-01 13221 20202.0 436.8 1327.04 12321.0
        3 2016-07-01 13108 17180.8 472.5 1307.90 10256.4
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-04
          • 1970-01-01
          • 1970-01-01
          • 2018-12-09
          • 1970-01-01
          相关资源
          最近更新 更多