23. pandas 추가 – 데이터 분석 by 그룹화 +피벗 테이블(pivot_table)
county_facts.csv
primary_results.csv
필요한 패키지 import
%matplotlib nbagg
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
데이터 2개 읽기
primary = pd.read_csv("python_da/data/2016_presidential_election/primary_results.csv", sep=",")
counties = pd.read_csv("python_da/data/2016_presidential_election/county_facts.csv", sep=",")
primary에는, 미국내 주 - 카운티 별, 각 정당, 후보자의 데이터 및 득표율 데이터
counties라는 primary의 칼럼 중 fips라는 코드를 식별자를 하여, 각 유권자별 데이터가 나와있다.
head()와 shape와 columns까지 확인해보자.
데이터 분석-1 : 각 후보별 전체지역 득표수
각 후보들별로 전체지역 득표수를 계산해보자.
이전 방식이라면 후보를 의미하는 candidate의 유니크한 값들을 추출한 다음, 반복문을 돌리면서 마스크로 votes열만 뽑아 낸 뒤, 통계량을 계산했다.
데이터 그룹화기능을 사용하면, 이를 한 줄에 끝낼 수 있다.
( 각 ~별 -> groupby의 기준열로 들어간다.)
( ~를 계산 -> 데이터그룹화의 결과물에 [ "칼럼명" ] 으로 추출한다)
- 각 후보별 득표수를 계산할 것이므로, 각 후보의 unique한 이름들만 확인해준다.(분석과정에서 필요한 것은 아니다)
primary["candidate"].unique() - primary 전체 DataFrame에 대해서 groupby()를 할 것인데, 기준열이 candidate열 이다.
각 후보별로 데이터를 계산하므로,groupby()의 기준열로 쓰면, 각 성분인 후보들을 기준으로 데이터가 그룹화되서 계산할 수 있다.
그룹화된 결과물에서 DataFrame 전체가 아니고, votes열만 필요하므로, 그룹화된 결과물에 열인덱싱 처리를 해준다.
마지막으로, 득표수를 계산하려면, 그룹별로 votes열의 합을 구해야하기 때문에 sum()함수를 적용한다.
primary.groupby("candidate")["votes"].sum() - 투표수(성분)별 오름차순으로 보기 좋게 정렬하기 위해서, 맨 뒤에 .sort_values()적용해서 새로운 변수에 담아준다.
(변수에 담아야지, plot을 그릴 수 있다!)
이 때, by= 정렬기준열 을 명시하지않은 것은, 열이 하나(votes열) 밖이기 때문이다.
candidate_to_votes_s = primary.groupby("candidate")["votes"].sum().sort_values() - 후보별 전체지역 득표수을 정렬한 것을, 수평 바 plot으로 나타내자.
candidate_to_votes_s.plot(kind="barh", fontsize=8)
(my : 각 ~~ 별 –> ~~열을 groupby()함수의 기준열로 삼아라! , a와 b의 ~ –> a + b (배반)으로 포함하는 열을 기준열로 삼아라!)
데이터 분석 – 2 : 각 주별, 공화당과 민주당의, 득표비율 계산
다시 데이터의 head()를 보자.
primary.head()
각 주별 ----------> state열이 기준열1
공화당과 민주당 –> party열이 기준열2
2가지 열을 groupby()함수의 [기준열]로 사용할 것이다.
득표비율 --------> votes열을 데이터그룹화의 [추출열]로 사용할 것이다.
- 데이터그룹화의 기준열을 state, party순으로 주어서, 각 주별 – 공화당/민주당 – 득표수(합)을 계산해보자.
계층적인덱스가 주 – 당 형태의 Series가 얻어질 것이다.
아직까지 우리가 원하는 모양(공화당과 민주당의 각 주별 득표비율)이 아니므로, 변수에 저장해주자.
state_party_votes_s = primary.groupby( ["state","party"] ) ["votes"].sum() - 비율을 구하기 위해서, 각 주의 전체 득표수를 나누어줘야한다.
기준열에 state열만 넣어서, votes열을 추출하여 sum()함수를 쓰면, 각 주별 전체 득표수가 나오므로
계산해서 변수에 담아주자.
state_to_votes_s = primary.groupby("state")["votes"].sum() - 이제 1에서 구한 Series를 2에서 구한 Series로 나눠준다.
이렇게 나누기(연산)을 할 때, 계층적 인덱스 中 가장 첫번째 층의 인덱스를 기준으로 계산되기 때문에,
1에서 기준열을 정할 때, state –> party 순으로, state열을 먼저 지정해야하는 것을 알 수 있다.
계산한 값을 새로운 변수에 담고 head()를 확인해보자.
state_party_to_vote_pcts_s = state_party_votes_s / state_to_votes_s
state_party_to_vote_pcts_s.head() - 이제 비율을 바탕으로 bar plot을 그려보자.
이 때, 민주당/공화당(2번째 층 인덱스)를 unstack()으로 컬럼으로 올리고 barplot을 그리자.
컬럼으로 보내면, 인덱스인 각 주(state)가 수평y축에 , 칼럼인 [민주/공화당]이 범례에 나타나면서 각 주별 2개의 막대가 생길 것이다.
이 때, stacked=True까지 주면, 이 나타나면서 막대에 합쳐진, 비율을 가지게 될 것이다.
간단히 분석해보자면, 대부분의 주가 공화당이 득표가 우세하고, 몇몇 주는, 민주당이 장악하였다.
my) 각 주별, a와 b의 -> 기준열로 사용할 것. 2개 주제 이상이면, 기준열 순차적으로
~를 계산 -> 데이터그룹화(groupby)의 결과물에 [""]열인덱싱으로 필요한열 추출
최종 결과물에 index-> barplot의 index / columns -> 한index에 세워지는 bar막대기 갯수 및 범례의 갯수
데이터 분석3 – 사용자 정의함수를 이용하여,
각 county별, 당선된 후보의, 백인유권자의 비율을 계산하기 -> 정당별, 당선된 후보들의 백인유권자 비율 보기
정치권에서 속설 중, 백인유권자들이 많은 지역일수록 ---> 공화당 후보가 당선될 확률이 높다라는 것이 있다. 이것을 증명하기 위해서
primary데이터에서 각 county별, 당선된 후보의 백인유권자의 비율을 계산해서 증명해보자.
즉, 각 county별로 그룹화 ->
각 그룹에 대해 투표수가 가장많은 행(당선자를 가진 행) 뽑는 함수 적용(사용자 정의함수) -> 여기까지는 각 county별 당선후보 데이터(행)을 뽑은 것
다른데이터에 있는 county별 백인유권자 정보를, 기준열(county = fips열)을 가지고 merging -> 붙혀진 칼럼명 이름바꾸기->
각 county별 당선후보에 대한 백인유권자비율을 구해진 상태다. 이제 이 데이터에서 ,
각 정당별, 당선후보자들의 (그룹화 기준 : party, candidate) 백인유권자비율(추출열)의 평균(통계함수)을 구하자.->
barplot 그리고 범위 및 index다 보이도록 수정하기
이번에는 집계함수를 직접 정의하여, 집계를 수행해보자.
- 통계(집계)함수를 정의하는데, func이라는 함수는, 데이터그룹화의 결과물(agg_df)에 대해, sort_values()함수를 이용해 votes열을 내림차순으로 정렬하고, 그 중 첫번째 성분을 뽑는 .iloc[0]으로 인덱싱하여,
대입되는 그룹화결과물의, votes열에 내림차순 정렬 후 1번째 행만 뽑기 = 가장 득표수가 많은 행을 뽑아낼 것이다.
func = lambda agg_df: agg_df.sort_values("votes", ascending=False ).iloc[0]
(당선된 후보 = 투표수가 많은 후보 = 투표열을 내림차순 정열후 1번째 행인 후보) - primary의 head()를 다시 한번 살핀 뒤, county를 대변하는 코드인 fips열을 그룹화 기준열로 사용해서 그룹화하고,
그룹화된 결과물에 사용자 정의함수를 사용할 수 있게 해주는 .agg()함수에다가,
그룹화결과물을 인자로 받아 votes열을 추출하여 votes열의 가장 큰 수(득표수가 가장 많아 당선)를 뽑아내는 func 함수를 인자로 주자.
그럼 primary를 fips(county)별로 그룹화한 결과물에, func함수를 적용하여, 각 county별 <votes순으로 내림차순하여, 득표수가 가장 큰 행이 후보이름 + 당명과 함께>을 뽑아내진다.
이것을 winners라는 변수에 담아서 살펴보자.
winners = primary.groupby("fips").agg(func)
winners
살펴보면) 각 county별 votes수가 가장 많은 행을 뽑아서 –> 그 county에 가장 많은 득표를 얻은 사람 + 당 까지 알 수 있다. - primary데이터에서 얻은 winners라는 각 county별 최다득표 후보와 당 데이터에다가
각 county별 백인유권자 정보를 붙혀넣어야한다!
앞서 read한 counties라는 df에서 얻어와야한다. columns 중에 RHI825214라는 칼럼이, 해당 county별 백인 윤권자 비율이다.
counties["RHI825214"].head()
이winnders와 counrties의 county에 대한 행의 갯수가 서로 다르나, 병합의 key열(들or인덱스)을 지정해서,
각각 동일한 기준성분에 대해 m x n형태로 합쳐주는 것을 pd.merge()함수라고 배웠다.
merging을 이용해서, fips를 기준으로 winner에다가county의 백인유권자 정보를 병합시켜보자.
(한쪽 데이터를 고정시켜서 병합시킬 때는, how=left or right인자) - 이제 counties에서는 fips열과 rhi825214열만 병합시킬 것이므로, merge()의 인자에서, 열인덱싱을 리스트형식으로 넣어준다.
그리고, 데이터를 확인해보면, winners에서는 fips가 그룹화의 기준이 된 결과 index로 있고 / counties에서는 fips가 열이므로,
pd.merge()의 인자에 left_index=True, right_on="fips" 로, [df의 인덱스 <----> 특정열2개 중 1열]이 서로의 병합기준이 된다고 지정해줘야한다.
how="left"인자를 통해서, left인 winners 에다가 병합시킬 것이다.
winners_county_races = pd.merge(winners, counties[ ["fips", "RHI825214"]],
left_index=True, right_on="fips", how="left")
새로운 데이터를 보게되면, 인덱스에 있던 fips가, 새로운데이터와 겹치는 부분으로 mxn형태로, 열로 왔고 우측에는 백인유권자 비율이 붙은 것을 확인할 수 있다. - 이제 백인유권자 비율의 컬럼(RHI825214)의 이름을 바꿔주자. rename()함수의 인자로, 컬럼 = {딕셔너리}형태로 바꿔준다.
이것을 다시 기존 데이터에 대입하면 바뀐 데이터가 된다.
winners_county_races = winners_county_races.rename(columns={"RHI825214" : "white_pcts"})
winners_county_races.head() - 이렇게 얻어진, 각 county별 최다득표자(winner)의 백인유권자 비율까지 표시된 데이터에다가,
party와, candidate를 그룹화 한뒤, 각 정당별 후보자들의 백인유권자 비율의 평균을 계산해보자.
( 각 county별 최다득표자들만 모았으니, 각 county별 당선자들이다. 이제 county를 잊고, 정당 별 후보자=당선자의 백인비율을 보는 것이다)
winners_county_white_pcts = winners_county_races.groupby(["party", "candidate"])["white_pcts"].mean()
winners_county_white_pcts - 수평 바 플롯을 그려보자.
winners_county_white_pcts.plot(kind="barh", fontsize=8) - .plot()을 그린 좌표평면 변수를 생성해서, 몇가지 수정해 이쁘게 보이도록 하자.
ax = winners_county_white_pcts.plot(kind="barh", fontsize=8)
(1)먼저, x축의 범위를 50부터 100까지 보자.(0~50까지는 모두 차 있으니까)
(2) index가 다 안보일 때는, 이 함수를 호출하자 : plt.tight_layout()
ax.set_xlim([50,100])
plt.tight_layout()
간단히 살펴보면 ) 공화당 후보(Rep.)가 당선된 county에 백인유권자의 비율이 75%으로 높긴 높다.
그런데 특이한 점은, 민주당 후보에서도 하나의 county에 백인유권자의 비율이 80%이상으로 높다.
피벗 테이블(pivot_table)로 데이터 분석하기
예제를 보면서 해석해보자.
1.
total_votes = primary.pivot_table( values = "votes" , index="state" , columns ="candidate", aggfunc="sum", fill_value=0 )
primary라는 df에, 피컷테이블함수를 적용시키는데,
values = 통계함수를 적용할 df의 특정열
index = 그룹화의 1번째 기준이면서, 피벗테이블(df)의 index로 가져올 primary의 특정열
columns = 그룹화의 2번째 기준이면서, 피벗테이블(df)의 columns로 가져올 primary의 특정열
aggfunc = 2개의 그룹화기준을 가지고 values에 들어간 특정열에 적용시킬 통계함수를 문자열로 표현
fill_value=0 NaN을 0으로 처리
각 주별, 당선자들의, 득표수, 총합
total_votes
2.
primary.pivot_table(values="fraction_votes", index="state_abbreviation", columns="party", aggfunc="mean")
values = fraction_votes(해당후보의 득표율)을 가지고, 통계함수를 계산할 것인데,
index에는 state의 축약어 / columns에서는 정당 으로 가져오면서, 2개를 기준으로 그룹화 한뒤,
aggfunc를 통해 <해당 후보의 득표율의> mean(평균값)을 구한다.
'빅데이터 관련 프로그래밍 > Python - bigdata(pandas 기초)' 카테고리의 다른 글
24. 실전 데이터분석(1~6) - pivot_table / groupby (0) | 2018.03.12 |
---|---|
참고 : pandas 추가 - 데이터분석3 요약 정리 (0) | 2018.03.11 |
22. pandas 추가 – 데이터 그룹화 함수 이해하기 (0) | 2018.03.05 |
21. pandas 추가 – DataFrame 데이터 변형(중복행 제거/ 매핑/ 치환/ 카테고리 자료형) (1) | 2018.03.03 |
20. pandas 추가 – 계층적 인덱싱(정렬함수, 통계함수적용, 인덱스와 칼럼 전환(stack,unstack)) (3) | 2018.03.02 |