【问题标题】:Extending data from one data frame to multiple rows in another in R在R中将数据从一个数据帧扩展到另一个数据帧的多行
【发布时间】:2012-08-16 13:55:12
【问题描述】:

我是 R 和这个列表的新手。我希望接下来的问题不是太基本或不了解情况。过去几个小时我一直在查看档案,但无济于事,所以我在这里发布。部分问题是我并不完全知道在引用我需要的功能时要使用的正确术语,这会使搜索变得困难。话虽如此,这就是我需要解决的问题:

我有一个如下所示的数据框:

   Subject Item Region   RT  
13     102    1  R1 1245  
14     102    4  R1 1677  
15     102    7  R1 1730  
25     103    1  R1  815  
26     103    4  R1  828  
27     103    7  R1  985  
1489     102    1  R2 356  
1490     102    4  R2 510  
1491     102    7  R2 544  
1501     103    1  R2 447  
1502     103    4  R2 486  
1503     103    7  R2 221  
...  

每个受试者对一个项目的多个区域都有一个 RT(反应时间)。并且每个主题都可以看到多个项目。

我希望计算异常值,然后对其进行规范化(尽管我不会真正担心这个线程中的解决方案)。作为第一步,我使用了一些简单的函数来计算每个主题的每个区域的平均值和 SD,并跨项目折叠(即(该主题在该区域中所有 RT 的平均值):

Mean = with(test, aggregate(RT, by = list(Subject,Region),mean, na.rm=TRUE))  
SD = with(test, aggregate(RT, by = list(Subject,Region),sd, na.rm=TRUE))  

然后我使用 cbind 并进行了一些重命名以将数据全部放在一个数据帧中:

Subject Region      Mean         SD  
1       102  R1 1143.7778  202.25530  
2       102  R2  431.8611  125.84393  
9       103  R1  923.0833  179.51098  
10      103  R2  344.1667  146.51192  
...  

问题是我现在需要将所有方法与每个主题的正确区域相关联。也就是说,我想生成如下所示的输出(请注意,所有主题 102 区域 R1 具有相同的均值和 SD,但不同的 RT 等):

Subject Item Region   RT Mean         SD  
13     102    1  R1 1245 1143.7778  202.25530  
14     102    4  R1 1677 1143.7778  202.25530  
15     102    7  R1 1730 1143.7778  202.25530  
25     103    1  R1  815 923.0833  179.51098  
26     103    4  R1  828 923.0833  179.51098  
27     103    7  R1  985 923.0833  179.51098  
1489     102    1  R2 356 431.8611  125.84393   
1490     102    4  R2 510 431.8611  125.84393  
1491     102    7  R2 544 431.8611  125.84393  
1501     103    1  R2 447 344.1667  146.51192  
1502     103    4  R2 486 344.1667  146.51192  
1503     103    7  R2 221 344.1667  146.51192  

看来,merge 和 cbind 并不能完成将一个值扩展和匹配到另一个值的工作。也许我需要使用 melt 或一些使用键的功能?

我希望有人可以向我指出相关功能以供我阅读,以便我可以自己尝试,或者只是帮助一些代码。

感谢阅读...

【问题讨论】:

  • 为什么你觉得merge()在这里没用?
  • 没有“太基础的问题”,欢迎来到 SO 的 R 部分! ;-)
  • 我怀疑 merge() 不相关可能是没有根据的。也许我应该说我不明白如何让 merge() 工作来完成我需要的工作。我刚刚找到了这个链接,这似乎很相关:stackoverflow.com/questions/4227077/…

标签: r dataframe


【解决方案1】:

您可以使用 plyr 包中的 ddply 函数完成此任务。使用ddplyave函数:

test <- read.table(text="
Subject Item Region   RT  
13     102    1  R1 1245  
14     102    4  R1 1677  
15     102    7  R1 1730  
25     103    1  R1  815  
26     103    4  R1  828  
27     103    7  R1  985  
1489     102    1  R2 356  
1490     102    4  R2 510  
1491     102    7  R2 544  
1501     103    1  R2 447  
1502     103    4  R2 486  
1503     103    7  R2 221", header=T)

library(plyr)
ddply(test, .(Subject, Region), transform, Mean=ave(RT), SD=ave(RT, FUN=sd))
   Subject Item Region   RT      Mean        SD
1      102    1     R1 1245 1550.6667 266.03822
2      102    4     R1 1677 1550.6667 266.03822
3      102    7     R1 1730 1550.6667 266.03822
4      102    1     R2  356  470.0000 100.17984
5      102    4     R2  510  470.0000 100.17984
6      102    7     R2  544  470.0000 100.17984
7      103    1     R1  815  876.0000  94.62029
8      103    4     R1  828  876.0000  94.62029
9      103    7     R1  985  876.0000  94.62029
10     103    1     R2  447  384.6667 143.07457
11     103    4     R2  486  384.6667 143.07457
12     103    7     R2  221  384.6667 143.07457

您可以像以前一样使用aggregate 函数检查结果。

> with(test, aggregate(RT, by = list(Subject,Region),mean, na.rm=TRUE))  
  Group.1 Group.2         x
1     102      R1 1550.6667
2     103      R1  876.0000
3     102      R2  470.0000
4     103      R2  384.6667
> with(test, aggregate(RT, by = list(Subject,Region),sd, na.rm=TRUE))
  Group.1 Group.2         x
1     102      R1 266.03822
2     103      R1  94.62029
3     102      R2 100.17984
4     103      R2 143.07457

如您所见,由SubjectRegion 聚合的均值和标准差都放入您的data.frame (test) 中。

编辑

如果你想处理NA,你可能需要使用下面的编辑代码:

ddply(test, .(Subject, Region), transform, 
      Mean=ave(RT, FUN = function(x) mean(x, na.rm=TRUE)),
      SD=ave(RT, FUN=function(x) sd(x, na.rm=TRUE)))

【讨论】:

  • 您好 Jiber - 感谢您推荐 plyr。这似乎与我的完整数据集效果很好。另一个问题:对于现在嵌套在 ddply 中的平均值的计算,它是否默认为 na.rm-TRUE?
  • 你好@user1603288 你可以在我的回答中看到编辑,我添加了一种方法可以让你处理'NA'
  • @Jiber。谢谢 - 使用 ave() 对我来说是新的,但你的例子很有意义。非常感谢。
【解决方案2】:

这可以通过sqldf来完成

df1<-read.table(header=T,text="Subject Item Region   RT  
13     102    1  R1 1245  
14     102    4  R1 1677  
15     102    7  R1 1730  
25     103    1  R1  815  
26     103    4  R1  828  
27     103    7  R1  985  
1489     102    1  R2 356  
1490     102    4  R2 510  
1491     102    7  R2 544  
1501     103    1  R2 447  
1502     103    4  R2 486  
1503     103    7  R2 221")

df2<-read.table(header=T,text="Subject Region      Mean         SD  
1       102  R1 1143.7778  202.25530  
2       102  R2  431.8611  125.84393  
9       103  R1  923.0833  179.51098  
10      103  R2  344.1667  146.51192")  

library(sqldf)
sqldf("SELECT df1.*,df2.Mean,df2.SD from df1,df2
        WHERE df1.Region=df2.Region 
         GROUP BY df1.Region,df1.Subject,df1.Item")

#   Subject Item Region   RT      Mean       SD
#1      102    1     R1 1245 1143.7778 202.2553
#2      102    4     R1 1677 1143.7778 202.2553
#3      102    7     R1 1730 1143.7778 202.2553
#4      103    1     R1  815 1143.7778 202.2553
#5      103    4     R1  828 1143.7778 202.2553
#6      103    7     R1  985 1143.7778 202.2553
#7      102    1     R2  356  431.8611 125.8439
#8      102    4     R2  510  431.8611 125.8439
#9      102    7     R2  544  431.8611 125.8439
#10     103    1     R2  447  431.8611 125.8439
#11     103    4     R2  486  431.8611 125.8439
#12     103    7     R2  221  431.8611 125.8439

按地区、主题、项目排序

【讨论】:

    【解决方案3】:

    您已经完成了 99% 的工作。您唯一需要做的就是“美化”您的aggregate() 输出,以便它更礼貌地与merge() 配合使用。请注意,在下文中,您指定了输出列名称,以便它们可以轻松合并。

    然后,我们使用Reduce() 递归合并。

    Mean = with(test, aggregate(list(mean = RT), 
                                by = list(Subject = Subject, Region = Region), 
                                mean, na.rm=TRUE))
    SD = with(test, aggregate(list(sd = RT), 
                              by = list(Subject = Subject, Region = Region), 
                              sd, na.rm=TRUE))
    Reduce(function(x, y) merge(x, y), list(test, Mean, SD))
    #    Subject Region Item   RT      mean        sd
    # 1      102     R1    1 1245 1550.6667 266.03822
    # 2      102     R1    4 1677 1550.6667 266.03822
    # 3      102     R1    7 1730 1550.6667 266.03822
    # 4      102     R2    1  356  470.0000 100.17984
    # 5      102     R2    4  510  470.0000 100.17984
    # 6      102     R2    7  544  470.0000 100.17984
    # 7      103     R1    1  815  876.0000  94.62029
    # 8      103     R1    4  828  876.0000  94.62029
    # 9      103     R1    7  985  876.0000  94.62029
    # 10     103     R2    1  447  384.6667 143.07457
    # 11     103     R2    4  486  384.6667 143.07457
    # 12     103     R2    7  221  384.6667 143.07457
    # merge(merge(test, Mean), SD)
    

    【讨论】:

    • 嗨 mrdwab。感谢您的建议,感谢您尝试使用我迄今为止所做的工作。这可能很简单,但我不太明白这部分代码中发生了什么: (list(mean = RT).do you possible mean (list(mean, RT)??? 其余的,至少目前看来相当清楚。
    • @user1603288, list(mean = RT) 表示创建一个名为mean 的列。如果我将它命名为Mean,也许它不会那么混乱,因为有一个名为mean() 的函数。如果您不指定列名(在列表中,就像我在这里所做的那样),结果将类似于 Jilber 的 aggregate() 示例,其中列名为 Group.1Group.2x。因此,我建议“美化”您的 aggregate() 输出。
    • @mrwab。我确实理解您在聚合函数中分配名称(如果我可以这样说的话),主题和区域列表组件非常清楚。但是我仍然很难理解为什么您将 RT 分配给“平均值”(或“平均值”,正如您所建议的那样)。为了清楚起见,我是否可以将此语法理解为“在 RT 中(按主题和区域)对列 test 操作均值函数,然后将其命名为“均值”?这当然是它似乎在做的事情,但我想确保我知道这里发生了什么。谢谢!
    • 我的意思是:“对数据框“test”中的“RT”列(按主题和区域)操作均值函数,然后将其命名为“均值”?
    • @user1603288,是的。你的解释是正确的。通过将它们添加到第一个列表中,您可以一次聚合多个列。例如(愚蠢的例子),假设您想取RT 的平均值(在名为“Mean.RT”的列中)和Item 的平均值(在名为 ("Mean.Item" 的列中),您会这样做:list(Mean.RT = test$RT, Mean.Item = test$Item)。如果你没有分配输出列名,你最终会得到一些可怕的列名。试试看。
    【解决方案4】:

    这是一种蛮力,但它有效

    test <- data.frame(Subject=rep(c(102,103),2,each=3), Item=rep(c(1,4,7),4),Region=rep(c("R1","R2"),each=6), RT= c(1245,1677,1730,815,828,985,356,510,544,447,486,221))
    
    Mean = with(test, aggregate(RT, by = list(Subject,Region),mean, na.rm=TRUE))  
    SD = with(test, aggregate(RT, by = list(Subject,Region),sd, na.rm=TRUE))  
    
    aa <- data.frame(test, Mean=0, SD=0)
    
    for (i in 1:nrow(aa)) {
      for(j in 1:nrow(Mean)){
        if (aa$Subject[i]==Mean$Group.1[j] & aa$Region[i]==Mean$Group.2[j]) aa$Mean[i] <- Mean$x[j]
        if (aa$Subject[i]==SD$Group.1[j] & aa$Region[i]==SD$Group.2[j]) aa$SD[i] <- SD$x[j]
      }
    }
    

    【讨论】:

    • 感谢您的建议擦。其他方法可能更容易,因为我的主题和项目数量比我上面指出的要多。我希望建立一个更通用的例程,以便我可以将其应用于大量数据。但我还是会仔细研究一下,以便了解更多如何思考这个问题。
    猜你喜欢
    • 2022-10-25
    • 2020-08-20
    • 1970-01-01
    • 1970-01-01
    • 2013-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多