지속가능 발전과 대한민국 인구소멸

공공데이터포털 주민등록 인구데이터를 활용해 2005~2025년 변화를 분석하고, 2035년까지 추세선을 예측하여 지역 지속가능 정책을 설계하는 데이터 과학 프로젝트

1. 프로젝트 목표

기준연도는 2025년으로 설정합니다. 과거 20년은 2005~2025년, 미래 10년은 2026~2035년입니다. 전국 및 시도별 주민등록 인구 변화율을 계산하고, 선형 추세선으로 미래 인구를 예측합니다.

SDGs 11 지속가능한 도시SDGs 3 건강과 복지SDGs 4 교육SDGs 8 양질의 일자리SDGs 10 불평등 완화

2. 활용 데이터

추천 데이터: 행정안전부_통계연보_연도별 주민등록인구

공공데이터포털에서 활용신청 후 발급받은 일반 인증키를 SERVICE_KEY에 입력합니다.

  • 출처: 공공데이터포털(data.go.kr)
  • 제공기관: 행정안전부
  • 주요 항목: 연도, 서울, 부산, 대구, 인천, 대전, 세종, 경기, 강원, 충북, 충남, 전북, 전남, 경북, 경남, 제주 등
  • 분석 기간: 2005년~2025년
  • 예측 기간: 2026년~2035년

주의

공공데이터포털 API는 서비스별 요청 URL, 파라미터명, 응답 XML 태그명이 조금씩 다릅니다. 아래 코드는 자동 태그 탐색 함수를 넣어 두어 XML 구조가 조금 달라도 최대한 DataFrame으로 변환되도록 만들었습니다.

인증키 오류가 나면 “활용신청 승인”, “일반 인증키/디코딩 인증키”, “요청 주소”를 확인하세요.

3. 파이썬 분석 코드

# 지속가능 발전과 대한민국 인구소멸 분석
# 기준: 2025년 / 과거 20년: 2005~2025 / 미래 10년: 2026~2035
# 필요 라이브러리: pandas, numpy, matplotlib, requests

import requests
import xml.etree.ElementTree as ET
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

plt.rcParams["font.family"] = "Malgun Gothic"   # Windows: 맑은 고딕
plt.rcParams["axes.unicode_minus"] = False
plt.rcParams["figure.dpi"] = 130

# 1) 공공데이터포털 인증키 입력
SERVICE_KEY = "여기에_공공데이터포털_인증키를_붙여넣으세요"

# 2) 공공데이터포털 API 주소
# 공공데이터포털 > 행정안전부_통계연보_연도별 주민등록인구 > 상세기능 > 요청주소를 확인해 교체 가능
BASE_URL = "https://apis.data.go.kr/1741000/ResidentPopulationByYear/getResidentPopulationByYear"

params = {
    "serviceKey": SERVICE_KEY,
    "pageNo": 1,
    "numOfRows": 100,
    "type": "xml"
}

# 3) XML 응답을 DataFrame으로 바꾸는 함수
def xml_to_dataframe(xml_text):
    root = ET.fromstring(xml_text)
    rows = []

    # item, row 태그를 모두 후보로 탐색
    candidates = []
    for tag in ["item", "row"]:
        candidates.extend(root.findall(f".//{tag}"))

    # item/row가 없으면 하위 노드 중 자식이 많은 노드를 후보로 사용
    if not candidates:
        candidates = [node for node in root.iter() if len(list(node)) >= 3]

    for item in candidates:
        record = {}
        for child in list(item):
            record[child.tag] = child.text
        if record:
            rows.append(record)

    return pd.DataFrame(rows).drop_duplicates()

# 4) API 호출
res = requests.get(BASE_URL, params=params, timeout=20)
res.raise_for_status()

df_raw = xml_to_dataframe(res.text)
print("원본 컬럼:", df_raw.columns.tolist())
print(df_raw.head())

# 5) 컬럼명 자동 정리
# 실제 API 컬럼명이 다르면 아래 후보 목록에 컬럼명을 추가하세요.
year_candidates = ["year", "statsYear", "stdrYear", "연도", "통계연도"]
region_candidates = ["region", "ctpv", "sido", "시도", "지역", "구분"]
pop_candidates = ["population", "totPop", "totalPopulation", "인구수", "총인구수", "계"]

def find_col(df, candidates):
    lower_map = {c.lower(): c for c in df.columns}
    for cand in candidates:
        if cand in df.columns:
            return cand
        if cand.lower() in lower_map:
            return lower_map[cand.lower()]
    return None

year_col = find_col(df_raw, year_candidates)
region_col = find_col(df_raw, region_candidates)
pop_col = find_col(df_raw, pop_candidates)

# 6) 넓은 형태 자료 처리: 연도 컬럼 + 지역별 컬럼 형태인 경우
if year_col and not region_col:
    df = df_raw.copy()
    df[year_col] = pd.to_numeric(df[year_col].astype(str).str.extract(r"(\d{4})")[0], errors="coerce")
    value_cols = [c for c in df.columns if c != year_col]
    long_df = df.melt(id_vars=year_col, value_vars=value_cols, var_name="지역", value_name="인구")
    long_df = long_df.rename(columns={year_col: "연도"})
else:
    # 긴 형태 자료 처리: 연도, 지역, 인구 컬럼이 각각 있는 경우
    long_df = df_raw.rename(columns={year_col: "연도", region_col: "지역", pop_col: "인구"})

# 7) 숫자 정리
long_df["연도"] = pd.to_numeric(long_df["연도"].astype(str).str.extract(r"(\d{4})")[0], errors="coerce")
long_df["인구"] = (
    long_df["인구"].astype(str)
    .str.replace(",", "", regex=False)
    .str.replace(" ", "", regex=False)
)
long_df["인구"] = pd.to_numeric(long_df["인구"], errors="coerce")
long_df = long_df.dropna(subset=["연도", "인구"])
long_df["연도"] = long_df["연도"].astype(int)

# 8) 분석 기간 필터링
base_year = 2025
start_year = base_year - 20
end_year = base_year + 10
past = long_df[(long_df["연도"] >= start_year) & (long_df["연도"] <= base_year)].copy()

# 9) 전국 합계 만들기
national = past.groupby("연도", as_index=False)["인구"].sum()
national["지역"] = "전국"

# 10) 지역 선택: 전국, 전북, 서울, 경기 예시
selected_regions = ["전국", "전북", "전라북도", "서울", "서울특별시", "경기", "경기도"]
plot_df = pd.concat([national, past], ignore_index=True)
plot_df = plot_df[plot_df["지역"].isin(selected_regions)].copy()

# 11) 지역별 추세선 예측 함수
def make_forecast(data, region_name):
    d = data[data["지역"] == region_name].sort_values("연도")
    if len(d) < 2:
        return None

    x = d["연도"].to_numpy()
    y = d["인구"].to_numpy()

    # 1차 선형 회귀: y = ax + b
    a, b = np.polyfit(x, y, 1)

    years = np.arange(start_year, end_year + 1)
    pred = a * years + b

    result = pd.DataFrame({
        "연도": years,
        "예측인구": pred,
        "지역": region_name,
        "기울기_연평균증감": a
    })
    return result

forecasts = []
for region in plot_df["지역"].unique():
    f = make_forecast(plot_df, region)
    if f is not None:
        forecasts.append(f)

forecast_df = pd.concat(forecasts, ignore_index=True)

# 12) 시각화: 전국 추세선
region = "전국"
actual = plot_df[plot_df["지역"] == region]
pred = forecast_df[forecast_df["지역"] == region]

plt.figure(figsize=(10, 5.8))
plt.plot(actual["연도"], actual["인구"], marker="o", linewidth=2.5, label="실제 인구")
plt.plot(pred["연도"], pred["예측인구"], linestyle="--", linewidth=2.5, label="추세선 예측")
plt.axvline(2025, linestyle=":", linewidth=2, label="기준연도 2025")
plt.title("대한민국 주민등록 인구 추세와 2035년 예측")
plt.xlabel("연도")
plt.ylabel("인구")
plt.grid(True, linestyle=":", alpha=0.5)
plt.legend()
plt.tight_layout()
plt.savefig("korea_population_trend_2035.png")
plt.show()

# 13) 지역별 감소 위험도 계산
region_summary = []
for region in plot_df["지역"].unique():
    d = plot_df[plot_df["지역"] == region]
    f = forecast_df[forecast_df["지역"] == region]
    if d.empty or f.empty:
        continue

    pop_2005 = d.loc[d["연도"].idxmin(), "인구"]
    pop_2025 = d.loc[d["연도"].idxmax(), "인구"]
    pop_2035 = f[f["연도"] == 2035]["예측인구"].iloc[0]
    slope = f["기울기_연평균증감"].iloc[0]

    past_rate = (pop_2025 - pop_2005) / pop_2005 * 100
    future_rate = (pop_2035 - pop_2025) / pop_2025 * 100

    if future_rate <= -10:
        risk = "고위험"
    elif future_rate <= -5:
        risk = "주의"
    else:
        risk = "상대안정"

    region_summary.append({
        "지역": region,
        "2005인구": round(pop_2005),
        "2025인구": round(pop_2025),
        "2035예측": round(pop_2035),
        "2005_2025변화율(%)": round(past_rate, 2),
        "2025_2035예측변화율(%)": round(future_rate, 2),
        "연평균증감": round(slope),
        "위험도": risk
    })

summary_df = pd.DataFrame(region_summary).sort_values("2025_2035예측변화율(%)")
print(summary_df)
summary_df.to_csv("population_extinction_summary.csv", index=False, encoding="utf-8-sig")

# 14) 정책 제안 자동 문장 만들기
def policy_message(row):
    if row["위험도"] == "고위험":
        return "생활인구 유입, 청년 주거, 지역대학-기업 연계, 의료·돌봄 거점 확충이 시급합니다."
    elif row["위험도"] == "주의":
        return "일자리 질 개선, 교통 접근성 강화, 보육·교육 인프라 유지 정책이 필요합니다."
    else:
        return "인구 집중에 따른 주거·교통·환경 부담을 줄이는 지속가능 도시정책이 필요합니다."

summary_df["정책제안"] = summary_df.apply(policy_message, axis=1)
print(summary_df[["지역", "위험도", "정책제안"]])

4. 분석 인사이트 예시

  1. 총량 감소: 전국 인구가 감소 추세이면 노동력, 소비시장, 병역자원, 지방재정 기반이 함께 약화될 수 있습니다.
  2. 지역 격차: 수도권은 상대적으로 안정적이지만 비수도권 일부 지역은 청년 유출과 고령화가 동시에 진행될 수 있습니다.
  3. 학교와 지역: 학령인구 감소는 학교 통폐합, 지역 교육격차, 지역대학 위기로 이어질 수 있습니다.
  4. 돌봄 수요 증가: 인구 감소 지역일수록 의료·교통·돌봄 접근성이 지속가능성의 핵심 지표가 됩니다.

핵심 질문

“사람이 줄어드는 지역을 어떻게 살기 좋은 지역으로 바꿀 것인가?”

인구소멸 문제는 단순히 출생률 문제가 아니라 일자리, 주거, 교육, 교통, 의료, 문화, 기후위기 대응이 연결된 지속가능 발전 문제입니다.

5. 정책 개발안: 지역소멸 대응 5대 패키지

① 청년 정착
월세·창업·원격근무
② 교육 유지
작은학교+AI 원격수업
③ 의료·돌봄
공공의료 버스·방문돌봄
④ 생활인구
워케이션·관계인구

정책 1. 청년 로컬 정착 바우처

지역 기업 취업, 창업, 농생명·에너지·AI 분야 프로젝트 참여 청년에게 주거비와 교육비를 연계 지원합니다.

정책 2. 학교-지역대학-기업 연계 캠퍼스

고등학교, 지역대학, 공공기관, 기업이 함께 데이터 분석·AI·스마트팜·재생에너지 프로젝트를 운영합니다.

정책 3. 15분 생활권 의료·돌봄망

인구가 적은 읍면 지역에도 이동형 진료, 원격진료 보조, 고령자 교통 서비스를 제공해 삶의 질을 보장합니다.

정책 4. 생활인구 플랫폼

관광객이 아니라 정기적으로 지역을 방문하고 소비·학습·봉사·근무하는 관계인구를 데이터로 관리합니다.

정책 5. 빈집·폐교 재생

빈집은 청년 주거와 창업 공간으로, 폐교는 지역 과학·문화·돌봄 복합센터로 전환합니다.

데이터로 보는 대한민국 인구소멸과 지속가능 발전

2005년부터 2025년까지의 주민등록 인구 변화를 분석하고, 2035년까지의 추세를 예측합니다.

2005~2025

과거 20년 변화

2025

기준연도

2035

미래 10년 예측

문제

청년 유출 → 출생 감소 → 학교·상권 축소 → 의료·교통 약화 → 추가 유출의 악순환

해결 방향

인구를 억지로 늘리는 정책보다 살고 싶고 머물고 싶은 지역을 만드는 정책이 필요합니다.

우리의 제안

청년 정착 + 교육 혁신 + 의료·돌봄 + 생활인구 + 빈집 재생을 결합한 지역 지속가능 발전 모델

6. 수행평가 기준 예시