代码之家  ›  专栏  ›  技术社区  ›  Matteo B.

从宽到长形成一个巨大的数据表(1000000×4000别名8GB)

  •  1
  • Matteo B.  · 技术社区  · 6 年前

    我的磁盘上有这个8GB的csv文件。 每行有一个“匹配”。

    “匹配”由以下数据组成 id , date winner . 但它也有10个玩家拥有他们所有的数据。这些都储存在 participants.0.stats.visionScore , participants.1.stats.visionScore participants.0.stats.assists participants.9.stats.assists ,…我想你明白了。只是 participants.{number}.stats.{variable_name} . 每个参与者实际上都有数百个统计数据;这就是为什么我总共有大约4000列的原因。

    我这样读取数据:

    > d <- fread("Matches.csv")
    > head(d)
       participants.1.stats.totalDamageDealt
    1:                                118504
    2:                                 20934
    3:                                 76639
    4:                                123932
    5:                                160561
    6:                                237046
       participants.8.stats.totalDamageTaken participants.9.stats.totalPlayerScore
    1:                                 18218                                     0
    2:                                 12378                                     0
    3:                                 46182                                     0
    4:                                 19340                                     0
    5:                                 30808                                     0
    6:                                 36194                                     0
    ... [there are thousands of lines I omit here] ...
    

    当然,我现在想要一个数据的表示,其中一行对应于一个参与者。我想象这样的结果:

    > [magic]
    > head(d)
       participant             stats.totalDamageDealt
    1:           1                             118504
    2:           2                             190143
    3:           3                              46700
    4:           4                              60787
    5:           5                              78108
    6:           6                             124761
                      stats.totalDamageTaken                stats.totalPlayerScore
    1:                                 18218                                     0
    2:                                 15794                                     0
    3:                                 34578                                     0
    4:                                 78771                                     0
    5:                                 16749                                     0
    6:                                 11540                                     0
    ...
    

    但是所有的方法,比如 meld , cast reshape 需要我手动命名所有列。即使有 patterns 对于 MELD 最后,我不得不为每个参与者列出我所有的数百列。难道没有办法让这个东西在R中变长吗?

    2 回复  |  直到 6 年前
        1
  •  0
  •   Mako212    6 年前

    好的,使用您提供的数据样本:

    library(data.table)
    
    setDT(d) 
    
    d <- melt(d, measure = patterns("^participants"), value.name = "value")
    
    d <- d[,  `:=` (ID = gsub(".*?\\.(\\d+)\\..*","\\1", variable),
                    stats = gsub(".*?(stats\\..*)$","\\1", variable))
      ][, .(variable, value, ID, stats)]
    d <- dcast(d, ID ~ stats, value.var= "value", fun.aggregate = sum)
    

    编辑: 把这个写成 data.table 唯一的速度解决方案

    请注意,源数据中还有一些其他列,如 participantIdentities.6.player.accountId 你不说,所以我只是把他们排除在外。如果需要包括它们,您可以将它们添加到 patterns id.vars 在里面 melt .

    注意:您所转换的所有值都必须是数字,否则 dcast 会失败。我相信这将是您的完整数据集的一个问题。这意味着您需要正确地标识列,例如 participants.1.highestAchievedSeasonTier 作为 伊德瓦尔斯 在里面 熔化 或以其他方式将其排除在 DCAST .

    结果(我只是粘贴了许多的前4列)

      ID participants.4.timeline.xpPerMinDeltas.20-30 stats.goldEarned stats.perk3Var1
    1  1                                            0                0               0
    2  4                                           NA                0            3475
    3  7                                            0                0               0
    4  8                                            0                0               0
    5  9                                            0           105872               0
    
        2
  •  0
  •   Adam Sampson    6 年前

    我不能百分之百地确定我知道数据是如何排列的,但我想我已经知道了。从示例数据来看,参与者1有多行数据需要从原始数据进行totaldamagedetail,并且结果不需要聚合。如果不是这样,可能需要不同的步骤。我必须创建自己的示例数据来尝试运行这个。如果您想发布一组涵盖所有可能性的最小数据,这将是很有帮助的。

    否则,这里有一些方法可以使数据完全变长以提取参与者信息,然后再次变宽以使其成为您想要的格式。如果在使数据范围更广时需要任何聚合,那么 dcast 步骤。

    library(data.table)
    library(stringr)
    
    # Create example data
    dt <- data.table(participant.1.stats.visionScore = c(1,1.1,1.2,1.3,1.4,1.5),
               participant.1.stats.totalDamageDealt = c(7.1,8.1,9.1,10.1,11.1,12.1),
               participant.2.stats.visionScore = c(2,2.1,2.2,2.3,2.4,2.5),
               participant.2.stats.totalDamageDealt = c(7.2,8.2,9.2,10.2,11.2,12.2))
    
    # Make data totally long (not wide at all)
    dt <- melt(dt,measure.vars = names(dt))
    
    # Separate participant and stat details into columns
    dt[,participant := variable %>% str_extract("(?<=^participant\\.)\\d+")]
    dt[,stat := variable %>% str_extract("(?<=.stats.).+")]
    
    # Remove variable for cleanup
    dt[,variable := NULL]
    
    # Create an index to create a unique key in order to be able to dcast without aggregating
    dt[,index := 1:.N, by = list(participant,stat)]
    
    # dcast to make the data wide again
    dt <- dcast(dt,index + participant ~ stat, value.var = "value")
    
    # Sort to make it easier for a human to view the table
    dt <- dt[order(participant)]
    
    #     index participant totalDamageDealt visionScore
    # 1:      1           1              7.1         1.0
    # 2:      2           1              8.1         1.1
    # 3:      3           1              9.1         1.2
    # 4:      4           1             10.1         1.3
    # 5:      5           1             11.1         1.4
    # 6:      6           1             12.1         1.5
    # 7:      1           2              7.2         2.0
    # 8:      2           2              8.2         2.1
    # 9:      3           2              9.2         2.2
    # 10:     4           2             10.2         2.3
    # 11:     5           2             11.2         2.4
    # 12:     6           2             12.2         2.5