【问题标题】:Match by id and divide column values across two dataframes按 id 匹配并在两个数据帧中划分列值
【发布时间】:2017-05-18 01:15:03
【问题描述】:

帧:

df 1: 包含多行具有相同 id 的 500 列值

    id|val.1|val.2|...|val.500
---------------------------------
    1 | 240 | 234 |...|228
    1 | 224 | 222 |...|230
    1 | 238 | 240 |...|240
    2 | 277 | 270 |...|255
    2 | 291 | 290 |...|265
    2 | 284 | 282 |...|285

df 2:只包含一个唯一的 id(行)匹配 df-1 id 列和 500 个列值

    id|val.1|val.2|...|val.500
---------------------------------
    1 | 250 | 240 |...|245
    2 | 280 | 282 |...|281

我想根据 df 1 的列值除以 df 2 中对应的列值,根据它们的 id 得到 df 3:

    id|val.1|val.2|...|val.500
---------------------------------
    1 | 0.96| 0.98|...|0.93
    1 | 0.90| 0.93|...|0.94
    1 | 0.95| 1.00|...|0.98
    2 | 0.99| 0.96|...|0.91
    2 | 1.04| 1.03|...|0.94
    2 | 1.01| 1.00|...|1.01

根据 id 和列值对 df 1 值加权 df 2 。一段时间以来,我一直在摸索解决此问题的最佳方法,但没有取得太大进展。任何指导将不胜感激。谢谢

【问题讨论】:

    标签: r dataframe dplyr


    【解决方案1】:

    两种可能的方法:

    1:“宽”-方法

    使用dplyrpurrr 包:

    library(dplyr)
    library(purrr)
    
    df12 <- left_join(df1, df2, by = 'id')
    cbind(id=df12[,1], map2_df(df12[,2:4], df12[,5:7], `/`))
    

    使用data.table 包(方法借用自here):

    library(data.table)
    
    # convert to 'data.tables'
    setDT(df1)
    setDT(df2)
    
    # creates two vectors of matching columnnames
    xcols = names(df1)[-1]
    icols = paste0("i.", xcols)
    
    # join and do the calculation
    df1[df2, on = 'id', Map('/', mget(xcols), mget(icols)), by = .EACHI]
    

    两者都给出:

       id     val.1     val.2     val.3
    1:  1 0.9600000 0.9750000 0.9306122
    2:  1 0.8960000 0.9250000 0.9387755
    3:  1 0.9520000 1.0000000 0.9795918
    4:  2 0.9892857 0.9574468 0.9074733
    5:  2 1.0392857 1.0283688 0.9430605
    6:  2 1.0142857 1.0000000 1.0142349
    

    2:“长”方法

    另一种选择是将您的数据帧重新整形为长格式,然后merge/join 它们并进行计算。

    使用data.table-package:

    library(data.table)
    
    dt1 <- melt(setDT(df1), id = 1)
    dt2 <- melt(setDT(df2), id = 1)
    
    dt1[dt2, on = c('id','variable'), value := value/i.value][]
    

    使用dplyrtidyr 包:

    library(dplyr)
    library(tidyr)
    
    df1 %>% 
      gather(variable, value, -id) %>% 
      left_join(., df2 %>% gather(variable, value, -id), by = c('id','variable')) %>% 
      mutate(value = value.x/value.y) %>% 
      select(id, variable, value)
    

    两者都给出:

        id variable     value
     1:  1    val.1 0.9600000
     2:  1    val.1 0.8960000
     3:  1    val.1 0.9520000
     4:  2    val.1 0.9892857
     5:  2    val.1 1.0392857
     6:  2    val.1 1.0142857
     7:  1    val.2 0.9750000
     8:  1    val.2 0.9250000
     9:  1    val.2 1.0000000
    10:  2    val.2 0.9574468
    11:  2    val.2 1.0283688
    12:  2    val.2 1.0000000
    13:  1    val.3 0.9306122
    14:  1    val.3 0.9387755
    15:  1    val.3 0.9795918
    16:  2    val.3 0.9074733
    17:  2    val.3 0.9430605
    18:  2    val.3 1.0142349
    

    使用过的数据:

    df1 <- structure(list(id = c(1, 1, 1, 2, 2, 2), val.1 = c(240, 224, 238, 277, 291, 284), 
                          val.2 = c(234, 222, 240, 270, 290, 282), val.3 = c(228, 230, 240, 255, 265, 285)), 
                     .Names = c("id", "val.1", "val.2", "val.3"), class = "data.frame", row.names = c(NA, -6L))
    
    df2 <- structure(list(id = c(1, 2), val.1 = c(250, 280), val.2 = c(240, 282), val.3 = c(245, 281)),
                     .Names = c("id", "val.1", "val.2", "val.3"), class = "data.frame", row.names = c(NA, -2L))
    

    【讨论】:

    • 很棒的方法。加一个
    • 谢谢马克西姆斯!我使用了 data.table 格式,因为我可以(几乎)遵循代码。说真的,我如何将我的编码技能逐步提高到你的 50%?
    • @AnandRoopsind thx :-) 继续参与 SO:阅读并运行正确答案的代码(从 r-faq tag 的问题开始)。尝试解决问题:一开始这可能会令人沮丧,但你会做得更好。另请参阅info-page of the R-tag,其中列出了许多重要资源。关于data.table,具体见Getting started wiki on GitHub
    【解决方案2】:

    只要 data.frames 按列正确排序并且都具有相同的列,那么我认为以下基本 R 代码将完成您想要的。

    cbind(df1[1], df1[-1] / df2[match(df1$id, df2$id), -1])
    
      id     val.1     val.2   val.500
    1  1 0.9600000 0.9750000 0.9306122
    2  1 0.8960000 0.9250000 0.9387755
    3  1 0.9520000 1.0000000 0.9795918
    4  2 0.9892857 0.9574468 0.9074733
    5  2 1.0392857 1.0283688 0.9430605
    6  2 1.0142857 1.0000000 1.0142349
    

    这里,match(df1$id, df2$id) 将返回与 df2 的 id 对应的 df1 的行索引,因此 df2[match(df1$id, df2$id), -1] 将返回 df2 的相应行作为删除了 id 变量的 data.frame。当 id 变量被删除并且df1[-1] / df2[match(df1$id, df2$id), -1] 执行除法时,此 data.frame 的形状与 df1 匹配。最后 cbind 将 id 变量添加到最终的 data.frame 中。

    数据

    df1 <- structure(list(id = c(1L, 1L, 1L, 2L, 2L, 2L), val.1 = c(240L, 
    224L, 238L, 277L, 291L, 284L), val.2 = c(234L, 222L, 240L, 270L, 
    290L, 282L), val.500 = c(228L, 230L, 240L, 255L, 265L, 285L)), .Names = c("id", 
    "val.1", "val.2", "val.500"), class = "data.frame", row.names = c(NA, 
    -6L))
    
    df2 <- structure(list(id = 1:2, val.1 = c(250L, 280L), val.2 = c(240L, 
    282L), val.500 = c(245L, 281L)), .Names = c("id", "val.1", "val.2", 
    "val.500"), class = "data.frame", row.names = c(NA, -2L))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-02
      • 1970-01-01
      • 1970-01-01
      • 2016-07-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-15
      相关资源
      最近更新 更多