01 빈도수 / 유일값 확인
-01 빈도수 확인
-02 유일값
02 중복값 처리 (unique / duplicated / drop_duplicates)
-01 unique
-02 duplicated
03 shift (데이터의 이동)
-01 이전값 가져오기
-02 이후값 가져오기
-03 컬럼의 이동
-04 그룹별 이동
04 multi - level index
-01 생성
-02 색인
-03 연산
05 multi - level index의 처리
-01 drop
-02 sort_index
-03 swaplevel
01 빈도수 / 유일값 확인
-01 빈도수 확인
1) groupby + count
2) value_counts 메서드
emp.value_counts?
Signature:
emp.value_counts(
subset: 'IndexLabel | None' = None,
normalize: 'bool' = False,
sort: 'bool' = True,
ascending: 'bool' = False,
dropna: 'bool' = True,
) -> 'Series'
Docstring:
Return a Series containing the frequency of each distinct row in the Dataframe.
emp.value_counts(subset, # 도수를 계산할 대상 선택
normalize = False, # 비율 출력 여부
sort = True, # 정렬 여부
ascending = False, # 빈도수가 큰 순서대로 출력됨
dropna = True) # NA는 무시하고 도수 계산
emp.groupby('DEPTNO')['DEPTNO'].count()
emp.groupby('DEPTNO')['DEPTNO'].count()
Out[70]:
DEPTNO
10 3
20 5
30 6
Name: DEPTNO, dtype: int64
▲ key에 대해 정렬을 진행한다.
emp['DEPTNO'].value_counts()
emp['DEPTNO'].value_counts()
Out[71]:
DEPTNO
30 6
20 5
10 3
Name: count, dtype: int64
▲ DEPTNO 열에 대해 정렬을 진행한다.
emp['DEPTNO'].value_counts(normalize = True)
emp['DEPTNO'].value_counts(normalize = True)
Out[151]:
DEPTNO
30 0.428571
20 0.357143
10 0.214286
Name: proportion, dtype: float64
▲ normalize = True 옵션을 통해 도수가 아닌 비율을 출력했다.
+) .value_counts(normalize = True)로 클래스간 비율을 확인해야 하는 이유
이진 분류일 때 7:3 정도의 불균형은 거의 당연하다고 여겨질 정도로 흔하게 발생한다.
일반적으로 클래스 비율이 8:2를 초과하는 시점부터 클래스 불균형 문제를 본격적으로 고려해야 하며, 모델이 다수 클래스 중심으로 예측하는 경향이 강해질 가능성이 높아진다.
특히 고객 이탈 예측, 사망률 예측과 같이 소수 클래스에 대한 탐지가 더 중요한 문제에서는 단순 정확도(Accuracy)만으로 모델 성능을 평가하기 어렵다.
따라서 재현율(Recall), 정밀도(Precision), F1-Score와 같은 지표를 함께 고려하며, 필요에 따라 오버샘플링(Over Sampling), 언더샘플링(Under Sampling), 클래스 가중치(Class Weight) 조정 등의 기법을 적용해 클래스 불균형 문제를 완화해야 한다.
-02 유일값
emp['JOB'].unique()
emp['JOB'].unique()
Out[72]:
array(['CLERK', 'SALESMAN', 'MANAGER', 'ANALYST', 'PRESIDENT'],
dtype=object)
▲ sql의 distinct처럼 자동으로 정렬되어 리턴된다.
02 중복값 처리 (unique / duplicated / drop_duplicates)
-01 unique
Series에서만 호출이 가능하며 정렬을 자동으로 보장하지 않는다.
emp['JOB'].unique()
emp['JOB'].unique()
Out[73]:
array(['CLERK', 'SALESMAN', 'MANAGER', 'ANALYST', 'PRESIDENT'],
dtype=object)
-02 duplicated
emp['JOB'].duplicated() # 중복 여부 확인
emp['JOB'].duplicated()
Out[74]:
0 False
1 False
2 True
3 False
4 True
5 True
6 True
7 False
8 False
9 True
10 True
11 True
12 True
13 True
Name: JOB, dtype: bool
# 중복되지 않은 행만 출력 (중복행 제거)
emp.loc[~emp['JOB'].duplicated(), : ]
중복이 된 경우가 True이므로 '~'를 통해 중복되지 않은 고유한 값만 추출한다.
emp.loc[~emp['JOB'].duplicated(), :]
Out[76]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
0 7369 SMITH CLERK 7902.0 1980-12-17 0:00 800 NaN 20
1 7499 ALLEN SALESMAN 7698.0 1981-02-20 0:00 1600 300.0 30
3 7566 JONES MANAGER 7839.0 1981-04-02 0:00 2975 NaN 20
7 7788 SCOTT ANALYST 7566.0 1987-04-17 0:00 3000 NaN 20
8 7839 KING PRESIDENT NaN 1981-11-17 0:00 5000 NaN 10
# 중복된 행만 출력
emp.loc[emp['JOB'].duplicated(), :]
'~'를 제외하니 중복된 행만 출력됨을 확인할 수 있다.
emp.loc[emp['JOB'].duplicated(), :]
Out[77]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
2 7521 WARD SALESMAN 7698.0 1982-02-22 0:00 1250 500.0 30
4 7654 MARTIN SALESMAN 7698.0 1981-09-28 0:00 1250 1400.0 30
5 7698 BLAKE MANAGER 7839.0 1981-05-01 0:00 2850 NaN 30
6 7782 CLARK MANAGER 7839.0 1981-06-09 0:00 2450 NaN 10
9 7844 TURNER SALESMAN 7698.0 1981-09-08 0:00 1500 0.0 30
10 7876 ADAMS CLERK 7788.0 1987-05-23 0:00 1100 NaN 20
11 7900 JAMES CLERK 7698.0 1981-12-03 0:00 950 NaN 30
12 7902 FORD ANALYST 7566.0 1981-12-03 0:00 3000 NaN 20
13 7934 MILLER CLERK 7782.0 1982-01-23 0:00 1300 NaN 10
-03 drop_duplicates
emp.drop_duplicates?
Signature:
emp.drop_duplicates(
subset: 'Hashable | Sequence[Hashable] | None' = None,
*,
keep: 'DropKeep' = 'first',
inplace: 'bool' = False,
ignore_index: 'bool' = False,
) -> 'DataFrame | None'
Docstring:
Return DataFrame with duplicate rows removed.
emp.drop_duplicates(subset, # 중복체크 대상
keep = 'first', # 중복제거시 남길 대상 선택
ignore_index = False) # 제거된 행이 발생하기 때문에 index 재배치 여부를 묻는다.
emp.iloc[0:1,:] # slice를 사용하여 차원축소 방지
emp2 = pd.concat([emp, emp.iloc[0:1, :]], ignore_index = True)
pd.concat([emp, emp.iloc[0:1, :]], ignore_index = True)
Out[85]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
0 7369 SMITH CLERK 7902.0 1980-12-17 0:00 800 NaN 20
1 7499 ALLEN SALESMAN 7698.0 1981-02-20 0:00 1600 300.0 30
2 7521 WARD SALESMAN 7698.0 1982-02-22 0:00 1250 500.0 30
3 7566 JONES MANAGER 7839.0 1981-04-02 0:00 2975 NaN 20
4 7654 MARTIN SALESMAN 7698.0 1981-09-28 0:00 1250 1400.0 30
5 7698 BLAKE MANAGER 7839.0 1981-05-01 0:00 2850 NaN 30
6 7782 CLARK MANAGER 7839.0 1981-06-09 0:00 2450 NaN 10
7 7788 SCOTT ANALYST 7566.0 1987-04-17 0:00 3000 NaN 20
8 7839 KING PRESIDENT NaN 1981-11-17 0:00 5000 NaN 10
9 7844 TURNER SALESMAN 7698.0 1981-09-08 0:00 1500 0.0 30
10 7876 ADAMS CLERK 7788.0 1987-05-23 0:00 1100 NaN 20
11 7900 JAMES CLERK 7698.0 1981-12-03 0:00 950 NaN 30
12 7902 FORD ANALYST 7566.0 1981-12-03 0:00 3000 NaN 20
13 7934 MILLER CLERK 7782.0 1982-01-23 0:00 1300 NaN 10
14 7369 SMITH CLERK 7902.0 1980-12-17 0:00 800 NaN 20
▲ 총 15행이 되었으며 마지막에 smith 행이 추가되었다.
emp2.drop_duplicates()
emp2.drop_duplicates()
Out[87]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
0 7369 SMITH CLERK 7902.0 1980-12-17 0:00 800 NaN 20
1 7499 ALLEN SALESMAN 7698.0 1981-02-20 0:00 1600 300.0 30
2 7521 WARD SALESMAN 7698.0 1982-02-22 0:00 1250 500.0 30
3 7566 JONES MANAGER 7839.0 1981-04-02 0:00 2975 NaN 20
4 7654 MARTIN SALESMAN 7698.0 1981-09-28 0:00 1250 1400.0 30
5 7698 BLAKE MANAGER 7839.0 1981-05-01 0:00 2850 NaN 30
6 7782 CLARK MANAGER 7839.0 1981-06-09 0:00 2450 NaN 10
7 7788 SCOTT ANALYST 7566.0 1987-04-17 0:00 3000 NaN 20
8 7839 KING PRESIDENT NaN 1981-11-17 0:00 5000 NaN 10
9 7844 TURNER SALESMAN 7698.0 1981-09-08 0:00 1500 0.0 30
10 7876 ADAMS CLERK 7788.0 1987-05-23 0:00 1100 NaN 20
11 7900 JAMES CLERK 7698.0 1981-12-03 0:00 950 NaN 30
12 7902 FORD ANALYST 7566.0 1981-12-03 0:00 3000 NaN 20
13 7934 MILLER CLERK 7782.0 1982-01-23 0:00 1300 NaN 10
▲ 중복되었던 smith 행이 제거되어 14개 행이 리턴되었다. 각 행의 모든 값이 같을 때 중복으로 인정하였다.
emp.drop_duplicates('JOB')
emp.drop_duplicates('JOB')
Out[88]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
0 7369 SMITH CLERK 7902.0 1980-12-17 0:00 800 NaN 20
1 7499 ALLEN SALESMAN 7698.0 1981-02-20 0:00 1600 300.0 30
3 7566 JONES MANAGER 7839.0 1981-04-02 0:00 2975 NaN 20
7 7788 SCOTT ANALYST 7566.0 1987-04-17 0:00 3000 NaN 20
8 7839 KING PRESIDENT NaN 1981-11-17 0:00 5000 NaN 10
▲ JOB 열 기준으로 중복되는 모든 행이 삭제되었으며, keep = 'first' (기본값) 옵션에 의해 유 니크한 값을 가진 행 중 가장 먼저 확인가능한 행만 남았다.
emp.drop_duplicates('JOB', keep = 'last')
emp.drop_duplicates('JOB', keep = 'last')
Out[89]:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
6 7782 CLARK MANAGER 7839.0 1981-06-09 0:00 2450 NaN 10
8 7839 KING PRESIDENT NaN 1981-11-17 0:00 5000 NaN 10
9 7844 TURNER SALESMAN 7698.0 1981-09-08 0:00 1500 0.0 30
12 7902 FORD ANALYST 7566.0 1981-12-03 0:00 3000 NaN 20
13 7934 MILLER CLERK 7782.0 1982-01-23 0:00 1300 NaN 10
▲ JOB 열 기준으로 중복되는 모든 행이 삭제되었으며, keep = 'last' 옵션에 의해 유니크한 값을 가진 행 중 가장 마지막 행만 남았다.
03 shift (데이터의 이동)
행 및 컬럼의 이동을 진행한다.
이전 / 이후 행과 비교, 연산, 출력 등을 위한 처리에 필요한 메서드이다.
pandas에서 제공하며 sql의 lag, lead와 같은 기능을 수행한다.
emp.shift(periods, # 가져올 위치 (1이면 이전 값, 2이면 2개 이전 값)
freq, # 빈도
axis = 0, # 이동방향
fill_value) # 가져올 값이 없을 때의 대체값
-01 이전값 가져오기
emp['SAL'].shift()
emp['SAL'].shift()
Out[91]:
0 NaN
1 800.0
2 1600.0
3 1250.0
4 2975.0
5 1250.0
6 2850.0
7 2450.0
8 3000.0
9 5000.0
10 1500.0
11 1100.0
12 950.0
13 3000.0
Name: SAL, dtype: float64
▲ NA가 float type이므로 모두 float이 된다.
emp['SAL'].shift(2)
emp['SAL'].shift(2)
Out[92]:
0 NaN
1 NaN
2 800.0
3 1600.0
4 1250.0
5 2975.0
6 1250.0
7 2850.0
8 2450.0
9 3000.0
10 5000.0
11 1500.0
12 1100.0
13 950.0
Name: SAL, dtype: float64
emp['SAL'].shift(2, fill_value=0)
emp['SAL'].shift(2, fill_value=0)
Out[93]:
0 0
1 0
2 800
3 1600
4 1250
5 2975
6 1250
7 2850
8 2450
9 3000
10 5000
11 1500
12 1100
13 950
Name: SAL, dtype: int64
▲ NA가 0으로 치환되었다.
-02 이후값 가져오기
emp['SAL'].shift(-1)
emp['SAL'].shift(-1)
Out[94]:
0 1600.0
1 1250.0
2 2975.0
3 1250.0
4 2850.0
5 2450.0
6 3000.0
7 5000.0
8 1500.0
9 1100.0
10 950.0
11 3000.0
12 1300.0
13 NaN
Name: SAL, dtype: float64
-03 컬럼의 이동
import numpy as np
from pandas import Series, DataFrame
df = DataFrame(np.arange(1,26).reshape(5,5), columns = list('ABCDE'))
DataFrame(np.arange(1,26).reshape(5,5), columns = list('ABCDE'))
Out[143]:
A B C D E
0 1 2 3 4 5
1 6 7 8 9 10
2 11 12 13 14 15
3 16 17 18 19 20
4 21 22 23 24 25
df.shift()
df.shift()
Out[145]:
A B C D E
0 NaN NaN NaN NaN NaN
1 1.0 2.0 3.0 4.0 5.0
2 6.0 7.0 8.0 9.0 10.0
3 11.0 12.0 13.0 14.0 15.0
4 16.0 17.0 18.0 19.0 20.0
df.shift(axis=1)
df.shift(axis=1)
Out[146]:
A B C D E
0 NaN 1 2 3 4
1 NaN 6 7 8 9
2 NaN 11 12 13 14
3 NaN 16 17 18 19
4 NaN 21 22 23 24
-04 그룹별 이동
emp['SAL2'] = emp.groupby('DEPTNO')['SAL'].shift()
emp[['ENAME','DEPTNO','HIREDATE','SAL','SAL2']].sort_values('DEPTNO')
emp[['ENAME','DEPTNO','HIREDATE','SAL','SAL2']].sort_values('DEPTNO')
Out[150]:
ENAME DEPTNO HIREDATE SAL SAL2
4 CLARK 10 1981-06-09 0:00 2450 NaN
7 KING 10 1981-11-17 0:00 5000 2450.0
10 MILLER 10 1982-01-23 0:00 1300 5000.0
0 SMITH 20 1980-12-17 0:00 800 NaN
2 JONES 20 1981-04-02 0:00 2975 800.0
9 FORD 20 1981-12-03 0:00 3000 2975.0
12 SCOTT 20 1987-04-17 0:00 3000 3000.0
13 ADAMS 20 1987-05-23 0:00 1100 3000.0
1 ALLEN 30 1981-02-20 0:00 1600 NaN
3 BLAKE 30 1981-05-01 0:00 2850 1600.0
5 TURNER 30 1981-09-08 0:00 1500 2850.0
6 MARTIN 30 1981-09-28 0:00 1250 1500.0
8 JAMES 30 1981-12-03 0:00 950 1250.0
11 WARD 30 1982-02-22 0:00 1250 950.0
ex) 바로 직전에 입사한 상사보다 급여가 높은 직원의 이름, 부서번호, 급여 출력
emp = emp.sort_values('HIREDATE', ignore_index = True)
emp['MGR_SAL'] = emp['SAL'].shift(1)
emp.loc[emp['SAL'] > emp['MGR_SAL'], ['ENAME','DEPTNO','SAL']]
emp.loc[emp['SAL'] > emp['MGR_SAL'], ['ENAME','DEPTNO','SAL']]
Out[139]:
ENAME DEPTNO SAL
1 ALLEN 30 1600
2 JONES 20 2975
7 KING 10 5000
9 FORD 20 3000
12 SCOTT 20 3000
# [ 연습문제 - 빅분기 예상 문제 ]
# sales4.csv 파일에는 날짜, 지점, 판매량 3개 컬럼이 있으며 날짜/지점 순으로 정렬되어 있다.
# 지점 코드는 B01~B10이고 날짜는 2025-04-01부터 한 달치 데이터다.
# 각 지점별로 전일 대비 판매량이 감소한 날짜 수를 집계하고,
# 감소 날짜가 가장 많은 지점을 출력한다.
# 감소폭은 (당일 판매량 - 전일 판매량) / 전일 판매량 * 100 으로 계산하며,
# 해당 지점의 가장 큰 감소율을 절댓값으로 소숫점 넷째 자리까지 반올림하여 출력한다.
df = pd.read_csv('sales4.csv')
df = df.sort_values(['지점','날짜'], ignore_index = True)
df.head()
Out[470]:
날짜 지점 판매량 전일판매량 증가율
0 2025-04-01 B01 170 NaN NaN
1 2025-04-02 B01 156 170.0 -8.235294
2 2025-04-03 B01 136 156.0 -12.820513
3 2025-04-04 B01 136 136.0 0.000000
4 2025-04-05 B01 197 136.0 44.852941
df['전일판매량'] = df.groupby('지점')['판매량'].shift()
df['증가율'] = (df['판매량'] - df['전일판매량']) / df['전일판매량'] * 100
# 1) 감소 날짜가 가장 많은 지점
df2 = df.loc[df['증가율'] < 0 , : ]
result1 = df2['지점'].value_counts().idxmax()
print(result1)
# 2) 증가율
result2 = df2.loc[df2['지점'] == result1, '증가율'].abs().max()
print(round(result2, 4))
04 multi - level index
파이썬은 여러 depth (level)를 갖는 index를 구성할 수 있다.
level을 이용하여 level별 연산, 정렬, 그룹핑 등이 가능하다.
level 번호 가장 상위 레벨(바깥) 0, 1, 2, ...
-01 생성
df.index = [a1,a2] # 2 level index
df.columns = [a1,a2]
# 데이터 내의 특정 컬럼이 multi index가 되기를 원한다면 먼저 COL1, COL2 순서대로 정렬 후 인덱스 생성 권고!
df.set_index(['COL1','COL2'])
# ** INDEX 이름 부여
df.index.names = [상위레벨이름, 하위레벨이름]
df.columns.names = [상위레벨이름, 하위레벨이름]
df.index.names = [None, None]
df.columns.names = [None, None]
ex) index 직접 전달
df = DataFrame(np.arange(1,17).reshape(4,4))
df
Out[473]:
0 1 2 3
0 1 2 3 4
1 5 6 7 8
2 9 10 11 12
3 13 14 15 16
df.index = [['서울','서울','경기','경기'], ['C1','C2','C1','C2']]
df
Out[475]:
0 1 2 3
서울 C1 1 2 3 4
C2 5 6 7 8
경기 C1 9 10 11 12
C2 13 14 15 16
df.columns = [['2024','2024','2025','2025'], ['상반기','하반기','상반기','하반기']]
df
Out[479]:
2024 2025
상반기 하반기 상반기 하반기
서울 C1 1 2 3 4
C2 5 6 7 8
경기 C1 9 10 11 12
C2 13 14 15 16
df.index.names = ['지역','지점']
df.columns.names = ['연도','구분']
df
Out[482]:
연도 2024 2025
구분 상반기 하반기 상반기 하반기
지역 지점
서울 C1 1 2 3 4
C2 5 6 7 8
경기 C1 9 10 11 12
C2 13 14 15 16
ex)
df1 = pd.read_csv('병원현황.csv', encoding = 'cp949', skiprows=1)
df.head()
Out[500]:
시군구명칭 표시과목 2013. 4/4 ... 2009. 3/4 2009. 2/4 2009. 1/4
0 강남구 계 1343 ... 1135.0 1121.0 1097.0
1 강남구 내과 79 ... 71.0 72.0 71.0
2 강남구 신경과 6 ... 5.0 6.0 6.0
3 강남구 정신건강의학과 40 ... 42.0 42.0 40.0
4 강남구 외과 25 ... 19.0 18.0 18.0
df1 = df1.drop(columns = ['항목','단위'])
# 멀티 레벨 인덱스 설정
df1 = df1.set_index(['시군구명칭','표시과목'])
df.set_index(['시군구명칭','표시과목'])
Out[503]:
2013. 4/4 2013. 3/4 ... 2009. 2/4 2009. 1/4
시군구명칭 표시과목 ...
강남구 계 1343 1344 ... 1121.0 1097.0
내과 79 78 ... 72.0 71.0
신경과 6 6 ... 6.0 6.0
정신건강의학과 40 41 ... 42.0 40.0
외과 25 25 ... 18.0 18.0
... ... ... ... ...
금천구 핵의학과 0 0 ... 0.0 0.0
가정의학과 0 0 ... 1.0 1.0
예방의학과 0 0 ... NaN NaN
전문과목미표시전문의 29 29 ... 25.0 25.0
일반의 9 9 ... 10.0 10.0
# 멀티 레벨 컬럼 설정
g1 = df1.columns.str[:4]
g2 = df1.columns.str[6]
df1.columns = [g1,g2]
df1
Out[541]:
시군구명 표시과목 2013 ... 2010 2009
NaN NaN 4 3 2 ... 1 4 3 2 1
0 강남구 계 1343 1344 1349 ... 1176.0 1155.0 1135.0 1121.0 1097.0
1 강남구 내과 79 78 78 ... 72.0 71.0 71.0 72.0 71.0
2 강남구 신경과 6 6 6 ... 5.0 5.0 5.0 6.0 6.0
3 강남구 정신건강의학과 40 41 41 ... 41.0 40.0 42.0 42.0 40.0
4 강남구 외과 25 25 24 ... 21.0 20.0 19.0 18.0 18.0
.. ... ... ... ... ... ... ... ... ... ... ...
645 금천구 핵의학과 0 0 0 ... 0.0 0.0 0.0 0.0 0.0
646 금천구 가정의학과 0 0 0 ... 1.0 1.0 1.0 1.0 1.0
647 금천구 예방의학과 0 0 0 ... NaN NaN NaN NaN NaN
648 금천구 전문과목미표시전문의 29 29 29 ... 27.0 26.0 26.0 25.0 25.0
649 금천구 일반의 9 9 11 ... 8.0 9.0 10.0 10.0 10.0
-02 색인
1) 특정 컬럼 선택
df['2024'] # 상위레벨 컬럼 선택 (key indexing)
df['2024'] # 상위레벨 컬럼 선택 (key indexing)
Out[562]:
구분 상반기 하반기
지역 지점
서울 C1 1 2
C2 5 6
경기 C1 9 10
C2 13 14
df['상반기'] # 하위레벨 컬럼 선택 불가
df['상반기'] # 하위레벨 컬럼 선택 불가
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
File ~\anaconda3\Lib\site-packages\pandas\core\indexes\base.py:3812, in Index.get_loc(self, key)
3811 try:
-> 3812 return self._engine.get_loc(casted_key)
3813 except KeyError as err:
File pandas/_libs/index.pyx:167, in pandas._libs.index.IndexEngine.get_loc()
File pandas/_libs/index.pyx:196, in pandas._libs.index.IndexEngine.get_loc()
File pandas/_libs/hashtable_class_helper.pxi:7088, in pandas._libs.hashtable.PyObjectHashTable.get_item()
File pandas/_libs/hashtable_class_helper.pxi:7096, in pandas._libs.hashtable.PyObjectHashTable.get_item()
KeyError: '상반기'
The above exception was the direct cause of the following exception:
KeyError Traceback (most recent call last)
Cell In[563], line 1
----> 1 df['상반기'] # 하위레벨 컬럼 선택 불가
File ~\anaconda3\Lib\site-packages\pandas\core\frame.py:4112, in DataFrame.__getitem__(self, key)
4110 if is_single_key:
4111 if self.columns.nlevels > 1:
-> 4112 return self._getitem_multilevel(key)
4113 indexer = self.columns.get_loc(key)
4114 if is_integer(indexer):
File ~\anaconda3\Lib\site-packages\pandas\core\frame.py:4170, in DataFrame._getitem_multilevel(self, key)
4168 def _getitem_multilevel(self, key):
4169 # self.columns is a MultiIndex
-> 4170 loc = self.columns.get_loc(key)
4171 if isinstance(loc, (slice, np.ndarray)):
4172 new_columns = self.columns[loc]
File ~\anaconda3\Lib\site-packages\pandas\core\indexes\multi.py:3059, in MultiIndex.get_loc(self, key)
3056 return mask
3058 if not isinstance(key, tuple):
-> 3059 loc = self._get_level_indexer(key, level=0)
3060 return _maybe_to_slice(loc)
3062 keylen = len(key)
File ~\anaconda3\Lib\site-packages\pandas\core\indexes\multi.py:3410, in MultiIndex._get_level_indexer(self, key, level, indexer)
3407 return slice(i, j, step)
3409 else:
-> 3410 idx = self._get_loc_single_level_index(level_index, key)
3412 if level > 0 or self._lexsort_depth == 0:
3413 # Desired level is not sorted
3414 if isinstance(idx, slice):
3415 # test_get_loc_partial_timestamp_multiindex
File ~\anaconda3\Lib\site-packages\pandas\core\indexes\multi.py:2999, in MultiIndex._get_loc_single_level_index(self, level_index, key)
2997 return -1
2998 else:
-> 2999 return level_index.get_loc(key)
File ~\anaconda3\Lib\site-packages\pandas\core\indexes\base.py:3819, in Index.get_loc(self, key)
3814 if isinstance(casted_key, slice) or (
3815 isinstance(casted_key, abc.Iterable)
3816 and any(isinstance(x, slice) for x in casted_key)
3817 ):
3818 raise InvalidIndexError(key)
-> 3819 raise KeyError(key) from err
3820 except TypeError:
3821 # If we have a listlike key, _check_indexing_error will raise
3822 # InvalidIndexError. Otherwise we fall through and re-raise
3823 # the TypeError.
3824 self._check_indexing_error(key)
KeyError: '상반기'
df.loc['서울',:]
df.loc['서울',:]
Out[564]:
연도 2024 2025
구분 상반기 하반기 상반기 하반기
지점
C1 1 2 3 4
C2 5 6 7 8
df.loc['서울':'서울',:] # error (level 유지 불가)
UnsortedIndexError: 'Key length (1) was greater than MultiIndex lexsort depth (0)'
차원을 유지하려는 행위가 슬라이스 인덱싱인데, 슬라이스 인덱싱으로 레벨을 유지하는 것은 불가능하다.
따라서 색인 메서드가 필요하다.
df.loc['C1',:] # 하위레벨 인덱스 선택 불가
KeyError: 'C1'
df.iloc[[0,2],:]
df.iloc[:,[0,2]]
df.iloc[[0,2],:] # 위치기반 선택 가능
Out[570]:
연도 2024 2025
구분 상반기 하반기 상반기 하반기
지역 지점
서울 C1 1 2 3 4
경기 C1 9 10 11 12
df.iloc[:,[0,2]] # 위치기반 선택 가능
Out[571]:
연도 2024 2025
구분 상반기 상반기
지역 지점
서울 C1 1 3
C2 5 7
경기 C1 9 11
C2 13 15
# ** 멀티 레벨 인덱스 색인 메서드
df.xs(key, # 찾을 값
axis = 0, # 방향 (0 : index, 1 : column)
level = 0, # 레벨명 또는 레벨번호 전달
drop_level = True) # 레벨축소여부
df.xs('서울')
df.xs('서울')
Out[579]:
연도 2024 2025
구분 상반기 하반기 상반기 하반기
지점
C1 1 2 3 4
C2 5 6 7 8
df.xs('C1', level = 1)
df.xs('C1', level = 1)
Out[580]:
연도 2024 2025
구분 상반기 하반기 상반기 하반기
지역
서울 1 2 3 4
경기 9 10 11 12
df.xs('상반기', axis = 1, level = 1)
df.xs('상반기', axis = 1, level = '구분') 도 동일한 결과를 리턴한다.
df.xs('상반기', axis = 1, level = 1)
Out[581]:
연도 2024 2025
지역 지점
서울 C1 1 3
C2 5 7
경기 C1 9 11
C2 13 15
df.xs('서울', drop_level = False)
df.xs('서울', drop_level = False)
Out[583]:
연도 2024 2025
구분 상반기 하반기 상반기 하반기
지역 지점
서울 C1 1 2 3 4
C2 5 6 7 8
# 단 하나의 .xs 메서드를 사용하여 index와 column 모두를 한 번에 선택할 수는 없다. (양방향 접근 불가능)
df.xs('C2', level = 1).xs('하반기', axis = 1, level = 1)
df.xs('C2', level = 1).xs('하반기', axis = 1, level = 1)
Out[584]:
연도 2024 2025
지역
서울 6 8
경기 14 16
# ** 멀티 레벨의 순차접근
df.index
멀티레벨의 경우 각 인덱스 값을 순서에 따라 튜플로 저장하고 있다.
df.index
Out[586]:
MultiIndex([('서울', 'C1'),
('서울', 'C2'),
('경기', 'C1'),
('경기', 'C2')],
names=['지역', '지점'])
df.columns
각 열의 경우도 마찬가지이다.
df.columns
Out[585]:
MultiIndex([('2024', '상반기'),
('2024', '하반기'),
('2025', '상반기'),
('2025', '하반기')],
names=['연도', '구분'])
df.loc[:, ('2024', '상반기')]
df.loc[:, ('2024', '상반기')]
Out[591]:
지역 지점
서울 C1 1
C2 5
경기 C1 9
C2 13
Name: (2024, 상반기), dtype: int64
df.loc[[('서울', 'C1'),('경기', 'C2')], : ]
df.loc[[('서울', 'C1'),('경기', 'C2')], : ]
Out[592]:
연도 2024 2025
구분 상반기 하반기 상반기 하반기
지역 지점
서울 C1 1 2 3 4
경기 C2 13 14 15 16
[ 연습문제 ]
1) 강남구 병원 현황 선택
df1.xs('강남구')
df1.loc['강남구',:]
df1.loc['강남구',:]
Out[634]:
2013 ... 2009
4 3 2 1 ... 4 3 2 1
표시과목 ...
계 1343 1344 1349 1322 ... 1155.0 1135.0 1121.0 1097.0
내과 79 78 78 78 ... 71.0 71.0 72.0 71.0
신경과 6 6 6 6 ... 5.0 5.0 6.0 6.0
정신건강의학과 40 41 41 40 ... 40.0 42.0 42.0 40.0
외과 25 25 24 26 ... 20.0 19.0 18.0 18.0
정형외과 28 28 28 28 ... 26.0 25.0 26.0 26.0
신경외과 3 3 3 3 ... 2.0 2.0 2.0 2.0
흉부외과 3 3 3 3 ... 3.0 3.0 3.0 3.0
성형외과 319 315 313 309 ... 260.0 251.0 241.0 238.0
마취통증의학과 11 12 12 13 ... 11.0 11.0 10.0 10.0
산부인과 46 48 48 49 ... 50.0 49.0 49.0 50.0
소아청소년과 28 29 28 27 ... 28.0 28.0 28.0 28.0
안과 68 67 67 66 ... 61.0 61.0 62.0 62.0
이비인후과 51 50 48 47 ... 45.0 45.0 43.0 42.0
피부과 119 120 123 122 ... 107.0 108.0 108.0 105.0
비뇨기과 35 37 38 38 ... 39.0 40.0 40.0 39.0
영상의학과 11 11 12 12 ... 11.0 12.0 12.0 12.0
병리과 3 4 4 4 ... 3.0 3.0 3.0 3.0
진단검사의학과 1 1 1 1 ... 1.0 1.0 1.0 1.0
결핵과 0 0 0 0 ... 0.0 0.0 0.0 0.0
재활의학과 8 8 8 8 ... 11.0 10.0 10.0 8.0
핵의학과 0 0 0 0 ... 0.0 0.0 0.0 0.0
가정의학과 7 7 7 8 ... 8.0 8.0 8.0 8.0
예방의학과 0 0 0 0 ... NaN NaN NaN NaN
전문과목미표시전문의 316 321 330 307 ... 243.0 244.0 239.0 230.0
일반의 136 130 127 127 ... 110.0 97.0 98.0 95.0
2) 2013년 병원 현황 선택
df1['2013']
df1.loc[:, '2013']
df1.xs('2013', axis = 1)
df1.xs('2013', axis = 1)
Out[635]:
4 3 2 1
시군구명칭 표시과목
강남구 계 1343 1344 1349 1322
내과 79 78 78 78
신경과 6 6 6 6
정신건강의학과 40 41 41 40
외과 25 25 24 26
... ... ... ...
금천구 핵의학과 0 0 0 0
가정의학과 0 0 0 0
예방의학과 0 0 0 0
전문과목미표시전문의 29 29 29 30
일반의 9 9 11 10
3) 1분기 병원 현황 선택
df1.xs('4', axis = 1, level = 1)
df1.xs('4', axis = 1, level = 1)
Out[636]:
2013 2012 2011 2010 2009
시군구명칭 표시과목
강남구 계 1343 1301.0 1271.0 1247.0 1155.0
내과 79 77.0 73.0 74.0 71.0
신경과 6 6.0 5.0 5.0 5.0
정신건강의학과 40 39.0 37.0 38.0 40.0
외과 25 26.0 25.0 24.0 20.0
... ... ... ... ...
금천구 핵의학과 0 0.0 0.0 0.0 0.0
가정의학과 0 0.0 0.0 0.0 1.0
예방의학과 0 NaN NaN NaN NaN
전문과목미표시전문의 29 30.0 30.0 28.0 26.0
일반의 9 11.0 9.0 11.0 9.0
4) 강남구의 내과 현황을 출력
df1.xs('강남구').xs('내과')
df1.loc[[('강남구', '내과')],:]
df1.loc[[('강남구', '내과')],:]
Out[637]:
2013 2012 ... 2010 2009
4 3 2 1 4 3 ... 2 1 4 3 2 1
시군구명칭 표시과목 ...
강남구 내과 79 78 78 78 77.0 74.0 ... 73.0 72.0 71.0 71.0 72.0 71.0
-03 연산
df.sum()
df.sum(axis = 1)
df.sum()
Out[640]:
연도 구분
2024 상반기 28
하반기 32
2025 상반기 36
하반기 40
dtype: int64
df.sum(axis = 1)
Out[641]:
지역 지점
서울 C1 10
C2 26
경기 C1 42
C2 58
dtype: int64
df.sum(level = 1) # 수학통계메서드로는 level 연산 불가 -> groupby
TypeError: sum() got an unexpected keyword argument 'level'
df.groupby(axis=0, level=0).sum() # 지역별 총합
df.groupby(axis=0, level=0).sum()
C:\Users\-\Temp\ipykernel_12988\2083092394.py:1: FutureWarning: The 'axis' keyword in DataFrame.groupby is deprecated and will be removed in a future version.
df.groupby(axis=0, level=0).sum()
Out[645]:
연도 2024 2025
구분 상반기 하반기 상반기 하반기
지역
경기 22 24 26 28
서울 6 8 10 12
df.groupby(axis=1, level=0).sum() # 연도별 총합
=> df.T.groupby(level=0).sum().T
=> 행렬전치를 사용한 코드 작성을 추천하고 있다.
df.groupby(axis=1, level=0).sum()
C:\Users\-\ipykernel_12988\997034833.py:1: FutureWarning: DataFrame.groupby with axis=1 is deprecated. Do `frame.T.groupby(...)` without axis instead.
df.groupby(axis=1, level=0).sum()
Out[646]:
연도 2024 2025
지역 지점
서울 C1 3 7
C2 11 15
경기 C1 19 23
C2 27 31
05 multi - level index의 처리
-01 drop
df1.drop('계', axis=0, level=1)
df1.drop('계', axis=0, level=1)
Out[647]:
2013 2012 ... 2010 2009
4 3 2 1 4 ... 1 4 3 2 1
시군구명칭 표시과목 ...
강남구 내과 79 78 78 78 77.0 ... 72.0 71.0 71.0 72.0 71.0
신경과 6 6 6 6 6.0 ... 5.0 5.0 5.0 6.0 6.0
정신건강의학과 40 41 41 40 39.0 ... 41.0 40.0 42.0 42.0 40.0
외과 25 25 24 26 26.0 ... 21.0 20.0 19.0 18.0 18.0
정형외과 28 28 28 28 28.0 ... 25.0 26.0 25.0 26.0 26.0
... .. .. .. ... ... ... ... ... ... ...
금천구 핵의학과 0 0 0 0 0.0 ... 0.0 0.0 0.0 0.0 0.0
가정의학과 0 0 0 0 0.0 ... 1.0 1.0 1.0 1.0 1.0
예방의학과 0 0 0 0 NaN ... NaN NaN NaN NaN NaN
전문과목미표시전문의 29 29 29 30 30.0 ... 27.0 26.0 26.0 25.0 25.0
일반의 9 9 11 10 11.0 ... 8.0 9.0 10.0 10.0 10.0
-02 sort_index
df1.sort_index(axis=1, level=1) # 분기별로만 정렬되어서 출력 (1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4)
df1.sort_index(axis=1, level=0) # 연도별, 분기별 정렬
df1.sort_index(axis=1, level=[0,1])
df1.sort_index(axis=1, level=0)
Out[664]:
2009 ... 2013
1 2 3 4 ... 1 2 3 4
시군구명칭 표시과목 ...
강남구 계 1097.0 1121.0 1135.0 1155.0 ... 1322 1349 1344 1343
내과 71.0 72.0 71.0 71.0 ... 78 78 78 79
신경과 6.0 6.0 5.0 5.0 ... 6 6 6 6
정신건강의학과 40.0 42.0 42.0 40.0 ... 40 41 41 40
외과 18.0 18.0 19.0 20.0 ... 26 24 25 25
... ... ... ... ... ... ... ... ...
금천구 핵의학과 0.0 0.0 0.0 0.0 ... 0 0 0 0
가정의학과 1.0 1.0 1.0 1.0 ... 0 0 0 0
예방의학과 NaN NaN NaN NaN ... 0 0 0 0
전문과목미표시전문의 25.0 25.0 26.0 26.0 ... 30 29 29 29
일반의 10.0 10.0 10.0 9.0 ... 10 11 9 9
df1.sort_index(axis=1, level=[0,1], ascending = [False, True]) # 연도별 내림차순, 분기별 오름차순 정렬
Out[665]:
2013 ... 2009
1 2 3 4 ... 1 2 3 4
시군구명칭 표시과목 ...
강남구 계 1322 1349 1344 1343 ... 1097.0 1121.0 1135.0 1155.0
내과 78 78 78 79 ... 71.0 72.0 71.0 71.0
신경과 6 6 6 6 ... 6.0 6.0 5.0 5.0
정신건강의학과 40 41 41 40 ... 40.0 42.0 42.0 40.0
외과 26 24 25 25 ... 18.0 18.0 19.0 20.0
... ... ... ... ... ... ... ... ...
금천구 핵의학과 0 0 0 0 ... 0.0 0.0 0.0 0.0
가정의학과 0 0 0 0 ... 1.0 1.0 1.0 1.0
예방의학과 0 0 0 0 ... NaN NaN NaN NaN
전문과목미표시전문의 30 29 29 29 ... 25.0 25.0 26.0 26.0
일반의 10 11 9 9 ... 10.0 10.0 10.0 9.0
-03 swaplevel
df1.T # 행, 열 전치
Out[666]:
시군구명칭 강남구 ... 금천구
표시과목 계 내과 신경과 정신건강의학과 외과 ... 핵의학과 가정의학과 예방의학과 전문과목미표시전문의 일반의
2013 4 1343.0 79.0 6.0 40.0 25.0 ... 0.0 0.0 0.0 29.0 9.0
3 1344.0 78.0 6.0 41.0 25.0 ... 0.0 0.0 0.0 29.0 9.0
2 1349.0 78.0 6.0 41.0 24.0 ... 0.0 0.0 0.0 29.0 11.0
1 1322.0 78.0 6.0 40.0 26.0 ... 0.0 0.0 0.0 30.0 10.0
2012 4 1301.0 77.0 6.0 39.0 26.0 ... 0.0 0.0 NaN 30.0 11.0
3 1299.0 74.0 6.0 40.0 26.0 ... 0.0 0.0 NaN 30.0 11.0
2 1295.0 74.0 7.0 39.0 24.0 ... 0.0 0.0 NaN 29.0 12.0
1 1277.0 74.0 5.0 37.0 24.0 ... 0.0 0.0 NaN 29.0 11.0
2011 4 1271.0 73.0 5.0 37.0 25.0 ... 0.0 0.0 NaN 30.0 9.0
3 1253.0 73.0 5.0 37.0 27.0 ... 0.0 0.0 NaN 31.0 11.0
2 1303.0 76.0 5.0 39.0 25.0 ... 0.0 0.0 NaN 31.0 11.0
1 1286.0 77.0 5.0 39.0 25.0 ... 0.0 0.0 NaN 31.0 11.0
2010 4 1247.0 74.0 5.0 38.0 24.0 ... 0.0 0.0 NaN 28.0 11.0
3 1233.0 74.0 5.0 38.0 25.0 ... 0.0 0.0 NaN 28.0 10.0
2 1214.0 73.0 5.0 39.0 22.0 ... 0.0 1.0 NaN 27.0 9.0
1 1176.0 72.0 5.0 41.0 21.0 ... 0.0 1.0 NaN 27.0 8.0
2009 4 1155.0 71.0 5.0 40.0 20.0 ... 0.0 1.0 NaN 26.0 9.0
3 1135.0 71.0 5.0 42.0 19.0 ... 0.0 1.0 NaN 26.0 10.0
2 1121.0 72.0 6.0 42.0 18.0 ... 0.0 1.0 NaN 25.0 10.0
1 1097.0 71.0 6.0 40.0 18.0 ... 0.0 1.0 NaN 25.0 10.0
df1.T # 행, 열 전치
df1.swaplevel(i, # 첫 번째에 위치할 레벨의 이름 또는 번호
j, # 두 번째에 위치할 레벨의 이름 또는 번호
axis=0) # 전치방향
df1.swaplevel(0,1) # 전치의 의미가 없음 (상위레벨이 정렬되지 않았으므로)
df1.swaplevel(0,1)
Out[669]:
2013 ... 2009
4 3 2 1 ... 4 3 2 1
표시과목 시군구명칭 ...
계 강남구 1343 1344 1349 1322 ... 1155.0 1135.0 1121.0 1097.0
내과 강남구 79 78 78 78 ... 71.0 71.0 72.0 71.0
신경과 강남구 6 6 6 6 ... 5.0 5.0 6.0 6.0
정신건강의학과 강남구 40 41 41 40 ... 40.0 42.0 42.0 40.0
외과 강남구 25 25 24 26 ... 20.0 19.0 18.0 18.0
... ... ... ... ... ... ... ... ...
핵의학과 금천구 0 0 0 0 ... 0.0 0.0 0.0 0.0
가정의학과 금천구 0 0 0 0 ... 1.0 1.0 1.0 1.0
예방의학과 금천구 0 0 0 0 ... NaN NaN NaN NaN
전문과목미표시전문의 금천구 29 29 29 30 ... 26.0 26.0 25.0 25.0
일반의 금천구 9 9 11 10 ... 9.0 10.0 10.0 10.0
df1.sort_index(level=[1,0]).swaplevel(0,1) # 정상적으로 리턴됨
df1.sort_index(level=[1,0])
Out[671]:
2013 2012 ... 2010 2009
4 3 2 1 4 3 ... 2 1 4 3 2 1
시군구명칭 표시과목 ...
강남구 가정의학과 7 7 7 8 8.0 8.0 ... 10.0 9.0 8.0 8.0 8.0 8.0
강동구 가정의학과 5 5 5 5 5.0 5.0 ... 5.0 4.0 4.0 4.0 5.0 5.0
강북구 가정의학과 1 1 1 1 1.0 1.0 ... 4.0 4.0 4.0 4.0 4.0 4.0
강서구 가정의학과 19 19 18 17 17.0 17.0 ... 18.0 18.0 18.0 18.0 17.0 17.0
관악구 가정의학과 6 6 6 6 6.0 6.0 ... 6.0 7.0 7.0 7.0 7.0 7.0
... .. .. .. ... ... ... ... ... ... ... ... ...
용산구 흉부외과 0 0 0 0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0
은평구 흉부외과 0 0 0 0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0
종로구 흉부외과 0 0 0 0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0
중구 흉부외과 0 0 0 0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0
중랑구 흉부외과 0 0 0 0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0
[650 rows x 20 columns]
df1.sort_index(level=[1,0]).swaplevel(0,1)
Out[672]:
2013 2012 ... 2010 2009
4 3 2 1 4 3 ... 2 1 4 3 2 1
표시과목 시군구명칭 ...
가정의학과 강남구 7 7 7 8 8.0 8.0 ... 10.0 9.0 8.0 8.0 8.0 8.0
강동구 5 5 5 5 5.0 5.0 ... 5.0 4.0 4.0 4.0 5.0 5.0
강북구 1 1 1 1 1.0 1.0 ... 4.0 4.0 4.0 4.0 4.0 4.0
강서구 19 19 18 17 17.0 17.0 ... 18.0 18.0 18.0 18.0 17.0 17.0
관악구 6 6 6 6 6.0 6.0 ... 6.0 7.0 7.0 7.0 7.0 7.0
... .. .. .. ... ... ... ... ... ... ... ... ...
흉부외과 용산구 0 0 0 0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0
은평구 0 0 0 0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0
종로구 0 0 0 0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0
중구 0 0 0 0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0
중랑구 0 0 0 0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0
[ 연습문제 ]
df1에서
df1.drop('계', axis=0, level=1)
1) 구별 병원개수 총합
df1.groupby(axis=0, level = 0).sum()
Out[659]:
2013 2012 ... 2010 2009
4 3 2 1 4 ... 1 4 3 2 1
시군구명칭 ...
강남구 2686 2688 2698 2644 2602.0 ... 2352.0 2310.0 2270.0 2242.0 2194.0
강동구 674 666 662 650 650.0 ... 634.0 628.0 632.0 620.0 614.0
강북구 414 418 422 430 430.0 ... 442.0 436.0 428.0 428.0 424.0
강서구 626 626 634 624 624.0 ... 624.0 616.0 612.0 600.0 594.0
관악구 602 608 612 608 612.0 ... 624.0 610.0 610.0 604.0 608.0
광진구 502 498 496 490 488.0 ... 474.0 472.0 458.0 452.0 450.0
구로구 474 474 474 464 458.0 ... 464.0 464.0 460.0 456.0 450.0
금천구 264 262 264 266 270.0 ... 254.0 256.0 252.0 248.0 250.0
노원구 648 644 646 642 640.0 ... 660.0 652.0 646.0 638.0 624.0
도봉구 296 298 292 292 294.0 ... 310.0 306.0 306.0 310.0 310.0
동대문구 470 468 466 462 470.0 ... 484.0 488.0 484.0 474.0 480.0
동작구 476 480 478 478 478.0 ... 482.0 482.0 476.0 468.0 468.0
마포구 606 604 598 594 588.0 ... 562.0 564.0 562.0 556.0 550.0
서대문구 382 382 370 372 374.0 ... 382.0 382.0 396.0 392.0 400.0
서초구 1102 1088 1082 1074 1078.0 ... 954.0 938.0 922.0 916.0 900.0
성동구 338 342 346 344 338.0 ... 332.0 336.0 334.0 342.0 348.0
성북구 534 524 532 534 534.0 ... 522.0 524.0 530.0 532.0 528.0
송파구 880 872 878 880 866.0 ... 840.0 834.0 830.0 824.0 816.0
양천구 516 520 520 528 530.0 ... 514.0 514.0 512.0 506.0 510.0
영등포구 574 586 588 576 578.0 ... 578.0 564.0 554.0 552.0 548.0
용산구 222 224 228 228 234.0 ... 222.0 224.0 224.0 224.0 226.0
은평구 544 542 536 530 526.0 ... 510.0 502.0 504.0 508.0 504.0
종로구 330 338 348 346 346.0 ... 346.0 340.0 336.0 326.0 324.0
중구 422 420 424 428 420.0 ... 402.0 402.0 406.0 414.0 410.0
중랑구 428 422 420 422 426.0 ... 442.0 440.0 440.0 440.0 440.0
2) 연도별 병원개수 총합
df1.groupby(axis=1, level=0).sum()
Out[657]:
2009 2010 2011 2012 2013
시군구명칭 표시과목
강남구 계 4508.0 4870.0 5113.0 5172.0 5358.0
내과 285.0 293.0 299.0 299.0 313.0
신경과 22.0 20.0 20.0 24.0 24.0
정신건강의학과 164.0 156.0 152.0 155.0 162.0
외과 75.0 92.0 102.0 100.0 100.0
... ... ... ... ...
금천구 핵의학과 0.0 0.0 0.0 0.0 0.0
가정의학과 4.0 2.0 0.0 0.0 0.0
예방의학과 0.0 0.0 0.0 0.0 0.0
전문과목미표시전문의 102.0 110.0 123.0 118.0 117.0
일반의 39.0 38.0 42.0 45.0 39.0
3) 표시과목별 연도별 총합
df1.groupby(axis=0, level=1).sum().groupby(axis=1, level=0).sum()
Out[656]:
2009 2010 2011 2012 2013
표시과목
가정의학과 752.0 758.0 725.0 704.0 731.0
결핵과 0.0 0.0 0.0 0.0 0.0
계 28255.0 29126.0 29560.0 29734.0 29962.0
내과 3543.0 3644.0 3697.0 3723.0 3788.0
마취통증의학과 505.0 547.0 598.0 646.0 695.0
병리과 20.0 26.0 25.0 30.0 28.0
비뇨기과 948.0 951.0 952.0 925.0 910.0
산부인과 1838.0 1796.0 1748.0 1683.0 1602.0
성형외과 1450.0 1550.0 1616.0 1631.0 1701.0
소아청소년과 2068.0 2099.0 2087.0 2067.0 2077.0
신경과 120.0 135.0 142.0 146.0 154.0
신경외과 198.0 207.0 212.0 204.0 197.0
안과 1562.0 1589.0 1604.0 1611.0 1616.0
영상의학과 220.0 212.0 196.0 189.0 182.0
예방의학과 0.0 0.0 0.0 0.0 2.0
외과 774.0 806.0 813.0 802.0 790.0
이비인후과 2095.0 2162.0 2239.0 2273.0 2290.0
일반의 2327.0 2390.0 2366.0 2430.0 2468.0
재활의학과 365.0 370.0 374.0 382.0 376.0
전문과목미표시전문의 5275.0 5609.0 5794.0 5856.0 5891.0
정신건강의학과 984.0 957.0 956.0 963.0 985.0
정형외과 1668.0 1692.0 1720.0 1710.0 1722.0
진단검사의학과 24.0 24.0 22.0 19.0 16.0
피부과 1493.0 1576.0 1644.0 1714.0 1713.0
핵의학과 0.0 0.0 0.0 0.0 0.0
흉부외과 26.0 26.0 30.0 26.0 28.0'아이티윌_데이터 분석 55기 > 강의내용 필기_Python' 카테고리의 다른 글
| #11 11일차_다양햔 replace 형태, long <-> wide 변환 (0) | 2026.05.26 |
|---|---|
| #9 9일차_ multi - level index 실습 (0) | 2026.05.21 |
| #7 7일차_논리연산자/포함연산자, pandas index 설정, pandas 정렬, 벡터화 내장된 문자열 메서드, idxmax / idxmin (0) | 2026.05.19 |
| #6 6일차_pd의 행·열 결합 / 수학 및 통계 함수·메서드 / 결측치 처리 (0) | 2026.05.18 |
| #5 5일차_형 변환 함수/매서드, SQL사용, DB 연동, array (0) | 2026.05.15 |