【问题标题】:How to merge two tables with 'holes' in R如何在R中合并两个带有“洞”的表
【发布时间】:2026-02-05 17:50:01
【问题描述】:

我有来自三种不同实验条件、两种不同模式的数据,我已经计算并存储在第一个 data.frame 中,每个模式的每个条件的平均值和标准差。好像

t1 <- data.frame(condition = rep(c("A","B","C"),times=2),
             mode = rep(c(1,2),each=3),
             mean = rnorm(6),
             sd = rnorm(6))

然后,我计算了 mann-whitney 秩和检验的每个成对比较条件。生成的 data.frame 如下所示:

t2 <- data.frame(mode = rep(c(1,2),each=3),
             test = rep(c("AvB","AvC","BvC"),2),
             pvalue = runif(6,0,0.2)
             )

我想将两个 data.frames 与“holes”组合在一个 data.frame 中,每个测试显示模式、实际测试条件的均值和 p 值。 我想到了这样的事情:

mode    mean A  mean B  mean C  test    pvalue
1       1.34    1.12            A v B   0.067
1       1.34            0.98    A v C   0.021
1               1.12    0.98    B v C   0.345

我知道结果表中存在漏洞——不太适合在其上运行统计信息——但我的目标是创建一个 .tex 表(使用 xtable())来显示所有可能的成对测试,并且,同时显示每个模式下每个条件下变量的均值。这是为了在纸质附录中展示。

谢谢!

【问题讨论】:

  • 在您的t1 数据框中,rep 调用之一需要times 而不是each(否则您不会获得唯一标识符)。
  • 正确@tegancp,谢谢。已编辑。

标签: r merge dataframe


【解决方案1】:

没有使用 reshape2 的 plyr 或 dplyr 的解决方案。它可以处理更多的条件和测试,并且不需要硬编码比较。

library(reshape2)
#make column with variables that are tested (so can be used if many pairs/changing
#names as long as there is a clear separation
t2$var1 <- gsub("v.+","",t2$test)
t2$var2 <- gsub(".+v","",t2$test)

#combine data in long format
t3 <- merge(t1,t2,by="mode")

#create mean_na vector with removed means when test is not performed
t3$mean_na <- with(t3, ifelse(condition==var1|condition==var2,mean,NA))

#cast to table
res_temp <- dcast(mode+test~condition,value.var="mean_na",data=t3)
res_temp

#re-add pvalue
result_final <- merge(res_temp,t2[,c("mode","test","pvalue")],by=c("mode","test"))

> result_final
  mode test           A          B        C     pvalue
1    1  AvB -0.56047565 -0.2301775       NA 0.13114116
2    1  AvC -0.56047565         NA 1.558708 0.14170609
3    1  BvC          NA -0.2301775 1.558708 0.10881320
4    2  AvB  0.07050839  0.1292877       NA 0.11882840
5    2  AvC  0.07050839         NA 1.715065 0.05783195
6    2  BvC          NA  0.1292877 1.715065 0.02942273

【讨论】:

    【解决方案2】:

    这是一个想法:

    library(tidyr)
    library(dplyr)
    
    t2 %>% 
      separate(test, into = c("cond1", "cond2"), sep = "v", remove = FALSE) %>%
      gather(key, condition, -mode, -pvalue, -test) %>%
      select(-key) %>%
      left_join(t1 %>% select(-sd)) %>% 
      spread(condition, mean) %>%
      setNames(c(names(.)[1:3], paste("mean", names(.)[4:6])))
    

    这给出了:

    #  mode test      pvalue     mean A    mean B     mean C
    #1    1  AvB 0.053444134 -0.6264538 0.1836433         NA
    #2    1  AvC 0.077222819 -0.6264538        NA -0.8356286
    #3    1  BvC 0.002678067         NA 0.1836433 -0.8356286
    #4    2  AvB 0.076477591  1.5952808 0.3295078         NA
    #5    2  AvC 0.173938169  1.5952808        NA -0.8204684
    #6    2  BvC 0.068069799         NA 0.3295078 -0.8204684
    

    如果您想将结果传递到 xtable 中,您可以添加:

    ... %&gt;% xtable() %&gt;% print(type = "html")

    <!-- html table generated in R 3.2.1 by xtable 1.7-4 package -->
    <!-- Fri Jun 19 18:45:36 2015 -->
    <table border=1>
    <tr> <th>  </th> <th> mode </th> <th> test </th> <th> pvalue </th> <th> mean A </th> <th> mean B </th> <th> mean C </th>  </tr>
    <tr> <td align="right"> 1 </td> <td align="right"> 1.00 </td> <td> AvB </td> <td align="right"> 0.05 </td> <td align="right"> -0.63 </td> <td align="right"> 0.18 </td> <td align="right">  </td> </tr>
    <tr> <td align="right"> 2 </td> <td align="right"> 1.00 </td> <td> AvC </td> <td align="right"> 0.08 </td> <td align="right"> -0.63 </td> <td align="right">  </td> <td align="right"> -0.84 </td> </tr>
    <tr> <td align="right"> 3 </td> <td align="right"> 1.00 </td> <td> BvC </td> <td align="right"> 0.00 </td> <td align="right">  </td> <td align="right"> 0.18 </td> <td align="right"> -0.84 </td> </tr>
    <tr> <td align="right"> 4 </td> <td align="right"> 2.00 </td> <td> AvB </td> <td align="right"> 0.08 </td> <td align="right"> 1.60 </td> <td align="right"> 0.33 </td> <td align="right">  </td> </tr>
    <tr> <td align="right"> 5 </td> <td align="right"> 2.00 </td> <td> AvC </td> <td align="right"> 0.17 </td> <td align="right"> 1.60 </td> <td align="right">  </td> <td align="right"> -0.82 </td> </tr>
    <tr> <td align="right"> 6 </td> <td align="right"> 2.00 </td> <td> BvC </td> <td align="right"> 0.07 </td> <td align="right">  </td> <td align="right"> 0.33 </td> <td align="right"> -0.82 </td> </tr>
    </table>

    数据

    set.seed(1)
    
    t1 <- data.frame(condition = rep(c("A","B","C"),times=2),
                     mode = rep(c(1,2),each=3),
                     mean = rnorm(6),
                     sd = rnorm(6))
    
    t2 <- data.frame(mode = rep(c(1,2),each=3),
                     test = rep(c("AvB","AvC","BvC"),2),
                     pvalue = runif(6,0,0.2))
    

    【讨论】:

    • 这很好,可以解决问题,但我现在(还)不熟悉 dplyr ......我对上面的 reshape2 答案更放心。这提出了下一个问题,即:我应该学习 dplyr 并切换到它吗?值得努力吗?谢谢!
    • @PaoloCrosetto 很多知识渊博的人都使用data.table。我自己更喜欢dplyr*.com/questions/21435339/…
    【解决方案3】:

    这适用于相当小的数据;如果你真的有更多的条件,这种方法不会很有趣:

    library(reshape2)
    library(dplyr)
    
    means <- dcast(t1, mode~condition, value.var='mean')
    
    results <- merge(t2, means) %>%
        # extract conditions of each test row
        mutate(first=substr(test,1,1), second=substr(test,3,3), 
               # replace untested condition means with ""
                  meanA=ifelse(first=='A'|second=='A', A, ""),
                  meanB=ifelse(first=='B'|second=='B', B, ""),
                  meanC=ifelse(first=='C'|second=='C', C, "")) %>%
        # discard unwanted columns
        select(mode, meanA, meanB, meanC, test, pvalue)
    
    > print(results)
      mode  meanA  meanB meanC test     pvalue
    1    1 -0.646 -0.778        AvB 0.03597074
    2    1 -0.646        0.014  AvC 0.11394383
    3    1        -0.778 0.014  BvC 0.14393726
    4    2  0.083  0.275        AvB 0.16493966
    5    2  0.083        0.619  AvC 0.06548713
    6    2         0.275 0.619  BvC 0.08474118
    

    【讨论】:

    • 很好的解决方案,但你猜对了:我确实有更多的条件,这只是一个小例子。
    • 对; Heroka 的答案很好地处理了多种情况