Linear Regression(선형회귀)

데이터를 가장 잘 대표하는 직선(선형식) 을 찾아서, 보지 않은 값을 예측 하는 것 선형 회귀는 데이터의 패턴을 직선으로 표현하는 것

최적의 회귀모델이란?

실제값(관측값)과 모델이 예측한 값의 오차(차이) 가

가장 작아지도록 만드는 직선을 찾는 것

즉, “최적의 회귀모델”이란?

MSE가 가장 작아지는 w0, w1 값을 찾는 직선

단순 회귀 (Simple Regression)

독립변수가 하나일 때의 회귀모델 하나의 x값으로 y값을 예측할 때 사용

예를 들어,

  • 독립변수(x) : 일한 시간
  • 종속변수(y) : 받은 급여

이 관계를 1개의 직선으로 표현하는 것이 단순 회귀

다중 회귀 (Multiple Regression)

독립변수(입력)가 여러 개일 때 사용하는 회귀모델

예를 들어,

“집값(y)”은 하나의 요인만으로 결정되지 않고

다음과 같은 여러 요인의 영향을 받음

 

변수 설명

CRIM 1인당 범죄율
RM 방의 개수
AGE 1940년 이전에 지어진 주택 비율
TAX 세금 수준
LSTAT 저소득층 비율
  • 단순 회귀는 변수 1개로 예측
  • 다중 회귀는 여러 변수를 동시에 고려해서 더 현실적인 예측을 함
  • 모델 학습은 결국 “오차가 최소가 되는 w(가중치)와 b(절편)를 찾는 과정”이다

다중 회귀의 회귀 계수

회귀식이란?

다중 회귀모델은 여러 독립변수(입력값)으로 하나의 종속변수(출력값)를 예측하는 모델

 

각 항의 의미

기호 변수 회귀계수 해석

Temp 온도 +1.52 온도가 1도 올라갈 때, 오존량이 1.52만큼 증가 → 긍정적 영향
Wind 바람세기 -3.57 바람이 1 증가할 때, 오존량이 3.57만큼 감소 → 부정적 영향
Solar.R 일사량 +0.07 햇빛(일사량)이 1 증가할 때, 오존량이 0.07만큼 증가
절편(intercept) -53.37 모든 변수가 0일 때의 기준 오존값

해석 방법

“온도가 높고, 바람이 약하고, 햇빛이 강할수록 오존 농도가 증가한다.”

즉, 각 변수(Temp, Wind, Solar.R)는 오존량(Ozone)에 영향을 주는 요인이고,

회귀계수(coef_) 값이 클수록 영향력이 크다는 뜻

회귀모델을 선형회귀로 만들면 각 변수들 앞의 회귀계수(가중치)를 확인해봐야함

어느 변수의 회귀계수가 큰지

회귀계수 확인

print(list(x_train))
print(model.coef_)
print(model.intercept_)
  • coef_은 각 변수의 가중치(영향력)
  • intercept_은 절편을 의미하고,이들을 이용해 위의 회귀식을 구성할 수 있음

다중 회귀식은 여러 변수들이 결과에 미치는 영향력을 수식으로 표현한 것

각 변수 앞의 숫자(회귀계수)는

“그 변수가 1만큼 변할 때 결과(y)가 얼마나 변하는지”를 뜻함

양수 → 결과를 증가시키는 변수,

음수 → 결과를 감소시키는 변수

 

 

분류(Classification) 모델

“이 데이터가 어떤 종류(범주) 인가를 구분하는 모델”

즉: 결과값이 글자나 라벨(label) 형태 데이

(예: 합격/불합격, 고양이/강아지, 스팸/일반메일 등)

🔹 예시

공부시간 결과

20시간 합격
10시간 불합격
  • 이 데이터를 학습해서
  • “15시간 공부한 학생은 합격일까 불합격일까?” 를 맞추는 문제 👉 분류 문제

🔹 대표 알고리즘

  • Logistic Regression (이름은 회귀지만, 분류용!)
  • Decision Tree Classifier
  • Random Forest Classifier
  • K-Nearest Neighbors (KNN)
  • XGBoost Classifier

🔹 성능 평가 지표

  • 정확도 (Accuracy) → 얼마나 많이 맞췄는가
  • 정밀도 (Precision) → 맞다고 한 것 중 진짜로 맞은 비율
  • 재현율 (Recall) → 실제 정답 중 모델이 잘 찾아낸 비율
  • F1-score, Confusion Matrix 등

분류 모델 평가란?

분류 모델은 정답(실제값) 과 예측값 이 같은지 다른지를 비교해서

“얼마나 정확하게 맞췄는가”로 성능을 평가

💡핵심 아이디어

분류 모델은 어떤 데이터가 0인지(부정), 1인지(긍정) 를 예측하는 모델

예를 들어:

  • 스팸메일(1)인가 아닌가(0)
  • 환자가 병이 있다(1) 없다(0)
  • 시험 합격(1) 불합격(0)

분류 모델 평가 지표(Accuracy, Precision, Recall)

실제값 예측값 이름 뜻

1 1 TP (True Positive) 실제 1을 1로 예측함 (정답)
0 0 TN (True Negative) 실제 0을 0으로 예측함 (정답)
1 0 FN (False Negative) 실제 1을 0으로 예측함 (놓침)
0 1 FP (False Positive) 실제 0을 1로 예측함 (잘못 탐지)

Confusion Matrix 혼동행렬 = cross tab

# 모듈 불러오기
from sklearn.metrics import confusion_matrix

# 성능 평가
confusion_matrix(y_test, y_pred)

(1) 정확도 (Accuracy) 또는 정분류율

전체 중에 모델이 정답을 맞춘 비율

# 모듈 불러오기
from sklearn.metrics import accuracy_score

# 성능 평가
accuracy_score(y_test, y_pred)

(2) 정밀도 (Precision)

모델이 ‘1’이라고 예측한 것 중에 실제로 1인 비율

 

# 모듈 불러오기
from sklearn.metrics import precision_score

# 성능 평가
precision_score(y_test, y_pred, average=None)

(3) 재현율 (Recall) 또는 민감도

실제로 1인 것 중에서 모델이 1이라고 맞춘 비율

# 모듈 불러오기
from sklearn.metrics import recall_score

# 성능 평가
recall_score(y_test, y_pred, average=None)

(4) F-1 Score

정밀도(Precision)재현율(Recall) 을 한 번에 고려해서 평가하는 지표를 설명

모델이 얼마나 정확하게 예측했는지(Precision) 와

얼마나 놓치지 않고 잘 찾아냈는지(Recall)

두 가지를 균형 있게 잘하고 있는가를 나타내는 점수

정밀도(Precision)재현율(Recall)조화평균(Harmonic Mean)

조화평균(Harmonic Mean) 을 쓰는 이유는,

둘 중 하나라도 값이 작으면 전체 점수도 확 떨어지게 만들기 때문

지표 값

Precision 1.0
Recall 0.1

모델이 "맞다고 한 건 다 맞긴 하지만" 거의 다 놓침 (Recall 낮음)

F1이 낮다 → 균형이 안 맞다는 뜻

지표 값

Precision 0.8
Recall 0.8

둘 다 고르게 좋을 때

 

F1도 높음 → 균형이 잘 맞는 좋은 모델

한 줄 요약

지표 의미 F1-Score와 관계

Precision “맞다고 한 것 중 진짜 맞은 비율” 너무 높고 Recall 낮으면 불균형 ⚠️
Recall “진짜 맞는 것 중 맞게 예측한 비율” 너무 높고 Precision 낮으면 불균형 ⚠️
F1-Score “두 성능의 균형” 둘 다 적당히 높을 때 최고

언제 F1-Score를 쓰냐면

✔️ 정답(1)이 적은 불균형 데이터일 때

✔️ Precision과 Recall 둘 다 중요할 때

예: 스팸메일 분류, 질병 진단, 이상 탐지 등

F1-Score는 “정확히 맞춘 비율(Precision)”과

놓치지 않은 비율(Recall)”을 균형 있게 평가하는 점수

값이 1에 가까울수록 → 완벽한 분류 모델!

# 모듈 불러오기
from sklearn.metrics import f1_score

# 성능 평가
f1_score(y_test, y_pred, average=None)

 

회귀(Regression) 모델

“이 데이터가 얼마인지(숫자값) 예측하는 모델”

즉: 결과값이 숫자형(연속형) 데이터

(예: 집값, 점수, 온도, 판매량 등)

🔹 예시

공부시간 점수

20시간 90점
10시간 70점
  • 이 데이터를 학습해서
  • “15시간 공부한 학생은 몇 점일까?” 를 예측하는 문제 👉 회귀 문제

🔹 대표 알고리

  • Linear Regression (선형 회귀)
  • Decision Tree Regressor
  • Random Forest Regressor
  • K-Nearest Regressor
  • XGBoost Regressor

🔹 성능 평가 지표

  • MAE (평균 절대 오차)
  • MSE (평균 제곱 오차)
  • RMSE (제곱근 평균 제곱 오차)
  • R² (결정계수)

회귀 모델 평가란?

모델이 예측한 값(ŷ) 과 실제 값(y) 의 차이, 즉 오차(error) 를 계산해서

모델이 얼마나 정확하게 예측했는지 평가하는 과정이에요.

결국 회귀 모델의 평가는 “오차들의 평균”을 구하는 과정

💡핵심 아이디어

  • 회귀 문제에서는 정답이 숫자로 되어 있음
  • (예: 키, 집값, 점수, 온도 등)
  • 예측한 숫자와 실제 숫자는 완전히 같을 수 없어요 → 항상 차이(오차) 가 생긴다
  • 그래서 “오차가 얼마나 작은가”로 모델의 성능을 판단

📊 성가 평가 지표 (자주 쓰는 방법)

평가 지표 의미 해석 기준

MAE (Mean Absolute Error) 오차의 절댓값 평균 → 예측이 실제와 얼마나 떨어져 있는지 작을수록 좋음
MSE (Mean Squared Error) 오차를 제곱해서 평균 → 큰 오차에 더 큰 패널티 작을수록 좋음
RMSE (Root Mean Squared Error) MSE의 제곱근 → 실제 단위와 같아 이해 쉬움 작을수록 좋음
R² (결정계수) 예측이 실제 데이터를 얼마나 잘 설명하는가 (0~1) 1에 가까울수록 좋음

실제 값(y) 예측 값(ŷ) 오차y-ŷ

10 12 +2
15 14 -1
20 19 -1
  • MAE = (2 + 1 + 1) / 3 = 1.33
  • MSE = (4 + 1 + 1) / 3 = 2.0
  • RMSE = √2.0 = 1.41

💡 핵심 정리

  • 오차 계열(MAE, MSE, RMSE) → 작을수록 모델이 실제값에 더 가깝다
  • 결정계수(R²) → 클수록 모델이 전체 데이터를 더 잘 설명한다

결정계수 (R-squared)

모델이 실제 데이터를 얼마나 잘 설명하고 있는지를 나타내는 수치

  • 값의 범위: 0 ~ 1 (가끔은 음수도 나올 수 있음)
  • 1에 가까울수록 → 모델이 데이터를 잘 설명함
  • 0에 가까울수록 → 모델이 거의 설명하지 못함

📊 직관적으로 이해하기

상황 설명 R² 값

모델이 완벽하게 예측함 예측값 = 실제값 → 오차 0 R² = 1.0
모델이 아무것도 못 맞춤 예측이 평균 수준으로만 나옴 R² = 0
모델이 오히려 더 나쁨 평균보다 더 엉뚱하게 예측함 R² < 0

1) MAE(Mean Absolute Error)

# 모듈 불러오기
from sklearn.metrics import mean_absolute_error

# 성능 평가
print('* MAE:', mean_absolute_error(y_test, y_pred))

2) MSE(Mean Squared Error)

# 모듈 불러오기
from sklearn.metrics import mean_squared_error

# 성능 평가
print('* MSE:', mean_squared_error(y_test, y_pred))

3) RMSE(Root Mean Squared Error)

# 모듈 불러오기
from sklearn.metrics import mean_squared_error

# 성능 평가
print('* RMSE:', np.sqrt(mean_squared_error(y_test, y_pred)))

4) MAPE(Mean Absolute Percentage Error)

# 모듈 불러오기
from sklearn.metrics import mean_absolute_percentage_error

# 성능 평가
print('* MAPE:', mean_absolute_percentage_error(y_test, y_pred))

5) R2-Score

# 모듈 불러오기
from sklearn.metrics import r2_score

# 성능 평가
print('* R-2:', r2_score(y_test, y_pred))

근데 어떨 때 어떤 식을 쓰는거지 ?

회귀(숫자 예측) 문제일 때

상황 추천 지표 이유

일반적인 회귀 문제 MAE, MSE, RMSE 오차가 얼마나 작은지 확인하기
큰 오차가 특히 중요할 때 MSE or RMSE 제곱을 하기 때문에 큰 오차에 더 큰 패널티 줌
해석을 직관적으로 하고 싶을 때 MAE “평균적으로 예측이 실제값에서 이 정도 차이 난다” 라고 바로 해석 가능
전체 설명력을 보고 싶을 때 모델이 데이터를 얼마나 잘 설명하는지(설명력) 보여줌

다온 궁금증 어쨋든 예제로 볼 때 수치로 나오는데 R2 스코어의 경우

설명력을 어디서 알 수 있는거지???

그런데 모델이 데이터를 얼마나 잘 설명하느냐는?

실제 점수(y)가 얼마나 그 선(예측값 ŷ)에 가깝게 붙어 있냐로 판단

  • 만약 모든 점이 선 위에 정확히 있다면 → 완벽히 설명 (R² = 1)
  • 점들이 선에서 멀리 떨어져 있다면 → 설명력이 낮음 (R² = 0에 가까움)

산점도를 그렸을 때

(1) 모델이 데이터를 잘 설명할 때

📈 데이터들이 선 위에 거의 다 붙어 있음

  • 예측값이 실제값과 거의 같음
  • 오차가 작음
  • R² ≈ 1.0 (100%)

→ 모델이 “공부시간과 점수의 관계”를 잘 설명했다고 말함

공부시간 →

(2) 모델이 데이터를 못 설명할 때

📉 데이터들이 선에서 멀리 흩어져 있음

  • 예측값과 실제값 차이가 큼
  • R² ≈ 0

→ 모델이 “공부시간과 점수의 관계를 거의 설명 못한다”는 뜻

공부시간 →

머신러닝 개념

  • 컴퓨터가 사람 명의 없이도 스스로 규칙과 패턴을 찾아내고 학습하는 기술
  • 스스로 학습해서 새로운 데이터가 주어졌을 때 예측하거나 분류할 수 있게 됨
  • 머신이 데이터를 통해 배우는 방식

분류(Classification)와 회귀(Regression)

  • 모델링 하기 전 원하는 결과가 분류인지 회귀인지 이해해야함 분류 - 데이터를 보고 yes냐 no냐, fail이냐 pass냐 … 이게 어떤 종류인지 맞히는 것 회귀 - 양을 측정하는 것 = 숫자를 예측하는 것

구분 분류 (Classification) 회귀 (Regression)

예시 데이터 공부시간 → 합격/불합격 공부시간 → 점수
입력값 (X) 공부시간 공부시간
출력값 (Y) “합격 / 불합격” 처럼 문자나 범주형 “점수(숫자)” 처럼 연속형 숫자
예측하고 싶은 것 새로운 학생이 합격할까? 불합격할까? 새로운 학생의 점수는 몇 점일까?
결과의 형태 ‘라벨(label)’ ‘숫자(value)’
예시 질문 “10시간 공부한 학생은 합격할까?” “10시간 공부한 학생은 몇 점일까?”

🧩 분류(Classification) 문제

“합격/불합격”, “스팸/일반메일”, “고양이/강아지”처럼 결과가 범주(종류) 로 나뉠 때!

구분 내용

자주 쓰는 알고리즘 - DecisionTreeClassifier (의사결정나무) - KNeighborsClassifier (K-최근접 이웃) - LogisticRegression (로지스틱 회귀 — 이름에 회귀 있지만 분류용!) - RandomForestClassifier (랜덤포레스트) - XGBClassifier (XGBoost 분류기)
평가 지표 - accuracy_score → 전체 중 정답 비율 - recall_score → 실제 정답 중 맞춘 비율 - precision_score → 맞다고 한 것 중 진짜 정답 비율 - classification_report →
위 지표들을 한눈에 정리 - confusion_matrix → 정답/오답 표로 정리  

📌 **결과가 라벨(label)**로 나오는 문제 (예: 0, 1, “합격/불합격”)

📏 회귀(Regression) 문제

📊 “점수”, “가격”, “온도”처럼 결과가 숫자(연속값) 로 나올 때!

구분 내용

자주 쓰는 알고리즘 - LinearRegression (선형회귀) - KNeighborsRegressor (K-최근접 회귀) - DecisionTreeRegressor (의사결정나무 회귀) - RandomForestRegressor (랜덤포레스트 회귀) - XGBRegressor (XGBoost 회귀)
평가 지표 - mean_absolute_error (평균 절대 오차, MAE) - mean_squared_error (평균 제곱 오차, MSE) - root_mean_squared_error (RMSE) - mean_absolute_percentage_error (MAPE) - r2_score (설명력, 얼마나 잘 맞았는지)

📌 결과가 숫자(value) 로 나오는 문제 (예: 70점, 23.5도)

모델

  • 데이터로부터 패턴을 찾아 수학식으로 정리해 놓은것
  • 모델링 : 오차가 적은 모델을 만드는 과정

모델의 목적 - 표본(샘플)을 가지고 모집단(전체)을 예측하기 위해서

독립변수, 종속변수

핵심 개념

구분 뜻 쉽게 말하면

**독립변수    
(Independent Variable)** 결과에 영향을 주는 원인 “시험 공부 시간”, “운동량”, “광고비”
종속변수 (Dependent Variable) 독립변수에 의해 결정되는 결과 “시험 점수”, “체중 변화”, “매출액”

독립변수 → 원인 / 입력값 (X) Feature

종속변수 → 결과 / 출력값 (Y) Target

📊 머신러닝 관점

역할 의미

독립변수 모델이 이용하는 입력 데이터
종속변수 예측하려는 목표값

오차

  • 평균 = 가장 단순한 모델. 평균도 모델이다
  • 모델 예측값과 관측값(실제값)의 차이
  • 우리의 목표는 오차값을 평균보다 줄여서 평균보다 나은 모델을 만드는 것 수치 데이터에 대해서는 평균, 분류 데이터에 대해서는 최빈값 보다 나아야 성능이 좋다

가변수화(또는 더미 변수화, One-hot encoding)

문자나 범주형 데이터를 숫자(0과 1)로 바꾸는 과정

왜냐하면 대부분의 머신러닝 모델은 숫자 데이터만 계산할 수 있기 때문

두가지 목적

(1) 문자 데이터를 숫자로 바꾸는 효과

Gender (원본 데이터) Male Female 원핫인코딩

Male 1 0 남자면 1
Female 0 1 여자면 1
Male 1 0 남자면 1
Female 0 1 여자면 1

가변수화 과정은 하나만 1을 갖기 때문에 One-Hot-Encoding이라고 부른다

(2) 숫자의 크기가 비교되지 않게 숫자형 범주값을 별도의 독립된 변수로 떼는 것

서로 크기 비교가 안 되는 범주(카테고리)를 모델이 ‘순서가 있는 숫자’로 오해하지 않도록 각각 따로 분리한다는 뜻

색깔 숫자로 바꾼 값

빨강 1
파랑 2
초록 3

이렇게 바꾸면 모델이 이렇게 생각할 수 있음

“초록(3)은 빨강(1)보다 3배 크네!”

하지만 색깔은 크고 작음이 없는 ‘범주형 데이터’

그래서 이렇게 숫자로 넣으면 잘못된 의미를 만들어버림

그래서 하는 게 바로 “가변수화(= 원핫인코딩)”

각 범주를 서로 독립된 변수(열) 로 만들어 주는 거

색깔 빨강 파랑 초록

빨강 1 0 0
파랑 0 1 0
초록 0 0 1

이제 숫자의 크고 작음은 사라지고, “어떤 색인지”만 표시됨

→ (2)는 안해도 되지만 (1)은 안하면 에러남

Gender (원본 데이터) Male Female

Male 1 0
Female 0 1
Male 1 0
Female 0 1

이 표에서 Male이 없어도 Female변수만 있어도 Male값을 예측할 수 있음

Gender (원본 데이터) Male Female

Male   0
Female   1
Male   0
Female   1

여자가 아닌건 남자라는거고 남자가 아닌건 여자라는거임 변수들이 같은말을 하는데 굳이 여러개 둘 필요가 없음

여러개 있으면 모델이 혼란스러워해

그래서

drop=True를 지정해 가변수화 결과로 만들어진 열 중 하나를 제거

 

데이터 준비

(1) 결측치 처리

# 결측치 확인
data.isnull().sum()

확인하고
# 전날 값으로 결측치 채우기
예제 데이터가 시계열 데이터였고 결측치가 solar.R이라 전날꺼로 채우면 될 것 같아서
이걸로 했음
data.ffill(inplace=True)

# 확인
data.isnull().sum()

(2) 변수 제거 : 분석에 의미 없다고 판단되는 변수 제거

# 변수 제거
drop_cols = ['Month', 'Day']
data.drop(columns=drop_cols, inplace=True)
#data.drop(columns=drop_cols, inplace=True) 이렇게 써도 됨

# 확인
data.head()

데이터 분리

  • 데이터 셋을 학습용, 검증용, 평가용 데이터로 분리함

  • 근데 수업에서는 편의상 학습용, 평가용 데이터로 나눌거임(머신러닝에서만)

(3) x, y 분리

  • 우선 target 변수를 명확히 지정
  • target을 제외한 나머지 변수들 데이터는 x로 선언
  • target 변수 데이터는 y로 선언
  • 이 결과로 만들어진 x는 데이터프레임, y는 시리즈
  • 이후 모든 작업은 x, y를 대상으로 진행
# target 확인
타겟은 내가 판단해서 정하는 것
target = 'Ozone'

# 데이터 분리
x = data.drop(target, axis=1) inplace=True를 주면 x값은 none이 됨 그래서 주면 안돼
원본 데이터는 그대로 둬야하니까
y = data.loc[:, target]

(4) 학습용, 평가용 데이터 분리

  • 학습용, 평가용 데이터를 적절한 비율로 분리
  • 반복 실행 시 동일한 결과를 얻기 위해 random_state 옵션을 지정
# 모듈 불러오기
from sklearn.model_selection import train_test_split

# 7:3으로 분리
x_train, x_test, y_train, y_test = train_test_split(x,y
,test_size=0.3,random_state = 1) random_state를 주지 않으면 진짜 막 섞임

Scikit-Learn

  • 지도/비지도 학습 알고리즘을 제공하는 대표적인 파이썬 라이브러리
  • 여러 알고리즘을 같은 구조의 코드로 사용할 수 있어 배우기 쉬움

과대적합 vs 과소적합

구분 뜻 비유

과적합 (Overfitting) 훈련 데이터에는 너무 잘 맞지만, 새로운 데이터에는 잘 못 맞추는 상태 시험 예상문제만 외워서 실제 시험을 망치는 학생
과소적합 (Underfitting) 훈련 데이터조차 제대로 학습하지 못한 상태 공부를 거의 안 해서 기본 문제도 틀리는 학생

예를 들어

조카에게 야구공을 주고 공에 대해 학습을 해라

조카가 야구공을 보고 공은 둥글구나, 가죽으로 씌워져있네, 공은 실밥이 있구나, 돌덩이처럼 딱딱하네, 내 주먹만하네, …

근데 축구공, 농구공, 럭비공, 배구공 등은 공이라고 골라내지 못하고 야구공만 공이라고 인지함

→ 과적합

세 가지 상태로 비교

상태 설명 훈련 데이터 성능 테스트 데이터 성능

과소적합 너무 단순함 (덜 배움) 낮음 낮음
적합 적당히 잘 배움 (일반화 잘됨) 높음 높음
과적합 너무 외움 (훈련에만 맞춤) 매우 높음 낮음

모델이 적절히 학습하게 만드는 과정 = 튜닝

모델링

  • 회귀인지 분류인지에 따라 사용할 알고리즘과 평가 방법이 달라짐
  • 우선 다음 알고리즘과 평가 방법을 사용하겠음 맛보기 코드로
    • 알고리즘: LinearRegression
    • 평가방법: mean_absolute_error

(1) 모델링

# 1단계: 불러오기
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
# 2단계: 선언하기
model = LinearRegression() 선형 회귀모델 쓸거다
# 3단계: 학습하기
model.fit(x_train, y_train) 학습 데이터로 학습하자

학습이 끝나면 성능이 어떻든 모델이 만들어짐
# 4단계: 예측하기
y_pred = model.predict(x_test) x 테스트로 예측해봐 
아직 y 테스트는 모델에게 주지 않았기 때문

# 5단계: 평가하기
mean_absolute_error(y_test, y_pred)

(2) 예측값 실제값 비교

# 예측값, 실젯값 확인
print(y_pred[:10]) 이 자체가 배열이니까 벨류즈 안쓰고
print(y_test.values[:10]) y 테스트 결과는 시리즈니까 .values 결과 = 배열
# 예측값, 실젯값 시각화 비교
plt.plot(y_pred)
plt.plot(y_test.values) y_test는 시리즈니까 배열로 가져오기 위해 y_test.values
plt.legend(['predicted', 'Actual']) 범례
plt.show()

시각화

Histogram

  • Seaborn의 histplot() 함수로 Histogram을 그린다
sns.histplot(x='BloodPressure', hue='Outcome', data=diabetes, bins=20)
plt.show()

Density Plot

  • Seaborn의 kdeplot() 함수로 Density Plot을 그린다

① kdeplot(..., hue='Outcome')

  • 당뇨병환자여부의 비율이 유지된 채로 표시
  • 두 그래프의 아래 면적의 합이 1
sns.kdeplot(x='BloodPressure', hue='Outcome', data=diabetes)
plt.show()

② kdeplot(..., hue='Outcome', common_norm=False)

  • common_norm 매개변수 값을 False로 지정하면 두 그래프 각각의 아래 면적이 1이 된다
  • common_norm 매개변수의 기본값은 True

 

multiple='fill' 지정

  • multiple 매개변수 값을 'fill' 로 지정해 비율을 비교가능
  • 단, 양의 비교가 아닌 비율을 비교
  • 페인트 칠 한 것 처럼 보임

① kdeplot(..., hue='Outcome', multiple='fill')

sns.kdeplot(x='BloodPressure', hue='Outcome', data=diabetes, multiple='fill')
plt.axhline(diabetes['Outcome'].mean(), color='r')
plt.show()

② histplot(..., hue='Outcome', multiple='fill')

sns.histplot(x='BloodPressure', hue='Outcome', data=diabetes, bins=20, multiple='fill')
plt.axhline(diabetes['Outcome'].mean(), color='r')
plt.show()

수치화

로지스틱 회귀 .Logit()

  • 수치형 VS 범주형에 맞는 가설 검정 도구는 없음
  • 로지스틱 회귀 모델로 p-value를 구해서 차이가 있는지 없는지를 확인해보면 되겠다
temp = diabetes.loc[diabetes['BloodPressure'].notnull()]
model = sm.Logit(temp['Outcome'], temp['BloodPressure'])
result = model.fit()
print(result.pvalues)

교차표(Crosstab)

  • 범주vs범주 데이터 비교하기 위해서는 Pandas의 crosstab() 함수를 사용해 교차표를 만들어야함

 

크로스탭 만들기

pd.crosstab(diabetes['BMIStatus'], diabetes['Outcome'])
  • 'index': 각 행의 합으로 각 요소를 나눠서 각 행의 상대적인 비율을 보여준다(각 행의 합이 1이 됨).
  • 'columns': 각 열의 합으로 각 요소를 나눠서 각 열의 상대적인 비율을 보여준다(각 열이 합이 1이 됨).
  • 'all': 전체 합으로 각 요소를 나눠서 전체 데이터셋에서 각 셀의 상대적인 비율을 보여준다(전체 합이 1이 됨).

pd.crosstab(diabetes['BPStatus'], diabetes['Outcome'], normalize='columns')

pd.crosstab(diabetes['BPStatus'], diabetes['Outcome'], normalize='index') 보통 이걸 씀

pd.crosstab(diabetes['BPStatus'], diabetes['Outcome'], normalize='all')

 

 

 

시각화

(크로스탭 만들고, 노말라이즈 인덱스 준 다음, 시각화)

  • 100% Stacked Bar Plot
  • Mosaic Plot

100% Stacked Bar

  • normalize='index' 를 설정한 교차표 작성
  • normalize='index'를 지정했으므로 각 행의 합은 1
table = pd.crosstab(diabetes['BPStatus'], diabetes['Outcome'], normalize='index')
display(table)

table.plot(kind='bar', stacked=True)
plt.axhline(1-diabetes['Outcome'].mean(), color='r')
plt.xticks(rotation=0)
plt.show()

mosaic plot

  • 100% Stacked Bar는 비율만 비교하므로 양에 대한 비교는 할 수 없음
  • Mosaic Plot으로 양에 대한 비교
  • statsmodels.graphics.mosaicplot의 mosaic() 함수로 Mosaic Plot을 그린다
mosaic(diabetes, ['BMIStatus', 'Outcome'])
plt.axhline(1-diabetes['Outcome'].mean(), color='r')
plt.show()

시각화 결과를 분석하는 방법

  • 귀무가설이 참일 때 나올 그래프의 모양(아래 그림)
  • 평균선 여기서 벗어나면, '차이가 있다'., '관련이 있다'는 말

 

 

수치화

카이제곱검정

  • 범주형 변수들 사이에 관련이 있는지(연관이 있는지) 수치화 하는 방법

즉 , “두 변수 사이에 관계가 있나, 그냥 우연인가?” 를 보는 검사

  • scipy.stats 라이브러리의 chi2_contingency() 함수로 카이제곱검정을 수행
table = pd.crosstab(diabetes['BPStatus'], diabetes['Outcome'])

result = spst.chi2_contingency(table)
print('* 카이제곱통계량:', result[0])
print('* p-value:', result[1])
print('* 기대빈도:\\n',result[3])

 

🍎 예시

“흡연 여부(Yes/No)”와 “폐질환 발생 여부(Yes/No)”가 관련이 있을까?

흡연 여부 폐질환 있음 폐질환 없음 합계

흡연자 40 60 100
비흡연자 10 90 100

이럴 때 카이제곱검정을 하면,

  • “흡연과 폐질환이 무관하다면 이런 비율이 나올 확률”을 계산
  • 그 확률(p-value)이 작으면 → “우연이 아니라 관련이 있다!”

⚙️ 작동 원리

  1. 기대빈도 계산
  2. → “두 변수에 아무 관계가 없다고 가정하면 이런 비율이 나올 거야.”
  3. 실제값(관찰된 비율) 과 비교
  4. → “실제 데이터가 예상과 얼마나 다른가?” 계산
  5. 그 차이를 χ²(카이제곱) 값으로 표현
  6. → 값이 클수록 “예상과 너무 다르다 = 관련 있다”는 뜻!

기대빈도

  • 두 변수 사이에 아무 관련이 없다고 가정했을 때, 각 칸(조합)에 기대되는 값(빈도)

즉, “만약 흡연과 폐질환이 진짜 아무 상관이 없다면, 각 칸에 몇 명쯤 들어가야 자연스러울까?”

(“만약 흡연과 폐질환이 상관없다면 이렇게 나올 거야~”라는 예상 값)

그걸 계산한 게 바로 기대빈도

기대빈도 = ‘관련이 없다면 나올 법한 예상 숫자’

실제 값이 이 예상과 많이 다르면 → “관련이 있다!”

 

 

가설과 가설 검정

  • 모집단(Population)과 표본(Sample)
    • 모집단 - 우리가 알고싶은 데이터
    • 표본 - 그 대상의 일부 데이터
  • 우리는 일부분(표본)으로 전체를 추정하고 싶음
  • 모집단에 대한 가설을 수립
    • 가설은 보통 X와 Y의 관계를 표현 예1: X에 따라 Y가 차이가 있다. 예2: X와 Y는 관계가 있다.
  • 표본을 가지고 가설이 진짜 그러한 지 검증
  • 비즈니스 이해단계에서
    • 비즈니스 문제로부터 우리의 관심사(y = target)를 도출하고,
    • y에 영향을 주는 요인(x)들을 뽑아서 초기 가설을 수립함

귀무가설 - 당신 주장 = 내 주장을 반대하는 입장

매장지역(𝑥2)과 수요량(y)은 아무런 관련이 없다

대립가설 - 내 주장

매장지역(𝑥2)과 수요량(y)은 관련이 있다

양 끝단을 보면 2.5%가 있는데 그 영역 보다 작은 영역이면 귀무가설을 기가할 충분한 근거가 있음을 의미

  • 가설검정(hypothesis testing)유의확률(p-value) 개념을 설명하는 자료

상황

“A매장과 B매장의 수요량에 차이가 있는가?”

즉, 두 집단의 평균이 같은지(차이가 없는지) 검정하는 상황

  • 귀무가설(H₀) : 두 매장의 수요량에 차이가 없다.
  • 대립가설(H₁) : 두 매장의 수요량에 차이가 있다.

그래프 의미

이미지의 곡선은 확률밀도함수(정규분포) 로,

‘차이가 얼마나 큰가(0을 기준으로)’를 나타낸다

  • 0 근처 → 차이가 거의 없음 (귀무가설이 맞을 가능성 높음)
  • 0에서 멀수록 → 차이가 큼 (대립가설을 지지할 가능성 높음)

노란색 영역 (유의수준 α = 0.05)

그래프의 양쪽 끝 = 노란색 부분 약 5%(0.05)

이 영역은 “귀무가설이 맞다고 생각했는데, 실제로는 틀린 경우의 확률” 즉 유의수준(α) 을 나타냄

  • 만약 실제 데이터가 이 영역에 들어간다면→ 귀무가설을 기각하고 대립가설을 채택
  • → “지금 관측된 데이터는 너무 극단적이어서 귀무가설이 맞다고 보기 어렵다”

즉, “A와 B 매장의 수요량이 다르다”고 결론 내리는 거예요.

 

 

시각화 - Bar Plot, Box Plot

  • Bar Plot을 사용해 두 집단의 평균 비교

바플롯이 만들어낸 평균 그래프에서 그 평균의 차이는 표본의 평균의 차이

우리는 모집단을 볼 수 없기 때문에.

그럼 이 표본의 평균의 차이가 모집단에도 의미가 있을까?

그래서 이 평균 비교표만 봤을 땐 차이가 있어 보이지만 확실하지 않기에

수치화가 필요함(T 통계량)

  • Bar Plot
sns.barplot(x='Outcome', y='BMI', data=diabetes, palette='deep') 
# palette: deep, bright, pastel, dark, muted, colorblind
plt.show()
  • 박스플롯(분포를 확인)
sns.boxplot(x='Outcome', y='BMI', data=diabetes, palette='deep')
plt.show()

수치화

  1. t-검정 (두 범주)
  2. ANOVA (세 범주 이상)

t - 검정 : 두 집단 비교

  • 두 그룹의 평균이 진짜로 다른지 확인하는 방법 예) 남학생 평균 키 : 170cm 여학생 평균 키 : 160cm “이 10cm 차이가 진짜로 다른 건지, 아니면 우연히 나온 건지”를 확인해주는 게 t-검정
  • 평균 차이를 표준오차(Standard Error)와 비교하여 "진짜 차이"인지 검정
  • scipy.stats 라이브러리의 ttest_ind() 함수로 t-검정을 수행

표준 오차와 표준 편차

  • 표준편차: 개별 데이터들이 평균에서 얼마나 흩어졌는지를 나타냄
  • 표준오차(SE): 표본 평균들이 모평균에서 얼마나 흩어졌는지를 나타냄

구분 뜻 비유

표준편차 학생 한 명 한 명의 점수가 평균에서 얼마나 다른가 같은 반 학생들끼리 점수 차이
표준오차(SE) 여러 반의 평균이 진짜 평균에서 얼마나 다른가 각 반 평균 점수들의 차이

즉, 표준편차는 개인 차이, 표준오차는 평균의 흔들림

t-statistics, t-통계량, t-value

  • 두 집단의 평균 차이를 표준오차(SE)로 나눈 값

  • t 값이 크면 평균 차이가 크고 우연일 가능성이 작다
  • 일반적으로 t-통계량 값이 -2보다 작거나 2보다 크면 차이가 있다고 봄 평균차이가 표준오차보다 충분히 크면 ‘진짜 차이’

즉 ! 두 변수(범주값)에 평균의 차이가 있냐 없냐를 보는 것

  • 범주 값이 3개 이상이면 t-통계량을 쓰기엔 너무 부담스러움 → 분산분석
s1 = rd.sample(pop1, 200)
s2 = rd.sample(pop2, 200)
t_test = spst.ttest_ind(s1, s2)
t-통계량 호출 방법은 쉬움 ttset_ind(표본1, 표본2)

print('* t-statistic:', t_test[0])
print('* p-value:', t_test[1])

분산분석(ANOVA) - 여러 집단을 한꺼번에 비교하기 위해 필요한 방법

  • 세 집단 이상의 평균 분석(두 집단은 t 통계량으로)
  • 평균 비교를 하려면 보통 t검정(두 집단 비교)을 쓰지만 예를 들어 3개라고 치면 3번이나 따로 검정해야함 → 비교가 많아질수록 실수할 확률(오류)가 커진다

f-statistics, f-통계량, f-value

  • 두 개 이상의 집단 간 분산의 비율을 검정하는 데 사용되는 통계량
  • 각 집단 내에서의 분산과 각 집단 간의 분산의 비율을 계산
  • f-통계량 값이 크다는 것은 각 집단 간 차이가 통계적으로 유의미하다는 것
  • f-통계량 값이 2~3 이상이면 차이가 있다

집단 간 분산 : 집단끼리의 차이(분산) 집단 내 부산 : 각 집단 안의 흩어짐(분산)

  • 집단 간 차이가 크면 → 평균이 다르다 (대립가설 채택)
  • 집단 내 차이가 크면 → 비슷하다 (귀무가설 유지)

그림 A는 집단간 분산은 크지만 집단 내 분산은 작음 = f 통계량 값이 크다(2보다 큼)

그림 B는 집단간 분산과 집단 내 분산이 모두 큼 = f 통계량 값이 거의 1이 나옴

그림 C는 집단 간 분산은 차이가 크지 않지만 집단 내 분산은 큼 = f 통계량이 1보다도 작아짐 (분모가 커지니까)

temp = diabetes.loc[(diabetes['BPStatus'].notnull()) & (diabetes['Age'].notnull())]
low = temp.loc[temp['BPStatus']=='Low', 'Age']
normal = temp.loc[temp['BPStatus']=='Normal', 'Age']
high = temp.loc[temp['BPStatus']=='High', 'Age']

anova = spst.f_oneway(low, normal, high)
print('* f-statistic:', anova[0])
print('* p-value:', anova[1])

 

시각화 - 산점도(Scatter Plot)

  • 두 변수 간의 상관관계를 시각화 하는 가장 기본적인 방법
  • 그래프(시각화)만으론 판단이 어려워서 수치화(분석)가 필요함
Seaborn의 scatterplot() 함수로 산점도 그리기

sns.scatterplot(x='Wind', y='Ozone', data=air, s=30, ec=None)
 s=30 점 크기 ec=None 점 테두리 색
plt.show()

Joint plot 으로도 표현 가능

  • Seaborn의 jointplot() 함수는 두 개의 변수 사이의 관계를 시각화하기 위한 유용한 도구
  • 기본적으로 산점도를 그려주고, 히스토그램으로 각 변수의 분포를 보여줌
  • KDE(Kernel Density Estimation) 그래프를 추가하여 밀도 추정 결과도 확인할 수 있다
  • kind 매개변수를 사용하여 reg, hex, kde 등 다양한 형태의 그래프를 그릴 수 있음
sns.jointplot(x='Solar.R', y='Ozone', data=air, kind='hex'
, marginal_kws=dict(bins=20))
plt.show()

결과분석

  • 산점도에서 또렷한 패턴이 보인다면, 강한 관계(특히, 직선의 패턴이 보인다면)

수치화(분석) - 상관분석(Correlation Analysis)

  • 두 변수 간의 선형 상관관계를 수치화해서 파악하는 방법
  • 0에 가까울수록 상관관계가 없음을 나타냄
  • 상관관계를 나타내는 두 가지 숫자: 공분산, 상관계수
    • 둘 다 얼마나 직선으로 값들이 모여 있는지를 수치화한 것
    • 공분산으로 단순히 상관관계의 방향은 알 수 있으나 상관관계 정도는 알 수 없음

상관계수r (pearsonr 피어슨 r)

  • scipy 패키지
    • 두 변수로부터 상관계수 구하기
      • 결과: (상관계수, p-value)

 

  • 경험에 의한 대략의 기준(절대적인 기준이 절대 아님)
    • 강한: 0.5 < 𝑟 ≤ 1 중간: 0.2 < 𝑟 ≤ 0.5 약한: 0.1 < 𝑟 ≤ 0.2 (거의)없음: 𝑟 ≤ 0.1

상관계수 0.68은 강하다고 볼 수 있음

상관계수가 강하다고 볼 수 있을까? 를 뒷받침해주는게 p-vlue

p-value가 작을수록 귀무가설이 틀릴 수 있다(0.5 보다 작을 수록 더 강하다 우리 주장을 내세울 수 있다)

 

수치화(분석) - 상관분석(Correlation Analysis)

  • 수치형 → 수치형 관계를 수치화해 비교하고자 한다면 상관분석을 수행
  • 상관계수와 p-value를 사용해 두 변수의 상관관계를 확인할 수 있다
  • scipy.stats 라이브러리의 pearsonr() 함수로 상관계수를 확인
result = spst.pearsonr(air['Temp'], air['Ozone'])

print(result)
print('* 상관계수:', result[0])
print('* p-value:', result[1])

PearsonRResult(statistic=np.float64(0.6833717861490116)

, pvalue=np.float64(2.1977698002001854e-22))

  • 상관계수: 0.6833717861490116
  • p-value: 2.1977698002001854e-22

강한 상관관계가 있다. 귀무가설을 재검토할 필요가 있음

  • 주의: 결측치가 있으면 계산되지 않습니다. 반드시 .notnull()로 제외하고 수행해야 함
air2 = air.loc[air['Solar.R'].notnull()] 결측치 제거
result = spst.pearsonr(air2['Solar.R'], air2['Ozone'])

print(result)
print('* 상관계수:', result[0])
print('* p-value:', result[1])

PearsonRResult(statistic=np.float64(0.2800681334905376)

, pvalue=np.float64(0.000617587878856653))

  • 상관계수: 0.2800681334905376
  • p-value: 0.000617587878856653

p-value가 작음 = 상관관계가 있다

p-value 0.05로 봄(5퍼센트)

상관계수확인 corr()

air.corr(numeric_only=**True**)

numeric_only=True 상관계수는 수치형 데이터니까

참고 : (배경색 표시하기) 히트맵처럼

air.corr(numeric_only=True).style.background_gradient(cmap='Blues')

  • Seaborn의 heatmap() 함수로 상관계수를 시각화
plt.figure(figsize=(6, 6))
sns.heatmap(air.corr(numeric_only=True),
            annot=True, -> 숫자로 표현
            fmt='.3f', -> 소숫점 세자리까지
            cmap='Blues', -> 시원한 색깔
            vmin=-1, -> 색상을 -1부터 1까지
            vmax=1,
            square=True, -> 정사각형으로
            cbar=False) -> 위에 vmin어쩌고 그거 색상 바 없애기
plt.show()

상관계수의 한계


정리

CRISP-DM을 보며

비즈니스 문제 - 문제를 파악하고

마지막에는 문제가 해결되었나?를 파악해야함

가설수립

가설에 대한 추가 설명

우리가 가지고 있는 표본(CSV)를 가지고 모집단을 예측해야해

그래서 우린 가설을 세우지(모집단에 대한 가설)

X → Y

BMI → Outcome (BMI가 Outcome에 영향이 있을 것이다)

대립가설 - 상관계수 0.87 일때

vs

귀무가설 (영향이 없을 것이다) 0.87이 모집단에서 발생할 수 있는 확률이 0.0000003 (희귀)

이 정도면 우리가 귀무가설말고 대립가설을 선택해야하지 않을까?

대립가설의 뒷받침 근거가 되는 것이 p-value

→ 모집단에 대한 가설이기 때문에 뭐가 좋다 나쁘다 우리가 정할 순 없지만

통계 수치를 보고 무엇이 더 나을지 판단할 수는 있음

= 모집단(미래 데이터)에 대한 가설을 수립하고

우리가 가지고 있는 표본(과거 데이터)

표본을 가지고 최대한 모집단을 확인하고 싶은거고

나아가 모집단을 예측하고 싶어 - 머신러닝

덴시티플롯 - 확률분포함수

를 쓰냐면 우리가 가지고 있는 수치형 데이터는 너무 많기 때문에 개별적으로 함수를 풀어

정리할 수 없어서 그래프로 정리한 것

그래프는 함수에 의해 그려지는 것

 

 

 

  • 범주형 변수는 정해진 몇 개의 값이 여럿 모여있는 변수
  • 범주형 변수안에 포함된 범숫값 각각의 빈도수와 비율이 분석 대상이 된다

Bar 플롯 = 두 범주의 개수를 확인

Seaborn의 Count Plot = 알아서 집계가 돼서 보여준다

파이차트는 잘 안씀

수치화

  • 범주형 변수는 범주별 빈도수와 비율을 기초 통계량을 통해 확인
  • value_counts() 메소드는 범주형 변수에 포함된 범줏값 각각의 개수를 카운트 해 줌
  • normalize=True 옵션을 지정해 개수가 아닌 비율 확인
print(diabetes['BMIStatus'].value_counts())
print('-' * 25)
print(diabetes['BMIStatus'].value_counts(normalize=True))

 

🔍 해석

  • 비만(Obese)이 전체에서 62.4%를 차지
  • 과체중(Overweight)이 23.6%, 정상(Normal)이 13.5%를 차지
  • 저체중(Underweight)은 0.5%로 매우 적은 비율
print(diabetes['Outcome'].value_counts())
print('-' * 25)
print(diabetes['Outcome'].value_counts(normalize=True))

 

🔍 해석

  • 당뇨가 아닌 사람이 65.1%
  • 당뇨인 사람 34.8%

→ 범주값이 뭐가 있고 그게 몇개야 걔가 몇 퍼센트 차지하고 있어에 관심 있지(빈도)

Outcome의 평균이 뭐야? 이런거에 관심 없음

 

 

 

시각화

Bar Plot

  • 범주 이름과 값이 필요하므로 집계 작업이 선행되어야 함
  • 판다스의 value_counts() 를 사용하여 집계
    • 집계 결과의 index: 범줏값 이름
    • 집계 결과의 values: 값
  • 집계 결과를 Matplotlib의 bar() 함수로 시각화
첫번째. 집계 과정

temp = diabetes['BMIStatus'].value_counts()
print(temp)
print('-'*25)
print(temp.index) # 바플롯 그릴때 이게 x축으로
print(temp.values) # 이게 y축으로 감

 

빨간색이 인덱스 노란색이 밸류즈

두번째. 시각화

temp = diabetes['BMIStatus'].value_counts()

plt.bar(x=temp.index.astype(str), height=temp.values)
astype(str) 문자면 상관 없는데 그릴게 숫자라면 쓸데 없는 값들도 그려지게 됨
**숫자가 문자화 돼서 중간값이 출력되지 않게 해주는 역할**

plt.show()

Seaborn의 countplot() 함수를 사용하면 집계 과정 없이도 Bar Plot을 그릴 수 있다

sns.countplot(x='BMIStatus', data=diabetes)
plt.show()

이게 좋다… 위에 집계과정 없으니까는(첫번째 과정이 필요없음)

 

 

 

 

 

Pie Chart _ 잘 안쓴다. 피하자 우리는 바플롯, 카운트플롯을 쓰자

  • 범주별 값의 빈도수가 아닌 비율을 비교할 때는 Pie Chart를 사용
  • Pie Chart 역시 집계를 먼저 해야 함
# 집계
temp = diabetes['BMIStatus'].value_counts()
print(temp.index)
print(temp.values)
# 시각화
temp = diabetes['BMIStatus'].value_counts()

plt.pie(x=temp.values, labels=temp.index, autopct='%.2f%%')
plt.show()

 

 

EDA & CDA

  • 그래서 우리는 다음의 사항을 알아야 함 ① (언제, 어떤) 그래프 그리고 (어떻게) 해석 ② (언제, 어떤) 기초 통계량을 구하고 (어떻게) 해석 ③ (언제, 어떤) 가설 검정 방법을 사용하고 (어떻게) 해석
  • 보통 다음의 순서대로 진행함 ① 개별 변수(feature + target)의 분포를 살펴봄 ② feature와 target 간의 관계를 살펴봄 (가설을 확인하는 단계) ③ feature들 간의 관계를 살펴봄

 

단변량 분석

수치형과 범주형

범주형 데이터

숫자로 저장된 자료지만 범주형 일 수 있음 - Outcome

수치형 데이터의 수치화는 최솟값, 최댓값, 평균값, 표준편차, 사분위수로 분석하는거고

시각화는 분포를 보는 것

 

 

 

 

수치화

  • 수치형 변수를 수치화해 분석할 때는 평균, 중앙값, 최빈값, 4분위수대푯값을 사용
  • describe() 메소드를 사용해 수치형 변수의 통계 정보를 쉽게 확인 가능

대푯값 ( mean(), median(), mode(), describe()

1. 평균

  • mean() 메소드로 평균을 구함

diabetes['BMI'].mean()

2. 중앙값(median)

  • median() 메소드로 중앙값을 구함

diabetes['BMI'].median()

3. 최빈값(데이터 중에서 가장 빈번하게 나타나는 값, 즉 빈도가 가장 높은 값을 최빈값이라고 함)

  • mode() 메소드로 최빈값을 확인
  • 같은 빈도의 값이 여럿 존재할 수 있으므로 최빈값은 여러 개 존재 할 수 있음

diabetes['BMIStatus'].mode()

0    Obese
Name: BMIStatus, dtype: object

 

diabetes['BMIStatus'].mode()[0]
'Obese'

 

실제 최빈값은 다음과 같이 인덱스를 사용해 조회

4. 4분위수

  • describe() 메소드로 4분위수를 확인할 수 있음
count    757.000000
mean      32.457464
std        6.924988
min       18.200000
25%       27.500000
50%       32.300000
75%       36.600000
max       67.100000
Name: BMI, dtype: float64

 

 

기술통계 정보 - 수치형 데이터 확인 describe()

  • 변수 하나에 대한 기술통계 정보를 describe() 메소드로 확인

(왼) 시리즈값으로 확인 (오) 대상 변수를 리스트 형태로 전달해 데이터프레임 형태로 결과를 표시

🔍 해석

  • BMI는 체질량지수를 의미
  • 전체 데이터는 768건
  • 전체 768건 중 BMI 값이 확인된 것은 757건 / 나머지는 결측치 / 결측치 有
  • BMI 범위는 최소 18.2에서 최대 67.1까지이며, 일부 이상치 존재
  • 평균 BMI는 32.46으로, WHO 기준상 ‘비만’ 범주
  • BMI의 25%, 50%, 75% 분위값은 각각 27.5, 32.3, 36.6
  • BMI가 25 이상인 과체중/비만 인원이 전체의 상당 비율을 차지

🔍 해석

  • 768건 모두 나이 정보를 보유함 (결측치 없음)
  • 나이 범위는 최소 21세부터 최대 81세까지
  • 평균 나이는 약 33.24세로 비교적 젊은 연령대 중심
  • 표준편차가 약 11.76으로 연령 분포에 다양성이 있음
  • 나이 중앙값(50%)은 29세로 절반의 환자가 29세 이하
  • 사분위수 25%: 24세 이하, 75%: 41세 이하
  • 24세~41세 구간에 전체의 절반이 위치

 

 

수치형 데이터의 시각화

제일 기본적인 시각화 방법 : Histogram

  • Matplotlib의 hist() 함수로 Histogram을 그린다
plt.hist(x='BMI', data=diabetes)
plt.hist(x='BMI', data=diabetes, bins=20, 
alpha=0.7(투명도), edgecolor='k'(테두리색)) 이렇게 바꾸면 밑에 sns랑 비슷해 보임
plt.xlabel('BMI')
plt.ylabel('Frequency')
plt.show()
  • Seaborn의 histplot() 함수로 Histogram을 그린다 [bins 옵션을 사용해 구간 개수를 적절히 지정]
sns.histplot(x='BMI', data=diabetes ,bins=20)
plt.show()

Seaborn은 알아서 예쁘게 되는데 Matplotlib은 필요하면 알아서 꾸며야함

Density Plot(밀도 함수)

  • Histogram은 빈즈에 의해 모양이 바뀌지만 kde플롯은 바뀌지 않음
1. Pandas가 제공하는 plot() 메소드에 kind='kde' 를 지정해 
Density Plot을 쉽게 그릴 수 있음

diabetes['BMI'].plot(kind='kde')
plt.show()
2. Seaborn의 kdeplot() 함수를 사용해 Density Plot을 그림

sns.kdeplot(x='BMI', data=diabetes)
plt.show()

📌 확률 밀도 함수

셀 수 있는 값의 분포, 즉 이산 확률 분포는 표로 표현 할 수 있음

(예를 들면 주사위를 던져 1 ~ 6이 나올 수 있는 확률)

반면에 셀 수 없는 값의 분포, 즉 연속 확률 분포는 대상 값이 너무 많아 표로 표현할 수 없다

그래서 연속 확률 분포는 함수(=그래프), 즉 그래프로 표현

(예 예를 들어 키가 140~180 사이인 학생들의 키 분포)

 

 

Box Plot (교안 / 질문이 중요하다고 했던 박스플롯 박사)

  • Box Plot은 이해하기가 다소 어렵지만, 데이터 분포를 확인하는 유익한 시각화 도구
  • Matplotlib의 boxplot() 함수를 사용해 Box Plot을 그린다
plt.boxplot(x='BMI', data=diabetes[diabetes['BMI'].notna()]) 결측치는 제외하고
plt.show()
  • 주의: 결측치가 있으면 그래프가 그려지지 않는다
Seaborn의 boxplot() 함수를 사용해 Box Plot 그리기

sns.boxplot(x='BMI', data=diabetes[diabetes['BMI'].notna()])
sns.boxplot(x='BMI', data=diabetes)**Seaborn**은 결측치가 있어도 그려짐
plt.show()

쓰고 싶은거 쓰면 됨

★★ 박스플롯의 의미

IQR : 25%와 75% 사이의 차이

만약 75% 가 20이고 25% 가 5라면 IQR은 15

**Q3에서 IQR*1.5만큼 쭈욱 가보면 어느 경계가 나오지만 이 경계는 박스플롯에 나타나지 않음

**Q1에서 IQR*1.5만큼 쭈욱 가봐도 어느 경계가 나오지만 이 경계는 박스플롯에 나타나지 않음

이 선들을 넘어 서는 값들은 이상치

이상치 제외 최댓값과 최솟값과 **갔을때 경계 사이에는 값이 없음

 

시계열 데이터 시각화

Matplotlib의 plot() 함수를 사용해 Line Plot

air['Date'] = pd.to_datetime(air['Date'])

plt.plot('Date', 'Ozone', data=air, label='Ozone')
plt.plot('Date', 'Temp', data=air, label='Temp')
plt.xlabel('Date')
plt.legend()
plt.show()
Seaborn의 lineplot() 함수를 사용해 Line Plot

sns.lineplot(x='Date', y='Ozone', data=air, label='Ozone')
sns.lineplot(x='Date', y='Temp', data=air, label='Temp')
plt.legend()
plt.show()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+ Recent posts