Pandas: Как узнать процентное соотношение членов группы к каждой подгруппе? - PullRequest
5 голосов
/ 28 января 2020

( Выборка данных и попытки в конце вопроса )

С таким фреймом данных:

    Type    Class   Area    Decision
0   A       1       North   Yes
1   B       1       North   Yes
2   C       2       South   No
3   A       3       South   No
4   B       3       South   No
5   C       1       South   No
6   A       2       North   Yes
7   B       3       South   Yes
8   B       1       North   No
9   C       1       East    No
10  C       2       West    Yes 

Как узнать, какой процент каждый тип [A, B, C, D], принадлежащий каждой области [North, South, East, West]?

Желаемый результат:

    North   South   East    West
A   0.66    0.33    0       0
B   0.5     0.5     0       0
C   0       0.5     0.25    0.25

Моя лучшая попытка на данный момент:

df_attempt1= df.groupby(['Area', 'Type'])['Type'].aggregate('count').unstack().T

Что возвращает :

Area  East  North  South  West
Type                          
A      NaN    2.0    1.0   NaN
B      NaN    2.0    2.0   NaN
C      1.0    NaN    2.0   1.0

И я полагаю, что я могу основываться на этом, вычисляя суммы на полях и добавляя 0 для пропущенных наблюдений, но я действительно буду признателен за предложения по более элегантным подходам.

Спасибо за любые предложения!

Код:

import pandas as pd

df = pd.DataFrame(
    {
        "Type": {0: "A", 1: "B", 2: "C", 3: "A", 4: "B", 5: "C", 6: "A", 7: "B", 8: "B", 9: "C", 10: "C"},
        "Class": {0: 1, 1: 1, 2: 2, 3: 3, 4: 3, 5: 1, 6: 2, 7: 3, 8: 1, 9: 1, 10: 2},
        "Area": {0: "North", 1: "North", 2: "South", 3: "South", 4: "South", 5: "South", 6: "North", 7: "South", 8: "North", 9: "East", 10: "West"},
        "Decision": {0: "Yes", 1: "Yes", 2: "No", 3: "No", 4: "No", 5: "No", 6: "Yes", 7: "Yes", 8: "No", 9: "No", 10: "Yes"},
    }
)

dfg = df[['Area', 'Type']].groupby(['Area']).agg('count').unstack()

df_attempt1 = df.groupby(['Area', 'Type'])['Type'].aggregate('count').unstack().T

Ответы [ 5 ]

7 голосов
/ 28 января 2020

Вы можете использовать функцию crosstab:

pd.crosstab(df['Type'], df['Area'], normalize='index')

Выход:

Area  East     North     South  West
Type                                
A     0.00  0.666667  0.333333  0.00
B     0.00  0.500000  0.500000  0.00
C     0.25  0.000000  0.500000  0.25
4 голосов
/ 28 января 2020

Вы уже были достаточно близко. Следующее должно сделать трюк:

df.groupby('Type')['Area'].value_counts(normalize = True).unstack(fill_value=0)

Вывод:

Area    East    North       South       West
Type                
A       0.00    0.666667    0.333333    0.00
B       0.00    0.500000    0.500000    0.00
C       0.25    0.000000    0.500000    0.25

Если порядок важен, вы можете изменить порядок данных, манипулируя его атрибутом столбцов

3 голосов
/ 28 января 2020

Я думаю, что вы можете go для value_counts(normalize = True):

>>> df.groupby('Type')['Area'].value_counts(normalize = True).unstack().fillna(0)
Area  East     North     South  West
Type                                
A     0.00  0.666667  0.333333  0.00
B     0.00  0.500000  0.500000  0.00
C     0.25  0.000000  0.500000  0.25
2 голосов
/ 28 января 2020

Вы можете сделать это следующим образом:

import pandas as pd
df = pd.DataFrame([r.split() for r in '''Index Type    Class   Area    Decision
0   A       1       North   Yes
1   B       1       North   Yes
2   C       2       South   No
3   A       3       South   No
4   B       3       South   No
5   C       1       South   No
6   A       2       North   Yes
7   B       3       South   Yes
8   B       1       North   No
9   C       1       East    No
10  C       2       West    Yes'''.split('\n')])
df.columns = df.iloc[0]
df = df.iloc[1:]

table = pd.pivot_table(df, values='Class', index=['Type'], columns=['Area'], aggfunc='count').fillna(0)
table = table.div(table.sum(axis=1), axis=0)

Мы делим каждый столбец на соответствующую сумму строк таблицы.

Это дает:

Area  East     North     South  West
Type                                
A     0.00  0.666667  0.333333  0.00
B     0.00  0.500000  0.500000  0.00
C     0.25  0.000000  0.500000  0.25 
1 голос
/ 28 января 2020
(
    df.groupby('Type')
    .apply(lambda x: x.groupby('Area').Class.count()).unstack(fill_value=0)
    .transform(lambda x: x/x.sum(), axis=1)
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...