代码之家  ›  专栏  ›  技术社区  ›  HSJ

如何按r中的data.table将分组行复制到列中?

  •  0
  • HSJ  · 技术社区  · 6 年前

    我在使用 collect/unite/spread>technique in dpylr in r in another question here( 如何复制分组后的行时遇到内存错误。在r中按dplyr/tidyverse行到列中?(a>)。

    这是我用作示例的数据帧: (对不起,这个问题大部分都是重复前面的问题)

    df<-data.frame(
    hid=c(1,1,1,1,2,2,2,2,2,3,3,3,3)、
    Mid=C(1,2,3,4,1,2,3,4,5,1,2,3,4),
    tmid=c(“010”,“01010”,“010”,“01020”,
    “010”,“0120”,“010”,“010”,“020”,
    “010”,“01010”,“010”,“01020”),
    thid=c(“010”,“02020”,“010”,“02020”,
    “000”,“0120”,“010”,“010”,“010”,
    “010”,“02020”,“010”,“02020”)。
    )
    
    
    

    我想要的输出如下所示:

    hid mid tmid thid_1 tmid_2 tmid_3 tmid_4 tmid_5 thid_1 thid_2 thid_3 thid_4 thid_5
    *<dbl><dbl><fctr><fctr><fctr><fctr><fctr><fctr><fctr><fctr><fctr><fctr><fctr><fctr><fctr>
    1 1 1 010 010 01010 010 01020 0 010 02020 010 02020 0 0
    2 1 2 01010 02020 010 01010 010 01020 0 010 02020 010 02020 0 0
    3 1 3 010 010 010 01010 010 01020 0 010 02020 010 02020 0 0
    4 1 4 01020 02020 010 01010 010 01020 0 010 02020 010 02020 0 0
    5 2 1 010 000 010 0120 010 020 000 0120 010 010
    6 2 0120 0120 010 0120 010 010 020 000 0120 010 010
    7 2 3 010 010 010 0120 010 020 000 0120 010 010
    8 2 4 010 010 010 0120 010 020 000 0120 010 010
    9 2 5 020 010 0120 010 010 020 000 0120 010 010
    10 3 1 010 010 01010 010 01020 0 010 02020 010 02020 0 0
    11 3 2 01010 02020 010 01010 010 01020 0 010 02020 010 02020 0 0
    12 3 3 010 010 010 01010 010 01020 0 010 02020 010 02020 0 0
    13 3 4 01020 02020 010 01010 010 01020 0 010 02020 010 02020 0 0
    
    
    

    此操作的图像如下所示:

    我想做的是:

    • thidtmidinto column
    • thid_x中的后缀号tmid_x是由mid定义的;但是,最大数量的mid是不可扩展的(它在实际大数据集中从18-10扩展)。
    • midis grouped byhidto define how manymids are stored in eachhid
    • 如果值不存在,则应使用0(即,某些hidhave 5mids,但有些只有4个,因此tmid_5应为0 for suchhid)。

    但是,当我在上一个问题中使用collect/unite/spread技术执行此操作时,会遇到一个内存错误,即“cannot allocate 11.4Gb of memory.

    此错误的原因可能是collectfunction需要在拆分之前创建其参数中指定的所有组合。在64位版本的r中,实际数据帧有大约80000条记录,超过16GB RAM。

    你有什么建议可以在不做这么大的中间记录的情况下得到同样的结果吗?如果不需要这样的中间操作,也许data.table->code>会有所帮助,但是我使用了dplyr->code>并且从未使用过该包。 我想让您的想法超越这个问题,并将学习新的软件包,基于进一步步骤的分析需求。How to copy grouped rows into column by dplyr/tidyverse in R?)

    这是我用作示例的数据帧: (对不起,这个问题大部分都是重复前面的问题)

    df <- data.frame(
        hid=c(1,1,1,1,2,2,2,2,2,3,3,3,3),
        mid=c(1,2,3,4,1,2,3,4,5,1,2,3,4),
        tmid=c("010","01010","010","01020",
               "010","0120","010","010","020",
               "010","01010","010","01020"),
        thid=c("010","02020","010","02020",
               "000","0120","010","010","010",
               "010","02020","010","02020")
        )
    

    我想要的输出如下所示:

         hid   mid  tmid   thid  tmid_1  tmid_2  tmid_3  tmid_4  tmid_5  thid_1  thid_2  thid_3  thid_4  thid_5
     * <dbl> <dbl> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> 
     1     1     1   010    010    010  01010    010  01020      0    010  02020    010  02020      0
     2     1     2 01010  02020    010  01010    010  01020      0    010  02020    010  02020      0
     3     1     3   010    010    010  01010    010  01020      0    010  02020    010  02020      0
     4     1     4 01020  02020    010  01010    010  01020      0    010  02020    010  02020      0
     5     2     1   010    000    010  0120     010    010    020    000   0120    010    010    010
     6     2     2  0120   0120    010  0120     010    010    020    000   0120    010    010    010
     7     2     3   010    010    010  0120     010    010    020    000   0120    010    010    010
     8     2     4   010    010    010  0120     010    010    020    000   0120    010    010    010
     9     2     5   020    010    010  0120     010    010    020    000   0120    010    010    010
    10     3     1   010    010    010  01010    010  01020      0    010  02020    010   02020     0
    11     3     2 01010  02020    010  01010    010  01020      0    010  02020    010   02020     0
    12     3     3   010    010    010  01010    010  01020      0    010  02020    010   02020     0
    13     3     4 01020  02020    010  01010    010  01020      0    010  02020    010   02020     0
    

    此操作的图像如下所示: enter image description here

    我想做的是:

    • 转换thidtmid进入列
    • 后缀号thid_xtmid_x由定义mid;但是,最大中间不可扩展(在实际大数据集中,它从1扩展到8-10)
    • 中间分组依据hid定义多少中间存储在每个隐藏
    • 如果值不存在,则应使用0(例如,一些隐藏5中间但是有些只有4个,因此tmid_5应该为0隐藏)

    但是,当我使用收集/联合/传播在上一个问题中,它遇到一个内存错误,即无法分配11.4GB的内存。

    也许这个错误的原因是gather函数需要在拆分之前创建其参数中指定的所有组合。实际数据帧有大约80000条记录,在64位版本的R.

    你有什么建议可以在不做这么大的中间记录的情况下得到同样的结果吗?也许data.table如果不需要这样的中间操作,可能会有所帮助,不过我以前用过DPLYR从来没有用过那个包裹。 我想让你的想法超越这个问题,并将学习新的包的基础上,需要进一步的分析步骤。

    1 回复  |  直到 6 年前
        1
  •  1
  •   r2evans    6 年前

    我想你可以结合使用 spread left_join 要获得所需的:

    library(dplyr)
    library(tidyr)
    
    a <- select(df, -thid) %>%
      spread(mid, tmid, sep="_") %>%
      rename_at(vars(matches("^mid_")), funs(paste0("t", .)))
    b <- select(df, -tmid) %>%
      spread(mid, thid, sep="_") %>%
      rename_at(vars(matches("^mid_")), funs(gsub("^m", "th", .)))
    
    left_join(df, a, by="hid") %>%
      left_join(b, by="hid")
    #    hid mid  tmid  thid tmid_1 tmid_2 tmid_3 tmid_4 tmid_5 thid_1 thid_2 thid_3 thid_4 thid_5
    # 1    1   1   010   010    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
    # 2    1   2 01010 02020    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
    # 3    1   3   010   010    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
    # 4    1   4 01020 02020    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
    # 5    2   1   010   000    010   0120    010    010    020    000   0120    010    010    010
    # 6    2   2  0120  0120    010   0120    010    010    020    000   0120    010    010    010
    # 7    2   3   010   010    010   0120    010    010    020    000   0120    010    010    010
    # 8    2   4   010   010    010   0120    010    010    020    000   0120    010    010    010
    # 9    2   5   020   010    010   0120    010    010    020    000   0120    010    010    010
    # 10   3   1   010   010    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
    # 11   3   2 01010 02020    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
    # 12   3   3   010   010    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
    # 13   3   4 01020 02020    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
    

    清理 NA 值应该足够简单,但可能需要重新考虑它们(添加 "0" )或者只是用 stringsAsFactors=FALSE .