티스토리 뷰
그룹 연산(Group by)
- 연산대상.groupby(그룹핑 대상)
- groupby의 결과는 Dictionary 형태
- groupby 수행 시 결과는 보여주지 않음
<pandas.core.groupby.groupby.DataFrameGroupBy object at 0x000001E8F2CBA9E8>로 그룹핑이 되었다고만 출력
- 분리 -> 적용 -> 결합
: 다른 언어와 다르게 파이썬은 분리(split)까지 동작. 적용과 결합을 위해 연산 메서드를 적용
pd.groupby?
pd.groupby(*args, **kwargs)
#. 그룹 연산(pd.groupby)
sub = pd.read_csv('subway.csv', encoding='cp949')
# 노선번호별 승차에 대한 평균
# 방법 1) 일부 컬럼 전달(속도상 유리)
sub['승차'].groupby(sub['노선번호']).mean()
# 방법 2) 전체(연산 가능한 모든 컬럼) 전달 후 색인
sub.groupby(sub['노선번호']).mean()
sub.groupby(sub['노선번호']).mean()['승차']
sub.groupby(sub['노선번호'])['승차'].mean()
#. 여러 함수 적용 (.agg)
sub.iloc[:,[0,2,3]].groupby('노선번호').agg(['sum','mean'])
#. 요약 (.describe)
data = sub.iloc[:,[0,2,3]].groupby('노선번호').agg(['sum','mean'])
data.describe() # 문자열은 제외 후 요약
#. 지정 그룹으로 행or열 묶기
sub = pd.read_csv('subway.csv', encoding='cp949')
sub['노선번호'] = sub['노선번호'].map(lambda x : int(x.split('_')[1])) # 노선번호 정제
sub = sub.set_index('노선번호').iloc[:,1:].T # 정제된 노선번호를 index로 지정, 시간 컬럼을 제외 후 행/열 전치
ar1 = np.where(sub.columns <= 4, 'one', 'two') # 지정 그룹으로 묶기
sub.groupby(ar1, axis=1).sum()
#. 그룹별 데이터 수 확인 (.count, .size)
sub.groupby(sub['노선번호'])['승차'].count()
sub.groupby(sub['노선번호'])['승차'].size()
#. group_key(index) 생략
data3.groupby('역').apply(top,'승차')
* Duplicated level name: " ", assigned to level 1, is already used for level 0 오류 발생 시 필요
data3.groupby('역', group_keys=False).apply(top,'승차')
#. Q1
import pandas as pd
import numpy as np
from pandas import Series, DataFrame
import matplotlib.pyplot as plt
%matplotlib qt
# subway2.csv 파일을 읽고
sub2 = pd.read_csv('subway2.csv', encoding='cp949', skiprows=True)
sub2 = sub2.fillna(method='ffill') # NA값을 앞 행의 값으로 채우기
# 1) 각 시간대 별 승차와 하차의 평균과 합
sub2.groupby('구분').mean() # 시간대별 승하차의 평균
sub2.groupby('구분').sum() # 시간대별 승하차의 합
sub2.groupby('구분').agg(['sum','mean']) # 시간대별 승하차의 평균과 합
# agg : 여러 그룹 연산을 수행 시, 함수를 결합해서 출력
# 2) 각 역별 전체 승차와 하차의 평균과 합
sub2.set_index(['전체','구분']).mean(1).unstack()
= sub2.groupby(['전체','구분']).mean().mean(1).unstack() # mean()이 두 번 사용된 이유는, groupby의 결과가 dictionary 형태이므로, 그룹별 mean()(여기서는 변화가 없겠지만)을 통해 DataFrame 형태로 변환시킨 후, mean(1)을 적용시키기 위함
sub2.set_index(['전체','구분']).sum(1).unstack()
= sub2.groupby(['전체','구분']).sum().sum(1).unstack() # 마찬가지로 sum()이 두 번 사용된 이유는, groupby의 결과가 dictionary 형태이므로, 그룹별 sum()(여기서는 변화가 없겠지만)을 통해 DataFrame 형태로 변환시킨 후, sum(1)을 적용시키기 위함
# 3) 각 시간대 별 승차수가 가장 높은 역
data1 = sub2.set_index(['전체','구분'])
data1.xs('승차', level=1).idxmax()
# 4) 승차가 가장 많은 top 10개의 역을 구하고 각 역의 시간대별 승차의 증감추세를 도표화
data2 = data1.xs('승차', level=1)
ind = data1.xs('승차', level=1).sum(1).sort_values(ascending=False)[:10].index
Index(['강 남', '잠 실', '신 림', '삼 성', '강 변', '고속터미', '선 릉', '서울역(1)', '구로공단', '신 촌'],
dtype='object', name='전체')
data3 = data2.loc[ind]
data3.columns = data3.columns.str[:2].astype('int')
data3.columns.names = ['시간']
data3.T.plot()
plt.xticks(data3.columns)
# 5) 지역별 승차의 합
data3.groupby(['강남','강남','강남','강남','강남','강남','강남','강북','강남','강북',]).sum()
# 6) 오전/오후 승차의 합
ar1 = np.where(data3.columns <= 12,'오전','오후')
data3.groupby(ar1,axis=1).sum()
#. Q2 (사용자 정의 함수 전달)
sub = pd.read_csv('subway2.csv', encoding='cp949', skiprows=True)
sub = sub.fillna(method='ffill')
data1 = sub.set_index(['전체','구분']) # 멀티 인덱스
data2 = data1.xs('승차',level=1) # 승차 인덱스 추출
data3 = data2.stack().reset_index() # .reset_index : index를 columns으로
# groupby(, as_index=False) : 인덱스를 컬럼으로
data3.columns = ['역','시간','승차']
data3.groupby('역', group_keys=False).apply(top,'승차') # group_keys : key 생략
# 역별 승하차 합계
data1.groupby(level=0).sum() # groupby에 level 전달 가능
# 전체 역의 승하차 합계
data1.groupby(level=1).sum() # 전체 역의 승하차 합계
# 사용자 정의 함수의 전달 예
f1 = lambda x : x.max() - x.min()
sub.groupby('전체')['05~06'].apply(f1)
# top(df,col,n) 함수 생성 및 적용
top = lambda data, col, n=5 : data.sort_values(by=col,ascending=False)[:n]
df1 = DataFrame(data2.stack(), columns=['승차']) # 컬럼 전달을 위해 dataframe으로 변환
df1.groupby(level=0, group_keys=False).apply(top,'승차')
*Duplicated level name: " ", assigned to level 1, is already used for level 0 오류 발생 원인,
groupby 키가 원본에 포함 시, 키 값이 중복되면 키 충돌로 에러 발생 => group_keys=False 옵션으로 해결
#. Q3
# kimchi_test파일을 불러온 후
kimchi = pd.read_csv('kimchi_test.csv', encoding='cp949')
# 1) 각 년도별 제품별 판매량과 판매금액의 평균
kimchi.groupby(['판매년도','제품'])['수량','판매금액'].mean().unstack() # unstack 하위 인덱스가 컬럼화
# stack 컬럼의 인덱스화
# 2) 각 년도별 제품별 판매처별 판매량과 판매금액 평균
kimchi.groupby(['판매년도','제품','판매처'])['판매금액','수량'].mean().unstack()
# 3) 각 제품별 판매수량이 0~ 10000, 10000~20000, 20000~ 의 판매량을 기록한 월이 몇 회인지 확인
l1 = [0,10000,20000,100000]
c1 = pd.cut(kimchi['수량'], l1, right=False)
c1.groupby([kimchi['제품'],c1]).count().unstack()
# 4) 각 김치별로 가장 많이 팔리는 월과 해당 월의 판매량을 김치이름과 함께 출력
kimchi.groupby(['제품','판매월'])['수량'].sum().unstack(level=0)
kimchi.groupby(['제품','판매월'])['수량'].sum().unstack(level=0).idxmax()
# 5) 각 월별로 김치의 판매량을 비교할 수 있도록 막대그래프로 표현
data = kimchi.groupby(['제품','판매월'])['수량'].sum().unstack(level=0)
plt.rc('font', family='MalGun Gothic')
data.plot(kind='bar')
plt.ylim([0,300000])
plt.xticks(rotation=0)
#. Q3
# 병원현황.csv 데이터를 불러온 후
hosp = pd.read_csv('병원현황.csv',engine='python', skiprows=1)
data1 = hosp.drop(['항목','단위'], axis=1).set_index(['시군구명칭','표시과목']) # 멀티 컬럼 설정
col1 = data1.columns.str.split('. ').str.get(0) # 컬럼명 분리
col2 = data1.columns.str.split('. ').str.get(1)
data1.columns=[col1,col2] # 컬럼명 설정
# 1) 각 년도별 구별 병원의 수 출력
# 1. 데이터의 '계' 인덱스 활용
data_total = data1.xs('계', level=1)
data_total.groupby(axis=1, level=0).sum()
# 2. 데이터의 '계' 인덱스 미활용
data_rm = data1.drop('계', level=1)
data_rm.groupby(axis = 1, level=0).sum() # 컬럼의 같은 연도끼리 그룹
data_rm.groupby(axis = 1, level=0).sum().groupby(axis=0,level=0).sum() # 컬럼의 같은 연도끼리 그룹 후 인덱스의 같은 구끼리 그룹
# 2) 성형외과의 년도별 증가 추이
data1.xs('성형외과', level=1).groupby(level=0, axis=1).sum() # 인덱스가 성형외과에 해당하는 데이터만 추출 후, 같은 연도끼리 그룹
plot1 = data1.xs('성형외과', level=1).groupby(level=0, axis=1).sum().sum()
1. 2.
plot1.index = plot1.index.astype('int')
plot1.plot()
plt.xticks(plot1.index)
# 3) 강남구 년도별 증가 추이
plot2 = data_rm.xs('강남구').groupby(level=0, axis=1).sum().sum()
plot2.index = plot2.index.astype('int')
plot2.plot()
plt.xticks(plot2.index)
# 4) 2013년 기준, 각 병원의 구별 점유율을 출력
data2 = data_rm.xs('2013',axis=1).sum(1).unstack()
f1 = lambda x : round(x / x.sum() * 100, 2)
data2.apply(f1).dropna(axis=1)
data2.apply(f1).sum() # 결과 확인 (반올림으로 발생한 약간의 오차)
data2.apply(f1)['성형외과'].sort_values(ascending=False) # 특정 병원의 점유율이 많은 구 확인
# 5) 년도별 각 병원의 총 건수를 병원별로 비교할수 있도록 막대그래프 표현
plot3 = data_rm.groupby(level=0, axis=1).sum().groupby(level=1, axis=0).sum().T
plt.rc('font', family='MalGun Gothic')
plot3.plot(kind='bar', ylim=(0,7000))
plt.xticks(rotation=0)
plt.legend(fontsize='small')
참고: KIC 캠퍼스 머신러닝기반의 빅데이터분석 양성과정
'Python > Process' 카테고리의 다른 글
[Python] 시계열 데이터 가공 (0) | 2019.02.20 |
---|---|
[Python] 정규표현식 (re Module) (0) | 2019.02.18 |
[Python] DataFrame의 데이터 변형 메서드 (0) | 2019.02.15 |
[Python] 피벗 (.pivot, .pivot_table) (0) | 2019.02.14 |
[Python] 데이터 결합 (np.concatenate, pd.concat) (0) | 2019.02.14 |