2017-01-12 15 views
2

Я использую pandas.read_csv для чтения большого (5 ГБ, ~ 97 миллионов строк X 7 столбцов) txt-файла с python (облако точек).python: Улучшение способа чтения большого (5GB) txt-файла

Мне нужно прочитать первые три столбца (которые представляют координаты x, y, z) и извлечь ограничительную рамку моего облака точек (в форме [x_min, y_min, z_min, x_max, y_max, z_max ]).

Как бы то ни было, мой код (см. Ниже) занимает несколько часов, чтобы закончить (на самом деле это началось вчера, и оно еще не закончилось ...). Аппарат, с которым я работаю, - это процессор Intel Xeon 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 
+1

Я не уверен, что чтение части CSV, но не было бы лучше, чтобы установить х/г/г мин и макс переменных на значения по умолчанию, может быть 0, до того, как цикл и сэкономить 6 слов «если» и 6 вызовов функций в каждом цикле? – mouckatron

+0

Как написано, вы не можете различать время, потраченное на чтение 'csv', в фреймворк данных и время, затрачиваемое на вычисление поля. Я бы отделил 2 шага и напечатал какой-то оператор, например 'df.info()' между ними. – hpaulj

+0

@ umbe1987 Помимо quesiton, о котором вы просили. Можете ли вы также включить небольшой Dataframe и желаемый результат? – MYGz

ответ

2

Поскольку у меня нет 5GB файл готов для тестирования, я могу только предположить, что эти два вопроса замедлять:

  1. читает файл построчно (и преобразование каждой строки в dataframe)
  2. сложная логика в том числе и locals() доступа элементов для каждой строки

Для решения этих точек увеличить chunksize аргумент что-то большое, что по-прежнему помещается в память без подкачки. Я предполагаю, что чанкизы в thounsands или даже больше будут работать хорошо.

Затем упростить (векторизовать) логику. Вы можете легко вычислить ограничительную рамку куска, а затем обновить «большую» ограничительную рамку, если она не включает в себя все границы блоков.Нечто подобное:

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

wow, только 1min23s! ... Удивительно, если результат верен, но кажется, что это будет .. Скоро проверит это и примет ответ в том случае, если это так. – umbe1987

+0

** 1min23s ** Приятно слышать :) – kazemakase

+0

Я в восторге! ... – umbe1987

1

Пожалуйста, исправьте меня, если я неправильно понял вопрос. Вам нужно вычислить «ограничивающий прямоугольник» - какой-то минимальный «ящик», содержащий все ваши баллы?

Что делать, если make 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) 

Этот подход серьезным преимуществом - он читает файл строка за строкой после строки обрабатывается, она выбрасывается , Так что практически он может работать с файлами любой длины - даже терабайтами!

+0

хотя последний подход хорош в отношении памяти, используемой программой, в моем случае это не подходит, потому что это слишком медленно, к сожалению. – umbe1987

+0

Сколько времени занимает? –

+0

4min23s. Все еще неплохо. Спасибо за поддержку. +1! – umbe1987

 Смежные вопросы

  • Нет связанных вопросов^_^