python - 使用 pandas 解析大量日期 - 可扩展性 - 性能下降速度快于线性

标签 python performance pandas dataframe scalability

在使用 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)

耗时是:
10k: 0.011 秒
100k: 0.10 秒
1米:1.2秒
10 米:300 秒

你看,时间与记录数呈线性关系,直到 100 万,但随后出现大幅下降。

这不是内存问题。我有 16GB,我在 Pandas 中使用这种大小的数据帧没有任何问题,只有日期解析看起来很慢。

我尝试使用 infer_datetime_format=True,但速度相似。对于 1000 万条记录来说也是一个巨大的下降。

然后我尝试注册我自己的天真的日期解析器:

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
)

现在是时候了:
10k: 0.045 秒
100k: 0.36 秒
1 米:3.7 秒
10 米:36 秒

对于较小的文件,该例程比默认的 pandas 解析器慢,但对于较大的文件,它可以完美地线性扩展。所以它看起来真的像是标准日期解析例程中的某种性能泄漏。

好吧,我可以使用我的解析器,但它非常简单、愚蠢,而且显然很慢。我更愿意使用智能、健壮和快速的 Pandas 解析器,前提是我能以某种方式解决可伸缩性问题。如果可以通过一些深奥的参数或其他东西解决,有人会知道吗?

更新

感谢大家迄今为止的帮助。

毕竟,日期解析似乎存在可重现的性能问题,但与可扩展性无关。我原来的分析是错误的。

你可以试试下载这个文件 https://www.dropbox.com/s/c5m21s1uif329f1/slow.csv.tar.gz?dl=0 并在 Pandas 中解析它。格式和一切都是正确的,所有数据都是有效的。只有 100k 条记录,但解析它们需要 3 秒 - 而从生成的常规序列中解析 100k 条记录需要 0.1s。

发生了什么:我没有像@exp1orer 那样按常规序列生成原始测试数据。我正在对我们的真实数据进行抽样,它们的分布并不是那么规律。该序列总体上以恒定的速度增长,但存在一些局部不规则和无序片段。而且,显然,在我的 10M 样本中,恰好有一个部分让 pandas 特别不高兴,解析时间很长。导致所有速度缓慢的只是文件内容的一小部分。但我无法发现该部分与文件其余部分之间的任何主要差异。

更新 2

所以,缓慢的原因是有一些奇怪的日期,比如 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

这两个 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]

结论:Pandas 花费了 39 倍的时间,因为其中一行的日期“错误”,最后 Pandas 离开了 df< 中的 from DF 作为字符串

旧答案:

它对我来说很公平(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")

检查:

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

结论:当我在指定日期格式的地方使用 date_parser 时,它会快一点,所以 read_csv 不必猜测它。差异约为。 30%

关于python - 使用 pandas 解析大量日期 - 可扩展性 - 性能下降速度快于线性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36484575/

相关文章:

java - 大内存如何优化内存使用?

python - 使用 pandas 在 python 中进行时间连接

python - 使用对新/旧索引的容差在 Pandas 中重新索引数据框

Python:如何将列表中的元组 ('a' 、 'b' ) 和元组 ('b' 、 'a' ) 算作同一事物?

python - fillna 与 None 串联

python - 系统等待时,如何在pygame中播放声音?

C# NAudio 获取音频文件持续时间/性能

c# - 以下两个语句有什么区别?

python - 试图运行一个 Python 程序,但打开的只是一个 DOS 窗口

python - pandas iterrows 和循环计数器的问题