Почему pandas.series.map так шокирующе медленен? - PullRequest
0 голосов
/ 01 июня 2018

Иногда я просто ненавижу использовать промежуточное ПО.Возьмем для примера: я хотел бы иметь справочную таблицу, которая отображает значения из набора входных (доменных) значений в выходные (диапазонные) значения.Отображение является уникальным.Карта 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

facepalm .При n = 10000000 его (0,01 / 3) секунды на отображаемое значение.

Итак, вопросы:

  • Series.map , как ожидается, будет вести себя так?Почему это так смехотворно медленно?Я думаю Я использую его, как показано в документации.
  • есть быстрый способ использовать панд для поиска в таблице.Похоже на вышесказанное не так ли?

1 Ответ

0 голосов
/ 01 июня 2018

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

Была проблема с прогревом.(двойной лицевой щиток).Панда молча создает и кэширует хеш-индекс при первом использовании (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 раз быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...