首页 文章

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

提问于
浏览
2

我有一个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,它在 df$sample 的经验CCDF上返回一组 <x,y> 点,如下所示:

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

请注意,返回的 <x,y> 点数为"arbitrary" . 输入样本和输出 <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中的列因子 .

Solution:

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

3 回答

  • 4

    一次性解决方案使用 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
    

    编辑 . 正如@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
    
  • 3

    更新:如果我理解你想要的正确...

    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
    
  • 3

    答案你想要添加一个解决方案,解释如何从 by 命令的输出开始获得所需的结果 . 我是_2450462的例子:

    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 函数 .

相关问题