< BMI 값을 통한 당뇨병 진행률 예측 >
사용 데이터 : sklearn.datasets.load_diabetes() (10개 특성을 가진 당뇨병 데이터셋)
사용 알고리즘 : LinearRegression() - 단순 선형 회귀
평가 방법 : 시각화를 통한 예측선과 실제값 비교
시각화 : matplotlib를 통한 산점도 + 회귀선
< 주요 라이브러리 분석 >
import pandas as pd #데이터 프레임 형태로 조작할 수 있는 도구 (이번 예제에서 직접 사용은 안함)
import numpy as np #수치 계산용 (차원 변형 np.newaxis에 사용)
import matplotlib.pylot as plt #시각화 (그래프 출력)
from sklearn.linear_model import LinearRegression #선형회귀모델
from sklearn.datasets import load_diabetes #당뇨병 예제 데이터셋
from sklearn.model_selection import train_test_split #훈련용/테스트용 데이터 분할
scikit-learn의 예제 데이터셋은 기본적으로 numpy 배열 형태로 제공되기 때문에 head()가 안됨.
data : 독립변수 (x)
target : 종속변수 (y)
feature_names : 변수이름
DESCR : 데이터셋 설명 텍스트
< 코드 뜯어먹기 >
diabetes = load_diabetes()
X = diabetes.data #10개의 입력 특성(독립변수)
y = diabetes.target #예측하고자 하는 값 (종속변수, 당뇨병 진행률)
-> 데이터 로드 및 분리
X = X[:, np.newaxis, 2] #BMI특성만 선택 (2번 인덱스)
-> 배열 x에서 특정한 열 하나만 골라내서, 2차원 배열로 바꾸는 과정
예를 들어 원래 데이터가 아래처럼 생겼다고 할 때
X = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
이걸 numpy 배열이라고 생각하면 아래와 같이 표현됨
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
: -> 모든 행을 선택한다는의미
np.newaxis -> 차원을 하나 더 만들어줌 (배열 모양을 조정)
2 : 2번 열을 선택 (0번부터 시작하므로 세 번째 열)
실행 결과 :
[[3],
[6],
[9]]
원래 (3,) 형태의 1차원 배열이었던 게 [[3],[6],[9]] 처럼 2차원 배열로 바뀌게 된다
X[:, 2] → 모든 행의 2번 열(BMI)만 가져옴 → (442,) 형태
np.newaxis → 차원을 강제로 추가 → (442, 1) 형태로 바꿈
Q. 왜 2차원 배열로 바꿔야 하나?
Scikit-learn 같은 머신러닝 모델에서는 데이터가 반드시 2차원 형태로 들어가야 하는 경우가 많음!
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
-> 전체 데이터의 20%는 테스트용, 80%는 훈련용으로 분리
model = LinearRegression()
model.fit(X_train, y_train)
-> 선형회귀 모델 객체 생성, 실제로 데이터를 이용해 기울기(a), 절편(b) 학습
print(f'기울기(slope) : {model.coef_[0]:.2f}') # 소수점 2째자리까지
print(f'절편(intercept) : {model.intercept_:.2f}') #소수점 2째자리까지
-------------------
기울기(slope) : 998.58
절편(intercept) : 152.00
coef_ : 회귀 직선의 기울기 (BMI가 1 증가할 때, 당뇨 진행률이 얼마나 증가하는가)
intercept_ : 절편 (BMI가 0일 때 예측값)
y_pred = model.predict(X_test) #예측
# 예측 결과 시각화
plt.rc('font', family='Malgun Gothic')
plt.scatter(X_test, y_test, color='blue', label='실제 데이터')
plt.plot(X_test, y_pred, color='red', label='예측(회귀) 선')
plt.xlabel('BMI(체질량 지수)')
plt.ylabel('당뇨병 진행률')
plt.title('선형 회귀 - 당뇨병 예측 (BMI)')
plt.legend()
plt.grid(True)
plt.show()
* 선의 기울기 : 상승추세
빨간색 선은 우상향 추세. 즉 BMI(체질량 지수)가 증가할수록 당뇨병 진행률이 높아지는 경향이 있다.
* 선 주변 데이터의 분포 : 직선에서 떨어져 흩어져 있음
선형 회귀 모델이 데이터를 완벽하게 설명하지 못하지만 전반적인 경향성(추세)을 어느 정도 잘 나타내고 있음을 의미
* 선과 점 사이의 거리 (오차)
각 점에서 빨간 직선까지의 거리가 바로 오차(예측값과 실제값의 차이)를 나타낸다.
데이터가 많이 흩어져 있어, 이 선형회귀 모델이 높은 정확도로 개별 데이터를 예측하기 어렵다는 점도 알 수 있음.
하지만 평균적인 경향 (일반적인 BMI 증가 -> 당뇨병 진행률 증가)은 잘 반영하고 있다.
< 인사이트 >
단순 선형 회귀는 변수가 하나일 대 사용
실제 실무에서는 대부분 다중 선형 회귀 (변수 여러 개) 사용
model.score(x_test, y_test)를 통해 결정계수(R2)를 구하면 예측력 평가 가능
r2 = model.score(x_test, y_test)
print(r2)
< 선형회귀를 이용한 광고비 기반 매출 예측 >
설명 : 회사는 다양한 광고 채널 (TV, 라디오, 신문)에 광고비를 집행하고 있다. 이때 광고비 지출이 매출(판매량)에 어떤 영향을 주는지 분석하고, 광고비만 보고 매출을 예측할 수 있는지 모델을 만들어보자.
모델 평가지표는 MSE, R2로 평가하고 시각화해보자
데이터 셋 : https://www.kaggle.com/datasets/ashydv/advertising-dataset
Advertising Dataset
www.kaggle.com
주요 컬럼 :
- TV : TV 광고비
- Radio : 라디오 광고비
- Newspaper : 신문 광고비
- Sales : 실제 판매량
< 필수 라이브러리 >
import pandas as pd #csv 읽기 및 데이터프레임 처리
import numpy as np #수학 계산 도구
import matplotlib.pyplot as plt # 시각화 도구
from sklearn.linear_model import LinearRegression #선형 회귀 모델 생성
from sklearn.model_selection import train_test_split # 훈련/테스트 데이터 분할
from sklearn.metrics import mean_squared_error, r2_Score #평가 지표 (오차, 설명력 계산)
- r2_score()는 회귀문제에서 거의 항상 사용됨 : 예측한 값이 실제 값을 얼마나 잘 설명하는지를 나타내는 지표 (0~1)
# 2. 데이터 로딩
df = pd.read_csv('assets/advertising.csv')
print(df.head())
df.info()
----
TV Radio Newspaper Sales
0 230.1 37.8 69.2 22.1
1 44.5 39.3 45.1 10.4
2 17.2 45.9 69.3 12.0
3 151.5 41.3 58.5 16.5
4 180.8 10.8 58.4 17.9
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 TV 200 non-null float64
1 Radio 200 non-null float64
2 Newspaper 200 non-null float64
3 Sales 200 non-null float64
dtypes: float64(4)
memory usage: 6.4 KB
# 3. 독립변수 / 종속변수 분리
X = df[['TV', 'Radio', 'Newspaper']] # 광고비
y = df['Sales'] # 판매량(매출)
# 4. 훈련/테스트 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.2,
random_state=42
)
# 5. 모델 생성 및 학습
model = LinearRegression()
model.fit(X_train, y_train)
-> 선형 모델 객체 생성 후 .fit()으로 학습
# 6. 모델 평가 지표 출력
print ('회귀계수(각 광고비의 영향) : ', model.coef_) # 회귀계수 : [0.05450927 0.10094536 0.00433665]
print('절편(기본 판매량) :', model.intercept_) # 절편(기본 판매량) : 4.714126402214127
---
TV광고비를 1 늘리면 판매량이 평균 0.05 증가
라디오 광고비를 1 늘리면 판매량이 평균 0.1 증가
신문 광고비를 1 늘리면 판매량이 평균 0.004 증가
광고비를 지출하지 않아도 측정되는 기본 판매량 : 4.714...
y_pred = model.predict(X_test)
-> 테스트 데이터(X_test)에 대한 예측값 구함
# 평가 지표 출력
mse = mean_squared_error(y_test, y_pred) #평균제곱오차 (낮을수록 좋음, 예측 오차의 크기)
print(f'평균제곱오차(MSE) : {mse:.2f}')
r2 = r2_score(y_test, y_pred) #결정 계수 (1에 가까울 수록 좋음, 설명력)
print(f'결정계수(R^2) : {r2:.2f}')
평균제곱오차(MSE) : 2.91 => 오차가 평균 2.91의 제곱만큼 발생
결정계수(R^2) : 0.91 => 전체 판매량 변동 중에서 91%는 광고비로 설명 가능함
=> 빨간 점선 근처에 파란색 점이 대부분 모여있음 -> 이는 모델이 실제값에 매우 근접한 예측을 하고 있다는 걸 의미
< 실무 활용 팁 >
- 회귀 계수 해석 : 변수별로 비즈니스 인사이트 도출 가능
- 신문 광고 효과 없음 : 제외하고 모델 개선 가능
- 고차항 변환 : 비선형 관계가 있을 경우 x^2, log(x) 등으로 변형
- 모델 저장 : joblib이나 pickle로 저장해 웹서버/배치에 적용 가능
'Data Analysis' 카테고리의 다른 글
DecisionTreeClassifier 의사결정나무 : 소득수준 예측 예제 (0) | 2025.06.21 |
---|---|
Encoding : 문자형이나 범주형 데이터를 숫자형 데이터로 변환하는 과정 (0) | 2025.06.17 |
회귀모델 평가 지표, 회귀 vs 분류 비교, 알고리즘 선택 가이드 (0) | 2025.06.17 |
Regression 회귀 알고리즘, 선형회귀, 릿지회귀, 라쏘회귀, 다항회귀, SVR, 랜덤포레스트 (1) | 2025.06.17 |
KNN 실습 : 의류 이미지 속성 분류 (2) | 2025.06.09 |