python:改进我阅读大型 (5GB) txt 文件的方式

python: Improving the way I am reading a large (5GB) txt file

我实际上正在使用 pandas.read_csv 读取一个大的(5GB,约 9700 万行 X 7 列)txt 文件 python(点云)。

我需要读取前三列(代表 x、y、z 坐标),并检索我的点云的边界框(格式为 [x_min、y_min, z_min, x_max, y_max, z_max]).

就目前而言,我的代码(见下文)需要几个小时才能完成(实际上它是昨天开始的,但还没有完成...)。我正在使用的机器是 Intel Xeon CPU ES-1630 v3 @ 3.70GHz 3.70GHz。我正在使用 python 3.6 64 位。

我的代码的几个关键点...

阅读相同的函数文档,它读到使用 usecols 参数 * 导致更快的解析时间和更低的内存使用量*。所以我只包含了我感兴趣的列。

我并不完全了解 chunksize 论点的真正用处(也许我使用它的方式不对...)。当我使用它时,我想它是逐行读取文件,也许这不是最好的方法。

这是代码,任何建议(也关于使用 pandas.read_csv 以外的其他方法)将不胜感激。

def bounding_box(filename):
startTime = datetime.now()  # initialize counter

for row in pd.read_csv(filename, sep='\s+', header=None, chunksize=1, skiprows=1, usecols=[0, 1, 2]):
    if not 'x_min' in locals():
        x_min = row.iat[0, 0]
    if not 'y_min' in locals():
        y_min = row.iat[0, 1]
    if not 'z_min' in locals():
        z_min = row.iat[0, 2]

    if not 'x_max' in locals():
        x_max = row.iat[0, 0]
    if not 'y_max' in locals():
        y_max = row.iat[0, 1]
    if not 'z_max' in locals():
        z_max = row.iat[0, 2]

    x_min = row.iat[0, 0] if row.iat[0, 0] < x_min else x_min
    y_min = row.iat[0, 1] if row.iat[0, 1] < y_min else y_min
    z_min = row.iat[0, 2] if row.iat[0, 2] < z_min else z_min

    x_max = row.iat[0, 0] if row.iat[0, 0] > x_max else x_max
    y_max = row.iat[0, 1] if row.iat[0, 1] > y_max else y_max
    z_max = row.iat[0, 2] if row.iat[0, 2] > z_max else z_max

bbox = [x_min, y_min, z_min, x_max, y_max, z_max]
print("TIME OF PROCESSING: {}".format(datetime.now() - startTime))  # print time of execution

return bbox

如果我误解了问题,请纠正我。您需要计算一个 "bounding box" - 包含所有点数的最小值 "box"?

如果像这样为任何坐标设置 min() 和 max() 会怎样?

# some very easy DataFrame for demo
>>> df=pd.DataFrame({0:[1,2,3], 1:[3,4,5], 2:[3,4,1]})

>>> df
     0  1  2
  0  1  3  3
  1  2  4  4
  2  3  5  1

 >>> df[0].min(), df[0].max()   #  Xmin, Xmax
 (1, 3)

 >>> df[1].min(), df[1].max()   # Ymin, Ymax
 (3, 5)

 >>> df[2].min(), df[2].max()   # Zmin, Zmax
 (1, 4)

然而,如果它是唯一的任务 pandas 将是 "overkill"。更快更好的解决方案是逐行读取文件并进行如下检查:

 import csv, math
 c = csv.reader(open('data/1.csv', 'r'), delimiter=',')
 xmin = +math.inf
 xmax = -math.inf

 for row in c:
     x = int(row[1])   ##   or another column
     xmin = min(xmin, x)
     xmax = max(xmax, x)
     # the same code for Y and Z

 print(xmin, xmax)

这种方法有很大的优势——它在处理行后读取文件 line-by-line,然后将其丢弃。所以实际上它可以处理任何长度的文件 - 甚至 TB!

由于我没有准备好进行测试的 5GB 文件,我只能猜测这两个问题会拖慢您的速度:

  1. 逐行读取文件(并将每一行转换为数据帧)
  2. 复杂的逻辑,包括 locals() 和每行的元素访问

要解决这些问题,请将 chunksize 参数增加到无需分页仍适合内存的大参数。我想数千甚至更多的块大小会很好。

然后简化(向量化)逻辑。您可以轻松计算块的边界框,然后在不包含所有块边界的情况下更新 'big' 边界框。类似的东西:

import numpy as np
import pandas as pd

filename = 'test.csv'

bbox_min = np.zeros(3) + np.inf
bbox_max = np.zeros(3) - np.inf
for chunk in pd.read_csv(filename, sep='\s+', header=None, chunksize=10000, skiprows=1, usecols=[0, 1, 2]):
    chunkmin = chunk.values.min(axis=0)
    chunkmax = chunk.values.max(axis=0)

    bbox_min = np.minimum(bbox_min, chunkmin)
    bbox_max = np.maximum(bbox_max, chunkmax)

bbox = np.ravel([bbox_min, bbox_max])