아프리카의 $700B 부채 위기를 모니터링하기 위해 ML 플랫폼을 구축했습니다 - 배운 점

발행: (2025년 12월 15일 오전 06:25 GMT+9)
7 min read
원문: Dev.to

Source: Dev.to

문제: 7천억 달러 규모의 블라인드 스팟

아프리카 9개국이 현재 부채 위기에 처해 있습니다. 대륙 전체 주권 부채는 7천억 달러를 넘어가며, 몇몇 국가에서는 부채 서비스가 정부 수입의 40 % 이상을 차지합니다.

2022년 붕괴는 많은 사람을 놀라게 했습니다: 가나는 “관리 가능한 부채 수준”에서 18개월도 채 되지 않아 주권 디폴트에 빠졌습니다. 잠비아, 모잠비크, 에티오피아도 유사한 궤적을 보였습니다.

핵심 문제: 전통적인 모니터링은 후행 지표에 의존합니다. IMF가 한 국가를 “고위험”으로 표시할 때는 예방 조치를 취하기엔 이미 늦은 경우가 많습니다.

머릿속에 떠오른 질문: 머신러닝이 더 이른 경고 신호를 제공할 수 있을까?


내가 만든 것

Africa‑Debt‑Intelligence는 실시간 주권 부채 위험 모니터링 플랫폼으로:

  • IMF World Economic OutlookWorld Bank International Debt Statistics에서 재정 데이터를 집계
  • ML 클러스터링 및 시계열 분석을 활용해 위험 점수(0‑100 척도) 생성
  • 신뢰 구간을 포함한 5년 뒤 부채 궤적 예측
  • 각 국가의 위험 프로필에 맞춘 정책 권고 제공
  • 재정 지표가 임계값을 초과하면 실시간 알림 발송

현재 이 플랫폼은 15개 사하라 이남 아프리카 경제를 모니터링하고 있으며, 이는 지역 GDP의 **85 %**에 해당합니다.

Africa Debt Intelligence Dashboard

GitHub Repository:
Tech Stack: Python, React, scikit‑learn, pandas, REST APIs


기술 아키텍처

데이터 파이프라인

공공 API에서 자동으로 데이터 수집:

def load_and_clean_data(filepath: str) -> pd.DataFrame:
    """
    Load long‑format fiscal data and perform cleaning operations.
    """
    df = pd.read_csv(filepath)

    # Convert time to year format
    df['Year'] = pd.to_datetime(df['Time']).dt.year

    # Handle missing values with forward fill + interpolation
    df = df.groupby(['Country', 'Indicator']).apply(
        lambda x: x.interpolate(method='linear')
    ).reset_index(drop=True)

    # Normalize fiscal indicators to % of GDP
    gdp_data = df[df['Indicator'] == 'GDP'][['Country', 'Year', 'Amount']]
    gdp_data = gdp_data.rename(columns={'Amount': 'GDP'})

    df = df.merge(gdp_data, on=['Country', 'Year'], how='left')

    # Create normalized ratios
    indicators_to_normalize = ['External_Debt', 'Revenue', 'Expenditure', 'Deficit']
    for ind in indicators_to_normalize:
        mask = df['Indicator'] == ind
        df.loc[mask, 'Normalized_Value'] = (
            df.loc[mask, 'Amount'] / df.loc[mask, 'GDP'] * 100
        )

    return df

추적하는 주요 지표

  • 부채‑대‑GDP 비율
  • 재정 균형 (% GDP)
  • 수입‑대‑GDP 비율
  • 부채 서비스 비율
  • GDP 성장률
  • 인플레이션율
  • 외채 노출액
  • 외환보유고(수입 개월수)

위험 점수 모델

비지도 학습과 도메인‑특화 가중치를 결합:

from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

def generate_risk_scores(df: pd.DataFrame) -> pd.DataFrame:
    """
    Generate composite risk scores using K‑means clustering
    and weighted fiscal indicators.
    """
    features = [
        'Debt_to_GDP', 'Fiscal_Balance', 'Revenue_to_GDP',
        'Debt_Service_Ratio', 'GDP_Growth', 'Inflation'
    ]

    # Standardize features
    scaler = StandardScaler()
    X_scaled = scaler.fit_transform(df[features])

    # K‑means clustering to identify risk groups
    kmeans = KMeans(n_clusters=4, random_state=42)
    df['Risk_Cluster'] = kmeans.fit_predict(X_scaled)

    # Weighted composite score
    weights = {
        'Debt_to_GDP': 0.25,
        'Debt_Service_Ratio': 0.25,
        'Fiscal_Balance': 0.20,
        'Revenue_to_GDP': 0.15,
        'GDP_Growth': 0.10,
        'Inflation': 0.05
    }

    df['Risk_Score'] = sum(
        df[feature] * weight
        for feature, weight in weights.items()
    )

    # Normalize to 0‑1 scale
    df['Risk_Score'] = (
        (df['Risk_Score'] - df['Risk_Score'].min()) /
        (df['Risk_Score'].max() - df['Risk_Score'].min())
    )

    return df

위험 임계값

  • 0.00‑0.40 – 낮은 위험 (녹색)
  • 0.41‑0.60 – 중간 위험 (노란색)
  • 0.61‑0.75 – 높은 위험 (주황색)
  • 0.76‑1.00 – 위기 위험 (빨간색)

시계열 예측

ARIMA 모델을 사용해 5년간 부채‑대‑GDP 예측을 신뢰 구간과 함께 생성:

from statsmodels.tsa.arima.model import ARIMA

def forecast_debt_trajectory(country_data: pd.DataFrame,
                             periods: int = 20) -> dict:
    """
    Generate 5‑year debt‑to‑GDP forecast with confidence intervals.
    """
    model = ARIMA(country_data['Debt_to_GDP'], order=(2, 1, 2))
    fitted_model = model.fit()

    forecast = fitted_model.forecast(steps=periods)
    conf_int = fitted_model.get_forecast(steps=periods).conf_int()

    return {
        'forecast': forecast,
        'lower_bound': conf_int.iloc[:, 0],
        'upper_bound': conf_int.iloc[:, 1]
    }

직면한 도전 과제

도전 과제 1: 데이터 품질 지옥

아프리카 거시경제 데이터는 자주 수정되거나 불규칙적이며 누락되는 경우가 많습니다.
예시: 가나의 부채‑대‑GDP 비율이 2023년에 소급적으로 15 포인트 상승해 재작성되면서 과거 모습이 크게 바뀌었습니다.

해결 방안

  • IMF, World Bank, AfDB 등 다중 소스와 교차 검증
  • 누락된 분기 데이터를 보간
  • 신뢰 수준을 표시하는 데이터‑품질 플래그 추가
  • 이상치를 수동으로 점검

도전 과제 2: “위험” 정의하기

위험 점수를 어떻게 해석하고 검증할 것인가?

해결 방안

  • 2000‑2023년 사이의 역사적 부채 위기 사례에 대해 백테스트 수행
  • 점수 > 0.70이 실제 위기 10건 중 8건을 사전에 포착함을 확인
  • 평균 선행 시간: 14개월 (위기 발생 전)
  • 예측과 실제 결과를 비교한 혼동 행렬 구축

역사적 검증 결과

  • 가나 2022: 18개월 전(점수 0.82) 경고
  • 잠비아 2020: 16개월 전(점수 0.79) 경고
  • 모잠비크 2016: 12개월 전(점수 0.75) 경고

도전 과제 3: 해석 가능하게 만들기

정책 입안자는 왜 국가가 경고되는지 이해해야 합니다.

해결 방안

  • 위험 점수의 주요 원인을 보여주는 특성 중요도 분석
  • 각 요인의 기여도 분해 제공
  • 특정 취약점에 맞춘 정책 권고서 작성
  • 예시 문구: “부채 서비스가 수입의 62 %를 차지해 위험이 상승했습니다.”

도전 과제 4: 데이터 최신성 유지

API가 지연되거나 실패할 수 있으며, 수동 입력은 확장성이 없습니다.

해결 방안

  • 월간 자동 ETL 파이프라인 운영
  • API 실패 시 캐시된 데이터로 대체
  • 대시보드에 데이터 최신성 표시 지표 제공
Back to Blog

관련 글

더 보기 »