주제
1. Scikit-learn 소개
2. 지도학습에 대하여
3. 선형 회귀와 선형 분류
4. 실습
Scikit-learn 소개
- 다양한 머신러닝 알고리즘이 구현되어 있는 오픈소스 패키지
- 데이터 처리, 파이프라인, 여러 학습 알고리즘, 전 / 후처리 등 다양한 기능을 제공
- 주요 객체 :
- Estimator(추정기) :
- fit() 메서드를 활용하여 학습을 진행
- 데이터로부터 패턴을 학습하고 결과로 모델 내부 파라미터를 조정
- Predictor(예측기) :
- predict() 메서드를 활용
- 학습된 모델을 사용해 새로운 데이터에 대한 예측을 수행
- Transformer(변환기) :
- 데이터를 새로운 형태로 변환하기 위해 transform() 메서드 활용
- 군집화, PCA 차원 축소 등의 과정을 위해 fit_transform() 메서드를 활용
- Model(모델) :
- 모델의 학습 적합도를 확인할 수 있도록 score() 메서드를 제공
- 학습된 모델의 성능을 평가할 수 있음
- Estimator(추정기) :
- 파이프라인
- 머신러닝 워크플로우의 여러 단계를 하나의 수준으로 연결하는 작업
- Pipeline은 이름과 추정기 객체가(key, value) 쌍으로 구성되어야 함
- make_pipeline 함수는 key 값을 자동 할당
- 파이프라인의 마지막을 제외하고는 모두 변환기(transformer)여야 함
- 마지막은 추정기, 예측기 , 변환기가 올 수 있음
지도학습에 대하여
- 문제(Task) : 머신 러닝 기법을 활용해 해결하고자 하는 대상
- 지도학습의 흔한 문제의 종류 :
- 회귀 문제(Regression problem)
- 분류 문제(Classification problem)
1. 회귀 문제(Regression Problem)
- 입력 데이터를 바탕으로 정확한 숫자 형태의 결과를 예측하는 문제
- 예. 내일 주식 가격은?
2. 분류 문제(Classification Problem)
- 입력으로 주어지는 데이터를 정해진 보기 중 하나로 분류하는 문제
- 보기 : 클래스(class)
- 세분화 :
- 이진 분류 문제 : 주어지는 클래스가 2개인 경우
- 다중 클래스 문제 : 모델이 여러 클래스를 내보내야 하는 경우
데이터 분할 : 학습 / 검증 / 평가
| 학습 데이터(train data) | 검증 데이터(validation data) | 평가 데이터(test data) |
| 순수하게 학습을 하는 과정에서 사용하는 데이터 갖고 있는 전체 데이터 중 가장 많은 비율을 차지(약 80%) |
학습 중간에 머신 러닝 모델이 어느 정도 학습되었는지를 주기적으로 확인하는데 사용하는 데이터 (약10%) | 학습과는 별도의 과정으로, 모델이 생성된 후 학습한 모델의 최종 성능을 평가하기 위해 사용되는 데이터 (약 10%) 학습 과정에서는 절대 사용되지 않음 |
과적합(Overfitting)
- 모델이 특정 훈련 데이터에 지나치게 학습되어 새로운 데이터나 테스트 데이터에서 잘 작동하지 않는 상태
- 일반화 능력(generalization)이 떨어진 상태
- 단순히 데이터를 외워버린 경우를 뜻함
- 방지법 :
- 데이터 양 늘리기
- 모델의 복잡도 줄이기
- 규제 같은 정규화 기법 사용하기

손실 함수(Loss function)
- 손실(Loss) : 모델이 얼마나 잘 하고 있는지 또는 못하고 있는지를 수치화한 것
- 손실 함수 : 모델의 예측값과 실제 정답 사이의 차이를 측정하는 지표. 손실은 적을수록 성능이 좋다는 뜻
- 머신 러닝 모델을 학습하는 과정은 결국 손실을 줄이는 과정!
- 손실 함수의 종류는 문제의 유형에 따라 다름 :
- 회귀 문제 : 평균 제곱 오차(Mean Squared Error, MSE)
- 분류 문제 : 교차 엔트로피(Cross Entropy)
- 이진 분류 문제 : 로그 손실(Log Loss)
파라미터(Parameter)와 최적화(Optimization)
- 파라미터 : 모델이 내부적으로 갖고 있는 변수로, 데이터로부터 학습하는 패턴 관계를 표현하며 모델의 예측 성능에 직접적인 영향을 미침
- 최적화 : 모델의 성능을 최적화하거나, 오류를 최소화하기 위해 모델의 파라미터를 조절하는 과정을 의미. 즉, Loss값이 최소가 되는 파라미터를 찾는 것이 목표
분류 문제와 회귀 문제
- 분류 문제
| 로지스틱 회귀(Logistic Regression) | 결정 트리 분류기(Decision Tree Classifier) | 랜덤 포레스트(Random Forest) | 서포트 벡터 머신(Support vector Machine, SVM) |
| 이진 분류 문제에 적합. 확률을 직접 예측하는 확률 추정 접근으로 결과를 예측 |
데이터를 분할하는 결정 트리를 사용. 직관적이고 이해가 쉬움 |
여러 결정 트리의 결합으로 앙상블 기법에 해당. 높은 정확도를 보이며 과적합 문제를 방지 |
데이터를 최적으로 분리하는 결정 경계를 찾는데 강력한 알고리즘. 어려운 형태의 데이터라도 비선형 계산이 가능한 다양한 커널 트릭이 있어 해를 구할 수 있음 |
- 회귀 문제
| 선형 회귀(Linear Regression) | 라쏘 혹은 릿지 회귀(Lasso & Ridge Regression) | 결정 트리 회귀(Decision Tree Regression) | 서포트 벡터 회귀(Support Vector Regression, SVR) | K-최근접 이웃 회구(K-Nearest Neighbors Regression) |
| 독립 변수와 종속 변수 간의 선형 관계를 모델링 | 규제 기법을 이용해 과적합을 방지하고 일반화 성능이 향상된 선형 모델 | 결정 트리를 이용해 회귀 문제에 적용 | 분류 모델인 SVM을 회귀에 적용한 알고리즘 | 주어진 데이터 포인트에서 가장 가까운 K개의 이웃 데이터의 평균으로 예측값을 결정. 데이터 자체만을 활용한 추정(비모수적 추적)이 가능 |
선형 회귀와 선형 분류
선형 관계란?
- 독립 변수가 파라미터의 값만큼 일정한 비율로 결과 종속 변수에 영향을 미치는 관계
- 파라미터들이 어떠한 실수(혹은 벡터)와 가중 합(곱하기 & 더하기)으로 표현된 것
- 파라미터들이 선형 결합을 이루고, 종속 변수의 값을 표현할 수 있을 때 선형 모델이라고 함

- x1, x2, .... , xn : 독립 변수 혹은 특징(feature), 보통 입력한는 데이터
- w1, ... , wn : 파라미터, 찾아내야 하는 값
- y : 종속 변수
- "선형적"이라는 것은 관점에 따라 다르기 때문에 보통 파라미터가 종속 변수에 미치는 영향이 선형적이라는 가정 하에 선형 모델을 사용
- 머신 러닝 모델 학습 → 특정한 제약 조건이 주어진 상태에서 파라미터의 적절한 값을 찾는 것 → Loss를 줄이는 최적의 상태
- 선형 모델의 가정 :
- 서로 다른 독립 변수는 서로 상관성이 없어야 함
- 만약 두 독립 변수 사이에 높은 상관관계가 있다면 다중공선성(multicollinearity)라는 문제가 발생 → 정확도, 신뢰성 저하
선형 회귀
- 선형 회귀 모델을 사용한다는 것 → 데이터 특징에 대한 선형 결합으로 회귀 문제를 풀겠다는 뜻

- ŷ : 예측값
- w0은 절편 혹은 편향
- 가중합으로 표현되는 다항식은 행렬곱(Xw)으로 표현 가능

- n : 전체 데이터의 수
- p : 입력 데이터가 갖고 있는 특성의 수
비용 함수
- 목표값과 예측값 사이의 계산을 통해 정의
- 회귀 문제의 비용 함수는 평균 제곱 오차(Mean Squared Error, MSE)
- 평균 제곱 오차 : 두 값 사이의 양적 차이의 제곱 평균으로 비용 함수(J(w))를 정의

- 이런 비용 함수를 최소화하는 파라미터(w)들을 찾아야 함
- 잔차의 제곱값이 가질 수 있는 최소의 파라미터를 찾는 작업이므로 최소제곱법(Ordinary Least square, OLS)라고도 함

최적화 방법론
- 최적화 : 특정 문제에서 최적의 해를 찾는 과정
- 최적 : 보통 특정 함수의 최소값 혹은 최대값을 찾는 것
- 선형 회귀를 위한 최적화 방법 :
- 정규 방정식(Normal Equation)
- 경사 하강법(Gradient Descent)
1. 정규 방정식(Normal Equation)
- 정규 방정식 : 비용 함수(J(w))의 도함수를 구하고, 그것이 0이 되는 파라미터(w)를 구하는 식

- J(w)는 이차방정식의 곡선의 형태를 띄고 있음 → 이를 최적화하기 위해서는 최소값이 되는 w를 찾아야 함 → 곡선이 최소가 되는 지점 = 도함수가 0이 되는 지점 = 기울기가 0이 되는 지점의 해를 구하는 것이 정규 방정식!
- 시간 복잡도 : O(p³)
- X^TX의 역행렬 계산이 필요
- 일반적으로 n >> p인 경우에 유용
2. 경사 하강법(Gradient Descent)
- 비용 함수를 최소화하기 위해 반복해서 파라미터를 조정해가는 방법
- 임의로 잡은 초기 파라미터 값을 기준으로 비용 함수의 기울기(Gradient)를 계산하여, 기울기가 줄어드는 방향으로 파라미터를 수정 이동
- 기울기가 0에 가까워지면 멈춤
- 주의 사항
- 적절한 학습률(learning rate, 학습 속도)에 대한 탐구가 필요
- 값이 너무 작다면 최적화 소요 시간 ↑
- 값이 너무 크다면 발산 혹은 최적값 도달 가능성 ↓
- 적절한 학습률(learning rate, 학습 속도)에 대한 탐구가 필요

- 비용 함수를 통한 전체 비용을 대상으로 각 파라미터의 미분값을 구하고, 현재 값을 기준으로 기울기가 작아지는 방향(-gradient)으로 이동

2.1 확률적 경사 하강법(Stochastic Gradient Descent, SGD)
- 경사 하강법은 학습 데이터가 많은 경우 시간 소요가 큼
- 이를 극복하기 위해 사용되는 것이 확률적 경사 하강법
- 확률적 경사 하강법 : 전체 데이터 중 임의로 일부 데이터를 샘플링하여 그것을 대상으로 경사 하강법을 진행
- 작은 데이터로 수정 이동을 반복하므로 빠른 수렴이 가능함
- 데이터가 많거나(n >>) 특성 feature가 많은 경우(p >>) 사용이 용이

3. 정규 방정식 vs. 경사 하강법
| 정규 방정식 | 경사 하강법 |
| 튜닝할 변수가 없이 명시적으로 해를 제공 | 특성 수와 샘플의 수에 민감도가 적음 |
| 특성의 수가 많다면 계산 복잡도와 메모리가 많이 필요 | 반복적인 연산이 필요, 변수 튜닝이 결과에 영향을 줄 수 있음 |
| 훈련 세트가 크지 않은 상황에서 빠르게 해를 구하기 좋음 |
다중공선성(multicollinearity)
- 입력 데이터가 갖고 있는 특징값들 사이에 상관 관계가 존재할 때 발생하는 문제
- 안정성과 해석력 저하
- 정규 방정식 해 풀이에 사용되는 (X^TX)^-1 이 존재하지 않을 수 있음
- 이를 해결하기 위해 SVD-OLS라는 회피 방법이 존재
SVD-OLS, Singular Value Decomposition-OLS
- 학습 데이터를 모아둔 행렬 X에 SVD를 적용해 특이값 분해 (X = UΣV^T)
- 강한 다중공선성이 있는 경우, 해를 다른 방식으로 구하는 방법
- 특이값이 분해된 입력 X에 OLS 방식의 풀이를 적용하면 다음과 같은 식이 된다

- 즉 X를 사용할 수 없으니(역행렬이 존재하지 않음), 특이값 분해를 이용하여 X를 특이값으로 치환 후 해를 구하는 것
- 시간 복잡도 : O(np^2)
규제(Regulation)를 사용하는 선형 모델
- 과적합이 발생하면 파라미터인 w의 값이 매우 커지게 됨
- w의 값이 너무 커지지 않도록 규제를 가해 문제를 회피할 수 있음
- 기존 비용 함수에 제어할 변수 항목을 추가하는 방식으로 규제를 진행
- 추가로 규제 강도를 조절할 수 있는 새로운 변수 α를 추가
- 규제를 추가해 일반화 성능에 도움이 되도록 설계한 모델 :
- 라쏘 회귀(Lasso regression)
- 릿지 회귀(Ridge regression)
1. 라쏘 회귀(Lasso regression)
- 머신 러닝 모델의 파라미터의 절댓값(L1 norm)의 합 항을 추가

- L1 규제는 일부 파라미터의 값을 완전히 0으로 만들 수 있음
- 이를 통해 모델이 사용하는 데이터의 특성 중 불필요한 특성을 무시하는 효과를 가져옴
- 변수가 많고 일부의 변수가 중요한 역할을 하는 경우 활용

- 베타햇에서부터 라쏘 회귀를 나타낸 다이아몬드 모형까지 제일 가까운 루트는 다이아몬드의 각 꼭지점
- 꼭지점은 베타1이나 베타2가 0이 되는 지점 → 불필요한 특성을 무시함
2. 릿지 회귀(Ridge regression)
- 릿지 회귀는 제곱합(L2 norm) 항을 추가

- L2 규제는 파라미터 값을 적당히 작게 만듦 (0에 가까운 값이지만 0은 아님)
- 입력으로 받는 데이터의 모든 부분을 이용해 출력을 판단하는데 사용
- 모든 특성이 출력 결과에 적당히 영향을 미치는 경우에 유용함

- 베타햇으로부터 릿지 회귀를 나타낸 원까지의 거리는 0에 가깝지만 0은 아니다
선형 분류
로지스틱 회귀(Logistic Regression)
- 이진 분류 문제를 해결하기 위한 기본 알고리즘 중 하나
- 입력 데이터가 후보 클래스 중 각각의 클래스일 확률을 예측하는 모델
- 예. 병아리의 이미지를 보고 병아리 98%, 강아지 2%라고 예측하는 것
- 확률을 직접적으로 예측(확률 추정)하는 방식
- 분류 문제를 회귀 방식으로 풀어서 로지스틱 "회귀"
- 예측한 특정 클래스의 확률값이 50% 이상이면 → 양성(positive, 해당 클래스에 속한다)
- 예측한 특정 클래스의 확률값이 50% 미만이면 → 음성(negative)
- 다중 클래스 분류 문제의 접근법 :
- One-vs-One (OvO)
- One-vs-Rest (OvR)
- Softmax Regression
- 로지스틱 회귀도 선형 모델의 조건을 가정함

- logit hat : 결과로 뽑아낼 확률값의 로짓값
- p̂ : 로짓 결과를 확률의 형태로 변경한 확률 추정치
- σ : 로짓을 확률로 변경하기 위한 함수 (로지스틱 함수)
- ŷ : 추정 확률로부터 구한 머신 러닝 모델의 예측
로짓(로그 오즈), 로지스틱 함수
- 오즈(odds) : 특정 사건이 발생할 확률(p)과 발생하지 않을 확률(1-p)의 비율

- 로그 오즈(log-odds) : 오즈에 log 함수를 씌운 결과로, 로짓(logit)이라고도 함. 결과를 ±∞의 범위를 갖도록 변환.

- 로지스틱 : 로그 오즈의 역함수로, 로짓을 입력으로 주면 확률 p를 반환
- 출력은 항상 0 ~ 1 사이의 값을 가짐
- 함수의 개형이 S자 모양이어서 Sigmoid(σ)라고 부름


- 정리 :
- 로지스틱 회귀 모델의 출력 결과는 로짓에 해당
- 따라서 특정 클래스일 확률(p)를 알기 위해 로지스틱 함수를 사용
- 왜 확률을 바로 구하지 않는가?
- 확률의 입장에서 변화량은 구간에 따라 다른 의미를 가짐
- 예. 0.49 ↔ 0.50 vs. 0.98 ↔ 0.99 는 같은 0.01 차이지만 전자는 클래스가 달라질 수 있음
- 즉, 출력 결과의 해석이 선형적이지 않을 수 있음
- 따라서 우선 오즈에 로그를 취해 ±∞로 결과를 무한히 확장시켜놓고, 역함수를 활용해 확률(p)를 계산하는 것!
비용 함수
- 분류도 마찬가지로 정답과의 차이로 비용 함수를 계산
- 분류 문제는 log 함수를 이용한 로그 손실(log loss) 값을 사용
- 목적 데이터의 클래스가 양성일 경우(y=1)와 음성일 경우(y=0)로 나누어 하나의 데이터에 대한 비용 함수를 고려한 식은 다음과 같다

- p̂ 는 실제 정답 y를 따라가게 됨

- 위의 식을 하나의 식으로 보자면 다음과 같다

- 실제 정답(y)에 따라 각 항이 삭제되어 똑같은 식으로 볼 수 있음
- 전체 학습 데이터에 대한 비용 함수는 모든 비용 함수의 평균

분류 문제의 최적화
- 분류 문제도 마찬가지로 비용 함수를 최소화시킬 수 있는 파라미터를 찾아야 함
- 로그 로스(log loss)의 경우 회귀 문제의 정규 방정식같은 직접적으로 계산 가능한 해가 없음
- 따라서 경사 하강법을 사용해야함
- 혹은 라쏘 / 릿지 회귀의 규제 방법론을 사용할 수 있음
경사 하강법 - 파라미터 업데이트(로지스틱 회귀)
- 기울기가 작아지는 방향을 찾기 위해 각 파라미터의 편미분값을 구함(1/N은 생략됨)

- Chain rule에 의해 연쇄적으로 계산하면 결과적으로 편미분값은 다음과 같다

- 이를 이용하여 새로운 파라미터(w new)로 업데이트

실습
1. 선형 회귀 모델 실습
- 케글의 의료비 개인 데이터셋을 사용
- 데이터 셋 : https://www.kaggle.com/datasets/mirichoi0218/insurance?rvi=1
Medical Cost Personal Datasets
Insurance Forecast by using Linear Regression
www.kaggle.com
- 문제 정의 : 주어진 건강 및 인구통계학적 정보를 바탕으로 개인의 연간 의료 보험료 예측
- 입력 : 독립 변수들
- 출력 : 개인 의료비(종속 변수)
1.1 EDA 진행
- 데이터를 탐색하며 데이터의 특징, 구조, 패턴, 이상치, 변수 간의 관계 등을 이해
- 데이터에 대한 직관을 얻거나, 후속 분석에 필요한 모델링 전략 수립의 통찰을 얻을 수 있음
- 기초 통계 분석 : 평균, 중앙값, 표준편차, 최소 / 최대값
- 총 1338개의 데이터, 7개의 특성
- 데이터 타입은 정수형, 실수형, 문자열
- 시각화 : 데이터 패턴, 이상치, 경향성 식별
- 데이터 타입을 나눠서 분포 확인
- 카테고리 데이터는 종속 변수와의 관계를 살펴볼 수 있음


- 변수간 관계 파악 : 변수 간 상관관계 분석

- 이상치 탐지 : 다른 데이터의 특성에서 벗어난 비정상적 데이터 식별
- 결측치 분석 : 누락 데이터 확인
- 누락 없음
1.2 데이터 전처리
- 카테고리형 변수는 수치형으로 변경해야 함
- 원-핫 인코딩(One-hot encoding) 방식을 사용
- Pandas의 get_dummies 함수를 사용하여 예를 들어 성별이라면, 성별_남성과 성별_여성이라는 별도의 열을 만들고 0과 1로 표현
- 이때 인자로 drop_first=True를 해주어야 첫 카테고리를 삭제한다
- 삭제하는 이유는 삭제하지 않으면 새로 생긴 변수들 간의 강한 상관관계로 인한 다중공선성 문제가 발생하기 때문
insurance_encoded = pd.get_dummies(insurance_data, drop_first=True)
insurance_encoded

1.3 학습 및 평가 데이터 분리
- 데이터를 학습 / 검증 / 평가 과정으로 나누어야 하지만 실습의 경우 학습과 평가로만 분리
- 먼저 독립 변수와 종속 변수를 분리한다
- 이후 sklearn의 내장 함수인 train_test_split이라는 함수를 사용
- test_size인자는 학습과 평가 데이터 사이의 비율을 의미(이 경우 학습 데이터는 20%를 사용)
from sklearn.model_selection import train_test_split
# 종속 변수인 charges를 분리
y_column = ['charges']
# 종속 변수를 원래 데이터에서 삭제
X = insurance_encoded.drop(y_column, axis=1)
# 출력값에 종속 변수 열 지정
y = insurance_encoded[y_column]
# 학습과 평가 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.2,
random_state=42)
1.4 특성 스케일링
- 필수는 아니지만 권장되는 단계
- 서로 다른 수치형 데이터 특성 사이의 값 범위를 비슷하게 맞춰주는 과정
- 효과 :
- 경사 하강법을 사용하는 과정에서 수렴 속도↑
- 규제 모델 사용 시 일부 특성에 강하게 규제가 걸리는 과정을 피할 수 있음
- 방법 :
- StandardScaler
- 평균 0, 표준편차 1로 조정
- 데이터의 분포가 정규분포일 경우 사용하면 best!
- 일반적으로 많이 사용
- MinMaxScaler
- 최댓값 1, 최솟값 0이 되도록 조정
- 이상치가 큰 영향을 미치는 경우 사용
- StandardScaler
from sklearn.preprocessing import StandardScaler
# 인코딩된 열과 수치형 데이터 분리
encoded_columns = list(set(insurance_encoded.columns) - set(insurance_data.columns)) # ['region_southwest', 'region_southeast', 'region_northwest', 'smoker_yes', 'sex_male']
continuous_columns = list(set(insurance_encoded.columns) - set(encoded_columns) - set(y_column)) # ['bmi', 'age', 'children']
# 스케일링 방법 선택
scaler = StandardScaler()
# 수치형 데이터만 스케일링 진행
X_train_continuous = scaler.fit_transform(X_train[continuous_columns])
X_test_continuous = scaler.fit_transform(X_test[continuous_columns])
# 스케일 된 데이터와 스케일에 사용되지 않은 데이터 조합
X_train_continuous_df = pd.DataFrame(X_train_continuous, columns=continuous_columns)
X_test_continuous_df = pd.DataFrame(X_test_continuous, columns=continuous_columns)
X_train_categorical_df = X_train[encoded_columns].reset_index(drop=True)
X_test_categorical_df = X_test[encoded_columns].reset_index(drop=True)
X_train_final = pd.concat([X_train_continuous_df, X_train_categorical_df], axis=1)
X_test_final = pd.concat([X_test_continuous_df, X_test_categorical_df], axis=1)

- age, children, bmi의 범위가 비슷해짐
1.5 모델 구축 및 결과 확인
평가 진행
- MSE 값을 이용하여 평균적인 예측 실패 정도를 판단할 수 있음
- 하지만 MSE 값만으로는 잘 한건지 아닌지 판단하기 어려움 → 산점도 시각화 활용 (y = x에 가까울수록 좋은 예측)
- 학습 모델을 불러와 학습 진행
from sklearn.linear_model import LinearRegression
# 선형 회귀 모델 초기화 및 학습
linear_reg = LinearRegression()
linear_reg.fit(X_train_final, y_train)
# 학습된 모델의 계수(coefficients) 및 절편(intercept) 출력
coefficients = linear_reg.coef_
intercept = linear_reg.intercept_
print('#'*20, '학습된 파라미터 값', '#'*20)
print(coefficients)
print('#'*20, '학습된 절편 값', '#'*20)
print(intercept)

- MSE 평가 진행
from sklearn.metrics import mean_squared_error
# 예측 수행
y_train_pred = linear_reg.predict(X_train_final)
y_test_pred = linear_reg.predict(X_test_final)
# 평가 지표 계산: MSE
mse_train = mean_squared_error(y_train, y_train_pred)
mse_test = mean_squared_error(y_test, y_test_pred)
print('학습 데이터를 이용한 MSE 값 :', mse_train)
print('평가 데이터를 이용한 MSE 값 :', mse_test)

- 산점도 시각화로 평가 확인
# 테스트 데이터셋에 대한 실제 값과 예측 값을 산점도로 시각화
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_test_pred, alpha=0.6)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--') # 완벽한 예측을 나타내는 대각선
plt.xlabel('Real Values')
plt.ylabel('Predict Values')
plt.title('Real vs Predict')
plt.show()

- 작은 값들에 대해서는 좋은 예측이 진행되었다고 볼 수 있다
- 하지만 값이 커질수록 예측값과 실제값의 차이가 존재한다
선형 회귀 모델 학습 진행
- 선형 회귀 모델에 영향을 미치는 변수의 중요도
- w0값을 위해 bias를 추가 (내장 함수를 이용하면 자동으로 추가해서 결과를 보여줌, 실습을 위해 수동으로 추가)
from sklearn.linear_model import LinearRegression
# 편항 추가
X_train_final['bias'] = 1
linear_reg = LinearRegression()
linear_reg.fit(X_train_final, y_train)
coefficients = linear_reg.coef_
intercept = linear_reg.intercept_
1.6 결과 해석
- 회귀 모델이 사용한 변수 중 중요한 변수를 추출
- 선형 모델의 장점으로 파라미터를 시각화해 이것의 중요도를 알 수 있음
coeff_df = pd.DataFrame({'feature': X_train_final.columns, 'coefficient': linear_reg.coef_.flatten()})
# 계수의 절대값을 기준으로 내림차순 정렬
coeff_df['abs_coefficient'] = coeff_df['coefficient'].abs()
coeff_df_sorted = coeff_df.sort_values(by='abs_coefficient', ascending=False)
# 변수의 영향력을 확인
coeff_df_sorted


- 그래프에 따르면, 흡연자일수록 의료비를 많이 낸다고 볼 수 있다
- 그 다음으로는 나이와 bmi가 관계가 크다고 할 수 있다
- 반면 성별(남성)은 의료비와 큰 상관관계가 없다고 할 수 있다
1.6.1 잔차 분포
- 정답과의 차이인 잔차(residual)의 분포를 확인
- 무작위 분포 : 좋은 분포
- 특정 패턴이 존재 : 데이터를 완전히 파악하지 못함
# 정답과의 차이를 보이는 잔치(residual)을 시각화해
# 이것의 분포를 확인해 데이터의 패턴을 알마나 잘 포착하는지를 판단
# 무작위로 분포되어야 좋은 상황
# 잔차 도출
y_pred = linear_reg.predict(X_train_final)
residuals = y_train - y_pred
# 잔차 시각화
plt.figure(figsize=(10, 6))
plt.scatter(y_pred, residuals)
plt.axhline(y=0, color='red', linestyle='--')
plt.xlabel('Predict')
plt.ylabel('Residual')
plt.title('Residual Analysis')
plt.show()

- 결과 확인 :
- 예측값이 커질수록 분포가 넓어짐
- 큰 예측값에서 2개의 그룹이 존재함
- 해석 및 추후 필요 행동 :
- 의료비가 큰 경우 해석력이 떨어지므로 비선형적 특성이 있을 수 있음
- 비선형 모델을 선택하거나 로그 혹은 제곱근 변환 등의 비선형 근사법 적용
- 이상치의 영향이 있을 수 있으므로 이상치 제거
- 의료비가 큰 경우 해석력이 떨어지므로 비선형적 특성이 있을 수 있음
2. 선형 분류 모델 실습
- 케글의 비행 경험 만족도 데이터 사용
- 데이터 셋 : https://www.kaggle.com/datasets/sjleshrac/airlines-customer-satisfaction?rvi=1
Airlines Customer satisfaction
Customer satisfaction with various other factors
www.kaggle.com
- 문제 정의 : 주어진 탑승객의 개인 및 여행 경험 정보를 바탕으로 비행의 만족도 예측
- 입력 : 독립 변수들(개인 정보, 설문 정보, 여행 정보)
- 출력 : 종속 변수(비행의 만족도)
2.1 EDA
- 총 129,880 개의 데이터와 23개의 특성
- 데이터 타입 : 수치형, 서수형(순서나 등급을 나타냄. 순서는 중요하나 차이는 균일하지 않음), 범주형
- 누락 : Arrival Delay in Minutes
- 출발 및 도착 지연 시간에는 outlier가 보임 → 만족도에 영향을 줄 수 있음을 고려
- 만족도 결과에 따른 분포도 확인
- 이상치 확인
- Delay time에 극단적인 값이 존재
- 상관관계 확인
- 출발 시간이 늦으면 도착 시간도 늦음 → 두 변수 사이에 큰 상관관계 예상 → 선형 모델에 부정적 영향을 미칠 수 있음을 인지
- 서수형 데이터
- 0 - 5점에 해당하는 설문 평가 데이터
- 극단적으로 치우친 문항은 없어보임
- 모델 개발 입장에서 특별히 주의할 변수는 보이지 않음
- 상관관계 : 특정 문항 사이에 높은 상관관계가 보임
2.2 데이터 전처리
- 누락 데이터를 포함한 데이터는 제거
- EDA 과정에서 판단한 제외 데이터(극단적인 값) 제거
- Delay time 시간을 기준으로 clipping
- 카테고리형 변수 인코딩
airplane_cate_encoded = pd.get_dummies(airplane_cleaned[category_columns], drop_first=True)
airplane_target_encoded = pd.get_dummies(airplane_cleaned[y_column], drop_first=True)
airplane_combined = pd.concat([airplane_target_encoded,
airplane_cleaned[numeric_columns + ordinal_columns],
airplane_cate_encoded],
axis=1)
airplane_combined

2.3 일부 특성만 사용
- 종속 변수를 제외한 22개의 변수 중 특정 변수와 큰 상관관계가 있는 변수도 존재함
- 해석력과 일반화 향상을 위해 종속 변수와 여러 독립 변수 사이의 상관관계를 활용하여 상위 15개의 변수만 취함
2.4 데이터 분할
- 마찬가지로 학습 데이터(80%)와 평가 데이터(20%)로 분리
2.5 모델 구축 및 결과 확인
2.5.1 선형 분류 모델 학습 진행
- LogisticRegression() 객체를 생성하여 사용
- bias 항은 따로 추가하지 않아도 자동 추가됨
from sklearn.linear_model import LogisticRegression
# 선형 회귀 모델 초기화 및 학습
logistic_reg = LogisticRegression()
logistic_reg.fit(X_train, y_train)
# 학습된 모델의 계수(coefficients) 및 절편(intercept) 출력
coefficients = logistic_reg.coef_
intercept = logistic_reg.intercept_
print('#'*20, '학습된 파라미터 값', '#'*20)
print(coefficients)
print('#'*20, '학습된 절편 값', '#'*20)
print(intercept)

2.5.2 평가 진행(정확도, Accuracy)
- 예측한 결과가 실제 결과의 일치 혹은 불일치를 기반으로 정확도를 구할 수 있음
- 일치 데이터의 수 / 전체 데이터의 수
- 학습 데이터와 평가 데이터를 기준으로 평가 진행
from sklearn.metrics import accuracy_score
# 예측 수행
y_train_pred = logistic_reg.predict(X_train)
y_test_pred = logistic_reg.predict(X_test)
# 평가 지표 계산: 정확도 (맞은수/전체)
acc_train = accuracy_score(y_train, y_train_pred)
acc_test = accuracy_score(y_test, y_test_pred)
print('학습 데이터를 이용한 Acc 값 :', acc_train)
print('평가 데이터를 이용한 Acc 값 :', acc_test)

- 정확도 말고도 matrix를 평가할 수 있는 방법 : Confusion Matrix
- 정답의 영역과 오답의 영역을 시각화하여 확인
- 좌상 → 우하 방향 대각선 위치의 값이 클수록 좋은 결과
# Confusion matrix 생성을 위한 준비
from sklearn.metrics import confusion_matrix
cm_train = confusion_matrix(y_train, y_train_pred)
cm_test = confusion_matrix(y_test, y_test_pred)
# 학습 데이터를 활용한 confusion matrix
plt.imshow(cm_train, interpolation='nearest', cmap='Blues')
plt.title("Confusion Matrix (Train)")
plt.colorbar()
tick_marks = np.arange(len(np.unique(y_train)))
plt.xticks(tick_marks, np.unique(y_train))
plt.yticks(tick_marks, np.unique(y_train))
plt.xlabel("Predicted Label")
plt.ylabel("True Label")
# 각 셀에 숫자 표시
for i in range(cm_train.shape[0]):
for j in range(cm_train.shape[1]):
plt.text(j, i, cm_train[i, j], ha="center", va="center", color="black")

2.6 결과 해석
- 로지스틱 회귀 모델에 영향을 미치는 변수의 중요도
coeff_df = pd.DataFrame({'feature': X_train.columns, 'coefficient': logistic_reg.coef_.flatten()})
# 계수의 절대값을 기준으로 내림차순 정렬
coeff_df['abs_coefficient'] = coeff_df['coefficient'].abs()
coeff_df_sorted = coeff_df.sort_values(by='abs_coefficient', ascending=False)
# 변수의 영향력을 확인
coeff_df_sorted
- 시각화하여 확인

- 결과 :
- 충성고객이 아닌 고객들의 불만족도가 높을 것이라고 볼 수 있다.
- 또한 이코노미 클라스를 이용했을 때, 고객의 성별이 남성일 때 불만족도가 높을 것이라고 볼 수 있다
- 음료와 음식도 불만족스럽다면 평가가 좋게 나오지 못할 확률이 높다.
- 해석 및 추후 필요 행동 :
- 충성 고객이 아닌 고객들을 충성 고객으로 만들기 위해 음료수와 음식의 퀄리티를 높이는 방안을 제시해볼 수 있다
- 남성 고객의 불만족도가 높은 것을 보아, 보통 남성들의 신장이나 체형이 여성보다 크기 때문에 이코노미 클래스 좌석이 더 좁고 불편하게 느껴질 수도 있을 것으로 보인다.
느낀점
강사님이 용어부터 로직까지 하나하나 자세하게 알려주셔서 이해하기가 크게 어렵지 않았다. 비유도 적절하게 들어주시고 무엇보다 수식으로만 설명하지 않으셔서 다행이라고 생각했다. 그래도 각 문제를 해결하기 위한 방법과 알고리즘의 식은 알고 있어야 나중에 scikit-learn 패키지의 내장 함수를 사용하더라도 그 내부의 과정을 이해할 수 있고, 사용하기도 수월할 것 같다. 그리고 실습을 통해서 차근차근 EDA부터 모델 학습과 평가까지 해보니까 이제서야 데이터 분석가가 만들어낼 수 있는 프로젝트(결과물)이 어떤 모습을 하고, 어떤 부분이 담겨있는지 명확해진 것 같다. 매 프로젝트가 끝나고나서야 이런 강의가 있다는 건 참 아쉬운 일인 것 같다.
'Data Science > TIL (Today I Learned)' 카테고리의 다른 글
| 프로그래머스 데이터분석 데브코스 1기 - 49일차 (1) | 2024.02.01 |
|---|---|
| 프로그래머스 데이터분석 데브코스 1기 - 48일차 (0) | 2024.01.31 |
| 프로그래머스 데이터분석 데브코스 1기 - 46일차 (1) | 2024.01.29 |
| 프로그래머스 데이터분석 데브코스 1기 - 45일차 (1) | 2024.01.26 |
| 프로그래머스 데이터분석 데브코스 1기 - 44일차 (1) | 2024.01.25 |