在 Python 中转置 table 比压缩数组更有效?

More efficient way than zipping arrays for transposing a table in Python?

我一直在尝试在集群上转置我的 table 2000000 多行和 300 多列,但似乎我的 Python 脚本由于内存不足而被杀死。我只想知道除了使用数组之外,是否有人对存储我的 table 数据的更有效方法有任何建议,如下面的代码所示?

import sys
Seperator = "\t"
m = []
f = open(sys.argv[1], 'r')
data = f.read()
lines = data.split("\n")[:-1]
for line in lines:
    m.append(line.strip().split("\t"))
for i in zip(*m):
    for j in range(len(i)):
        if j != len(i):
            print(i[j] +Seperator)
        else:
            print(i[j])
    print ("\n")

非常感谢。

由于列数远小于行数,我会考虑将每一列写入单独的文件。然后将它们组合在一起。

import sys
Separator = "\t"
f = open(sys.argv[1], 'r')
for line in f:
   for i, c in enumerate(line.strip().split("\t")):
      dest = column_file[i]  # you shoud open 300+ file handlers, one for each column
      dest.write(c)
      dest.write(Separator)

# all you need to do after than is combine the content of you "row" files

如果无法将所有文件存储到内存中,可以读取 n 次:

column_number = 4  # if necessary, read the first line of the file to calculate it
seperetor = '\t'
filename = sys.argv[1]

def get_nth_column(filename, n):
    with open(filename, 'r') as file:
        for line in file:
            if line:  # remove empty lines
                yield line.strip().split('\t')[n]


for column in range(column_number):
    print(seperetor.join(get_nth_column(filename, column)))

请注意,如果文件格式不正确,将引发异常。有需要的可以抓。

读取文件时:使用 with 构造,以确保您的文件将被关闭。并直接在文件上迭代,而不是先读取内容。它更具可读性和效率。

首先要注意的是您对变量的处理不慎。您将一个大文件作为单个字符串加载到内存中,然后是一个字符串列表,然后是一个字符串列表列表,最后转置该列表。这将导致您在开始转置之前将文件中的所有数据存储三次。

如果文件中的每个字符串只有大约 10 个字符长,那么您将需要 18GB 的​​内存来存储它(2e6 行 * 300 列 * 10 字节 * 3 个重复项)。这是在您考虑 python 个对象的所有开销之前(每个字符串对象约 27 个字节)。

这里有几个选项。

  • 通过为每个旧行读取一次文件并一次追加每个新行(牺牲时间效率)来逐步创建每个新的转置行。
  • 为每个新行创建一个文件并在末尾合并这些行文件(牺牲磁盘 space 效率,如果由于数量限制在初始文件中有很多列,则可能会出现问题进程可能拥有的打开文件数)。

使用有限数量的打开文件进行移调

delimiter = ','

input_filename = 'file.csv'
output_filename = 'out.csv'

# find out the number of columns in the file
with open(input_filename) as input:
    old_cols = input.readline().count(delimiter) + 1

temp_files = [
    'temp-file-{}.csv'.format(i)
    for i in range(old_cols)
]

# create temp files
for temp_filename in temp_files:
    open(temp_filename, 'w') as output:
        output.truncate()
with open(input_filename) as input:
    for line in input:
        parts = line.rstrip().split(delimiter)
        assert len(parts) == len(temp_files), 'not enough or too many columns'
        for temp_filename, cell in zip(temp_files, parts):
            with open(temp_filename, 'a') as output:
                output.write(cell)
                output.write(',')

# combine temp files
with open(output_filename, 'w') as output:
    for temp_filename in temp_files:
        with open(temp_filename) as input:
            line = input.read().rstrip()[:-1] + '\n'
            output.write(line)