티스토리 뷰
Multi-index & Multi-column
#. 생성
- 인덱스의 개수, 상위 level & 하위 level의 개수가 일치해야 함
- 생성할 일은 많지 않음 :(
1. Series
s1 = Series([1,2,3,4,5,6], index=[['a','a','b','b','c','c'], [1,2,1,2,1,2]])
s1
a 1 1
2 2
b 1 3
2 4
c 1 5
2 6
dtype: int64
2. DataFrame 생성 후 설정
df1 = DataFrame({'value':[1,2,3,4,5,6],
'ind1':['a','a','b','b','c','c'],
'ind2':[1,2,1,2,1,2]})
df1 = df1.set_index(['ind1','ind2']) # 리스트 형식으로 인덱스에 동시 전달 가능
# df1.index = [df1['ind1'], df1['ind2']]
# df1.drop(['ind1','ind2'],axis=1)
3. DataFrame 생성과 함께 설정
df2 = DataFrame(np.arange(16).reshape(4,4),
index = [[1,1,2,2],['s1','s2','s1','s2']],
columns = [['apple','apple','banana','banana'], ['price','qty','price','qty']],
)
#. Series 멀티 색인
# 기본 색인
# xs() 메서드를 활용한 색인 : axis=0 (축), level=0 (깊이) default
s1
a 1 1
2 2
b 1 3
2 4
c 1 5
2 6
dtype: int64
s1.xs('a')
s1['a'] # 상위 level key 색인
1 1
2 2
dtype: int64
s1['a':'b'] # 상위 level 슬라이스 색인
a 1 1
2 2
b 1 3
2 4
dtype: int64
s1[['a','c']] # 특정 상위 level key 색인
a 1 1
2 2
c 1 5
2 6
dtype: int64
s1.xs(2, level=1)
s1[:,2] # 하위 level 색인 (이차원 색인처럼 사용)
a 2
b 4
c 6
dtype: int64
s1.xs(('a',1))
s1['a',1] # 상위, 하위 level 색인
1
s1.xs(('b',2), level=[0,1])
b 2 4
dtype: int64
#. DataFrame 멀티 색인
# 기본 색인
# xs() 메서드를 활용한 색인 : axis=0, level=0 (default)
- axis=0 (row), axis=1 (column)
- level=0 (상위 레벨), level = 1 (하위 레벨)
- xs() 메서드로 column색인 시 축 설정 필요(axis가 default로 0이므로)
- 특정 레벨 or 특정 축만 가능하고 동시 선택은 불가
df2
df2.xs('apple', axis=1)
df2['apple'] # 컬럼색인 우선
df2['apple','price'] # 상위, 하위 level 색인
1 s1 0
s2 4
2 s1 8
s2 12
Name: (apple, price), dtype: int32
df2['apple','price'][1] # 추가 색인을 통해 index를 색인 가능
s1 0
s2 4
Name: (apple, price), dtype: int32
df2.xs('apple', level = 0, axis = 1).xs(2, level=0)
# apple 컬럼의 2번째 레벨
#. 계층 순서 변경 (.swaplevel)
df1 = DataFrame(np.arange(16).reshape(4,4), index=[['a','a','b','b'], [1,2,1,2]],
columns = [['col1','col1','col2','col2'], ['c1','c2','c1','c2']])
df1
df1.swaplevel? # 계층 순서 변경
df1.swaplevel(i=-2, j=-1, axis=0)
df1.swaplevel(0,1) # index의 계층 순서 변경
df1.swaplevel(0,1, axis=1) # column의 계층 순서 변경
#. 컬럼의 인덱스화 (.Stack)
df1.stack? # 컬럼의 인덱스화(그룹 연산 시 용이)
df1.stack(level=-1, dropna=True)
# dropna = False 로 옵션 지정 시, NA값 출력
df1
df1.stack() # 하위 컬럼 인덱스화
df1.stack(level=0) # 상위 컬럼 인덱스화
#. 인덱스의 컬럼화 (.unStack)
# 인덱스의 컬럼화(그룹 연산 시 용이)
df1.unstack?
df1.unstack(level=-1, fill_value=None)
# unstack 결과, 하위 그룹에 속하지 않는 값은 NA로 처리 => fill_value 옵션으로 NA 치환
df1
df1.unstack() # 하위 인덱스 컬럼화
df1.unstack(level = 0) # 상위 인덱스 컬럼화
#. 연산
df1
df1.sum?
sw.sum(axis=None, skipna=None, level=None, numeric_only=None, min_count=0, **kwargs)
df1.sum(0) # 서로 다른 행별 합
col1 c1 24
c2 28
col2 c1 32
c2 36
dtype: int64
df1.sum(1) # 서로 다른 컬럼별 합
a 1 6
2 22
b 1 38
2 54
dtype: int64
df1.sum(0, level=0) # 상위 인덱스의 합
df1.sum(1, level=0) # 상위 컬럼의 합
#. Q1
### multi_index_ex1.csv 파일을 읽고 다음을 수행
data = pd.read_csv("multi_index_ex1.csv", encoding='cp949', sep=',')
data
### 1) 각 인덱스와 컬럼을 multi-index를 갖도록 설정
data = data.set_index(['지역','지역.1']) # index 설정
data.index.names = ['품목','상세품목'] # index name 설정
data.columns = [data.columns.map(lambda x : x[:2]), data.iloc[0]] # column 설정
data = data.iloc[1:] # set_column 메서드가 없으므로 원본에서 제거 필요
data.columns.names = ['지역','지점'] # column name 설정
data = data.astype('int') # 데이터를 숫자형 타입으로 변환
data
### 2) 컴퓨터의 서울지역 판매량 출력
data.xs('컴퓨터').xs('서울',axis=1)
data.loc['컴퓨터', '서울'] # 색인하려는 level이 둘 다 상위 level이므로 loc메서드로 색인 가능
### 3) 서울지역의 컴퓨터의 각 세부항목별 판매량의 합계 출력
data.loc['컴퓨터', '서울'].apply(sum, 1)
상세품목
노트북 3399
데스크탑 4730
dtype: int64
### 4) 각 지역의 A지점의 TV 판매량 출력
data.xs('A', level=1, axis=1).xs('TV', level=1)
### 5) 각 지역 C지점의 모바일의 각 세부항목별 판매량 평균 출력
round(data.xs('C', level=1, axis=1).xs('모바일').mean(1), 2)
상세품목
핸드폰 8807.67
태블릿 1585.00
dtype: float64
### 6) 서울지역의 A지점의 노트북 판매량 출력
data['서울','A'].xs('노트북', level=1)
품목
컴퓨터 1000
Name: (서울, A), dtype: int32
#. Q2
### employment.csv 파일을 읽고
emp = pd.read_csv("employment.csv", encoding='cp949', sep=',')
emp = emp.set_index('고용형태') # 고용형태 컬럼을 인덱스로 사용
s1 = emp.columns.map(lambda x : x[:4])
s2 = emp.iloc[0].map(lambda x : x.split(' ')[0])
emp.columns = [s1, s2] # 컬럼 지정
emp = emp.iloc[1:]
emp.columns.names = ['년도', '구분'] # 컬럼 이름 설정
f1 = lambda x : x.replace('-','0') # '-' 기호 치환
emp = emp.applymap(f1)
f2 = lambda x : x.replace(',','') # 천 단위 구분기호 치환
emp = emp.applymap(f2)
emp = emp.astype('float') # 데이터 손실을 막기 위해 정수, 실수가 합쳐진 데이터의 경우 실수(float)으로 통일
emp
### 1) 정규근로자의 월급여액을 년도별로 출력
emp.xs('월급여액', level=1, axis=1).loc['정규근로자'] # 멀티인덱스의 상위 컬럼 선택 후 인덱스 색인
년도
2007 2027.0
2008 2151.0
2009 2199.0
2010 2285.0
2011 2385.0
2012 2502.0
2013 2566.0
Name: 정규근로자, dtype: float64
### 2) 각 년도별 근로자 총근로일수의 평균 출력
emp.xs('총근로일수', level=1, axis=1).sum(axis=1) # 멀티인덱스의 상위 컬럼 선택 후 서로 다른 컬럼별 연산
고용형태
전체근로자 151.5
전체근로자(특수형태포함) 0.0
정규근로자 156.1
비정규근로자 136.5
비정규근로자(특수형태포함) 0.0
특수형태근로종사자 0.0
재택/가내근로자 136.3
파견/용역근로자 143.0
일일근로자 120.8
단시간근로자 129.8
기간제근로자 150.0
한시적근로자 151.9
dtype: float64
### 3) 각 년도별 정규근로자와 비정규근로자의 월급여액의 차이 계산
emp.xs('월급여액', level=1, axis=1).loc['정규근로자'] - emp.xs('월급여액', level=1, axis=1).loc['비정규근로자']
년도 # 키가 동일하므로 연산 가능
2007 882.0
2008 962.0
2009 997.0
2010 1066.0
2011 1103.0
2012 1189.0
2013 1194.0
dtype: float64
#. Q3
### 역별 승하차의 총 합
sub = pd.read_csv("subway2.csv", encoding='cp949', sep=',') # skiprows=1
sub.columns = sub.iloc[0].map(lambda x : x[:2] + '시') # 첫 행을 컬럼으로 사용
sub = sub.iloc[1:]
sub.iloc[:,0] = sub.iloc[:,0].fillna(method='ffill').map(lambda x : x.split('(')[0]) # 인덱스로 사용할 첫 컬럼의 NA 치환
sub = sub.set_index(['전체시', '구분시']) # 인덱스 설정
# sub.set_index([sub.iloc[:,0], sub.iloc[:,1]]) => 위치기반으로 설정 시 원본 컬럼 제거 불가
sub.index.names = ['역','구분'] # 익덱스 이름 설정
sub = sub.applymap(lambda x : int(x.replace(',',''))) # 천 단위 구분기호 제거
sub.sum(1).sum(level=0)
sub.sum(axis=0, level=0).sum(1) # sum(연산 방향)
역
서울역 4174067
시 청 3290230
종 각 3121065
종로3 3197729
종로5가 1699115
...
신용산 1119068
이 촌 599060
동 작 248554
총신대 1712004
남태령 71443
Length: 107, dtype: int64
'Python > Process' 카테고리의 다른 글
[Python] 데이터 결합 (np.concatenate, pd.concat) (0) | 2019.02.14 |
---|---|
[Python] 데이터 병합(Join) - pandas.merge (0) | 2019.02.14 |
[Python] Pandas - DataFrame 관련 메서드 (0) | 2019.02.11 |
[Python] DataFrame 그룹 함수 적용 - map,apply,applymap (0) | 2019.02.10 |
[Python] Pandas - DataFrame (0) | 2019.02.08 |