У меня есть неуклюжий файл CSV, который имеет несколько разделителей: разделитель для нечисловой части это ','
, для числовой части ';'
, Я хочу построить фрейм данных только из числовой части настолько эффективно, насколько это возможно.
Я сделал 5 попыток: среди них, используя аргумент converters
pd.read_csv
, используя регулярное выражение с engine='python'
, используя str.replace
. Все они более чем в 2 раза медленнее, чем чтение всего файла CSV без преобразований. Это слишком медленно для моего варианта использования.
Я понимаю, что сравнение не похоже на сравнение, но оно демонстрирует, что общая низкая производительность не связана с вводом/выводом. Есть ли более эффективный способ считывания данных в числовой кадр данных Pandas? Или эквивалентный массив NumPy?
Приведенная ниже строка может использоваться для целей тестирования.
# Python 3.7.0, Pandas 0.23.4
from io import StringIO
import pandas as pd
import csv
# strings in first 3 columns are of arbitrary length
x = '''ABCD,EFGH,IJKL,34.23;562.45;213.5432
MNOP,QRST,UVWX,56.23;63.45;625.234
'''*10**6
def csv_reader_1(x):
df = pd.read_csv(x, usecols=[3], header=None, delimiter=',',
converters={3: lambda x: x.split(';')})
return df.join(pd.DataFrame(df.pop(3).values.tolist(), dtype=float))
def csv_reader_2(x):
df = pd.read_csv(x, header=None, delimiter=';',
converters={0: lambda x: x.rsplit(',')[-1]}, dtype=float)
return df.astype(float)
def csv_reader_3(x):
return pd.read_csv(x, usecols=[3, 4, 5], header=None, sep=',|;', engine='python')
def csv_reader_4(x):
with x as fin:
reader = csv.reader(fin, delimiter=',')
L = [i[-1].split(';') for i in reader]
return pd.DataFrame(L, dtype=float)
def csv_reader_5(x):
with x as fin:
return pd.read_csv(StringIO(fin.getvalue().replace(';',',')),
sep=',', header=None, usecols=[3, 4, 5])
Проверки:
res1 = csv_reader_1(StringIO(x))
res2 = csv_reader_2(StringIO(x))
res3 = csv_reader_3(StringIO(x))
res4 = csv_reader_4(StringIO(x))
res5 = csv_reader_5(StringIO(x))
print(res1.head(3))
# 0 1 2
# 0 34.23 562.45 213.5432
# 1 56.23 63.45 625.2340
# 2 34.23 562.45 213.5432
assert all(np.array_equal(res1.values, i.values) for i in (res2, res3, res4, res5))
Результаты сравнительного анализа:
%timeit csv_reader_1(StringIO(x)) # 5.31 s per loop
%timeit csv_reader_2(StringIO(x)) # 6.69 s per loop
%timeit csv_reader_3(StringIO(x)) # 18.6 s per loop
%timeit csv_reader_4(StringIO(x)) # 5.68 s per loop
%timeit csv_reader_5(StringIO(x)) # 7.01 s per loop
%timeit pd.read_csv(StringIO(x)) # 1.65 s per loop
Обновить
Я открыт для использования инструментов командной строки в качестве последнего средства. В той степени, я включил такой ответ. Я надеюсь, что есть решение на чистом Python или Pandas с сопоставимой эффективностью.