我有一个大的gzip文件(5000列×1M行),由0和1组成:
0 1 1 0 0 0 1 1 1....(×5000)
0 0 0 1 0 1 1 0 0
....(×1M)
我想转置它,但使用numpy或其他方法只需将整个表加载到RAM上,我就有6GB的空间可供使用。在
出于这个原因,我想使用一种方法,将每一个转换后的行写入一个打开的文件,而不是将其存储在RAM中。我想出了以下代码:
^{pr2}$然而,这是非常缓慢的。谁能给我另一个解决方案吗?有没有办法将列表作为列(而不是行)附加到现有打开的文件中?(伪代码):
with open("output.txt", w) as out:
with gzip.open("file.txt", rt) as file:
for line in file:
transposed_line = line.transpose()
out.write(transposed_line, as.column)
更新
用户7813790的回答引导我找到以下代码:
import numpy as np
import random
# create example array and write to file
with open("array.txt", "w") as out:
num_columns = 8
num_lines = 24
for i in range(num_lines):
line = []
for column in range(num_columns):
line.append(str(random.choice([0,1])))
out.write(" ".join(line) + "\n")
# iterate over chunks of dimensions num_columns×num_columns, transpose them, and append to file
with open("array.txt", "r") as array:
with open("transposed_array.txt", "w") as out:
for chunk_start in range(0, num_lines, num_columns):
# get chunk and transpose
chunk = np.genfromtxt(array, max_rows=num_columns, dtype=int).T
# write out chunk
out.seek(chunk_start+num_columns, 0)
np.savetxt(out, chunk, fmt="%s", delimiter=' ', newline='\n')
它需要一个矩阵:
0 0 0 1 1 0 0 0
0 1 1 0 1 1 0 1
0 1 1 0 1 1 0 0
1 0 0 0 0 1 0 1
1 1 0 0 0 1 0 1
0 0 1 1 0 0 1 0
0 0 1 1 1 1 1 0
1 1 1 1 1 0 1 1
0 1 1 0 1 1 1 0
1 1 0 1 1 0 0 0
1 1 0 1 1 0 1 1
1 0 0 1 1 0 1 0
0 1 0 1 0 1 0 0
0 0 1 0 0 1 0 0
1 1 1 0 0 1 1 1
1 0 0 0 0 0 0 0
0 1 1 1 1 1 1 1
1 1 1 1 0 1 0 1
1 0 1 1 1 0 0 0
0 1 0 1 1 1 1 1
1 1 1 1 1 1 0 1
0 0 1 1 0 1 1 1
0 1 1 0 1 1 0 1
0 0 1 0 1 1 0 1
并在两个维度都等于列数(本例中为8)的2D块上迭代,将它们转置并附加到输出文件中。在
第一块被转置:
[[0 0 0 1 1 0 0 1]
[0 1 1 0 1 0 0 1]
[0 1 1 0 0 1 1 1]
[1 0 0 0 0 1 1 1]
[1 1 1 0 0 0 1 1]
[0 1 1 1 1 0 1 0]
[0 0 0 0 0 1 1 1]
[0 1 0 1 1 0 0 1]]
第二块转置:
[[0 1 1 1 0 0 1 1]
[1 1 1 0 1 0 1 0]
[1 0 0 0 0 1 1 0]
[0 1 1 1 1 0 0 0]
[1 1 1 1 0 0 0 0]
[1 0 0 0 1 1 1 0]
[1 0 1 1 0 0 1 0]
[0 0 1 0 0 0 1 0]]
等等
我尝试将每个新块作为列附加到out文件中,使用寻找(). 据我所知,seek()将文件开头的偏移量(即列)作为第一个参数,而0作为第二个参数意味着再次从第一行开始。所以,我猜下面这句话可以做到:
out.seek(chunk_start+num_columns, 0)
但是,它不会沿着以下行继续偏移。此外,它在第一行的开始处添加n=num_columns空格。输出:
0 0 0 1 0 1 1 1 0 1 1 0 1 0 0 0
1 1 0 1 1 0 1 0
1 1 1 0 1 1 1 1
1 1 1 1 1 1 0 0
1 0 1 1 1 0 1 1
1 1 0 1 1 1 1 1
1 0 0 1 0 1 0 0
1 1 0 1 1 1 1 1
对于如何正确地使用seek()来完成这项任务有什么见解吗?i、 e.要生成这个:
0 0 0 1 1 0 0 1 0 1 1 1 0 0 1 1 0 1 1 0 1 0 0 0
0 1 1 0 1 0 0 1 1 1 1 0 1 0 1 0 1 1 0 1 1 0 1 0
0 1 1 0 0 1 1 1 1 0 0 0 0 1 1 0 1 1 1 0 1 1 1 1
1 0 0 0 0 1 1 1 0 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0
1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 0 1 0 1 1 1 0 1 1
0 1 1 1 1 0 1 0 1 0 0 0 1 1 1 0 1 1 0 1 1 1 1 1
0 0 0 0 0 1 1 1 1 0 1 1 0 0 1 0 1 0 0 1 0 1 0 0
0 1 0 1 1 0 0 1 0 0 1 0 0 0 1 0 1 1 0 1 1 1 1 1
请注意,这只是一个虚拟的测试矩阵,实际的矩阵是5008列×大于1M的行。在
更新2
我已经找到了如何让这个工作,它也可以利用任何维度的块。在
import numpy as np
import random
# create example array and write to file
num_columns = 4
num_lines = 8
with open("array.txt", "w") as out:
for i in range(num_lines):
line = []
for column in range(num_columns):
line.append(str(random.choice([0,1])))
out.write(" ".join(line) + "\n")
# iterate over chunks of dimensions num_columns×chunk_length, transpose them, and append to file
chunk_length = 7
with open("array.txt", "r") as array:
with open("transposed_array.txt", "w") as out:
for chunk_start in range(0, num_lines, chunk_length):
# get chunk and transpose
chunk = np.genfromtxt(array, max_rows=chunk_length, dtype=str).T
# write out chunk
empty_line = 2 * (num_lines - (chunk_length + chunk_start))
for i, line in enumerate(chunk):
new_pos = 2 * num_lines * i + 2 * chunk_start
out.seek(new_pos)
out.write(f"{' '.join(line)}{' ' * (empty_line)}"'\n')
在本例中,它使用如下数组:
1 1 0 1
0 0 1 0
0 1 1 0
1 1 1 0
0 0 0 1
1 1 0 0
0 1 1 0
0 1 1 1
然后用4列×7行的块来转换它,所以第一块是
1 0 0 1 0 1 0
1 0 1 1 0 1 1
0 1 1 1 0 0 1
1 0 0 0 1 0 0
它被写入文件,从内存中删除,然后第二个块被
0
1
1
1
再次将其附加到文件中,因此最终结果是:
1 0 0 1 0 1 0 0
1 0 1 1 0 1 1 1
0 1 1 1 0 0 1 1
1 0 0 0 1 0 0 1
在工作但缓慢的解决方案中,您将读取输入文件5000次,这不会很快,但要使读取最小化,唯一简单的方法是在内存中全部读取。在
你可以尝试一些折衷办法,比如说,一次在内存中读取50列(约50MB),然后将它们作为行写入文件。这样你就可以把文件“只”读100遍。尝试几种不同的组合来获得您满意的性能/内存折衷。在
您可以在三个嵌套循环上执行此操作:
在最内部的循环中,将列值作为一行收集到一个二维数组中,中间循环的每个数组一行。在最外层的循环中,在进入内部循环之前清除数组,然后将其作为行打印到文件中。对于循环1的每次迭代。你将写下50行一百万列。在
如果不将整个目标文件加载到内存中,就不能在普通文件的中间插入—您需要手动向前移动尾随字节。因为你知道你的确切文件大小,然而,你可以预先分配它,并且总是在写入每个字节时寻找位置;可能也不是很快就能完成50亿次搜索。。。如果你的1和0分布得相当均匀,你可以用所有的0初始化文件,然后只写1(或者反过来写),以减少一半的查找次数。在
编辑:添加了如何实现分块的详细信息。在
如果您的数字都是0或1,那么每一行都有相同的长度(以字节为单位),因此您可以使用
file.seek
在文件中移动(而不是读入并忽略数据)。但是,对于gzip输入文件,这可能不是很有效。由于您正在编写一个未压缩的文件,您还可以使用seek
在输出中跳转。在一种更有效的转置数组的方法是读入一个适合RAM的块(例如1000x1000),使用
numpy.transpose
来转置块,然后将块写入转置数组中的位置。对于5000列但1M行的数组,使用5000x5000块(即读取)可能是最容易的 一次5000行完整的输入矩阵。这避免了在压缩的输入文件中seek
。然后,您必须将此块写入输出文件,为来自输入的后续行的列留空。在有关如何将块写入5000xN输出文件的更多详细信息(如注释中所要求的):
要写入第一个5000x5000块:
要写入第二个块:
相关问题 更多 >
编程相关推荐