boostcampaitech7 / level2-competitiveds-recsys-06

level2-competitiveds-recsys-06 created by GitHub Classroom
2 stars 0 forks source link

수도권 아파트 전세가 예측 프로젝트

프로젝트 구조

프로젝트 구조 ```bash ├── src # AI 모델 학습을 위한 부분 │ ├── config # config.yaml 값 가져 오는 함수 제공 │ ├── model # AI 모델 src ex) Light GBM, XGBoost │ └── pre_process # 모델 학습전 전처리 │ └── custom_wandb │ └── plot │ └── server ├── data #.gitignore │ └── .csv #.gitignore │ └── processed # 기타 csv 저장을 위한 저장소 | └── raw # 원본 csv 저장을 위한 저장소 ├── EDA # 개인 EDA 폴더 │ └── {팀원 명} │ ├──*.ipynb ├── app.py # 모델 학습을 위한 python 파일 ├── config-sample.yaml # 하이퍼 파라미터 및 모델 & 서버 선택을 위한 설정 값 ├── .gitignore ├── Readme.md └── requirements.txt ```
라이브러리 버전 **Python 버전 : 3.12.5** **Library 버전** - (requirements.txt) ```txt numpy==2.1.1 pandas==2.2.3 lightgbm==4.4.0 scikit-learn==1.5.2 tqdm==4.66.4 xgboost==2.1.1 scipy==1.14.1 black==24.8.0 plotly==5.24.1 matplotlib==3.9.2 geopy==2.4.1 swifter folium==0.17.0 pyproj==3.7.0 wandb==0.18.3 optuna==4.0.0 ```

목차

  1. 프로젝트 소개
  2. 팀 구성 및 역할
  3. 절차 및 방법
  4. EDA & Feature Engineering
  5. Modeling
  6. 최종 결과

1. 프로젝트 소개

2. 팀 구성 및 역할

이름 역할
김건율 팀장, EDA, 피처 엔지니어링, LGBM 모델링 및 앙상블
백우성 EDA, 피처 엔지니어링, XGBoost 모델링
유대선 프로젝트 설계, 모델링 자동화, EDA
이제준 EDA, RF 모델링
황태결 공원, 학교 데이터 EDA

3. 절차 및 방법

프로젝트 진행 과정

  1. 도메인 지식을 위한 스터디 진행 후, 주어진 데이터에 대해서 토론.
  2. 프로젝트를 위한 기본 구조 설립 및 코드 작성. (유대선)
  3. 주제(금리, 지하철, 공원, 학교, 아파트)별로 각자 EDA 진행.
  4. 각자 도출한 결과에 대해 공유하고 데이터 분석과 토론을 진행해 feature와 model 선택
  5. Feature Engineering으로 필요한 feature 생성
  6. 모델 훈련 및 하이퍼파라미터 튜닝
  7. 최종 제출 선택

협업 방식

4. EDA & Feature Engineering

우선 도메인 지식 스터디를 통해 팀원 모두가 데이터를 이해하고, 각자 주제 별 EDA를 진행한 뒤, 근거 있는 컬럼에 대해 Feature Engineering 진행. (각자 EDA 한 내용은 github의 EDA-개인별 폴더에 정리)

데이터

데이터 상세 | 컬럼 명 | 자료형 | 데이터 셋 | 설명 | | --- | --- | --- | --- | | index | int64 | train/test | 인덱스 | | area_m2 | float64 | train/test | 면적 | | contract_year_month | int64 | train/test | 계약년월 | | contract_day | int64 | train/test | 계약일 | | contract_type | int64 | train/test | 계약 유형(0: 신규, 1:갱신, 2:모름) | | floor | int64 | train/test | 층수 | | built_year | int64 | train/test | 건축 연도 | | latitude | float64 | train/test/subway/school/park | 위도 | | longitude | float64 | train/test/subway/school/park | 경도 | | age | int64 | train/test | 건물나이 | | deposit | float64 | train | **전세 실거래가(타겟 변수)** | | year_month | int64 | interest | 연월 | | interest_rate | float64 | interest | 이자율(연월에 해당하는 이자율) | | schoolLevel | object | school | 초등학교, 중학교, 고등학교 여부 | | area | float64 | park | 공원 면적 |

4-1. Apart data

4-2. subway, school, park data

부동산에선 ‘O세권’이란 단어를 사용한다. 일반적으로 아파트 근접 인프라가 잘 형성되어있으면 가격이 높아진다. 주어진 subway, school, park info 데이터의 위도, 경도를 활용해서 아파트 별 역세권, 학세권, 공세권을 판단할 수 있는 피처를 만들었다.

feature nearest_school_distance nearest_park_distance nearest_subway_distance
corr -0.059121 -0.108378 -0.410597

4-3. interest data

corr monthly_transaction interest_rate avg_deposit deposit_diff
monthly_transaction 1.000000 0.469879 0.455964 -0.219402
interest_rate 0.469879 1.000000 0.130927 -0.043196
avg_deposit 0.455964 0.130927 1.000000 0.129704
deposit_diff -0.219402 -0.043196 0.129704 1.000000

4-4. Feature Creation

recent_deposit

일반적으로 부동산 가격을 볼 때 가장 많이 보는 지표는 ‘최근 거래가’이다. 그래서 apt_idx와 area_m2가 같은 가장 최근 raw의 deposit을 찾아 최근 거래가 피처를 만들었다.

apt_deposit_rank

같은 apt_idx를 가진 raw끼리 groupby해서 평균 전세가격을 구하고, 서로 비교해 랭킹을 매겨놓은 피처.

grid_deposit

외부 행정동 데이터를 사용할 수 없기 때문에 주어진 위도, 경도를 기준으로 일정 크기의 격자(grid)로 나누어 행정동을 대체해서 근처 아파트들 끼리 묶어 활용했다. 이를 통해 test에 있는 아파트들이 어떤 구역에 속하는 지 파악이 가능해진다.

infra_count

4-2의 infra distance 피처만으로는 부족해 새롭게 생성했다. 각 grid에 속하는 subway, park, school의 수를 count해서 피처로 활용했다. 로그 변환된 평당 전세 가격과 상관계수는 0.493523(지하철), 0.226171(학교), 0.213145(공원)으로 나왔다.

5. Modeling

6. 최종 결과

  1. 아래의 서로 다른 하이퍼파라미터와 피처를 가진 XGBoost와 LightGBM 4가지 모델의 타겟 값(deposit)을 가중 평균해서 final 생성(0.125+0.125+0.25+0.5)

    • public score : 3483.0271 / private score : 4279.3377
  2. V9 데이터셋을 적용한 두 모델 LightGBM 25% + XGBoost 75%를 섞어 생성

    • public score : 3506.4542 / private score : 4307.9871
V9 데이터셋 ```python columns = ['contract_date_numeric', 'area_m2', 'floor', 'built_year', 'latitude', 'longitude', 'age', 'contract_0', 'contract_1', 'deposit', 'apt_idx', 'area', 'grid_deposit', 'apt_deposit_rank', 'apt_area_deposit_rank', 'recent_deposit', 'nearest_park_distance', 'nearest_park_idx', 'park_area', 'nearest_school_distance', 'nearest_school_idx', 'nearest_subway_distance', 'nearest_subway_idx', 'park_count', 'school_count', 'subway_count'] ```
최종 모델 하이퍼 파라미터 1. LGBM 1 HyperParameters ```json { "objective": "regression", "metric": "mae", "boosting_type": "gbdt", "num_leaves": 200, "learning_rate": 0.01, "feature_fraction": 0.8, "bagging_fraction": 0.7, "bagging_freq": 1, "num_boost_round": 15000, "early_stopping_rounds": 100, "gpu_platform_id": 0, "gpu_device_id": 0, } ``` 2. XGBoost 1 HyperParameters ```json { "objective": "reg:absoluteerror", "eval_metric": "mae", "max_depth": 10, "subsample": 0.8, "colsample_bytree": 0.8, "learning_rate": 0.01, "num_boost_round": 20000, "early_stopping_rounds": 100, "verbose_eval": 100, "device": "cuda" } ``` 3. LGBM 2 HyperParameters ```json { "objective": "regression", "metric": "mae", "boosting_type": "gbdt", "num_leaves": 64, "learning_rate": 0.05, "subsample": 0.8, "colsample_bytree": 0.8, "feature_fraction": 0.8, "lambda_l2": 0.1, "bagging_fraction": 0.7, "bagging_freq": 1, "num_boost_round": 50000, "early_stopping_rounds": 1000, "n_jobs": -1 } ``` 4. XGBoost 2 HyperParameters ```json { "objective": "reg:absoluteerror", "eval_metric": "mae", "max_depth": 6, "subsample": 0.8, "colsample_bytree": 0.8, "learning_rate": 0.05, "min_child_weight": 10, "reg_lambda": 0.1, "reg_alpha": 0, "num_boost_round": 50000, "early_stopping_rounds": 1000, "verbose_eval": 1000, "n_jobs": -1, "gamma": 0, } ```