【问题标题】:Why is pandas.series.map so shockingly slow?为什么 pandas.series.map 的速度如此之慢?
【发布时间】:2018-11-11 00:51:37
【问题描述】:

有些日子我只是讨厌使用中间件。以这个为例:我想要一个查找表,将一组输入(域)值中的值映射到输出(范围)值。映射是唯一的。 Python 地图可以做到这一点,但由于我认为地图很大,为什么不使用 ps.Series 及其索引,这增加了我可以做到的好处:

  • 传入多个值以作为一个系列进行映射(希望比字典查找更快)
  • 结果中保留了原始系列的索引

像这样:

domain2range = pd.Series(allrangevals, index=alldomainvals)
# Apply the map
query_vals = pd.Series(domainvals, index=someindex)
result = query_vals.map(domain2range)
assert result.index is someindex # Nice
assert (result.values in allrangevals).all() # Nice

按预期工作。但不是。上面的 .map 的时间成本随着 len(domain2range) 而不是(更明智地)O(len(query_vals)) 增加,如图所示:

numiter = 100
for n in [10, 1000, 1000000, 10000000,]:
    domain = np.arange(0, n)
    range = domain+10
    maptable = pd.Series(range, index=domain).sort_index()

    query_vals = pd.Series([1,2,3])
    def f():
        query_vals.map(maptable)
    print n, timeit.timeit(stmt=f, number=numiter)/numiter


10 0.000630810260773
1000 0.000978469848633
1000000 0.00130645036697
10000000 0.0162791204453

捂脸。在 n=10000000 时,每个映射值需要 (0.01/3) 秒。

所以,问题:

  • Series.map 是否应该表现得像这样?为什么它如此彻底,可笑的慢?我认为我正在使用它,如文档中所示。
  • 有没有一种使用 pandas 进行表查找的快速方法。好像不是上面的吗?

【问题讨论】:

  • @TemporalWolf 我要说的是,如果每个查询值需要 (1.44/3) 秒,那么它不会针对任何事情进行优化。
  • 以上代码可运行并提供数据。映射表从 0..n ==> 10..n+10 映射值,查询始终为 [1,2,3]。
  • 您确实意识到将number=10 传递给timeit 正在测量执行10 次的时间,对吧?
  • 好的。除以 10。还是不合理
  • 我已经用正确的时间更新了这个问题。仍然非常非常慢。

标签: python pandas


【解决方案1】:

https://github.com/pandas-dev/pandas/issues/21278

热身是问题所在。 (双掌)。 Pandas 在首次使用时默默地构建和缓存哈希索引 (O(maplen))。调用测试函数并预构建索引可以获得更好的性能。

numiter = 100
for n in [10, 100000, 1000000, 10000000,]:
    domain = np.arange(0, n)
    range = domain+10
    maptable = pd.Series(range, index=domain) #.sort_index()

    query_vals = pd.Series([1,2,3])

    def f1():
        query_vals.map(maptable)
    f1()
    print "Pandas1 ", n, timeit.timeit(stmt=f1, number=numiter)/numiter

    def f2():
        query_vals.map(maptable.get)
    f2()
    print "Pandas2 ", n, timeit.timeit(stmt=f2, number=numiter)/numiter

    maptabledict = maptable.to_dict()
    query_vals_list = pd.Series([1,2,3]).tolist()

    def f3():
        {k: maptabledict[k] for k in query_vals_list}
    f3()
    print "Py dict ", n, timeit.timeit(stmt=f3, number=numiter)/numiter
    print

pd.show_versions()
Pandas1  10 0.000621199607849
Pandas2  10 0.000686831474304
Py dict  10 2.0170211792e-05

Pandas1  100000 0.00149286031723
Pandas2  100000 0.00118808984756
Py dict  100000 8.47816467285e-06

Pandas1  1000000 0.000708899497986
Pandas2  1000000 0.000479419231415
Py dict  1000000 1.64794921875e-05

Pandas1  10000000 0.000798969268799
Pandas2  10000000 0.000410139560699
Py dict  10000000 1.47914886475e-05

...虽然有点令人沮丧的是,python 字典快了 10 倍。

【讨论】:

  • 不再使用 pandas .map。 Python 字典要快得多!
猜你喜欢
  • 2012-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-31
  • 1970-01-01
  • 1970-01-01
  • 2023-02-16
  • 2017-11-20
相关资源
最近更新 更多