我有一个笨拙的 CSV 文件,它有多个分隔符:非数字部分的分隔符是 ','
,数字部分的分隔符是 ';'
。我想尽可能高效地仅从数字部分构建数据框。
我做了 5 次尝试:其中,利用 pd.read_csv
的 converters
参数,使用正则表达式和 engine='python'
,使用 str.replace
。它们都比读取没有转换的整个 CSV 文件慢 2 倍以上。这对我的用例来说太慢了。
我知道这种比较不是对等的,但它确实表明整体性能不佳不是由 I/O 驱动的。有没有更有效的方法将数据读入数字 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 解决方案。
最佳答案
使用命令行工具
到目前为止,我发现的最有效的解决方案是使用专业的命令行工具将 ";"
替换为 ","
和 then 读入 Pandas。 Pandas 或纯 Python 解决方案在效率方面并不接近。
本质上,使用 CPython 或用 C/C++ 编写的工具可能优于 Python 级别的操作。
例如,使用 Find And Replace Text :
import os
os.chdir(r'C:\temp') # change directory location
os.system('fart.exe -c file.csv ";" ","') # run FART with character to replace
df = pd.read_csv('file.csv', usecols=[3, 4, 5], header=None) # read file into Pandas
关于python - 有效地将数据从 CSV 读取到具有多个分隔符的数据框中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54044022/