콘텐츠로 이동
Data Prep
상세

빈집 예측 모델

프로젝트 개요

집계구(OA, Output Area) 단위로 빈집 발생 확률을 예측하는 ML 파이프라인이다. 지방자치단체의 선제적 빈집 관리 정책 수립을 지원한다.

항목 내용
목적 단년후 빈집 발생 고위험 지역 예측
단위 집계구 (약 108,000개)
예측 대상 빈집 발생 확률 (0-1)
갱신 주기 재학습 버튼 클릭시
인프라 Oracle + PostgreSQL, Airflow

최근 업데이트 (2026-02)

날짜 변경 사항
02-25 클러스터링 알고리즘 HDBSCAN으로 변경 (노이즈 처리 개선)
02-20 새로운 파생변수 추가: 공실률 변화 추세
02-15 챗봇 연동 API 완료
02-10 Calibration 개선 (Isotonic Regression 적용)

파이프라인 구조

┌─────────────────────────────────────────────────────────────┐
│                   ML Pipeline (6 Steps)                     │
│                                                             │
│  Step 1: 데이터 통합                                        │
│  ├─ 인구 데이터 (통계청)                                   │
│  ├─ 건축물 데이터 (건축물대장)                             │
│  ├─ 토지 데이터 (토지대장)                                 │
│  ├─ 거래 데이터 (실거래가)                                 │
│  └─ 인프라 데이터 (학교, 병원 등)                          │
│                     │                                       │
│                     ▼                                       │
│  Step 2: 파생변수 생성                                      │
│  ├─ 인구 변화율                                            │
│  ├─ 고령화 지수                                            │
│  ├─ 건물 노후도                                            │
│  ├─ 접근성 지표                                            │
│  ├─ 거래 활성도                                            │
│  └─ [NEW] 공실률 변화 추세                                 │
│                     │                                       │
│                     ▼                                       │
│  Step 3: 클러스터링 [UPDATED: HDBSCAN]                     │
│  ├─ 지역 유형 분류 (도시/농촌/산업 등)                     │
│  ├─ 노이즈 포인트 별도 처리                                │
│  └─ 클러스터별 특성 프로파일                               │
│                     │                                       │
│                     ▼                                       │
│  Step 4: 모델 학습                                          │
│  ├─ 클러스터별 개별 모델                                   │
│  └─ XGBoost, LightGBM, CatBoost                            │
│                     │                                       │
│                     ▼                                       │
│  Step 5: 앙상블 + Calibration                              │
│  ├─ Soft Voting                                            │
│  └─ [NEW] Isotonic Regression Calibration                  │
│                     │                                       │
│                     ▼                                       │
│  Step 6: 단년 예측                                          │
│  └─ 현재 상태 → 미래 빈집 확률                             │
└─────────────────────────────────────────────────────────────┘

데이터 소스

원천 데이터

데이터 출처 갱신 주기 주요 변수
인구 통계 통계청 SGIS 연간 인구수, 연령별 인구, 세대수
건축물 대장 국토부 월간 건축년도, 용도, 면적, 층수
토지 대장 국토부 월간 지목, 면적, 공시지가
실거래가 국토부 월간 거래가격, 거래일, 면적
빈집 현황 지자체 연간 빈집 수, 위치, 상태

파생 변수

# 인구 관련
population_features = {
    'pop_change_rate': '5년간 인구 변화율',
    'aging_index': '고령화 지수 (65세 이상 / 15세 미만)',
    'youth_ratio': '청년 인구 비율 (20-39세)',
    'single_household_ratio': '1인 가구 비율',
    'dependency_ratio': '부양비 ((0-14 + 65+) / 15-64)'
}

# 건축물 관련
building_features = {
    'avg_building_age': '평균 건물 연령',
    'old_building_ratio': '30년 이상 건물 비율',
    'vacant_ratio_current': '현재 빈집 비율',
    'building_density': '건물 밀도 (건물수/면적)',
    'vacancy_trend': '[NEW] 3년간 공실률 변화 추세'  # 2026-02 추가
}

# 거래 관련
transaction_features = {
    'transaction_count': '연간 거래 건수',
    'price_change_rate': '5년간 가격 변화율',
    'transaction_velocity': '거래 회전율'
}

# 인프라 관련
infra_features = {
    'school_distance': '최근접 학교 거리',
    'hospital_distance': '최근접 병원 거리',
    'station_distance': '최근접 역/정류장 거리',
    'commercial_density': '상업시설 밀도'
}

모델링 상세

Step 3: 클러스터링 (HDBSCAN 변경)

기존 K-means 대비 HDBSCAN 장점: - 클러스터 수 자동 결정 - 노이즈 포인트 식별 - 비구형 클러스터 처리

from hdbscan import HDBSCAN

clusterer = HDBSCAN(
    min_cluster_size=500,
    min_samples=50,
    cluster_selection_epsilon=0.5,
    metric='euclidean'
)

clusters = clusterer.fit_predict(X_scaled)

# 노이즈 포인트 (-1) 별도 처리
noise_mask = clusters == -1
X_noise = X_scaled[noise_mask]
# 노이즈 포인트는 전역 모델 사용

클러스터 분포:

클러스터 특성 집계구 수 비율
0 도시 중심부 28,000 26%
1 신규 개발 지역 15,000 14%
2 고령화 농촌 32,000 30%
3 산업단지 주변 18,000 17%
4 관광/휴양 지역 8,000 7%
-1 노이즈 7,000 6%

Step 5: Calibration 적용

예측 확률의 신뢰성 향상을 위해 Isotonic Regression 적용.

from sklearn.calibration import CalibratedClassifierCV
from sklearn.isotonic import IsotonicRegression

# 방법 1: sklearn 내장
calibrated_model = CalibratedClassifierCV(
    base_estimator=ensemble_model,
    method='isotonic',
    cv=5
)

# 방법 2: 후처리 calibration
iso_reg = IsotonicRegression(out_of_bounds='clip')
iso_reg.fit(val_probs, val_labels)
calibrated_probs = iso_reg.predict(test_probs)

Calibration 효과:

지표 Before After
Brier Score 0.082 0.071
ECE (Expected Calibration Error) 0.045 0.018
실제 위험 그룹 포착률 82% 89%

평가 지표

지표 이전 성능 현재 성능 목표
AUC-ROC 0.82 0.85 > 0.80
Precision@10% 0.45 0.52 > 0.40
Recall@10% 0.38 0.44 > 0.35
지역별 Calibration 0.91 0.96 > 0.90

해석 가능성

import shap

# SHAP 분석
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_test)

# 전역 피처 중요도
shap.summary_plot(shap_values, X_test)

# 개별 예측 설명
shap.waterfall_plot(shap_values[0])

상위 피처 중요도 (2026-02 기준): 1. 인구 변화율 (5년) - 21% 2. 고령화 지수 - 18% 3. 공실률 변화 추세 [NEW] - 15% 4. 평균 건물 연령 - 12% 5. 거래 빈도 - 10%

챗봇 연동 API

빈집 챗봇에서 예측 결과 조회 가능.

# API 엔드포인트
@app.get("/api/v1/prediction/{oa_code}")
async def get_prediction(oa_code: str):
    """집계구별 빈집 예측 조회"""
    result = prediction_service.get_by_oa(oa_code)
    return {
        "oa_code": oa_code,
        "current_vacant_ratio": result.current,
        "predicted_vacant_ratio": result.predicted,
        "risk_level": result.risk_level,
        "top_factors": result.shap_top_3,
        "cluster": result.cluster_name
    }

@app.get("/api/v1/prediction/region/{region}")
async def get_region_summary(region: str):
    """지역 전체 요약"""
    return prediction_service.get_region_summary(region)

챗봇 질의 예시:

사용자: 의성군 빈집 예측 결과 알려줘

응답:
경북 의성군 빈집 예측 결과입니다:

**현황:**
- 현재 빈집률: 12.3%
- 등록 빈집: 3,050채

**1년 후 예측:**
- 예측 빈집률: 14.8% (+2.5%p)
- 위험 등급: 매우 높음

**주요 위험 요인:**
1. 인구 변화율 -8.2%/년 (고령화 가속)
2. 30년 이상 노후 건물 65%
3. 거래 건수 전년 대비 -23%

**고위험 집계구 TOP 3:**
- 금성면 대리: 예측 빈집률 28%
- 춘산면 신흥리: 예측 빈집률 25%
- 가음면 현리: 예측 빈집률 23%

Airflow DAG

from airflow import DAG
from airflow.operators.python import PythonOperator

dag = DAG(
    'vacant_house_prediction',
    schedule_interval=None,  # 수동 트리거
    start_date=datetime(2024, 1, 1)
)

# Step 1: 데이터 수집
collect_data = PythonOperator(
    task_id='collect_data',
    python_callable=collect_all_sources,
    dag=dag
)

# Step 2: 파생변수 생성
create_features = PythonOperator(
    task_id='create_features',
    python_callable=generate_derived_features,
    dag=dag
)

# Step 3-6: 모델링
run_pipeline = PythonOperator(
    task_id='run_ml_pipeline',
    python_callable=run_prediction_pipeline,
    dag=dag
)

# API 캐시 갱신
refresh_api_cache = PythonOperator(
    task_id='refresh_api_cache',
    python_callable=refresh_prediction_cache,
    dag=dag
)

# 의존성
collect_data >> create_features >> run_pipeline >> refresh_api_cache

결과 활용

대시보드 출력

집계구 코드 클러스터 현재 빈집률 단년 후 예측 위험 등급 주요 요인
11010101 도시 중심 2.3% 2.8% 낮음 건물 노후화
36020205 고령 농촌 8.5% 11.2% 매우 높음 인구 감소
28030103 산업단지 5.1% 5.9% 중간 거래 감소

정책 연계

위험 등급별 권고 조치:
├─ 매우 높음: 선제적 정비 계획, 예산 우선 배정
├─ 높음: 모니터링 강화, 소유자 상담
├─ 중간: 정기 점검, 예방 프로그램
└─ 낮음: 현행 유지

향후 계획

일정 작업 상태
3월 시계열 모델 추가 (N년 후 예측) 계획
3월 공간 자기상관 반영 계획
4월 모델 자동 재학습 스케줄러 계획

마지막 업데이트: 2026-02-25