np.unique
с return_counts=True
может работать лучше, поскольку не требует изменения формы:
values, counts = np.unique(df[['PLayer1_name', 'player2_name']],
return_counts=True)
s = pd.Series(counts, index=values).sort_values(ascending=False)
s
:
Caruna 2
Kasparov 2
Nakamura 2
B.Fisher 1
Wesley.So 1
dtype: int64
Некоторая информация о времени:
import numpy as np
import pandas as pd
df_ = pd.DataFrame({
'PLayer1_name': {0: 'Kasparov', 1: 'Caruna', 2: 'Nakamura', 3: 'Caruna'},
'player2_name': {0: 'B.Fisher', 1: 'Wesley.So', 2: 'Kasparov',
3: 'Nakamura'},
'Place': {0: 'Paris', 1: 'Tokyo', 2: 'S.Petersburg', 3: 'New York'}
})
Этот ответ:
def fn(df):
values, counts = np.unique(df[['PLayer1_name', 'player2_name']],
return_counts=True)
return pd.Series(counts, index=values).sort_values(ascending=False)
%timeit fn(df_)
640 µs ± 13.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Опция расплава Анурага Дабаса:
def fn2(df):
return df.melt(
None, ['PLayer1_name', 'player2_name']
)['value'].value_counts()
%timeit fn2(df_)
2.05 ms ± 203 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Опция стека Анурага Дабаса:
def fn3(df):
return (
df[['PLayer1_name', 'player2_name']].stack()
.droplevel(1).value_counts()
)
%timeit fn3(df_)
1.32 ms ± 51.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Я бы всегда выбирал такой вариант, как этот, не только из-за скорости, но и потому, что интуитивно понятно, что происходит за листами.
В любом подходе всегда есть плюсы и минусы. Но в этом случае я думаю, что
numpy
лучше всего.