【问题标题】:equivalent of melt+reshape that splits on column names相当于在列名上拆分的 melt+reshape
【发布时间】:2019-11-14 08:14:38
【问题描述】:

要点:如果您要投票结束,不给出理由是不好的形式。如果无需关闭即可改进,请花 10 秒时间写一个简短的评论。

问题:
如何以内存可以支持的方式进行以下“部分融化”?

详情:
我有几百万行和大约 1000 列。列名中包含 2 条信息。

通常我会融合到由一对列组成的数据框(或表),然后我会拆分变量名称以创建两个新列,然后我会使用一个新拆分来转换新列名, 一个用于行名。

这行不通。我的十亿左右数据行使额外的列不堪重负。

在 for 循环的“迭代力”(相对于蛮力)之外,是否有一种干净有效的方法来做到这一点?

想法:

  • 这有点像melt-colsplit-cast
  • 常见的库似乎是“dplyr”、“tidyr”、“reshape2”和“data.table”。
  • tidyr 的gather+separate+spread 看起来不错,但不喜欢没有唯一的行标识符
  • reshape2 的 dcast(我正在寻找 2d 输出)想要聚合
  • 蛮力丢失标签。蛮力我的意思是 df

更新(虚拟代码):

#libraries
library(stringr)

#reproducibility
set.seed(56873504)

#geometry
Ncol <- 2e3
Nrow <- 1e6

#column names
namelist <- numeric(length=Ncol)
for(i in 1:(Ncol/200)){
  col_idx <- 1:200+200*(i-1)
  if(i<26){
  namelist[col_idx] <- paste0(intToUtf8(64+i),str_pad(string=1:200,width=3,pad="0"))
  } else {
    namelist[col_idx] <- paste0(intToUtf8(96+i),str_pad(string=1:200,width=3,pad="0"))
  }
}

#random data
df <- as.data.frame(matrix(runif(n=Nrow*Ncol,min=0, max=16384),nrow=Nrow,ncol=Ncol))
names(df) <- namelist

我要查找的输出将有一列包含当前名称的第一个字符(单个字母字符),并且 colnames 将是 1 到 200。它比“df”宽得多,但没有完全融化.它也不会杀死我的 CPU 或内存。

(丑陋/手动)蛮力版:

(正在努力……)

【问题讨论】:

  • 你试过tidyr的tidyverse解决方案吗?
  • 如果没有更可重现的示例,很难提供帮助(您可以添加带有 dput 的演示数据片段吗?)。但是您似乎应该能够使用lapply 对每一列执行操作,这样可以节省您重塑庞大数据集的成本。
  • @jdobres - 你有虚拟数据的代码。我会检查 dput 和 lapply,但我很怀疑。块状结构让 lapply 看起来很硬。
  • @bob1 - 我卡在了展开部分。我可以收集和分离,但似乎不喜欢我没有唯一的行标识符。
  • 预期输出是什么?您是否也可以编写只有 100 行且具有预期输出的代码?我不确定我的计算机生成的 2E9 数据点是否良好

标签: r split reshape2 melt


【解决方案1】:

这里有两个选项都使用data.table

如果您知道每个列字符串总是有 200 个(或 n)与之关联的字段(即 A001 - A200),您可以使用 melt() 并制作一个测量变量列表。

melt(dt
     , measure.vars = lapply(seq_len(Ncol_p_grp), seq.int, to = Ncol_p_grp * n_grp, by = Ncol_p_grp)
     , value.name = as.character(seq_len(Ncol_p_grp))
)[, variable := rep(namelist_letters, each = Nrow)][]

#this data set used Ncol_p_grp <- 5 to help condense the data. 
        variable         1          2         3          4          5
     1:        A 0.2655087 0.06471249 0.2106027 0.41530902 0.59303088
     2:        A 0.3721239 0.67661240 0.1147864 0.14097138 0.55288322
     3:        A 0.5728534 0.73537169 0.1453641 0.45750426 0.59670404
     4:        A 0.9082078 0.11129967 0.3099322 0.80301300 0.39263068
     5:        A 0.2016819 0.04665462 0.1502421 0.32111280 0.26037592
    ---                                                              
259996:        Z 0.5215874 0.78318812 0.7857528 0.61409610 0.67813484
259997:        Z 0.6841282 0.99271480 0.7106837 0.82174887 0.92676493
259998:        Z 0.1698301 0.70759513 0.5345685 0.09007727 0.77255570
259999:        Z 0.2190295 0.14661878 0.1041779 0.96782695 0.99447460
260000:        Z 0.4364768 0.06679642 0.6148842 0.91976255 0.08949571

或者,我们可以使用rbindlist(lapply(...)) 遍历数据集并根据列中的字母对其进行子集化。

rbindlist(
  lapply(namelist_letters,
       function(x) setnames(
         dt[, grep(x, names(dt), value = T), with = F]
         , as.character(seq_len(Ncol_p_grp)))
  )
  , idcol = 'ID'
, use.names = F)[, ID := rep(namelist_letters, each = Nrow)][]

这个数据集中有 7800 万个元素,大约需要四分之一秒。我试图将它增加到 7.8 亿,但我只是没有真正的 RAM 来快速生成数据。

#78 million elements - 10,000 rows * 26 grps * 200 cols_per_group
Unit: milliseconds
             expr      min       lq     mean   median       uq      max neval
      melt_option 134.0395 135.5959 137.3480 137.1523 139.0022 140.8521     3
 rbindlist_option 290.2455 323.4414 350.1658 356.6373 380.1260 403.6147     3

数据:在上述所有内容之前运行:

#packages ----
library(data.table)
library(stringr)

#data info
Nrow <- 10000
Ncol_p_grp <- 200
n_grp <- 26

#generate data
set.seed(1)
dt <- data.table(replicate(Ncol_p_grp * n_grp, runif(n = Nrow)))

names(dt) <- paste0(rep(LETTERS[1:n_grp], each = Ncol_p_grp)
                    , str_pad(rep(seq_len(Ncol_p_grp), n_grp), width = 3, pad = '0'))

#first letter
namelist_letters <- unique(substr(names(dt), 1, 1))

【讨论】:

  • 做得很好。我会试一试,然后告诉你进展如何。
猜你喜欢
  • 2021-02-02
  • 1970-01-01
  • 2015-09-07
  • 2021-12-08
  • 1970-01-01
  • 2020-12-29
  • 1970-01-01
  • 2022-01-28
  • 2012-04-01
相关资源
最近更新 更多