Jan*_*rek 6 python performance scalability dataframe pandas
在使用Pandas 0.17.1解析大量日期时,我遇到了一个奇怪的性能问题.为了演示,我创建了只包含一列的CSV文件,其中包含"2015-12-31 13:01:01"格式的日期时间.示例文件包含10k,100k,1M和10M记录.我正在解析它:
start = timer()
pd.read_csv('10k_records.csv', parse_dates=['date'])
end = timer()
print(end - start)
Run Code Online (Sandbox Code Playgroud)
经过的时间是:
10k:0.011 s
100k:0.10 s
1m:1.2 s
10m:300 s
你看,时间与记录数量成线性关系直到100万,但随后出现了巨大下降.
这不是内存问题.我有16GB,我在Pandas中使用这种大小的数据帧而没有任何问题,只有解析日期似乎很慢.
我尝试使用infer_datetime_format = True,但速度相似.10米记录也是一个巨大的下降.
然后我尝试注册我自己的天真日期解析器:
def parseDate(t):
if type(t) is str :
st = str(t)
try:
return datetime.datetime(int(st[:4]),int(st[5:7]),int(st[8:10]),int(st[11:13]),int(st[14:16]),int(st[17:19]))
except:
return None
return datetime.datetime(0,0,0,0,0,0)
pd.read_csv(
'10k_records.csv', parse_dates=['date'],
date_parser=parseDate
)
Run Code Online (Sandbox Code Playgroud)
时间现在是:
10k:0.045 s
100k:0.36 s
1m:3.7 s
10m:36 s
该例程比较小的文件上的默认pandas解析器慢,但它对于较大的文件完全线性扩展.所以它看起来像标准日期解析例程中的某种性能泄漏.
好吧,我可以使用我的解析器,但它非常简单,愚蠢,而且显然很慢.我更喜欢使用智能,健壮,快速的Pandas解析器,只有我能以某种方式解决可扩展性问题.任何人都有任何想法,如果可以解决,可能是通过一些深奥的参数或什么?
感谢你们所有人的帮助.
毕竟,日期解析似乎存在可重现的性能问题,但它与可伸缩性无关.我原来的分析错了.
您可以尝试下载此文件 https://www.dropbox.com/s/c5m21s1uif329f1/slow.csv.tar.gz?dl=0 并在Pandas中解析它.格式和一切都是正确的,所有数据都是有效的.只有100k记录,但解析它们需要3秒 - 而从生成的常规序列中解析100k记录需要0.1秒.
发生了什么:我没有像@ exp1orer那样生成我的原始测试数据作为常规序列.我正在对我们的实际数据进行抽样,并且它们的分布并不常见.顺序总体上以不变的速度增长,但是存在一些局部不规则和无序的碎片.而且,显然,在我的10M样本中,碰巧有一个部分,这使得大熊猫特别不高兴,并且解析花了这么长时间.它只是文件内容的一小部分,导致所有的缓慢.但我无法发现该分数与文件其余部分之间的任何主要差异.
因此,缓慢的原因是有一些奇怪的日期,如20124-10-20.显然,在将数据导入Pandas之前,我需要做一些更多的预处理.
更新:
看看这个比较:
In [507]: fn
Out[507]: 'D:\\download\\slow.csv.tar.gz'
In [508]: fn2
Out[508]: 'D:\\download\\slow_filtered.csv.gz'
In [509]: %timeit df = pd.read_csv(fn, parse_dates=['from'], index_col=0)
1 loop, best of 3: 15.7 s per loop
In [510]: %timeit df2 = pd.read_csv(fn2, parse_dates=['from'], index_col=0)
1 loop, best of 3: 399 ms per loop
In [511]: len(df)
Out[511]: 99831
In [512]: len(df2)
Out[512]: 99831
In [513]: df.dtypes
Out[513]:
from object
dtype: object
In [514]: df2.dtypes
Out[514]:
from datetime64[ns]
dtype: object
Run Code Online (Sandbox Code Playgroud)
这两个 DF 之间的唯一区别在于行# 36867,我已在D:\\download\\slow_filtered.csv.gz文件中手动更正了该行:
In [518]: df.iloc[36867]
Out[518]:
from 20124-10-20 10:12:00
Name: 36867, dtype: object
In [519]: df2.iloc[36867]
Out[519]:
from 2014-10-20 10:12:00
Name: 36867, dtype: datetime64[ns]
Run Code Online (Sandbox Code Playgroud)
结论:Pandas 花费了 39 倍的时间,因为其中一行的日期为“错误”,并且最后 Pandasfrom在dfDF 中留下了作为字符串的列
旧答案:
它对我来说非常公平(pandas 0.18.0):
设置:
start_ts = '2000-01-01 00:00:00'
pd.DataFrame({'date': pd.date_range(start_ts, freq='1S', periods=10**4)}).to_csv('d:/temp/10k.csv', index=False)
pd.DataFrame({'date': pd.date_range(start_ts, freq='1S', periods=10**5)}).to_csv('d:/temp/100k.csv', index=False)
pd.DataFrame({'date': pd.date_range(start_ts, freq='1S', periods=10**6)}).to_csv('d:/temp/1m.csv', index=False)
pd.DataFrame({'date': pd.date_range(start_ts, freq='1S', periods=10**7)}).to_csv('d:/temp/10m.csv', index=False)
dt_parser = lambda x: pd.to_datetime(x, format="%Y-%m-%d %H:%M:%S")
Run Code Online (Sandbox Code Playgroud)
检查:
In [360]: fn = 'd:/temp/10m.csv'
In [361]: %timeit pd.read_csv(fn, parse_dates=['date'], dtype={0: pd.datetime}, date_parser=dt_parser)
1 loop, best of 3: 22.6 s per loop
In [362]: %timeit pd.read_csv(fn, parse_dates=['date'], dtype={0: pd.datetime})
1 loop, best of 3: 29.9 s per loop
In [363]: %timeit pd.read_csv(fn, parse_dates=['date'])
1 loop, best of 3: 29.9 s per loop
In [364]: fn = 'd:/temp/1m.csv'
In [365]: %timeit pd.read_csv(fn, parse_dates=['date'], dtype={0: pd.datetime}, date_parser=dt_parser)
1 loop, best of 3: 2.32 s per loop
In [366]: %timeit pd.read_csv(fn, parse_dates=['date'], dtype={0: pd.datetime})
1 loop, best of 3: 3.06 s per loop
In [367]: %timeit pd.read_csv(fn, parse_dates=['date'])
1 loop, best of 3: 3.06 s per loop
In [368]: %timeit pd.read_csv(fn)
1 loop, best of 3: 1.53 s per loop
Run Code Online (Sandbox Code Playgroud)
date_parser结论:当我使用指定日期格式的地方时,它会快一点,所以read_csv不必猜测它。差异约为。30%
| 归档时间: |
|
| 查看次数: |
1168 次 |
| 最近记录: |