로지스틱 회귀(Logistic Regression)는 이진(binary) 결과를 예측하기 위한 대표적인 통계 기법입니다. 이미 오래전부터 금융, 의료, 범죄학 등 다양한 사회과학 분야에서 폭넓게 활용되고 있는 검증된 방법론입니다.
이 글에서는 파이썬(Python)을 사용해 로지스틱 회귀를 직접 구현해 보겠습니다. 물론 R 같은 다른 언어로도 동일한 분석을 수행할 수 있습니다.
필요 라이브러리 설치
예제 프로그램에서 사용할 라이브러리는 다음과 같습니다.
Numpy: 수치 배열과 행렬 정의
Pandas: 데이터 처리 및 조작
Statsmodels: 파라미터 추정 및 통계 검정
Pylab: 그래프(플롯) 생성
CLI에서 아래 명령어를 실행하면 pip를 통해 해당 라이브러리들을 한 번에 설치할 수 있습니다.
>pip install numpy pandas statsmodels
로지스틱 회귀 활용 사례
파이썬에서 로지스틱 회귀를 테스트하기 위해, UCLA(Institute for Digital Research and Education)가 제공하는 로짓 회귀 데이터를 사용하겠습니다. 아래 링크에서 CSV 형식의 데이터를 내려받을 수 있습니다.
https://stats.idre.ucla.edu/stat/data/binary.csv
CSV 파일을 로컬에 저장한 후 읽어도 되고, 링크에서 바로 읽어와도 됩니다. 이 데이터를 통해 어떤 요인들이 대학원 입학에 영향을 미치는지 분석해 보겠습니다.
라이브러리 임포트 및 데이터셋 불러오기
pandas의 read_csv 함수를 사용해 데이터를 읽어옵니다.
import pandas as pd
import statsmodels.api as sm
import pylab as pl
import numpy as np
df = pd.read_csv('binary.csv')
# 링크에서 바로 읽어올 수도 있습니다
# df = pd.read_csv('https://stats.idre.ucla.edu/stat/data/binary.csv')
print(df.head())
출력 결과
admit gre gpa rank 0 0 380 3.61 3 1 1 660 3.67 3 2 1 800 4.00 1 3 1 640 3.19 4 4 0 520 2.93 4
출력 결과를 보면 'rank'라는 컬럼 이름이 보입니다. 'rank'는 pandas DataFrame의 메서드 이름이기도 하므로 충돌이 발생할 수 있습니다. 이를 피하기 위해 컬럼 이름을 'prestige'로 변경하겠습니다.
df.columns = ["admit", "gre", "gpa", "prestige"] print(df.columns)
출력 결과
Index(['admit', 'gre', 'gpa', 'prestige'], dtype='object')
컬럼 이름이 정상적으로 변경되었습니다. 이제 데이터셋이 어떤 내용을 담고 있는지 더 자세히 살펴보겠습니다.
데이터 요약
pandas의 describe 함수를 사용하면 데이터 전체에 대한 요약 정보를 한눈에 확인할 수 있습니다.
print(df.describe())
출력 결과
admit gre gpa prestige count 400.000000 400.000000 400.000000 400.00000 mean 0.317500 587.700000 3.389900 2.48500 std 0.466087 115.516536 0.380567 0.94446 min 0.000000 220.000000 2.260000 1.00000 25% 0.000000 520.000000 3.130000 2.00000 50% 0.000000 580.000000 3.395000 2.00000 75% 1.000000 660.000000 3.670000 3.00000 max 1.000000 800.000000 4.000000 4.00000
각 컬럼의 표준편차도 확인할 수 있습니다.
# 각 컬럼의 표준편차 확인 print(df.std())
출력 결과
admit 0.466087 gre 115.516536 gpa 0.380567 prestige 0.944460 dtype: float64
합격 여부(admit)와 출신 학교의 평판(prestige)을 교차시킨 빈도표도 만들어 보겠습니다.
# prestige별 합격 여부 빈도표 print(pd.crosstab(df['admit'], df['prestige'], rownames=['admit']))
출력 결과
prestige 1 2 3 4 admit 0 28 97 93 55 1 33 54 28 12
이번에는 데이터셋의 모든 컬럼을 히스토그램으로 시각화해 보겠습니다.
# 모든 컬럼 시각화 df.hist() pl.show()
출력 결과

더미 변수(Dummy Variables)
pandas는 범주형(categorical) 변수를 다루는 데 매우 유연한 기능을 제공합니다. get_dummies 함수를 사용하면 'prestige' 컬럼을 쉽게 더미 변수로 변환할 수 있습니다.
# prestige를 더미 변수로 변환 dummy_ranks = pd.get_dummies(df['prestige'], prefix='prestige') print(dummy_ranks.head())
출력 결과
prestige_1 prestige_2 prestige_3 prestige_4 0 0 0 1 0 1 0 0 1 0 2 1 0 0 0 3 0 0 0 1 4 0 0 0 1
회귀 분석에 사용할 깔끔한 데이터프레임을 새로 만들겠습니다. 이때 prestige_1은 기준(base) 범주 역할을 하므로 제외하고, 나머지 더미 변수만 포함합니다.
# 회귀용 데이터프레임 생성 cols_to_keep = ['admit', 'gre', 'gpa'] data = df[cols_to_keep].join(dummy_ranks.loc[:, 'prestige_2':])
출력 결과
admit gre gpa prestige_2 prestige_3 prestige_4 0 0 380 3.61 0 1 0 1 1 660 3.67 0 1 0 2 1 800 4.00 0 0 0 3 1 640 3.19 0 0 1 4 0 520 2.93 0 0 1
참고: 과거 코드에서 사용되던 .ix 인덱서는 최신 pandas 버전에서 제거되었습니다. 위 예제처럼 .loc을 사용하는 것이 좋습니다.
로지스틱 회귀 수행
이제 본격적으로 로지스틱 회귀를 수행합니다. 방법은 매우 간단합니다. 먼저 예측하려는 변수가 담긴 컬럼을 지정하고, 그다음 모델이 예측에 사용할 컬럼들을 지정하면 됩니다.
여기서는 gre, gpa, 그리고 더미 변수인 prestige_2, prestige_3, prestige_4를 독립변수로 사용해 admit(합격 여부)를 예측합니다.
train_cols = data.columns[1:] # Index(['gre', 'gpa', 'prestige_2', 'prestige_3', 'prestige_4'], dtype='object') logit = sm.Logit(data['admit'], data[train_cols]) # 모델 학습 result = logit.fit()
출력 결과
Optimization terminated successfully. Current function value: 0.573147 Iterations 6
결과 해석
statsmodels를 사용해 요약(summary) 출력을 생성해 보겠습니다.
print(result.summary2())
출력 결과
Results: Logit
=================================================================
Model: Logit No. Iterations: 6.0000
Dependent Variable: admit Pseudo R-squared: 0.083
Date: 2019-03-03 14:16 AIC: 470.5175
No. Observations: 400 BIC: 494.4663
Df Model: 5 Log-Likelihood: -229.26
Df Residuals: 394 LL-Null: -249.99
Converged: 1.0000 Scale: 1.0000
-----------------------------------------------------------------
Coef. Std.Err. z P>|z| [0.025 0.975]
-----------------------------------------------------------------
gre 0.0023 0.0011 2.0699 0.0385 0.0001 0.0044
gpa 0.8040 0.3318 2.4231 0.0154 0.1537 1.4544
prestige_2 -0.6754 0.3165 -2.1342 0.0328 -1.2958 -0.0551
prestige_3 -1.3402 0.3453 -3.8812 0.0001 -2.0170 -0.6634
prestige_4 -1.5515 0.4178 -3.7131 0.0002 -2.3704 -0.7325
intercept -3.9900 1.1400 -3.5001 0.0005 -6.2242 -1.7557
=================================================================
결과 객체(result object)를 사용하면 모델 출력의 일부분만 골라서 따로 살펴볼 수도 있습니다.
# 각 계수의 신뢰구간 확인 print(result.conf_int())
출력 결과
0 1 gre 0.000120 0.004409 gpa 0.153684 1.454391 prestige_2 -1.295751 -0.055135 prestige_3 -2.016992 -0.663416 prestige_4 -2.370399 -0.732529 intercept -6.224242 -1.755716
위 출력 결과에서 눈여겨볼 점은, 합격 확률과 지원자 학부 출신 학교의 평판(prestige) 사이에 역방향 관계(inverse relationship)가 있다는 것입니다.
즉, 상위권 학부를 졸업한 지원자(prestige_1 = True)는 상대적으로 낮은 순위의 학교(prestige_3 또는 prestige_4) 출신 지원자보다 대학원에 합격할 확률이 더 높다는 의미입니다. 이처럼 로지스틱 회귀를 활용하면 각 변수가 합격 여부에 미치는 영향을 계수 형태로 명확하게 해석할 수 있습니다.