파이썬으로 주민등록인구 데이터 조회하기

PNG

Python 라이브러리 PublicDataReader를 이용하면 최신 지역별 주민등록인구 데이터를 쉽게 가져올 수 있다. 해당 데이터는 국가통계포털(KOSIS) 웹 사이트에 접속해 직접 조회할 수도 있지만, KOSIS 공유서비스 Open API를 이용해서도 조회할 수 있다. PublicDataReader는 KOSIS 공유서비스 Open API의 데이터 조회 기능을 포함하고 있어, 이를 활용하면 원하는 데이터를 쉽게 찾고 조회할 수 있다. KOSIS 공유서비스 Open API 신청 방법과 PublicDataReader에서 제공하는 KOSIS 공유서비스 Open API의 모든 기능을 살펴보려면 Python으로 KOSIS 데이터 조회하기를 참고하면 된다. 여기서는 주민등록인구 데이터를 조회하는 방법을 다루기로 한다.


설치하기

  • 운영체제(OS)에 따라 아래 중 하나를 선택한다.
    • Windows: CMD(명령 프롬프트) 실행
    • Mac: Terminal(터미널) 실행

아래 Shell 명령어를 입력 후 실행한다.

pip install PublicDataReader --upgrade


라이브러리 임포트하기

앞에서 설치한 PublicDataReader에서 Kosis 클래스를 임포트한다. KOSIS 공유서비스에서 발급받은 오픈 API 사용자 인증키 정보를 service_key 변수에 할당한다. Kosis의 인자료 service_key를 입력하여 데이터 조회 인스턴스 api를 만든다.

from PublicDataReader import Kosis

# KOSIS 공유서비스 Open API 사용자 인증키
service_key = "사용자 인증키"

# 인스턴스 생성하기
api = Kosis(service_key)


조회할 데이터 찾기

api.get_data() 메서드의 첫 번째 인자로 ‘KOSIS통합검색’을 지정한다. searchNm에는 조회할 데이터를 찾기 위한 키워드를 입력한다. 반환된 데이터프레임에서 조회할 데이터를 찾아 기관ID(ORG_ID)통계표ID(TBL_ID) 값을 확인한다. ‘행정구역(읍면동)별/5세별 주민등록인구(2011년~)’ 데이터의 기관ID101이고, 통계표IDDT_1B04005N 이므로 이 값들을 데이터를 조회할 때 사용한다. 참고로 api.get_data() 메서드에 translate=False 옵션을 지정하면 영문 컬럼명으로 데이터를 조회할 수 있다. 이 인자의 기본값은 True이므로 국문 컬럼명으로 조회한다.

df = api.get_data(
    "KOSIS통합검색",
    searchNm="읍면동 주민등록 인구"
)
df.head(1)
기관ID 기관명 통계표ID 통계표명 조사ID 조사명 KOSIS목록구분 KOSIS통계표위치 통계표위치 통계표주요내용 수록기간시작일 수록기간종료일 통계표주석 추천통계표여부 KOSIS목록URL KOSIS통계표URL 검색결과건수 검색어명
0 101 행정안전부 DT_1B04005N 행정구역(읍면동)별/5세별 주민등록인구(2011년~) 2008001 주민등록인구현황 MT_ZTITLE 인구 > 주민등록인구현황 A > A_7 행정구역(동읍면)별 5세별 남자인구수 여자인구수 총인구수 개포3동 신당제4동 중림동... 2011 2022 * 등록구분의 "전체"는 "거주자", "거주불명자", "재외국민"이 포함된 자료입니... N https://kosis.kr/statisticsList/statisticsList... http://kosis.kr/statHtml/statHtml.do?orgId=101... 573 읍면동 주민등록 인구


데이터 수록 주기와 시점 확인

api.get_data() 메서드의 첫 번째 인자로 ‘통계표설명’을 지정한다. 통계표설명의 경우 상세기능도 추가적으로 지정해야 한다. 두 번째 인자로 ‘자료갱신일’을 입력하고, 위에서 복사해둔 기관ID와 통계표ID의 값들을 api.get_data()의 인자로 입력해 데이터 수록주기와 수록시점을 확인한다. 수록주기(PRD_SE) 별 최근 수록시점(PRD_DE) 값을 조회하면 수록주기가 년인 경우는 2022년, 수록주기가 월인 경우는 2022년 11월이 최신 데이터임을 알 수 있다.

df = api.get_data(
    "통계표설명",
    "자료갱신일",
    orgId="101",
    tblId="DT_1B04005N"
)

df.groupby(by=['수록주기']).agg({"수록시점": ["min", "max"]})
수록시점
min max
수록주기
2011 2022
201207 202212


데이터 항목 및 분류 확인하기

api.get_data() 메서드의 첫 번째 인자로 ‘통계표설명’을 지정한다. 두 번째 인자로 ‘분류항목’을 입력하고, 이번에도 기관ID와 통계표ID를 api.get_data()의 인자로 입력해 결과를 확인한다. 분류ID의 값이 ‘ITEM’ 이면 항목을 뜻하고 이 때, 분류값ID의 값을 통계자료 조회 시 itmId의 값으로 입력한다. 분류ID 값이 ITEM 이 아니고, 분류값순번 값에 숫자가 입력되어 있는 경우 이는 분류를 뜻하고, 분류값순번의 숫자 값이 분류 수준을 뜻한다. 예를 들어, 분류ID 값이 A이고, 분류값순번 값이 1이라면, 분류ID 값을 통계자료 조회 시 objL1의 값으로 입력한다.

item = api.get_data(
    "통계표설명",
    "분류항목",
    orgId="101",
    tblId="DT_1B04005N",
)
item.head()
기관ID 통계표ID 코드ID 코드명 분류ID 분류명 분류영문명 분류값ID 분류값명 분류값영문명 상위분류값ID 분류값순번 CD_ENG_NM
0 101 DT_1B04005N 14STD04553 ITEM 항목 Item code list T2 총인구수 Population NaN NaN Person
1 101 DT_1B04005N 14STD04553 ITEM 항목 Item code list T3 남자인구수 Male NaN NaN Person
2 101 DT_1B04005N 14STD04553 ITEM 항목 Item code list T4 여자인구수 Female NaN NaN Person
3 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 00 전국 Whole country NaN 1 NaN
4 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 11 서울특별시 Seoul NaN 1 NaN

통계표 조회 시 항목은 총인구수, 남자인구수 그리고 여자인구수 모두 사용하기로 한다. 분류값ID의 값인 T2, T3 그리고 T4를 모두 복사해둔다.

item.loc[item["분류ID"]=="ITEM"]
기관ID 통계표ID 코드ID 코드명 분류ID 분류명 분류영문명 분류값ID 분류값명 분류값영문명 상위분류값ID 분류값순번 CD_ENG_NM
0 101 DT_1B04005N 14STD04553 ITEM 항목 Item code list T2 총인구수 Population NaN NaN Person
1 101 DT_1B04005N 14STD04553 ITEM 항목 Item code list T3 남자인구수 Male NaN NaN Person
2 101 DT_1B04005N 14STD04553 ITEM 항목 Item code list T4 여자인구수 Female NaN NaN Person

분류1의 경우 전체 선택하기로 한다. 분류값ID를 일부 선택하려면 ‘00 11 11110’ 과 같이 공백으로 구분해 입력해야 하지만 전체 선택의 경우 ‘ALL’ 이라고 입력한다. 여기에서는 종류가 많으므로 직접 값을 복사하지 않고 넘어간다.

item.loc[item["분류ID"]=="A"]
기관ID 통계표ID 코드ID 코드명 분류ID 분류명 분류영문명 분류값ID 분류값명 분류값영문명 상위분류값ID 분류값순번 CD_ENG_NM
3 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 00 전국 Whole country NaN 1 NaN
4 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 11 서울특별시 Seoul NaN 1 NaN
5 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 11110 종로구 Jongno-gu 11 1 NaN
6 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 1111051500 청운효자동 Cheongunhyoja-dong 11110 1 NaN
7 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 1111053000 사직동 Sajik-dong 11110 1 NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ...
4182 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 5013058000 서홍동 Seohong-dong 50130 1 NaN
4183 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 5013059000 대륜동 Daeryun-dong 50130 1 NaN
4184 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 5013060000 대천동 Daecheon-dong 50130 1 NaN
4185 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 5013061000 중문동 Jungmun-dong 50130 1 NaN
4186 101 DT_1B04005N NaN NaN A 행정구역(동읍면)별 By Administrative District 5013062000 예래동 Yerae-dong 50130 1 NaN

4184 rows × 13 columns

분류2의 경우 연령별 구분은 사용하지 않고 총계만 조회하기로 한다. 따라서 분류값ID 값이 0인 경우만 해당하므로 0을 복사해둔다.

item.loc[item["분류ID"]=="B"]
기관ID 통계표ID 코드ID 코드명 분류ID 분류명 분류영문명 분류값ID 분류값명 분류값영문명 상위분류값ID 분류값순번 CD_ENG_NM
4187 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 0 Total NaN 2 NaN
4188 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 5 0 - 4세 0-4 Years old NaN 2 NaN
4189 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 10 5 - 9세 5-9 Years old NaN 2 NaN
4190 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 15 10 - 14세 10-14 Years old NaN 2 NaN
4191 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 20 15 - 19세 15-19 Years old NaN 2 NaN
4192 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 25 20 - 24세 20-24 Years old NaN 2 NaN
4193 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 30 25 - 29세 25-29 Years old NaN 2 NaN
4194 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 35 30 - 34세 30-34 Years old NaN 2 NaN
4195 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 40 35 - 39세 35-39 Years old NaN 2 NaN
4196 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 45 40 - 44세 40-44 Years old NaN 2 NaN
4197 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 50 45 - 49세 45-49 Years old NaN 2 NaN
4198 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 55 50 - 54세 50-54 Years old NaN 2 NaN
4199 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 60 55 - 59세 55-59 Years old NaN 2 NaN
4200 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 65 60 - 64세 60-64 Years old NaN 2 NaN
4201 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 70 65 - 69세 65-69 Years old NaN 2 NaN
4202 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 75 70 - 74세 70-74 Years old NaN 2 NaN
4203 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 80 75 - 79세 75-79 Years old NaN 2 NaN
4204 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 85 80 - 84세 80-84 Years old NaN 2 NaN
4205 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 90 85 - 89세 85-89 Years old NaN 2 NaN
4206 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 95 90 - 94세 90-94 Years old NaN 2 NaN
4207 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 100 95 - 99세 95-99 Years old NaN 2 NaN
4208 101 DT_1B04005N NaN NaN B 5세별 By Age Group (Five-Year) 105 100+ 100 Years old & over NaN 2 NaN


통계표 조회하기

api.get_data() 메서드의 첫 번째 인자로 ‘통계자료’를 지정한다. 행정구역(읍면동)별/5세별 주민등록인구(2011년~) 통계표를 조회를 위해 위에서 복사해둔 값들을 순서대로 api.get_data()의 인자로 입력한다. itmId의 값으로 모든 항목값을 입력했지만, objL1과 같이 ‘ALL’이라고 입력해도 전체 선택이 된다.

df = api.get_data(
    "통계자료",
    orgId="101",
    tblId="DT_1B04005N",
    objL1="ALL",
    objL2="0",
    itmId="T2 T3 T4",
    prdSe="M",
    startPrdDe="202211",
    endPrdDe="202211",
)
df.head()
기관ID 통계표ID 통계표명 분류명1 분류영문명1 분류값명1 분류값영문명1 분류값ID1 분류명2 분류영문명2 분류값명2 분류값영문명2 분류값ID2 항목ID 항목명 항목영문명 단위명 단위영문명 수록주기 수록시점 수치값
0 101 DT_1B04005N 행정구역(읍면동)별/5세별 주민등록인구(2011년~) 행정구역(동읍면)별 By Administrative District 전국 Whole country 00 5세별 By Age Group (Five-Year) Total 0 T2 총인구수 Population Person M 202211 51450829
1 101 DT_1B04005N 행정구역(읍면동)별/5세별 주민등록인구(2011년~) 행정구역(동읍면)별 By Administrative District 전국 Whole country 00 5세별 By Age Group (Five-Year) Total 0 T3 남자인구수 Male Person M 202211 25643889
2 101 DT_1B04005N 행정구역(읍면동)별/5세별 주민등록인구(2011년~) 행정구역(동읍면)별 By Administrative District 전국 Whole country 00 5세별 By Age Group (Five-Year) Total 0 T4 여자인구수 Female Person M 202211 25806940
3 101 DT_1B04005N 행정구역(읍면동)별/5세별 주민등록인구(2011년~) 행정구역(동읍면)별 By Administrative District 서울특별시 Seoul 11 5세별 By Age Group (Five-Year) Total 0 T2 총인구수 Population Person M 202211 9436836
4 101 DT_1B04005N 행정구역(읍면동)별/5세별 주민등록인구(2011년~) 행정구역(동읍면)별 By Administrative District 서울특별시 Seoul 11 5세별 By Age Group (Five-Year) Total 0 T3 남자인구수 Male Person M 202211 4574781


피벗 테이블 만들기

통계표 조회 결과를 아래와 같이 원하는 형태로 재구조화하여 분석 목적에 맞게 사용하면 된다.

pv = df.pivot(index=["분류값ID1","분류값명1","수록시점"], columns=["항목명"], values="수치값").reset_index()
pv.columns.name = None
pv['수록시점'] = pd.to_datetime(pv['수록시점'], format="%Y%m")
numCols = ["남자인구수","여자인구수","총인구수"]
for col in numCols:
    pv[col] = pd.to_numeric(pv[col])
pv
분류값ID1 분류값명1 수록시점 남자인구수 여자인구수 총인구수
0 00 전국 2022-11-01 25643889 25806940 51450829
1 11 서울특별시 2022-11-01 4574781 4862055 9436836
2 11110 종로구 2022-11-01 68488 73162 141650
3 1111051500 청운효자동 2022-11-01 5366 6311 11677
4 1111053000 사직동 2022-11-01 4041 5065 9106
... ... ... ... ... ... ...
3853 5013058000 서홍동 2022-11-01 5555 5670 11225
3854 5013059000 대륜동 2022-11-01 7846 7734 15580
3855 5013060000 대천동 2022-11-01 7030 6828 13858
3856 5013061000 중문동 2022-11-01 6227 6055 12282
3857 5013062000 예래동 2022-11-01 1987 1896 3883

3858 rows × 6 columns


참고

댓글남기기