要点:如果您要投票决定关闭,那是一种糟糕的形式,没有给出原因。如果无需关闭就可以改进,请花10秒钟写简短的评论。
问题:
如何以内存可以支持的方式进行以下“部分融化”?
详细信息:
我有几百万行和大约1000列。列的名称中包含2条信息。
通常,我将融合到由一对列组成的数据框(或表)中,然后对变量名进行拆分以创建两个新列,然后使用新拆分中的一个对新列名进行转换,一个用于行名。
这不起作用。我数十亿行的数据使更多的列淹没了我的记忆。
在for循环的“迭代力”(相对于蛮力)之外,是否有一种干净有效的方法?
想法:
更新(虚拟代码):
#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或内存。
(丑陋/手动)蛮力版本:
(正在处理...)
答案 0 :(得分:1)
这里有两个都使用data.table
的选项。
如果您知道每个列字符串始终都有200个(或n
)与之关联的字段(即A001-A200),则可以使用melt()
并列出测量变量。 / p>
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))