假设我有一个巨大的矩阵(玩具示例)

dat <- matrix(1:100,ncol = 10) 
colnames(dat) <- paste0("X",1:ncol(dat))
dat
      X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
 [1,]  1 11 21 31 41 51 61 71 81  91
 [2,]  2 12 22 32 42 52 62 72 82  92
 [3,]  3 13 23 33 43 53 63 73 83  93
 [4,]  4 14 24 34 44 54 64 74 84  94
 [5,]  5 15 25 35 45 55 65 75 85  95
 [6,]  6 16 26 36 46 56 66 76 86  96
 [7,]  7 17 27 37 47 57 67 77 87  97

该矩阵分为columns个,并写入多个文件

path <- paste0(getwd(),"/example/")
dir.create(path = path)
colum_id <- matrix(1:10,ncol = 2,byrow = T)
for(i in 1:nrow(colum_id)) write.csv(dat[,colum_id[i,]], file = paste0(path,i,".csv"), row.names = F)

文件夹中的文件 目录(路径)

[1] "1.csv" "2.csv" "3.csv" "4.csv" "5.csv"

..读取文件

paths <- paste0(path,dir(path))
lapply(paths , \(Path) head(read.csv(Path),2) )

[[1]]
  X1 X2
1  1 11
2  2 12

[[2]]
  X3 X4
1 21 31
2 22 32

[[3]]
  X5 X6
1 41 51
2 42 52

[[4]]
  X7 X8
1 61 71
2 62 72

[[5]]
  X9 X10
1 81  91
2 82  92

问题是,我如何才能将R个这些文件逐列组合在一起,而不将它们完全加载到内存中(因为文件非常大),从而将整个文件放到磁盘上.

推荐答案

Appending a column means writing to the middle of a csv file

追加列在columnar data format(如SQL或arrow)中是有意义的.注释中使用SQL的建议很好,here是使用RSQLite的答案,而RSQLite可以做到这一点.

在基于行的格式(如csv)中,追加一列实质上就是写入到纯文本文件的中间.这意味着从(最多)第一行的某个位置加载文件,然后重写该点之后的所有内容.

Append rows to a csv file instead

要编写大型纯文本文件,而无需将全部内容加载到RAM中,最好的方法是每次一行.在您的 case 中,这意味着:

  1. 从每个输入文件中一次读取一行.
  2. 每行cbind()块,组成一整行.
  3. 将该行写出为(在第一行的情况下)新文本文件的第一行,或(对于后续行)附加到现有文本文件的一行.

这将是简单的:

outfile <- "./example/big_out_file.csv"
N_ROWS <- 11
for (i in seq(0, N_ROWS - 1)) {
    line <- do.call(
        cbind,
        lapply(paths, \(f) read.table(f, sep = ",", skip = i, nrows = 1))
    )
    write.table(line, outfile, col.names = FALSE, append = TRUE, sep = ",", row.names = FALSE)
}

关键是将append = TRUE设置为write.table(),以便一次向现有文本文件追加一行(或在不存在的地方创建它).

我在这里将N_ROWS设置为11,因为我们知道输入有10行和一个标题.如果您不知道有多少行,您可以在不将文件读入内存的情况下进行判断,方法是使用fpeek::peek_count_lines()判断第一个块中的行数,即:

N_ROWS  <- fpeek::peek_count_lines(paths[1])

或者,如果你愿意,在this question的答案中还有其他方法.

这种方法的优点是不会一次将any个输入文件加载到内存中,正如您在注释中指出的那样.它一次读取每个输入文件的一行.这意味着有更多的读取操作,因此它将比读取每个文件一次慢得多,但这是权衡.根据您的内存限制,您可以通过一次阅读多行来加快速度.如果这样做,请确保分别读写标题,以避免将以下行强制为character行.

输出

我们可以判断,当读入时,输出与原始矩阵dat相同:

m <- as.matrix(read.csv(outfile))
head(m, 2)
#      X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
# [1,]  1 11 21 31 41 51 61 71 81  91
# [2,]  2 12 22 32 42 52 62 72 82  92
identical(dat, m) 
# [1] TRUE

R相关问答推荐

将coord_sf与geom_spatraster一起使用会更改分辨率

保存shiny 的代码嗅探器:避免$ Symbol问题

如何使用按钮切换轨迹?

如何在kableextra调用cell_spec()中忽略NA?

我想在R中总结一个巨大的数据框架,使我只需要唯一的lat、lon、Date(Year)和Maxium Value""""""""

如何在modelsummary中重命名统计数据?

Rplotly中的Sankey Diagram:意外连接&

如何在Chart_Series()中更改轴值的 colored颜色 ?

对于变量的每个值,仅 Select 包含列表中所有值的值.R

以更少间隔的较小表中的聚合离散频率表

R:用GGPLATE,如何在两个独立的变量中制作不同形状的散点图?

QY数据的处理:如何定义QY因素的水平

将工作目录子文件夹中的文件批量重命名为顺序

以不同于绘图中元素的方式对GG图图例进行排序

如何筛选截止年份之前最后一个测量年度的所有观测值以及截止年份之后所有年份的所有观测值

防止正则表达式覆盖以前的语句

自定义交互作用图的标签

计算来自单独分组的分幅的值的百分位数

使用函数从R中的列中删除标高

如何修改GT表中组名行的 colored颜色 ?