Mam taką ramkę DataFrame:

Kind   Status
1      True
2      False
3      True
2      False
2      True

Liczyłem rodzaje z tym df.Kind.sort_values() i dostałem to:

1       1
2       3
3       1

Teraz chcę zobaczyć, jak dużo rodzaju 2 jest prawdziwe lub fałszywe jako liczba i procent. Lubię to:

Art  True  False
  2     1      2
  2  0.33   0.66

Czy ktoś może mi pomóc? Z poważaniem

3
Sadiksk 4 czerwiec 2018, 16:08

3 odpowiedzi

Najlepsza odpowiedź

Crosstab + Div.

Korzystanie z pandas.crosstab:

res = pd.crosstab(df['Kind'], df['Status'])

res[['Pct False', 'Pct True']] = res.div(res.sum(axis=1), axis=0)

print(res)

Status  False  True  Pct False   Pct True
Kind                                     
1           0     1   0.000000   1.000000
2           2     1   0.666667   0.333333
3           0     1   0.000000   1.000000

Moim zdaniem jest to najbardziej naturalny sposób wyświetlania danych. Nie zaleca się łączenia liczych z wartościami procentowymi w jednej serii.

Crosstab + Crosstab Normalizuj

Alternatywnie można dołączyć do kilku wyników {X0}}, znormalizowany, drugi nie.

res = pd.crosstab(df['Kind'], df['Status'])\
        .join(pd.crosstab(df['Kind'], df['Status'], normalize='index'), rsuffix='_pct')

print(res)

Status  False  True  False_pct  True_pct
Kind                                    
1           0     1   0.000000  1.000000
2           2     1   0.666667  0.333333
3           0     1   0.000000  1.000000

Crosstab znormalizuje się tylko

Jeśli szukasz tylko procentowych, możesz po prostu użyć argumentu normalize:

res = pd.crosstab(df['Kind'], df['Status'], normalize='index')

print(res)

Status     False     True 
Kind                      
1       0.000000  1.000000
2       0.666667  0.333333
3       0.000000  1.000000
7
jpp 4 czerwiec 2018, 13:45

Możesz po prostu użyć:

g = df.loc[df['Kind']==2].groupby(['Kind', 'Status']).size().unstack()
pd.concat([g,g.apply(lambda x: round(x / (x[False]+x[True]), 2), axis=1)])

Wynik:

Status  False   True
Kind        
2   2.00    1.00
2   0.67    0.33
0
harvpan 4 czerwiec 2018, 13:38

Użyj groupby z < a href = "http://pandas.pydata.org/pandas-docs/stable/generated/pandas.core.groupby.Groupby.Size.html" rel = "NOFollow NefErr"> {X1}} i {X2}} dla obrotu przez count s:

df1 = df.groupby(['Kind','Status']).size().unstack(fill_value=0)
#alternative solution, slowier in large data
#df1 = pd.crosstab(df['Kind'], df['Status'])
print (df1)
Status  False  True 
Kind                
1           0      1
2           2      1
3           0      1

Następnie podziel przez sum i dołącz do oryginału:

df = df1.append(df1.div(df1.sum(axis=1), axis=0)).sort_index()
print (df)
Status     False     True 
Kind                      
1       0.000000  1.000000
1       0.000000  1.000000
2       2.000000  1.000000
2       0.666667  0.333333
3       0.000000  1.000000
3       0.000000  1.000000

print (df.loc[2])
Status     False     True 
Kind                      
2       2.000000  1.000000
2       0.666667  0.333333

Ale jeśli chcesz uniknąć konwersji integer s do float s zmiana append do join i dla unikalnych kolumn Dodaj add_prefix:

df = df1.join(df1.div(df1.sum(axis=1), axis=0).add_prefix('pct '))
print (df)
Status  False  True  pct False  pct True
Kind                                    
1           0     1   0.000000  1.000000
2           2     1   0.666667  0.333333
3           0     1   0.000000  1.000000

print (df.loc[[2]])

Status  False  True  pct False  pct True
Kind                                    
2           2     1   0.666667  0.333333
3
jezrael 4 czerwiec 2018, 13:23