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

python:改进我读取大型(5GB)txt文件的方式,python,pandas,numpy,io,large-files,Python,Pandas,Numpy,Io,Large Files,我实际上使用python(点云)读取一个大的(5GB,约9700万行X 7列)txt文件 我需要读取前三列(代表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。我使用的是Python3.6 64位 我的代码的几个关键点 在阅读相同的函数文档时,

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

我需要读取前三列(代表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。我使用的是Python3.6 64位

我的代码的几个关键点

在阅读相同的函数文档时,会发现使用
usecols
parameter*会导致更快的解析时间和更低的内存使用率*。所以我只包括了我感兴趣的可乐

我没有完全意识到
chunksize
参数的真正用处(可能我用错了方法…)。当我使用它时,我想它是逐行读取文件,也许这不是最好的方法

这是代码,任何建议(关于使用熊猫.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
def边界框(文件名):
startTime=datetime.now()#初始化计数器
对于pd.read_csv(文件名,sep='\s+',header=None,chunksize=1,skiprows=1,usecols=[0,1,2])中的行:
如果不是局部变量()中的“x_min”:
x_min=row.iat[0,0]
如果在locals()中不是“y_min”:
y_min=row.iat[0,1]
如果在locals()中不是“z_min”:
z_min=行iat[0,2]
如果不是局部变量()中的“x_max”:
x_max=行iat[0,0]
如果不是局部变量中的“y_max”:
y_max=行iat[0,1]
如果不是局部变量()中的“z_max”:
z_max=行iat[0,2]
如果row.iat[0,0]x_max,则x_max=row.iat[0,0],否则x_max
如果row.iat[0,1]>y_max,则y_max=row.iat[0,1]如果row.iat[0,1]>y_max,则y_max=row.iat[0,1]
如果row.iat[0,2]>z_max,则z_max=row.iat[0,2]如果row.iat[0,2]>z_max否则z_max
bbox=[x_min,y_min,z_min,x_max,y_max,z_max]
打印(“处理时间:{}.format(datetime.now()-startTime))#打印执行时间
返回bbox

如果我误解了这个问题,请纠正我。您需要计算一个“边界框”——包含所有点的最小“框”

如果对像这样的坐标做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)
然而,如果这是唯一的任务,熊猫将是“过度杀戮”。更快速、更好的解决方案是逐行读取文件并进行如下检查:

 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)

这种方法有很大的优势——它一行接一行地读取文件,然后将其丢弃。因此,实际上它可以处理任何长度的文件,甚至是TB

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

  • 逐行读取文件(并将每行转换为数据帧)
  • 复杂的逻辑,包括
    locals()
    和每行的元素访问
  • 要解决这些问题,请将
    chunksize
    参数增加到一个大参数,该参数仍然可以在不分页的情况下放入内存。我想thounsands中的chunksizes甚至更多都能很好地工作

    然后简化(矢量化)逻辑。您可以轻松计算块的边界框,如果“大”边界框不包含所有块边界,则可以更新该边界框。诸如此类:

    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])
    

    我不确定CSV读取部分,但在for循环之前,将x/y/z min和max变量设置为默认值(可能为0),并在每个循环中保存6个“if”语句和6个函数调用,这不是更好吗?正如所写,您无法区分将
    CSV
    读取到数据帧中所花费的时间,还有计算盒子的时间。我会将这两个步骤分开,并打印一些语句,例如
    df.info()
    between.@umbe1987,与您询问的问题分开。您还可以包含一个小的数据帧和您想要的结果吗?虽然最后一种方法对于程序使用的内存来说很好,但它不适合我的情况,因为它太慢了。需要多少时间?4min23s。还不错。谢谢你的支持+1.哇,只有13分钟!。。。不知道结果是否正确,但似乎是。。我会很快检查并接受答案,以备不时之需。很高兴听到:)你能把这些信息放大一点吗?我会尽快尝试并报告。如果可能的话,也许会更快。