10/2 Random Forest

레롤롤레로·약 8시간 전

랭체인AI

목록 보기
17/17

오늘은 어제 중고차 가격 예측에 사용한 결정 트리를 랜덤 포레스트로 확장하고, 통신사 고객 이탈 데이터로 분류 실습을 진행했다. 여러 트리의 결과를 합치는 방식과 특성 중요도를 확인했다.

중고차 가격을 랜덤 포레스트로 예측

어제 전처리한 중고차 데이터와 같은 학습·테스트 분할을 사용했다. 랜덤 포레스트는 여러 결정 트리를 학습하고, 회귀에서는 각 트리의 예측값을 평균 내어 최종 값을 구한다.

rf = RandomForestRegressor(random_state=2026)
rf.fit(X_train, y_train)

y_pred4 = rf.predict(X_test)
rmse = root_mean_squared_error(y_pred4, y_test)

이번에는 표준화 전의 입력값으로 학습했다. 테스트 R²는 약 0.943, RMSE는 약 0.754였다. 같은 테스트 데이터에서 확인한 오차는 아래와 같다.

모델테스트 RMSE
기본 결정 트리1.179
선형 회귀1.107
랜덤 포레스트0.754

특성 중요도에서는 신차 가격인 Present_Price가 약 0.902로 가장 높았고, 차량 나이인 Vehicle_Age가 약 0.069로 뒤를 이었다. 이번 모델의 분할 과정에서 어떤 특성이 많이 사용됐는지 살펴볼 수 있었다.

고객 이탈 데이터 전처리

통신사 고객 데이터는 7,043개 행으로, 고객 정보와 계약·서비스 이용 내역을 이용해 이탈 여부를 예측하는 문제였다. 고객 ID는 제외하고 각 컬럼의 고유값과 개수를 먼저 확인했다.

TotalCharges는 금액 컬럼인데 문자열로 읽혔다. 공백을 결측값으로 바꾼 뒤 실수형으로 변환하고 중앙값으로 채웠다.

telecom_df["TotalCharges"] = (
    telecom_df["TotalCharges"]
    .replace(r"^\s*$", np.nan, regex=True)
    .astype(float)
)
telecom_df["TotalCharges"] = telecom_df["TotalCharges"].fillna(
    telecom_df["TotalCharges"].median()
)

내 풀이에서는 성별과 Yes·No 컬럼을 직접 0·1로 변환하고, 나머지 범주형 컬럼에 더미 변수를 적용했다. 층화 추출로 데이터를 나눈 뒤 랜덤 포레스트를 학습하니 학습 정확도는 약 0.998, 테스트 정확도는 약 0.799였다. 학습 점수와 테스트 점수 사이에 차이가 있었다.

혼동 행렬과 classification_report()도 추가해, 전체 정확도와 이탈 고객을 찾아내는 성능을 함께 확인했다.

같이 풀면서 파생변수 추가

이후 같이 푼 코드에서는 배우자·부양가족 여부를 더한 FamilySize와 서비스 컬럼 중 Yes인 항목을 센 TotalServices를 추가했다. 계약 유형, 가입 기간, 월 청구액과 이탈 여부도 그래프로 비교했다.

범주형 입력값은 get_dummies()로 변환하고, 학습 5,634개와 테스트 1,409개로 나눴다. 트리 100개와 random_state=2026을 지정해 학습했다.

rf = RandomForestClassifier(
    n_estimators=100,
    n_jobs=-1,
    random_state=2026
)
rf.fit(X_train, y_train)

y_pred = rf.predict(X_test)
print(classification_report(y_test, y_pred))

특성 중요도는 누적 청구액, 가입 기간, 월 청구액 순으로 높았다.

두 풀이의 분류 결과 비교

테스트 데이터는 두 풀이 모두 유지 고객 1,035명, 이탈 고객 374명으로 구성됐다. 아래 정밀도·재현율·F1은 이탈 고객 클래스 기준이며, 분류 보고서에 표시된 소수 둘째 자리 값을 사용했다.

지표내 풀이같이 푼 풀이
전체 정확도79.91%79.35%
이탈 정밀도0.650.63
이탈 재현율0.530.52
이탈 F10.580.57

혼동 행렬을 실제 정답 기준으로 나누면 다음과 같다.

분류 결과내 풀이같이 푼 풀이
유지 고객을 유지로 예측927922
유지 고객을 이탈로 예측108113
이탈 고객을 유지로 예측175178
이탈 고객을 이탈로 예측199196

이번 실행에서는 내 풀이가 이탈 고객을 3명 더 찾아냈고, 유지 고객을 이탈로 잘못 분류한 경우도 5명 적었다. 다만 내 모델은 RandomForestClassifier()로 난수 시드를 지정하지 않았고, 같이 푼 모델은 random_state=2026을 사용했다. 파생변수와 모델 설정이 함께 달라졌으므로 이 차이를 파생변수 추가 효과로만 해석하기는 어렵다.

두 풀이 모두 실제 이탈 고객의 약 절반을 놓쳤다. 정확도가 약 80%여도 이탈 고객을 찾는 목적에서는 재현율을 함께 확인해야 한다. 다음 비교에서는 모델의 난수 시드와 설정을 맞춘 뒤 파생변수 유무에 따른 결과를 확인해 봐야겠다.

0개의 댓글