【问题标题】:Split a large dataframe into a list of data frames based on common value in column根据列中的共同值将大数据框拆分为数据框列表
【发布时间】:2019-12-25 14:56:40
【问题描述】:

我有一个包含 10 列的数据框,收集“用户”的操作,其中一列包含一个 ID(不是唯一的,标识用户)(第 10 列)。数据帧的长度约为 750000 行。我正在尝试提取由包含“用户”标识符的列拆分的单个数据帧(因此获取数据帧的列表或向量),以隔离单个参与者的操作。

ID | Data1 | Data2 | ... | UserID
1  | aaa   | bbb   | ... | u_001
2  | aab   | bb2   | ... | u_001
3  | aac   | bb3   | ... | u_001
4  | aad   | bb4   | ... | u_002

导致

list(
ID | Data1 | Data2 | ... | UserID
1  | aaa   | bbb   | ... | u_001
2  | aab   | bb2   | ... | u_001
3  | aac   | bb3   | ... | u_001
,
4  | aad   | bb4   | ... | u_002
...)

以下对我来说非常适合小样本(1000 行):

paths = by(smallsampleMat, smallsampleMat[,"userID"], function(x) x)

然后通过路径[1] 访问我想要的元素。

当应用于原始大数据帧甚至矩阵表示时,这会阻塞我的机器(4GB RAM,MacOSX 10.6,R 2.15)并且永远不会完成(我知道存在更新的 R 版本,但我相信这不是主要问题)。

似乎拆分的性能更高,并且在很长一段时间后完成,但我不知道(劣质 R 知识)如何将结果向量列表拼凑成矩阵向量。

path = split(smallsampleMat, smallsampleMat[,10]) 

我也考虑过使用big.matrix 等,但没有太多成功可以加快进程。

【问题讨论】:

    标签: r performance matrix split dataframe


    【解决方案1】:

    您可以使用例如轻松访问列表中的每个元素path[[1]]。您不能将一组矩阵放入原子向量并访问每个元素。矩阵是具有维度属性的原子向量。我会使用split 返回的列表结构,这就是它的设计目的。每个列表元素都可以保存不同类型和大小的数据,因此它非常通用,您可以使用*apply 函数进一步对列表中的每个元素进行操作。下面的例子。

    #  For reproducibile data
    set.seed(1)
    
    #  Make some data
    userid <- rep(1:2,times=4)
    data1 <- replicate(8 , paste( sample(letters , 3 ) , collapse = "" ) )
    data2 <- sample(10,8)
    df <- data.frame( userid , data1 , data2 )
    
    #  Split on userid
    out <- split( df , f = df$userid )
    #$`1`
    #  userid data1 data2
    #1      1   gjn     3
    #3      1   yqp     1
    #5      1   rjs     6
    #7      1   jtw     5
    
    #$`2`
    #  userid data1 data2
    #2      2   xfv     4
    #4      2   bfe    10
    #6      2   mrx     2
    #8      2   fqd     9
    

    使用[[ 运算符访问每个元素,如下所示:

    out[[1]]
    #  userid data1 data2
    #1      1   gjn     3
    #3      1   yqp     1
    #5      1   rjs     6
    #7      1   jtw     5
    

    或者使用*apply 函数对每个列表元素进行进一步的操作。例如,要取 data2 列的平均值,您可以像这样使用 sapply:

    sapply( out , function(x) mean( x$data2 ) )
    #   1    2 
    #3.75 6.25 
    

    【讨论】:

    • 我想知道dlply(df, .(userid))的性能,发现它比split差,即使不涉及require(plyr)的运行时间,谢谢你和OP!
    【解决方案2】:

    从 0.8.0 版本开始,dplyr 提供了一个名为 group_split() 的便捷函数:

    # On sample data from @Aus_10
    
    df %>%
      group_split(g)
    
    [[1]]
    # A tibble: 25 x 3
       ran_data1 ran_data2 g    
           <dbl>     <dbl> <fct>
     1     2.04      0.627 A    
     2     0.530    -0.703 A    
     3    -0.475     0.541 A    
     4     1.20     -0.565 A    
     5    -0.380    -0.126 A    
     6     1.25     -1.69  A    
     7    -0.153    -1.02  A    
     8     1.52     -0.520 A    
     9     0.905    -0.976 A    
    10     0.517    -0.535 A    
    # … with 15 more rows
    
    [[2]]
    # A tibble: 25 x 3
       ran_data1 ran_data2 g    
           <dbl>     <dbl> <fct>
     1     1.61      0.858 B    
     2     1.05     -1.25  B    
     3    -0.440    -0.506 B    
     4    -1.17      1.81  B    
     5     1.47     -1.60  B    
     6    -0.682    -0.726 B    
     7    -2.21      0.282 B    
     8    -0.499     0.591 B    
     9     0.711    -1.21  B    
    10     0.705     0.960 B    
    # … with 15 more rows
    

    不包括分组列:

    df %>%
     group_split(g, keep = FALSE)
    

    【讨论】:

    • 有没有办法使用删除的分组列命名列表?我知道我可以做到这一点:但想知道是否有办法在 dplyr ?names(f.vars.h1.list)
    【解决方案3】:

    偶然发现了这个答案,我实际上想要两个组(包含该用户的数据和包含除该用户之外的所有内容的数据)。对于这篇文章的细节来说不是必需的,但我想我会补充一下,以防有人在谷歌上搜索与我相同的问题。

    df <- data.frame(
         ran_data1=rnorm(125),
         ran_data2=rnorm(125),
         g=rep(factor(LETTERS[1:5]), 25)
     )
    
    test_x = split(df,df$g)[['A']]
    test_y = split(df,df$g!='A')[['TRUE']]
    

    它是这样的:

    head(test_x)
                x          y g
    1   1.1362198  1.2969541 A
    6   0.5510307 -0.2512449 A
    11  0.0321679  0.2358821 A
    16  0.4734277 -1.2889081 A
    21 -1.2686151  0.2524744 A
    
    > head(test_y)
                x          y g
    2 -2.23477293  1.1514810 B
    3 -0.46958938 -1.7434205 C
    4  0.07365603  0.1111419 D
    5 -1.08758355  0.4727281 E
    7  0.28448637 -1.5124336 B
    8  1.24117504  0.4928257 C
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多