Python Library/Pandas

[Pandas - Python] Pivot Tables and Cross-Tabulation - pivot_table(), crosstab()

바보1 2022. 6. 16. 01:57

데이터는 다음과 같습니다.

tips[:6]



    total_bill	tip	smoker	day	time	size	tip_pct
0	16.99	1.01	No	Sun	Dinner	2	0.059447
1	10.34	1.66	No	Sun	Dinner	3	0.160542
2	21.01	3.50	No	Sun	Dinner	3	0.166587
3	23.68	3.31	No	Sun	Dinner	2	0.139780
4	24.59	3.61	No	Sun	Dinner	4	0.146808
5	25.29	4.71	No	Sun	Dinner	4	0.186240

이후 pivot_table을 day와 smoker에 대해 설정하고, 함수를 적용하면

tips.pivot_table(index=['day', 'smoker'])



        	size		tip		tip_pct		total_bill
day	smoker				
Fri	No	2.250000	2.812500	0.151650	18.420000
        Yes	2.066667	2.714000	0.174783	16.813333
Sat	No	2.555556	3.102889	0.158048	19.661778
        Yes	2.476190	2.875476	0.147906	21.276667
Sun	No	2.929825	3.167895	0.160113	20.506667
        Yes	2.578947	3.516842	0.187250	24.120000
Thur	No	2.488889	2.673778	0.160298	17.113111
        Yes	2.352941	3.030000	0.163863	19.190588

groupby의 단점이 무엇이었죠?

바로 인터페이스가 불편하다는 점이었지만, pivot_table은 이를 해결한 함수입니다.

pivot_table은 groupby와 reshape를 활용하여 계층적 인덱싱을 만들어냅니다.

참고로 default 계산으로 mean 계산을 합니다.

 

tips.pivot_table(['tip_pct', 'size'], index=['time', 'day'],
                 columns='smoker')
                 
                 
                 
		size				tip_pct
	smoker	No		Yes		No		Yes
time	day				
Dinner	Fri	2.000000	2.222222	0.139622	0.165347
        Sat	2.555556	2.476190	0.158048	0.147906
        Sun	2.929825	2.578947	0.160113	0.187250
        Thur	2.000000	NaN		0.159744	NaN
Lunch	Fri	3.000000	1.833333	0.187735	0.188937
        Thur	2.500000	2.352941	0.160311	0.163863

앞에 [tip_pct, size]를 넣음으로써, 해당 데이터들만 보여줍니다.

 

tips.pivot_table(['tip_pct', 'size'], index=['time', 'day'],
                 columns='smoker', margins=True)
                 
                 

		size						tip_pct
	smoker	No		Yes		All		No		Yes		All
time	day						
Dinner	Fri	2.000000	2.222222	2.166667	0.139622	0.165347	0.158916
        Sat	2.555556	2.476190	2.517241	0.158048	0.147906	0.153152
        Sun	2.929825	2.578947	2.842105	0.160113	0.187250	0.166897
        Thur	2.000000	NaN		2.000000	0.159744	NaN		0.159744
Lunch	Fri	3.000000	1.833333	2.000000	0.187735	0.188937	0.188765
        Thur	2.500000	2.352941	2.459016	0.160311	0.163863	0.161301
All		2.668874	2.408602	2.569672	0.159328	0.163196	0.160803

margins를 통하여 전체에 대한 평균도 계산할 수 있습니다.

 

tips.pivot_table('tip_pct', index=['time', 'smoker'], columns='day',
                 aggfunc=len, margins=True)
                 
                 
                 
	day	Fri	Sat	Sun	Thur	All
time	smoker					
Dinner	No	3.0	45.0	57.0	1.0	106
        Yes	9.0	42.0	19.0	NaN	70
Lunch	No	1.0	NaN	NaN	44.0	45
        Yes	6.0	NaN	NaN	17.0	23
All		19.0	87.0	76.0	62.0	244

간단하네요.

 

tips.pivot_table('tip_pct', index=['time', 'size', 'smoker'],
                 columns='day', aggfunc='mean', fill_value=0)
                 
                 
                 
		day	Fri		Sat		Sun		Thur
time	size	smoker				
Dinner	1	No	0.000000	0.137931	0.000000	0.000000
       		Yes	0.000000	0.325733	0.000000	0.000000
	2	No	0.139622	0.162705	0.168859	0.159744
       		Yes	0.171297	0.148668	0.207893	0.000000
	3	No	0.000000	0.154661	0.152663	0.000000
...	...	...	...	...	...	...
Lunch	3	Yes	0.000000	0.000000	0.000000	0.204952
        4	No	0.000000	0.000000	0.000000	0.138919
		Yes	0.000000	0.000000	0.000000	0.155410
        5	No	0.000000	0.000000	0.000000	0.121389
        6	No	0.000000	0.000000	0.000000	0.173706

결측치에 대해서 0을 채워 넣은 모습입니다.


Cross-Tabulations : Crosstab

 

 

from io import StringIO
data = """\
Sample  Nationality  Handedness
1   USA  Right-handed
2   Japan    Left-handed
3   USA  Right-handed
4   Japan    Right-handed
5   Japan    Left-handed
6   Japan    Right-handed
7   USA  Right-handed
8   USA  Left-handed
9   Japan    Right-handed
10  USA  Right-handed"""
data = pd.read_table(StringIO(data), sep='\s+')

data


	Sample	Nationality	Handedness
0	1	USA		Right-handed
1	2	Japan		Left-handed
2	3	USA		Right-handed
3	4	Japan		Right-handed
4	5	Japan		Left-handed
5	6	Japan		Right-handed
6	7	USA		Right-handed
7	8	USA		Left-handed
8	9	Japan		Right-handed
9	10	USA		Right-handed
pd.crosstab(data.Nationality, data.Handedness, margins=True)


Handedness	Left-handed	Right-handed	All
Nationality			
Japan		2		3		5
USA		1		4		5
All		3		7		10

데이터를 축약하고 싶을 때, pivot_table을 이용할 수 있지만,

판다스에서는 crosstab을 이용하여 더 간단하게 축약할 수 있습니다.

지역을 인덱스로 하며, 어느 손잡이인지를 열로 하여 통계를 냅니다.

 

pd.crosstab([tips.time, tips.day], tips.smoker, margins=True)


	smoker	No	Yes	All
time	day			
Dinner	Fri	3	9	12
        Sat	45	42	87
        Sun	57	19	76
        Thur	1	0	1
Lunch	Fri	1	6	7
        Thur	44	17	61
All		151	93	244

시간과 요일을 인덱스로 하고, smoker를 열로 하며 통계를 냅니다.