将巨大的.dat文件快速加载到数组中最快的方法

4 投票
1 回答
2312 浏览
提问于 2025-04-28 18:10

我在StackExchange上花了很多时间寻找一个好的方法,把一个大约2GB的.dat文件加载到numpy数组中,但没有找到合适的解决方案。目前我已经成功地以非常快的速度(不到1分钟)将它加载为一个列表:

list=[]
f = open('myhugefile0')
for line in f:
    list.append(line)
f.close()

但是使用np.loadtxt会让我的电脑卡住,加载需要几分钟(大约10分钟)。我想知道有没有办法在不遇到np.loadtxt那种分配问题的情况下,把文件打开成一个数组?

补充说明:

输入数据是一个浮点数数组,大小为(200000, 5181)。这里有一行示例:

2.27069e-15 2.40985e-15 2.22525e-15 2.1138e-15 1.92038e-15 1.54218e-15 1.30739e-15 1.09205e-15 8.53416e-16 7.71566e-16 7.58353e-16 7.58362e-16 8.81664e-16 1.09204e-15 1.27305e-15 1.58008e-15

还有很多类似的行。

谢谢!

暂无标签

1 个回答

3

源代码来看,numpy.loadtxt包含了很多处理不同格式的代码。如果你有一个格式明确的输入文件,自己写一个专门针对你文件格式的函数其实并不难。可以参考下面这个(未经测试):

def load_big_file(fname):
    '''only works for well-formed text file of space-separated doubles'''

    rows = []  # unknown number of lines, so use list
    with open(fname) as f:
        for line in f:
            line = [float(s) for s in line.split()]
            rows.append(np.array(line, dtype = np.double))
    return np.vstack(rows)  # convert list of vectors to array

如果你事先知道行数和列数,另一种解决方案可能是:

def load_known_size(fname, nrow, ncol)
    x = np.empty((nrow, ncol), dtype = np.double)
    with open(fname) as f:
        for irow, line in enumerate(f):
            for icol, s in enumerate(line.split()):
                x[irow, icol] = float(s)
    return x

这样的话,你就不需要分配所有的中间列表了。

编辑:看起来第二种方案稍微慢一点,列表推导式可能比显式的for循环要快。结合这两种方案,并利用Numpy会自动把字符串转换成浮点数的这个技巧(我刚刚才发现),这样可能会更快:

def load_known_size(fname, nrow, ncol)
    x = np.empty((nrow, ncol), dtype = np.double)
    with open(fname) as f:
        for irow, line in enumerate(f):
            x[irow, :] = line.split()
    return x

要想进一步提高速度,可能需要用C或Cython写一些代码。我很想知道这些函数打开你的文件需要多长时间。

撰写回答