TIL - 머신러닝 과제

AnalytiCode·2025년 5월 7일

머신러닝 과제

검정통계량, p-value
검정통계량 -> p-value, 반비례함.

집단간 차이가 잇구나. 통계적 유의미!

p-value를 보고 결정만 하면됨 !!

5번 통계적 가설검정

Color, Season 컬럼에 대한 카이제곱 검정을 진행해주세요.
- 귀무가설과 대립가설을 작성해주세요.
- 두 범주형 자료의 빈도표를 만들어주세요. 이를 코드로 작성하여 기재해주세요.
- 카이제곱통계량, P-value 를 구해주세요.
그리고 이에 대한 귀무가설 채택/기각 여부와 그렇게 생각한 이유를 간략하게 설명해주세요.

카이제곱(stats.chisquare)

범주형 데이터의 분석(표본의 비율이나 빈도 비교)에 사용
범주형 데이터의 분포 확인독립성 확인을 위해 사용
적합도 검정과 독립성 검정이 있다.

chi² 작다 → 관측값과 기대값 비슷함
chi² 크다 → 관측값과 기대값 차이 큼
→ 이 차이가 우연일 가능성(p-value) 이 낮으면, 진짜 차이 있다고 판단

적합도 검정

범주형 데이터의 표본 분포가 모집단의 분포와 일치하는지 검정
귀무가설: 데이터가 기대한 확률분포와 일치한다
관찰된 분포와 기대분포가 일치하는지 검정
값이 크다 = 관측된 빈도와 기대빈도(기준 분포)간의 차이가 크다
= 귀무가설(기대분포와 같다)를 기각할 수 있다

분포: 각 경우의 수(또는 값)에 확률이 어떻게 배분되어 있는지 나타내는 것
뭐(경우의 수)가 얼마나 자주 일어날 것(확률) 같은지?를 숫자로 정리한 것.

ex) 주사위의 각 면이 동일한 확률로 나오는지 검정
확률분포, 각 결과(면)에 확률이 어떻게 분포되어 있느냐

개념설명
확률각 결과가 일어날 가능성 (예: 1/6)
분포여러 확률이 모인 구조 (예: 1~6 모두 1/6)
확률분포각각의 경우에 확률이 어떻게 배분됐는지 보여줌
적합도 검정관찰된 분포가 기대 분포와 일치하는지 검정

확률 : 경우가 일어날 가능성
확률분포 : 그 확률들이 모여서 전체를 어떻게 이루는가

관찰된 분포: 실제 주사위를 던졌을 때, 각 면이 나타난 횟수 분포
기대한 분포: 실제 주사위를 던졌을 때, 각 면이 동일한 횟수로 나타날 것.
적합도 검정: 이 두 분포가 얼마나 다른가

p가 높음 = 데이터가 귀무가설에 맞음 = 관찰데이터와 귀무가설 적합

독립성 검정

두 범주형 변수간의 독립성 검정
귀무가설: 두 범주형 변수는 서로 독립이다(영향x)
기대값과 관측값이 비슷하다
= 두 변수는 독립일 가능성이 높다
= chi2 값이 작다

카이제곱 통계량(chi2)는 기대값(두 변수는 독립이다, 기대값과 관측값의 차이가 적다)과 실제 관측값의 차이를 수치로 나타낸 것으로 실제 데이터와 기댓값 사이의 차이가 얼마나 큰지 나타냄

chi2값이 크다 = 차이가 크다 = 두 변수는 독립이 아닐 가능성이 높다 = 귀무가설 기각

p값이 높다 = 변수간 관계가 연관성이 없다 = 독립성이 있다
적합도 검정에서 p가 높으면 귀무가설 적합(의미가 없다).
독립성 검정에서 p가 높으면(적합도검정 - 의미가 없다) 독립성이 있다

Color, Season에 대한 카이제곱 검정은
아무래도 빈도표를 만드는걸 보니까
독립성 검정을 실행해야 할 듯

정리

구분적합성 검정 (Goodness of Fit)독립성 검정 (Test of Independence)
목적관측 분포가 기대 분포와 같은가?두 범주형 변수 간에 관계가 있는가?
귀무가설 (H₀)관측값은 기대 분포와 같다두 변수는 서로 독립이다
대립가설 (H₁)관측값은 기대 분포와 다르다두 변수는 서로 독립이 아니다 (관련 있다)
카이제곱 값이 작을 때관측값 ≈ 기대값 → 분포가 잘 맞는다관측값 ≈ 기대값 → 변수 간 관계 없음 (독립)
카이제곱 값이 클 때관측값과 기대값 차이 큼 → 분포가 다름관측값과 기대값 차이 큼 → 변수 간 관계 있음 (독립 아님)
p-value < 0.05귀무가설 기각 → 관측값은 기대 분포와 다름통계적으로 유의미한 차이 있음귀무가설 기각 → 두 변수는 관계 있음 (독립 아님)
p-value ≥ 0.05귀무가설 채택 → 관측값은 기대 분포와 차이 없음귀무가설 채택 → 두 변수는 독립적 (관계 없음)
예시주사위 눈이 전부 1~6이 1/6 확률로 나오는가?성별과 구매 여부는 관계가 있는가?

카이제곱 값 자체의 크기판단(크다/작다)는 자유도(행-1 * 열-1)에 따라 판단해야하는데,
해석시엔 p-value를 사용해서 p값이 0.05보다 작다면 유의미하다고 판단한다.

코드

a1 = pd.crosstab(df['Color'], df['Season'])
a1

chi2_stat, p_value, dof, expected = stats.chi2_contingency(a1)
critical_value = chi2.ppf(0.95, dof) # 유의수준 0.05 기준 임계값
print(f"유의수준 0.05 기준 임계값: {critical_value}")

print(f"독립성 검정 카이제곱 통계량: {chi2_stat}, p-값: {p_value}")

유의수준 0.05 기준 임계값: 92.80827038310771
독립성 검정 카이제곱 통계량: 64.6506366841786, p-값: 0.718551112120402

카이제곱 통계량이 유의수준 0.05 임계값보다 작아 관측값이 기댓값의 분포와 맞다고 해석할 수있고
p-value의 값이 0.7으로 0.05보다 크기때문에 귀무가설을 채택(두 변수는 독립)한다

6번 머신러닝

종속변수가 하나밖에 주어지지 않았기 때문에 단순선형회귀

모델을 돌릴 때 x값이 1차원배열이면 값 하나를 보고 모델을 만드는 것이기 때문에
꼭 2차원으로 만들어줘야한다

1D 배열:X = [10, 20, 30, 40, 60, 100]
각 광고 예산 값을 하나의 값으로 다루는 배열. 이 형태는 단일 특성(각 샘플에 대해 하나의 값만 제공)만을 모델에 전달.
하나의 샘플을 받는 것

2D 배열:X = [[10], [20], [30], [40], [60], [100]]
각 값이 하나의 데이터 샘플을 구성하고, 하나의 특성(여기서는 광고 예산)을 나타냄.
-> 모델은 각 샘플에 대해 하나의 특성 값만을 받음
여러개의 샘플을 받는 것

절편을 보면 광고예산이 0일때 기본 판매량이 50이다. (광고를 하나도 하지 않아도 50만큼 판매)
MSE 값이 클수록 오차가 큰데, 약 32로 성능이 좋지않다. 특히 R^2의 경우 음수가 나타나 성능이 매우 좋지않음을 시사한다.
따라서 선형모델은 데이터를 잘 반영하지 못한다.

도전1번


from sklearn.preprocessing import LabelEncoder
from sklearn.ensemble import RandomForestClassifier 
from imblearn.over_sampling import SMOTE
from sklearn.metrics import classification_report


encoder = LabelEncoder()

df["Discount Applied"] = encoder.fit_transform(df["Discount Applied"])

X = df[['Review Rating', 'Age', 'Previous Purchases']]
y = df['Discount Applied']

# 학습용/테스트용 나누기
X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size=0.3,
                                                    stratify=y,
                                                    random_state=42)

# SMOTE 적용

smote = SMOTE(random_state=42)
X_train_resampled, y_train_resampled = smote.fit_resample(X_train, y_train)


# 모델 학습
model = RandomForestClassifier(random_state=42)
model.fit(X_train_resampled, y_train_resampled)

# 테스트 데이터로 평가
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred, target_names = encoder.classes_))

도전 2번

from sklearn.preprocessing import LabelEncoder
from imblearn.over_sampling import SMOTE
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
from sklearn.preprocessing import StandardScaler


encoder = LabelEncoder()

df['Subscription Status'] = encoder.fit_transform(df['Subscription Status'])
df['Subscription Status'] = 1 - df['Subscription Status']

X = df[['Age','Purchase Amount (USD)','Review Rating']]
y = df['Subscription Status']

# 학습용/테스트용 나누기
X_train, X_test, y_train, y_test = train_test_split(X, y,
                                                    test_size=0.3,
                                                    stratify=y,
                                                    random_state=42)


smote = SMOTE(random_state=42)
X_train_resampled, y_train_resampled = smote.fit_resample(X_train, y_train)
                                 
                                 
# 모델 학습
model = LogisticRegression(random_state=42)
model.fit(X_train_resampled, y_train_resampled)

# 테스트 데이터로 평가
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred, target_names = encoder.classes_))



# 성능을 높이기 위해
# 1. calss_weight 추가
# 모델 학습
model = LogisticRegression(random_state=42,
                           class_weight='balanced')
model.fit(X_train_resampled, y_train_resampled)

# 테스트 데이터로 평가
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred, target_names = encoder.classes_)) -> 같은결과

# 2. 정규화
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train_resampled)
X_test_scaled = scaler.transform(X_test)

# 모델 학습
model = LogisticRegression(random_state=42, class_weight='balanced')
model.fit(X_train_scaled, y_train_resampled)

# 테스트 데이터로 평가
y_pred = model.predict(X_test_scaled)
print(classification_report(y_test, y_pred)) -> 성능 차이 거의 없음



new_customer = [[30, 50, 4.0]]
y_prob = model.predict_proba(new_customer)
print(f"이 고객이 구독취소할 확률 약 {round(y_prob[0][1] * 100)}%")

이 모델은 구독취소할 경우를 구독할 경우보다 더 잘 맞춘다. 그러나 예측 정확도를 비롯하여 성능이 낮게 나오기 때문에 신뢰도는 높지않다.

는 고작 50% → 거의 랜덤 추측 수준

모델은 이 고객이 구독을 취소할 가능성이 61%라고 판단함

즉, 구독을 유지할 확률은 39%

현재 모델 성능이 낮아 신뢰도는 높지 않지만, 이 예측만 보면 취소 쪽에 무게가 실림

전체적으로 모델 성능이 매우 낮음. 특히 구독 유지 예측 성능이 심각하게 낮다.

구독유지의 경우 구독취소보다

정밀도: 0.26 → 예측한 구독 유지 중 실제로 유지인 비율

재현율: 0.47 → 실제로 유지 중 예측에 성공한 비율

F1 점수: 0.33 → 조화 평균으로도 매우 낮음
👉 즉, 구독 유지 고객을 거의 잘 못 맞춤

1 (구독 취소)

정밀도: 0.72 → 예측한 취소 중 실제로 취소인 비율은 높음

재현율: 0.51 → 실제로 취소한 사람 중 절반만 예측 성공

F1 점수: 0.60 → 이 클래스는 그나마 쓸만한 수준

📌 전체 정확도: 0.50
예측 정확도는 고작 50% → 거의 랜덤 추측 수준

모델은 이 고객이 구독을 취소할 가능성이 61%라고 판단함

즉, 구독을 유지할 확률은 39%

현재 모델 성능이 낮아 신뢰도는 높지 않지만, 이 예측만 보면 취소 쪽에 무게가 실림

전체적으로 모델 성능이 매우 낮음. 특히 구독 유지 예측 성능이 심각하게 낮다.

0개의 댓글