将巨大的.dat文件快速加载到数组中最快的方法
我在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写一些代码。我很想知道这些函数打开你的文件需要多长时间。