【问题标题】:Sorting data from a large text file and convert them into an array对大型文本文件中的数据进行排序并将其转换为数组
【发布时间】:2020-09-30 05:55:47
【问题描述】:

我有一个包含一些数据的文本文件。

#this is a sample file
# data can be used for practice
total number = 5

t=1
dx= 10 10
dy= 10 10
dz= 10 10

1 0.1 0.2 0.3
2 0.3 0.4 0.1
3 0.5 0.6 0.9
4 0.9 0.7 0.6
5 0.4 0.2 0.1

t=2
dx= 10 10
dy= 10 10
dz= 10 10

1 0.11 0.25 0.32
2 0.31 0.44 0.12
3 0.51 0.63 0.92
4 0.92 0.72 0.63
5 0.43 0.21 0.14

t=3
dx= 10 10
dy= 10 10
dz= 10 10

1 0.21 0.15 0.32
2 0.41 0.34 0.12
3 0.21 0.43 0.92
4 0.12 0.62 0.63
5 0.33 0.51 0.14

我的目标是读取文件,找出列值为 1 和 5 的行并将它们存储为多维数组。就像 1 一样,它将是 a1=[[0.1, 0.2, 0.3],[0.11, 0.25, 0.32],[0.21, 0.15, 0.32]],对于 5,它将是 a5=[[0.4, 0.2, 0.1],[0.43, 0.21, 0.14],[0.33, 0.51, 0.14]]

这是我写的代码,

import numpy as np
with open("position.txt","r") as data:
    lines = data.read().split(sep='\n')
    a1 = []
    a5 = []
    for line in lines:

        if(line.startswith('1')):
            a1.append(list(map(float, line.split()[1:])))
        elif (line.startswith('5')):
            a5.append(list(map(float, line.split()[1:])))
a1=np.array(a1)
a5=np.array(a5)

我的代码与我上传的示例文件完美配合,但在实际情况下,我的文件相当大 (2gb)。用我的代码处理它会引发内存错误。我该如何解决这个问题?我的工作站中有 96GB。

【问题讨论】:

  • this question 的最佳答案的第二条评论对您有帮助吗?
  • @DavidWierichs 是的,这有帮助。实际上我已经这样做了,但整个事情仍然很慢。下面的答案相当有效率。

标签: python-3.x numpy sorting error-handling


【解决方案1】:

有几点需要改进:

  • 不要尝试将整个文本文件加载到内存中(这将节省 2 GB)。
  • 使用 numpy 数组而不是列表来存储数值数据。
  • 使用单精度浮点数而不是双精度浮点数。

因此,您需要估计您的阵列有多大。看起来 2 GB 的输入数据可能有 1600 万条记录。使用 32 位浮点数,您需要 16e6*2*4=128 MB 的内存。对于 500 GB 的输入,它将适合 33 GB 内存(假设您有相同的 120 字节记录大小)。

import numpy as np
nmax = int(20e+6) # take a bit of safety margin

a1 = np.zeros((nmax, 3), dtype=np.float32)
a5 = np.zeros((nmax, 3), dtype=np.float32)
n1 = n5 = 0

with open("position.txt","r") as data:
    for line in data:
        if '0' <= line[0] <= '9':
            values = np.fromstring(line, dtype=np.float32, sep=' ')
            if values[0] == 1:
                a1[n1] = values[1:] 
                n1 += 1
            elif values[0] == 5:
                a5[n5] = values[1:]
                n5 += 1

# trim (no memory is released)
a1 = a1[:n1]
a5 = a5[:n5]

请注意,通常不建议使用浮点等式 (==),但在 value[0]==1 的情况下,我们知道它是一个小整数,浮点表示是精确的。

如果您想节省内存(例如,如果您想并行运行多个 python 进程),那么您可以将数组初始化为磁盘映射数组,如下所示:

a1 = np.memmap('data_1.bin', dtype=np.float32, mode='w+', shape=(nmax, 3))
a5 = np.memmap('data_5.bin', dtype=np.float32, mode='w+', shape=(nmax, 3))

使用memmap,文件将不包含有关数据类型和数组形状(或人类可读描述)的任何元数据。我建议您在单独的作业中将数据转换为npz 格式;不要并行运行这些作业,因为它们会将整个数组加载到内存中。

n = 3
a1m = np.memmap('data_1.bin', dtype=np.float32, shape=(n, 3))
a5m = np.memmap('data_5.bin', dtype=np.float32, shape=(n, 3))
np.savez('data.npz', a1=a1m, a5=a5m, info='This is test data from SO')

你可以像这样加载它们:

data = np.load('data.npz')
a1 = data['a1']

根据磁盘空间成本、处理时间和内存之间的平衡,您可以压缩数据。

import zlib
zlib.Z_DEFAULT_COMPRESSION = 3 # faster for lower values
np.savez_compressed('data.npz', a1=a1m, a5=a5m, info='...')

如果float32 的精度比您需要的高,您可以truncate the binary representation for better compression

如果你喜欢内存映射文件,可以保存为npy格式:

np.save('data_1.npy', a1m)
a1 = np.load('data_1.npy', mmap_mode='r+')

但是你不能使用压缩,你最终会得到许多没有元数据的文件(数组大小和数据类型除外)。

【讨论】:

  • 感谢您的好建议。又一个问题来了。如果我排序为 '1' ,它将采用以第 1 列开头的任何行(例如:1,11,121 等)。是否可以只排序“1”或“11”?
  • 关于数据 2 GB 只是一个文件..但我有一些文件包含 500 GB 或更多的数据(分子动力学模拟)。只是在效率方面寻找一些东西。多处理在任何情况下都有帮助吗?我确实有 80 核处理器。
  • 我更新了答案以涵盖内存映射文件、多处理和 9 以上的数字。
  • 感谢您的详细回答。效果很好。
  • 如果你喜欢这个答案,你可以点击upvote按钮。 ;)
猜你喜欢
  • 2012-10-09
  • 2016-09-13
  • 2011-10-28
  • 2017-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-25
相关资源
最近更新 更多