Что-то, как это должно работать. Он будет быстрее, чем apply
, поскольку он использует векторизованные операции. Кроме того, вместо того, чтобы жестко кодировать результат apple
, он дает вам количество и проценты для всех покупок, независимо от того, сколько у вас может быть.
>>> df2 = df.reset_index().groupby(['Name', 'Purchase']).count().unstack('Purchase').fillna(0)
>>> df2.columns = df2.columns.droplevel(0)
>>>
>>> totals = df2.sum(axis=1)
>>> totals.name = 'tot-purchases'
>>>
>>> df3 = df2.divide(df2.sum(axis=1), axis=0)
>>>
>>> df2.columns = ['num-'+x for x in df2.columns]
>>> df3.columns = ['percent-'+x for x in df3.columns]
>>> dff = pd.concat([totals, df2, df3], axis=1)
>>>
>>> print(dff)
tot-purchases num-apple num-orange percent-apple percent-orange
Name
alice 2 2 0 1.000000 0.000000
bob 3 2 1 0.666667 0.333333
dave 1 0 1 0.000000 1.000000
>>> print(dff.loc[:,('tot-purchases', 'num-apple', 'percent-apple')])
tot-purchases num-apple percent-apple
Name
alice 2 2 1.000000
bob 3 2 0.666667
dave 1 0 0.000000
В основном он делит данные на группы по Name
и Purchase
, затем подсчитывает, сколько в каждой группе. Затем он задает имя Purchase
быть заголовком столбца, давая вам 2D DataFrame
где index
является Name
, то columns
является Purchase
типа, а значения отсчетов этого Purchase
типа для данного Name
. Тогда вопрос арифметики - получить проценты и итоговые суммы.
Если вы готовы изменить выход немного, вы можете сделать что-то еще более полезным с MultiIndex
:
>>> df2 = df.reset_index().groupby(['Name', 'Purchase']).count().unstack('Purchase').fillna(0)
>>> df2.columns.rename('Value',level=0, inplace=True)
>>> df2.columns = df2.columns.set_levels(['Count'], level=0)
>>>
>>> totals = df2.sum(axis=1)
>>> totals.name = ('Count', 'all')
>>>
>>> df3 = df2.divide(df2.sum(axis=1), axis=0)
>>> df3.columns = df3.columns.set_levels(['Percent'], level=0)
>>>
>>> dff = pd.concat([totals, df2, df3], axis=1)
>>>
>>> print(dff)
Count Percent
all apple orange apple orange
Name
alice 2 2 0 1.000000 0.000000
bob 3 2 1 0.666667 0.333333
dave 1 0 1 0.000000 1.000000
Мне нравится этот ответ, потому что это концептуально легче понять, хотя, как TheBlackCat указывает, вся итерация делает ее менее эффективной. Но он тоже работает. – Guerre