【问题标题】:How to copy grouped rows into column by data.table in R?如何在 R 中按 data.table 将分组的行复制到列中?
【发布时间】:2018-12-10 23:34:50
【问题描述】:

我在此处的另一个问题 (How to copy grouped rows into column by dplyr/tidyverse in R?) 中使用 dplyr 中的 dplyr 中的 gather/unite/spreadtechnique 将行复制到列中时遇到了内存错误 (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

此操作的图像如下所示:

我想在这个操作中做的是:

  • thidtmid 转换为列
  • thid_xtmid_x中的后缀号由mid定义;但是,mid 的最大数量不可扩展(在实际的大型数据集中它从 1 扩展到 8-10)
  • midhid 分组以定义每个 hid 中存储了多少 mids
  • 如果值不存在,则应使用0 填充(即,有些hid 有5 个mids,但有些只有4 个,因此对于这样的hid,tmid_5 应该为0)

但是,当我在上一个问题中使用gather/unite/spread 技术执行此操作时,遇到内存错误,提示无法分配 11.4GB 内存。

这个错误的原因可能是gather 函数需要在拆分之前创建其参数中指定的所有组合。实际数据框有大约 80,000 条记录,在我的 64 位版本 R 中超过 16GB RAM。

您有什么建议可以在不制作如此庞大的中间记录的情况下获得相同的结果吗?如果不需要这样的中间操作,也许data.table 可能会有所帮助,但是我曾经使用过dplyr 并且从未使用过该软件包。 我想让你的想法超越这个问题,并根据分析的需要学习新的包以进行进一步的步骤。

【问题讨论】:

  • 重新 RAM 成本,似乎避免操作将是最好的方法,正如 Moody Mudskipper 在之前的评论中所建议的那样。 (该操作只是将您的数据 n 次复制到难以使用的列名中。)
  • 是的,这个操作似乎有点快速和肮脏的解决方案。我会考虑其他更有效的方法。

标签: r dataframe dplyr type-conversion


【解决方案1】:

我认为您可以使用spreadleft_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 创建框架。

【讨论】:

  • 感谢您的建议。它成功了。我认识到有很多方法可以获得相同的结果。
  • Hideo,如果这充分解决了你的问题,你能"accept"回答吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-01
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-06
相关资源
最近更新 更多