2017-01-19 4 views
2

У меня есть dataframe с 2 столбцами. Я пытаюсь вычислить% от TypeB по количеству записей в ID следующим образом:Python Pandas GroupBy% расчет

Формула: (Граф TypeB)/(Нет записей в группе) * 100

Result : 
001 = (2/3) * 100 => 66.66 
002 = (0/2) * 100 => 0 
003 = (1/1) * 100 => 100 

Dataframe

ID Type 
001 TypeA 
001 TypeB 
001 TypeB 
002 TypeA 
002 TypeA 
003 TypeB 

Так далеко я смог GroupBy

byID = df.groupby('ID') 

Я читал панды перекрестную таблицу, но не могу выяснить, как подойти к решению

ответ

2

Вы можете использовать groupby с size для подсчета длины групп первых, перекроить по unstack с заполнением NaN по 0, а затем разделить столбец TypeB на sum, последний несколько по 100:

df = df.groupby(['ID','Type']).size().unstack(fill_value=0) 
print (df) 
Type TypeA TypeB 
ID     
1   1  2 
2   2  0 
3   0  1 

df1 = df.TypeB.div(df.sum(axis=1)).mul(100).reset_index(name='percentage') 
print (df1) 
    ID percentage 
0 1 66.666667 
1 2 0.000000 
2 3 100.000000 

Для RESHAPE возможно использование crosstab, но это немного slowier в большей dataframe:

df = pd.crosstab(df.ID,df.Type) 
print (df) 
Type TypeA TypeB 
ID     
1   1  2 
2   2  0 
3   0  1 

EDIT:

Вы можете использовать map для добавления нового столбца:

df1 = df.groupby(['ID','Type']).size().unstack(fill_value=0) 
print (df1) 
Type TypeA TypeB 
ID     
1   1  2 
2   2  0 
3   0  1 

df2 = df1.TypeB.div(df1.sum(axis=1)).mul(100) 
print (df2) 
ID 
1  66.666667 
2  0.000000 
3 100.000000 
dtype: float64 

df['percentage'] = df.ID.map(df2) 
print (df) 
    ID Type percentage 
0 1 TypeA 66.666667 
1 1 TypeB 66.666667 
2 1 TypeB 66.666667 
3 2 TypeA 0.000000 
4 2 TypeA 0.000000 
5 3 TypeB 100.000000 
+0

Hi @jezrael - Не могли бы вы помочь объяснить подход. Я очень признателен за то, как вы решили решение. – user6083088

+0

Это лучше? Я добавляю вывод 'df' после изменения. – jezrael

+0

спасибо @jezrael, это помогло мне, и теперь мне нужно найти способ добавления этого нового столбца «процент» в каждый идентификатор исходного фрейма. Ах! если только документы будут объяснять, как вы это делали. Очень признателен. – user6083088

1

Использование groupby с value_counts(normalize=True)
normalize автоматически разделит отсчеты по итогам.

df.groupby('ID').Type.value_counts(normalize=True).unstack(fill_value=0).TypeB 

ID 
001 0.666667 
002 0.000000 
003 1.000000 
Name: TypeB, dtype: float64 
+0

спасибо @piRSquared, это также работает. Но я могу только принять один ответ. – user6083088

Смежные вопросы