sol’s blog

Lending Club 데이터 분석: 데이터 개요, EDA, 전처리, 그리고 파생 변수 설계

sol-commits
sol-commits Jul 23, 2025
프로젝트 개요
• P2P 대출 플랫폼인 Lending Club에서는 투자자가 대출 신청자들의 신용위험을 면밀히 검토해야 하며, 채무 불이행(부도)의 위험은 투자 원금 및 이자의 손실로 이어질 수 있기 때문에 중요한 고려 요소
• Lending Club 플랫폼자체에서도 신청자의 신용도를 바탕으로 대출 승인 여부를 결정하고 등급(grade)에 따라 이자율을 책정
프로젝트 목표
• 포트폴리오의 위험 대비 초과수익을 최대화 = sharpe ratio 최대화
Sharpe Ratio
(포트폴리오 수익률 - 무위험이자율) / 수익률 변동성
• LC에서 부도가 예측되어 애출을 승인하지 않았더라면, 해당 투자금은 투자 결정 당시의 3년/5년만기 미 국채에 투자하였다고 가정
data shape
(1,755,295, 141) - 전체 데이터의 약 60% 정도
• 40% 정도는 Private 성능 확인하는 데 사용
internal rate of return
• LC의 대출은 원리금 균등사환 구조로 매월 일정한 상환금이 발생
• 투자자는 대출 실행 시 원금을 지급 → 대출자는 고정 상환금(원금 + 이자) 납입
• 본 프로젝트에서 IRR은 대출 투자 수익률을 측정하는 데 적용
 
 

데이터 전처리

loan_status(target value) 정제

loan_status(y label) unique 값들
  1. 'Fully Paid'
  1. 'Current'
  1. 'Charged Off'
  1. 'Late (16-30 days)'
  1. 'Late (31-120 days)'
  1. 'In Grace Period'
  1. 'Issued’
  1. 'Does not meet the credit policy. Status:Fully Paid'
  1. 'Does not meet the credit policy. Status:Charged Off'
  1. 'Default'
  1. nan

→ Current/Late 제외해야함. 대출의 최종 상태가 결정된 데이터만 사용하여야 하기 때문에

loan_status 값
의미
유지 여부
레이블
fully paid
대출 완납
✅ 유지
0(정상)
charged off
상환 실패(부도)
✅ 유지
1(부도)
Default
공식적 부도 상태
✅ 유지
1(부도)
Does not meet the credit policy. Status:Fully Paid
정책 미충족이지만 완납됨
✅ 유지
0(정상)
Does not meet the credit policy. Status:Charged Off
정책 미충족이며 부도
✅ 유지
1(부도)

대출 심사 시점에 얻을 수 없는 후행 정보가 포함된 변수들을 제거

대출 심사 시점에서 알 수 없는 컬럼 제외
  • 총 32개의 컬럼 제외

url 컬럼 제거

  • url 컬럼으로 획득할 수 있는 정보인 loan_id는 이미 id 컬럼으로 얻을 수 있는 정보이므로 제외

url 들어가봤을 때

policy_code 컬럼 제거

모든 컬럼이 다 하나의 값을 갖고 있기 때문에 제거

pymnt_plan 컬럼 제거

int_rate 타입 변경 (object → float)

 

term 타입 변경 (object → int)

annual_inc(연소득) 결측치 2개 drop

  • 둘 다 정상상환 라벨이므로 drop
python code

범주형 변수 중 빈도가 2% 미만인 범주 → 기타로 통합

참고:
  • 데이터가 적은 소수 범주에 과적합 되는 것을 방지

9 값인 사람은 모두 타겟 1(부도)라는 건데, 이는 9 값을 갖는 사람이 1명이기 때문.

acc_open_past_24mths

지난 24개월 내 개설 신용계좌 수

계좌 개설이 많으면 신용카드를 적극적으로 만든 것으로 해석되며, 과도한 신규계좌는 신용위험 상승 신호일수도

Callout icon'

빼야할까?

🔗 참고

  • 다른 프로젝트를 참고해보면, 다른 조건이 모두 동일할 때, 최근 24개월 동안 신규로 개설한 계좌가 1개 늘어나면, 채무불이행이 일어날 가능성이 기존보다 약 5% 높아진다는 결과를 얻었다고 함.

→ 빼는 건 ❌

 
 
  • 계좌 개설 0건은 흔하고, 두 자릿수 개설도 가능하나 20개 이상처럼 비정상적으로 큰 값은 이상치로 간주할 수 있을 듯
 

all_util

전체 신용한도 대비 사용률

utilization rate: (잔액 / 한도) * 100 → 0% ~ 100% 값이어야함

  • 결측치가 많아 단순 대체로는 한계가 있음. 동일한 정보를 담은 다른 변수(revol_util 등)을 활용
 

annual_inc & annual_inc_joint

  • 두 컬럼 통합(annual_inc_total)
    • python code

      annual_inc_joint의 결측률은 96% 이상으로, 공동 신청이 드문 데이터 특성상 대부분 NA임

       

      showfliers=False 시각화

대출액 대비 소득비율 등을 통해 상환 가능성을 평가하는데 활용

annual_inc_total > 60,000,000 이상인 눈에 띄는 outlier drop

 

대부분의 큰 값들이 Sourve Verified 에 있음

 

bc_open_to_buy

(리볼빙) 신용카드 사용 가능 한도 = 모든 신용카드 계좌의 총 한도 중 현재 남은 여유금액

0에 가까우면 카드 한도를 모두 소진했음을 의미

 

all_util과 bc_open_to_buy의 관계

bc_util

리볼빙 계좌 이용률

bc_util의 결측치는 적은데 all_util과 상관관계가 높음

all_util과 bc_util의 상관계수 = 0.6

이것도 100% 넘는 값들이 있음

  • bc_util의 계산식
    • bc_util = (revol_bal) / (revol_bal + bc_open_to_buy) * 100

      → 이렇게 직접 계산했을 때는 100을 넘는 값이 없음. 직접 계산해서 bc_util을 대체

      계산식 검증

      직접 계산한 bc_util - 데이터의 bc_util 차이 시각화

chargedoff_within_12_mths

최근 12개월 내 채무 불이행 건수

당연히 과거 1년 내 부도 경험이 있으면 새로운 대출 부도 확률도 높아질 것으로 예상됨

정상상환에서 78개의 NaN, 연체/부실에서 14개의 NaN을 가짐
→ 기록상 부도 이력이 확인되지 않았을 가능성이 큼. 0으로 대체. 혹시 실제 부도자 일부를 놓칠 수 있지만, 다른 변수로 어느정도 보완 가능할 것으로 예상됨

  • 1번 이상인 값들의 비율이 적으므로 이진 변수로 변경
    • NaN → 0
    • 0 → 0
    • 1 이상 → 1

dti & dti_joint

부채비율 및 공동 신청 부채 비율
  • 이것 또한 공동 대출, 개인 대출의 dti를 하나로 합친다.
    • 공동 대출이어도 주 채무자의 dti 값이 있음

    • 공동 대출 → dti_joint 사용
    • 개인 대출 → dti 사용
    • 주 채무자의 dti와 채무자 두명의 dti 값의 차이와 배수 차이를 파생변수로 추가
      • dti_dff = df[’dti_joint’] - df[’dti’]
      • dti_ratio = df[’dti_joint’] / df[’dti’]
      • python code
  • 이상치 처리
    • 금융기관에서 36~43% 이하를 권장, 50% 이상일 떈 “더는 허용하기 어려운 수준”으로 간주

    • 승인심사 기준 이상의 값을 단순화해 “고위험” 범주로 묶어버림
      • 즉, dti 이상치를 50으로 캡핑

 

earliest_cr_line

최초 신용거래 개설 날짜

신용 이력의 길이를 측정하는 지표

일반적으로 신용이력 기간이 길수록 부도 확률이 낮아지는 경향이 있음

  • 결측치 제거
    • 극소수이기 때문에 제거

결측치 14개
정상/상환이 13개

  • 데이터 예시
    • 'Sep-2005’

      → 신용 이력 연수로 변환

emp_length

재직 기간
 
  • 순서형인데, 원-핫 인코딩을 해도 될지?
    • 원-핫 인코딩 할 경우 → NaN 처리를 따로 안하여 emp_length_UNKOWN 으로 둘 수 있음. 하지만 순서형이 잘 반영이 될지..
    • 순서형으로 두게 될 경우 → NaN 처리를 어떻게 할지

emp_title

신청자가 기재한 직업명/직함, 자유 입력 문자열
  • 공통 키워드로 묶어 큰 범주(의료계, IT, 교육 등)로 분류해 사용하는 경우도 있다고 함. 그러나 일반적으로 emp_length, annual_inc 등 다른 변수로 충분히 유추 가능하다고 보고 제외한 프로젝트가 많은 것 같음. 또, 비용 대비 효과가 낮아 제거하는 게 나을 듯함.
    • 여유 시간이 있다면 진행해보는 것이 좋을 듯

fico_range_high & fico_range_low

FICO 신용점수 구간 상/하한(300 ~ 850)

P2P 대출에서는 이 FICO로 등급을 매겨 금리를 결정할 정도로 핵심 지표

  • 둘의 상관이 매우 높기 때문에 high나 low 둘 중에 하나 사용하거나 평균값을 사용하는 방법이 괜찮을 듯

EDA

sub_grade로만 int_rate(이자율)이 결정되는지?

sub_grade로만 결정되는 건 아님

  • sub_grade 별 int_rate 분포

application_type - Joint Application(공동 대출), Individual(개인 대출)

Joint Application(공동 대출)일 경우, fully paid 일 확률이 높을까?

오히려 Joint Application 이 정상상환 비율이 적음

  1. 공동 신청 자체가 위험군 일수도 있음
      • 공동 신청은 한 명만으로는 대출이 안 되거나, 신용이 낮은 사람이 포함되어 있을 가능성 높음
      • 두 명의 소득/신용을 합쳐서 겨우 조건을 맞춘 경우라면, 오히려 위험도가 높은 “구제성” 대출일 수도 있음
  1. 공동 신청은 대출 한도가 더 크기 때문에 연체 위험이 오히려 클 수도 이음
    1. 실제로 공동 대출일수록 대출 금액이 크다.

application_type 별 대출 목적 차이
  • 두 신청 유형 모두 부채통합/신용카드 상환이 대다수 목적
  • 공동신청은 주택개선, 의료 등 가족 중심의 고액 목적 비율이 조금 더 높음
  • 개인신청은 신용카드, 자동차, 휴가 등 비중이 더 높음

issue_d(대출 승인월) - 2007/6 ~ 2020/9

Initial List Status - W(Whole, 단일 투자자), F(Factional, 여러 투자자)

  • 두 그룹 모두 정상상환이 약 80% 정도
  • 대출의 투자 방식과 상관없이 연체/부실 비율, 정상상환 비율이 거의 똑같음

addr_state

  • 50개 주 + WA → 총 51개
  • 서로 인접한 저부실/고부실 주들이 군집(cluster) 형태로 분포함

dti(debt-to-income ratio)

  • outlier 포함
  • outlier 제외

annual_inc

  • outlier 포함
  • outlier 제외

funded_amnt, funded_amnt_inv

funded_amnt, funded_amnt_inv 의 값 차이가 나는 이유가 뭘까..

파생변수

소득 대비 대출금 비율

채무자의 상환 부담을 나타내는 지표

loan_amnt / annual_inc

dti 와 다른 점

  • dti에는 타 부채까지 포함되므로 신규 대출에 한정한 부채비율을 별도로 보기위함

월 납입액 대비 소득비율

매달 갚아야 할 금액 기준으로 부담을 측정

installment / (annual_inc/12)

  • 월 소득 중 몇 %가 해당 대출 상환에 쓰이는지 파악, 이 비율이 높으면 생활비 대비 상환 부담이 커서 부도 확률을 높일 수도 있음

신용기간(신용이력 길이)

채무자의 신용거래 시작 시점부터 대출 신청 시점까지의 기간(연수)

earliest_cr_line과 issue_d을 이용해 년수 차이를 계산

  • 신용기간이 길수록 오랜 신용기록을 보유한 것으로, 일반적으로 신용도가 안정적일 가능성이 높음

연체 이력 플래그

과거에 연체나 불량 기록이 있는지를 나타내는 이진 변수

delinq_2yrs > 0

  • 과거에 연체가 한 번이라도 있었다면 부도 확률이 높아질 수 있으므로 모델에 중요한 신호가 됨

최근 신용조회 빈도 플래그

최근 6개월 내 신용조회 수가 높으면 여러 곳에서 대출을 시도한 흔적으로 볼 수 잇음

inq_last_6mths

  • 신용공급 접근 난이도를 보여주는 지표로 간접적인 위험 신호

대출 등급/금리 파생

등급별로 분석도 해야함..

 

추천 글

BlogPro logo