将列表元素名称的data.frames列表合并为合并数据帧中的因子

时间:2011-07-27 18:04:56

标签: r

我有一个data.frame,如下所示,其中location是一个因素而sample是一些测量样本:

  location sample
1      'A'   0.10
2      'A'   0.20
3      'A'   0.15
4      'B'   0.15
5      'B'   0.99
6      'B'   0.54
...

我有一个函数ECCDFpts(df),其中df是一个data.frame,它在<x,y>的经验CCDF上返回一组df$sample点,如下所示:

    x     y
1 0.0  1.00
2 0.1  0.99
3 0.2  0.75
...

请注意,返回的<x,y>点数是“任意”。 输入样本与输出<x,y>行之间的一对一映射。

我想在每个因子(例如,位置)的基础上计算这个CCDF数据,产生这样的data.frame:

  location    x    y
1      'A'  0.0  1.0
2      'A'  0.1  1.0
3      'A'  0.2  0.3
4      'B'  0.0  1.0
5      'B'  0.1  1.0
6      'B'  0.2  0.7
...

我目前的做法是将初始数据框拆分为因子location

eccdfs_by_factor <- by(data, data$location, ECCDFpts)

这会产生data.frames列表:

data$location: A
    x    y
1 0.0  1.0
2 0.1  1.0
3 0.2  0.3
-----------------
data$location: B
    x    y
1 0.0  1.0
2 0.1  1.0
3 0.2  0.7

我不知道如何合并或取消将其重新分成我想要的形式,如前所示。我想合并,以便列表中的元素名称(data.frames)成为组合data.frame中的列因子。

解决方案:

显然,这是一个典型的分裂 - 应用 - 组合问题。最干净的solutions below使用plyr包函数ddply(...)来进行拆分,应用和组合在一行中!我不需要上面使用的基本by函数。

3 个答案:

答案 0 :(得分:4)

更新:如果我理解你想要的东西......

library(plyr)
ldply(your_data)

例如:

x <- list(a=data.frame(x=c(1,2,3,4),y=c(2,3,4,5)),
          b=data.frame(x=c(4,3,2,1),y=c(5,4,3,2)))
ldply(x)

  .id x y
1   a 1 2
2   a 2 3
3   a 3 4
4   a 4 5
5   b 4 5
6   b 3 4
7   b 2 3
8   b 1 2

答案 1 :(得分:3)

一次性解决方案使用plyr包。由于我不知道您的ECDFpts功能,我将自己编写以说明其用法。

# DEFINE DUMMY DATA
mydata = data.frame(
  location = rep(LETTERS[1:3], each = 3),
  sample   = runif(9)
)

# DEFINE DUMMY FUNCTION
myfunc = function(dat){
   x = dat - mean(dat)
   y = dat - median(dat)
   return(data.frame(x, y)) 
}

# USE PLYR TO APPLY FUNCTION BY LOCATION
library(plyr)
ans = ddply(mydata, .(location), transform, x = myfunc(sample)$x, 
         y = myfunc(sample)$y)

  location sample       x      y
1        A  0.911  0.3279  0.232
2        A  0.678  0.0958  0.000
3        A  0.159 -0.4237 -0.520
4        B  0.908  0.3096  0.048
5        B  0.860  0.2615  0.000
6        B  0.027 -0.5711 -0.833
7        C  0.745  0.0694  0.000
8        C  0.343 -0.3327 -0.402
9        C  0.939  0.2633  0.194

EDIT。正如@David在评论中所指出的那样,代码可以进一步简化为

# DEFINE DUMMY FUNCTION
myfunc = function(dat){
   x = with(dat, sample - mean(sample))
   y = with(dat, sample - median(sample))
   return(data.frame(x, y)) 
}

ans = ddply(mydata, .(location), myfunc)

  location       x        y
1        A -0.0308 -0.00564
2        A -0.0251  0.00000
3        A  0.0559  0.08102
4        B -0.4985 -0.69084
5        B  0.3062  0.11392
6        B  0.1923  0.00000
7        C -0.2894 -0.31495
8        C  0.0255  0.00000
9        C  0.2639  0.23838

答案 2 :(得分:3)

您收到的答案绰绰有余,但为了完整起见,我想添加一个解决方案,解释如何从by命令的输出开始获得所需的结果。我将使用一个稍微修改过的Ramnath示例来说明:

mydata = data.frame(
  location = rep(LETTERS[1:3], each = 3),
  sample   = runif(9)
)

# DEFINE DUMMY FUNCTION - slightly different from ramnath's
myfunc = function(dat){
    temp <- data.frame(x = runif(3), y = rnorm(3))
    return(temp) 
}         

您按location分割数据并使用by应用您的功能:

rs <- by(mydata,mydata$location,FUN = myfunc)

mydata$location: A
          x           y
1 0.2730105 -0.06923224
2 0.9354096 -0.18336131
3 0.6359926 -0.04054326
----------------------------------------------------------- 
mydata$location: B
          x           y
1 0.5621529 -0.26404739
2 0.8098687  0.07912883
3 0.7334650  0.38287794
----------------------------------------------------------- 
mydata$location: C
          x          y
1 0.8443924 -0.9055125
2 0.7922256  0.1757586
3 0.4923929 -0.1931579

现在,一个非常方便的事情是,我们可以使用do.callrbind重新将所有内容重新组合在一起:

result <- do.call(rbind,rs)

            x           y
A.1 0.2730105 -0.06923224
A.2 0.9354096 -0.18336131
A.3 0.6359926 -0.04054326
B.1 0.5621529 -0.26404739
B.2 0.8098687  0.07912883
B.3 0.7334650  0.38287794
C.1 0.8443924 -0.90551251
C.2 0.7922256  0.17575858
C.3 0.4923929 -0.19315789

但是等等,你说!添加我的位置列怎么样?那么,请注意do.call(rbind,rs)对结果的行名称所做的事情!我们可以通过从行名称中提取第一个字符来添加位置列:

result$location <- substr(row.names(result),1,1)

当然,这假定您的位置使用单个字符进行编码。但一般来说,生成的行名称应采用location.x形式,因此您可以始终使用strsplit或正则表达式来提取位置名称。

最后,您可以随时修改应用于每个部分的功能,以便在返回结果之前将位置名称添加为列,如下所示:

#Output not shown
myfunc1 = function(dat){
    temp <- data.frame(x = runif(3), y = rnorm(3))
    temp$location <- dat$location[1]
    return(temp) 
}
rs1 <- by(mydata,mydata$location,FUN = myfunc1)
result1 <- do.call(rbind,rs1)

所以你只需要以类似的方式修改你的ECCDFpts功能。