Существует много вопросов (1, 2, 3), касающихся подсчета значений в одной серии.
Тем не менее, есть меньше вопросов, рассматривающих лучший способ подсчета комбинаций из двух или более серий. Решения представлены (1, 2), но когда и почему каждый должен использовать каждый, это не обсуждается.
Ниже приведен сравнительный анализ трех потенциальных методов. У меня есть два конкретных вопроса:
- Почему
grouper
эффективнее, чемcount
? Я ожидал, чтоcount
будет более эффективным, так как он реализован в C. Превосходная производительностьgrouper
сохраняется, даже если количество столбцов увеличивается с 2 до 4. - Почему
value_counter
отставатьgrouper
на столько? Это связано со стоимостью создания списка или серии из списка?
Я понимаю, что результаты разные, и это также должно способствовать выбору. Например, фильтрация по счету более эффективна с непрерывными массивами numpy
сравнению с пониманием словаря:
x, z = grouper(df), count(df)
%timeit x[x.values > 10] # 749µs
%timeit {k: v for k, v in z.items() if v > 10} # 9.37ms
Однако основное внимание в моем вопросе уделяется эффективности построения сопоставимых результатов в серии по сравнению с словарем. Мои знания C ограничены, но я был бы признателен за любой ответ, который может указывать на логику, лежащую в основе этих методов.
Код бенчмаркинга
import pandas as pd
import numpy as np
from collections import Counter
np.random.seed(0)
m, n = 1000, 100000
df = pd.DataFrame({'A': np.random.randint(0, m, n),
'B': np.random.randint(0, m, n)})
def grouper(df):
return df.groupby(['A', 'B'], sort=False).size()
def value_counter(df):
return pd.Series(list(zip(df.A, df.B))).value_counts(sort=False)
def count(df):
return Counter(zip(df.A.values, df.B.values))
x = value_counter(df).to_dict()
y = grouper(df).to_dict()
z = count(df)
assert (x == y) & (y == z), "Dictionary mismatch!"
for m, n in [(100, 10000), (1000, 10000), (100, 100000), (1000, 100000)]:
df = pd.DataFrame({'A': np.random.randint(0, m, n),
'B': np.random.randint(0, m, n)})
print(m, n)
%timeit grouper(df)
%timeit value_counter(df)
%timeit count(df)
Результаты бенчмаркинга
Запуск на python 3.6.2, pandas 0.20.3, numpy 1.13.1
Характеристики машины: 64-битная Windows 7, двухъядерная 2,5 ГГц, 4 ГБ оперативной памяти.
Ключ: г = grouper
, v = value_counter
, с = count
.
m n g v c
100 10000 2.91 18.30 8.41
1000 10000 4.10 27.20 6.98[1]
100 100000 17.90 130.00 84.50
1000 100000 43.90 309.00 93.50
1 Это не опечатка.