목차

그로스 마케팅

그로스 마케팅 26일차(분류 모델, 로지스틱 회귀 개념과 활용, k-nn, 서포트 벡터 머신(svm))

makeyou 2025. 3. 12. 22:20

오늘은 k-nn, 서포트 벡터 머신(svm), 로지스틱 회귀를 진행했다.

k-nn에서 템플릿을 이용해 웹서비스 진행(예제는 실행했지만 내가 만든 csv로 파일 탑재해서 해보려고 했는데 실패 INDEX.HTML에서 수정하는 부분이 잘 안된것 같았다.)

로지스틱 회귀에서 진행한 웹서비스에서는 데이터 직접입력으로 진행해서 겨우 성공해서 다행이었다.(조금더 쉽게 할 수 있는 예제 같았다.)

수업이 실제로 4일 정도 남아서 갈수록 어려워지는 예제인것 같다. 그래도 많이 다뤄본 것들은 슥슥 해내는것을 보면 이런 저런 시도들을 해보는게 나쁜것 같지는 않다.(gcp를 통해 웹페이지 템플릿을 사용해 만들어 화면 띄우는건 잘한다.)

역시 반복이 답이다.

 

그리고 로지스틱 회귀를 했는데 아직 혼동행렬, MAE, MSE, RMSE를 활용하여 분석하는 능력이 약한 것도 체크했다.

+ 실습공간에 결과물 제출하는 페이지에서 동기분들의 분석과 아이디어를 많이 배우고 있다.

 

 

 

 

학습목표

- K-NN, SVM 개념과 활용

- 로지스틱 회귀 개념과 활용

 

 

 

 

k-NN 알고리즘 개요

  1. 거리 측정: 새로운 데이터 포인트와 모든 훈련 데이터 포인트 간의 거리를 계산합니다. 일반적으로 유클리드 거리(Euclidean Distance)를 사용하지만, 맨해튼 거리(Manhattan Distance) 등 다른 거리 측정 방법도 사용할 수 있습니다.
  2. 이웃 선택: 계산된 거리 값을 기준으로 가장 가까운 k개의 이웃을 선택합니다.
  3. 분류/회귀:
    • 분류: 선택된 k개의 이웃 중 가장 많은 클래스를 새로운 데이터 포인트의 클래스로 할당합니다. 즉, 다수결 투표(Majority Voting) 방식으로 클래스를 결정합니다.
    • 회귀: 선택된 k개의 이웃의 평균 값을 새로운 데이터 포인트의 예측 값으로 사용합니다.

빨간것 2개와 가까우니 빨간쪽으로 분류한다.

 

k-NN 그래프 설명:

  • 빨간색 원: 클래스 A에 속하는 데이터 포인트들입니다.
  • 파란색 삼각형: 클래스 B에 속하는 데이터 포인트들입니다.
  • 초록색 별: 분류되지 않은 새로운 데이터 포인트입니다.
  • 점선: 새로운 데이터 포인트와 가장 가까운 k개의 이웃을 연결하는 선입니다. 이 예제에서는 k=3으로 설정되어 있습니다.

k-NN 알고리즘:

  1. 새로운 데이터 포인트(초록색 별)와 모든 기존 데이터 포인트(빨간색 원과 파란색 삼각형) 사이의 거리를 계산합니다.
  2. 가장 가까운 k=3개의 이웃을 선택합니다. 이 이웃들은 점선으로 연결되어 있습니다.
  3. 선택된 이웃 중 다수결에 따라 새로운 데이터 포인트의 클래스를 결정합니다. 이 예에서는 새로운 데이터 포인트가 어떤 클래스에 속할지 결정합니다.

 

k-NN 알고리즘 수식 표현

k-NN 알고리즘의 주요 특징

  • 장점:
    • 이해하고 구현하기 쉽습니다.
    • 새로운 데이터에 대해 학습이 필요 없이 바로 예측할 수 있습니다.
  • 단점:
    • 데이터 포인트가 많아지면 계산량이 급격히 증가합니다.
    • 데이터의 차원이 높아지면(즉, 특징이 많아지면) 성능이 저하될 수 있습니다. 이를 차원의 저주(Curse of Dimensionality)라고 합니다.

 

다음의 코드는 한국 청소년들의 의류 구매패턴을 k-NN 알고리즘을 이용해 분석하고 학습한 뒤 추천하는 예시이다.

 

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

# 1. 가상 한국 청소년 의류 구매 패턴 데이터 생성 및 추천 정보 포함
def generate_korean_teen_fashion_data_with_recommendations():
    # 데이터 생성
    data = {
        'Teenager': ['Teen1', 'Teen2', 'Teen3', 'Teen4', 'Teen5', 'Teen6', 'Teen7', 'Teen8', 'Teen9', 'Teen10'],
        'Sportswear': [5, 3, 2, 4, 5, 2, 3, 4, 5, 1],
        'Casual': [3, 4, 5, 3, 2, 4, 3, 4, 2, 5],
        'Luxury': [2, 5, 4, 2, 3, 5, 2, 1, 3, 4],
        'Streetwear': [4, 2, 5, 4, 3, 1, 4, 5, 2, 3],
        'Fashionable': [5, 4, 3, 5, 4, 3, 2, 5, 4, 3],
        'Average_Spending': [100000, 150000, 80000, 95000, 120000, 60000, 110000, 140000, 130000, 90000]  # 원 단위
    }
    df = pd.DataFrame(data)

    # 추천 정보 추가
    recommendations = {
        'Teen1': {'Brand': 'Nike', 'Category': 'Sportswear', 'Spending': 100000},
        'Teen2': {'Brand': 'Adidas', 'Category': 'Casual', 'Spending': 150000},
        'Teen3': {'Brand': 'Gucci', 'Category': 'Luxury', 'Spending': 80000},
        'Teen4': {'Brand': 'Supreme', 'Category': 'Streetwear', 'Spending': 95000},
        'Teen5': {'Brand': 'Zara', 'Category': 'Fashionable', 'Spending': 120000},
        'Teen6': {'Brand': 'Uniqlo', 'Category': 'Casual', 'Spending': 60000},
        'Teen7': {'Brand': 'Puma', 'Category': 'Sportswear', 'Spending': 110000},
        'Teen8': {'Brand': 'H&M', 'Category': 'Fashionable', 'Spending': 140000},
        'Teen9': {'Brand': 'Adidas', 'Category': 'Casual', 'Spending': 130000},
        'Teen10': {'Brand': 'Nike', 'Category': 'Sportswear', 'Spending': 90000}
    }

    return df, recommendations

# 2. 데이터 로드 및 분할
df, brand_recommendations = generate_korean_teen_fashion_data_with_recommendations()

X = df[['Sportswear', 'Casual', 'Luxury', 'Streetwear', 'Fashionable', 'Average_Spending']]
y = df['Teenager']

# 3. K-NN 모델 학습
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X, y)

# 4. 새로운 청소년 구매 패턴 데이터
new_teen = pd.DataFrame({
    'Sportswear': [1],
    'Casual': [5],
    'Luxury': [2],
    'Streetwear': [5],
    'Fashionable': [3],
    'Average_Spending': [50000]  # 원 단위로 예상되는 지출 금액
})

# 5. 새로운 청소년의 구매 패턴에 따른 추천 패턴 예측
predicted_teen = knn.predict(new_teen)[0]
print(f"Predicted Teenager Similarity: {predicted_teen}")

# 6. 예측된 청소년 패턴에 따른 추천 브랜드, 카테고리 및 사용 금액
recommendation = brand_recommendations.get(predicted_teen, None)

# 올바른 형태의 데이터로 접근할 수 있도록 수정
if isinstance(recommendation, dict):
    print(f"Recommended Brand: {recommendation['Brand']}")
    print(f"Recommended Category: {recommendation['Category']}")
    print(f"Expected Spending: {recommendation['Spending']} 원")
else:
    print("No recommendation available.")

 

다시보니 조금 이해가 된다. 처음 나온 DATA는 각 10대가 직접매긴점수 OR 분석가가 평가,수집한 점수로 생각하고

아래 나오는 RECOMMENDATIONS는 각 TEEN1~TEEN2에게 추천하는 것을 입력한것으로 생각하면 맞는것 같다.

그리고 중첩 딕셔너리 형태였다. 강의 시간에 코드에 대해 오해를 했었던 것.

 

 

 

다음의 코드는 K-NN 알고리즘을 이용한 MBTI 분석 코드입니다.

 

main.py

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, classification_report
from mbti_explainer import explain_mbti  # 외부 모듈 불러오기

# 1. 가상의 MBTI 데이터 생성
# 사용자들의 외향성(Extraversion), 직관(Intuition), 사고(Thinking), 판단(Judging) 점수를 기반으로 MBTI 유형 데이터를 생성합니다.
data = {
    'Extraversion': [1, 3, 5, 2, 4, 2, 5, 4, 1, 3, 5, 4],  # 외향성 점수: 낮은 점수는 내향성을, 높은 점수는 외향성을 의미
    'Intuition': [3, 5, 1, 4, 2, 2, 1, 3, 5, 4, 1, 2],     # 직관 점수: 낮은 점수는 감각형(S), 높은 점수는 직관형(N)을 의미
    'Thinking': [5, 1, 4, 2, 3, 5, 1, 2, 4, 5, 1, 3],       # 사고 점수: 낮은 점수는 감정형(F), 높은 점수는 사고형(T)을 의미
    'Judging': [2, 4, 3, 5, 1, 2, 4, 3, 5, 1, 4, 2],        # 판단 점수: 낮은 점수는 인식형(P), 높은 점수는 판단형(J)을 의미
    'MBTI': ['INTJ', 'ENFP', 'ISTJ', 'ESFP', 'ENTP', 'INFJ', 'ESTJ', 'INFP', 'ISFJ', 'ENTJ', 'ENFJ', 'ISTP']  # MBTI 유형
}

# 데이터를 pandas 데이터프레임으로 변환합니다.
df = pd.DataFrame(data)

# 2. 특징과 레이블로 나누기
# X는 사용자의 특성(외향성, 직관, 사고, 판단)을 포함하며, y는 해당 사용자의 MBTI 유형을 나타냅니다.
X = df[['Extraversion', 'Intuition', 'Thinking', 'Judging']]
y = df['MBTI']

# 3. 데이터 분할 (학습 세트와 테스트 세트)
# 데이터를 학습 세트(70%)와 테스트 세트(30%)로 분할합니다.
# random_state=42로 설정하여 데이터 분할이 항상 동일하게 이루어지도록 합니다.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 4. k-NN 모델 학습
# K-NN 알고리즘을 사용하여 모델을 학습합니다. k=3으로 설정하여 가장 가까운 3개의 이웃을 참조합니다.
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train, y_train)

# 5. 예측 수행
# 학습된 모델을 사용하여 테스트 세트에 대한 예측을 수행합니다.
y_pred = knn.predict(X_test)

# 6. 모델 성능 평가
# 예측 결과의 정확도와 분류 보고서를 출력합니다.
# 정확도는 모델이 정확히 예측한 비율을 의미하며, 분류 보고서는 정밀도, 재현율 등을 포함합니다.
accuracy = accuracy_score(y_test, y_pred)
print(f'Accuracy: {accuracy * 100:.2f}%')
print("\nClassification Report:")
# zero_division=1 옵션을 추가하여 0으로 나누는 경우에 대해 1로 처리합니다.
print(classification_report(y_test, y_pred, zero_division=1))

# 7. 새로운 사용자 데이터 예측
# 새로운 사용자의 특징을 입력하여 MBTI를 예측합니다.
new_user = pd.DataFrame({
    'Extraversion': [3],  # 외향성: 2점, 이 점수가 낮을수록 내향성에 가깝고, 높을수록 외향성에 가까움
    'Intuition': [2],    # 직관: 4점, 이 점수가 낮을수록 감각형(S)에 가깝고, 높을수록 직관형(N)에 가까움
    'Thinking': [2],     # 사고: 3점, 이 점수가 낮을수록 감정형(F)에 가깝고, 높을수록 사고형(T)에 가까움
    'Judging': [2]       # 판단: 5점, 이 점수가 낮을수록 인식형(P)에 가깝고, 높을수록 판단형(J)에 가까움
})

# 학습된 모델을 사용하여 새로운 사용자에 대한 MBTI 유형을 예측합니다.
predicted_mbti = knn.predict(new_user)[0]
print(f"Predicted MBTI for the new user: {predicted_mbti}")

# 8. 예측된 MBTI 유형에 대한 설명 출력
# 예측된 MBTI 유형에 대한 설명을 외부 모듈에서 불러온 explain_mbti 함수를 통해 출력합니다.
explanation = explain_mbti(predicted_mbti)
print(f"Explanation: {explanation}")

 

mbti_explainer.py

# mbti_explainer.py

# 각 MBTI 유형에 대한 설명을 제공하는 함수ㅣ
def explain_mbti(mbti_type):
    descriptions = {
        'INTJ': 'INTJ는 분석적이고 독립적인 성향을 지닌 전략가입니다. 비전을 제시하고 체계적으로 문제를 해결합니다.',
        'ENFP': 'ENFP는 열정적이고 창의적인 성향을 지닌 사람들로, 새로운 아이디어와 인간관계를 중시합니다.',
        'ISTJ': 'ISTJ는 책임감 있고 신뢰할 수 있는 성향을 지닌 사람들로, 규칙과 절차를 중시합니다.',
        'ESFP': 'ESFP는 사교적이고 활발한 성향을 지닌 사람들로, 현재의 순간을 즐기며 실용적인 방법을 선호합니다.',
        'ENTP': 'ENTP는 독창적이고 변화를 선호하는 성향을 지닌 사람들로, 논쟁을 즐기며 새로운 아이디어에 개방적입니다.',
        'INFJ': 'INFJ는 직관적이고 이상주의적인 성향을 지닌 사람들로, 깊은 이해와 공감을 통해 세상을 변화시키려 합니다.',
        'ESTJ': 'ESTJ는 조직적이고 지도력이 강한 성향을 지닌 사람들로, 규율을 지키고 효율적으로 목표를 달성합니다.',
        'INFP': 'INFP는 이상주의적이고 창의적인 성향을 지닌 사람들로, 깊은 가치와 감정을 중시합니다.',
        'ISFJ': 'ISFJ는 따뜻하고 헌신적인 성향을 지닌 사람들로, 사람들을 돌보며 조화를 이루려 합니다.',
        'ENTJ': 'ENTJ는 결단력 있고 목표 지향적인 성향을 지닌 지도자들로, 전략적으로 계획하고 리더십을 발휘합니다.',
        'ENFJ': 'ENFJ는 외향적이고 사람 중심적인 성향을 지닌 사람들로, 타인을 돕고 영감을 주는 리더입니다.',
        'ISTP': 'ISTP는 분석적이고 실용적인 성향을 지닌 사람들로, 문제 해결에 능숙하며 즉흥적인 행동을 선호합니다.'
    }
    
    return descriptions.get(mbti_type, "Unknown MBTI type")

# 테스트를 위한 메인 함수
if __name__ == "__main__":
    test_type = 'INTJ'
    print(f'{test_type}: {explain_mbti(test_type)}')

 

두개 코드를 합쳐서 출력해야 결과가 나오는 것.

모듈 형태로 작업을 했어야 했는데 비슷하게 많이 보던 APP.PY로 웹서비스 하는거로 착각.(근데 모듈 자체를 까먹었다.)

먼저 아래 코드를 서브라임에서 저장을 하고 코랩에 업로드 후 위의 코드를 실행시키면 모듈 불러오기로 된다.

깜짝 복습? 그동안 배웠던게 이렇게 연계돼서 사용되는게 좋았다. 잘 따라갔다면 더 좋았겠지만 이제라도 알았으니 다행이다.

 

복습하며 되돌아 보니 첫번째 실습에서 코드에 대한 이해가 제대로 되지 않은 상태에서 진행이 되어서 오늘 오전 수업이 굉장히 힘들었던것 같다.

 

 

 

 

 

서포트 벡터 머신(SVM)

서포트 벡터 머신(SVM, Support Vector Machines)은 지도학습의 한 방법으로, 주로 분류(Classification)와 회귀(Regression) 문제에 사용됩니다. SVM은 주어진 데이터를 기반으로 최적의 초평면(Hyperplane)을 찾아, 새로운 데이터 포인트를 분류하거나 예측하는 역할을 합니다.

 

2차원에서는 구분짓기 힘들지만 3차원으로 구분한다. 등고선 느낌?

 

SVM 커널이란?

SVM 커널은 입력 데이터를 더 높은 차원의 공간으로 변환하는 수학적 함수입니다. 이렇게 하면 SVM 알고리즘이 클래스 간의 경계를 나타내는 초평면(결정 경계)을 찾는 것이 더 쉬워집니다.

쉽게 말해, 데이터가 원래 공간에서 선형적으로 구분되지 않을 때, 커널 트릭(kernel trick)을 사용하면 데이터를 새로운 공간으로 매핑하여 선형적으로 구분할 수 있게 만듭니다.

SVM 커널의 종류:

 

적절한 커널 선택하기

  • 선형 커널: 데이터가 거의 선형적으로 구분되는 경우에 사용되며, 다른 커널보다 계산 비용이 적습니다.
  • 다항 커널: 특징 간의 상호작용이 중요한 경우에 사용됩니다. 예를 들어, 자연어 처리(NLP) 작업에서 유용할 수 있습니다.
  • RBF 커널: 복잡한 비선형 경계를 처리할 수 있어 가장 널리 사용되는 커널입니다.
  • 시그모이드 커널: 신경망과 유사하게 동작하지만, 특수한 작업에만 사용됩니다.

커널 트릭 (Kernel Trick)

커널 트릭이란, SVM이 고차원 공간에서 두 벡터 간의 내적을 직접 계산하지 않고도 효율적으로 계산하는 방법을 의미합니다. 이 방법은 무한 차원 공간으로 데이터를 매핑하는 RBF와 같은 커널에서 매우 유용합니다.

 

 

활용 분야

  • 이미지 분류(Image Classification): 손글씨 숫자 인식에서 SVM은 각 숫자를 분류하는 데 사용될 수 있습니다.
  • 텍스트 분류(Text Classification): 스팸 필터링과 같은 이메일 분류 문제에서 SVM은 효과적인 도구입니다.
  • 의료 진단(Medical Diagnosis): SVM은 다양한 의료 데이터 분석에서 질병 진단을 위한 분류 도구로 활용됩니다.

지도학습에서의 사용

SVM은 지도학습(Supervised Learning)의 대표적인 분류 알고리즘으로, 라벨이 포함된 데이터를 학습하여 새로운 데이터의 라벨을 예측합니다. 이때, 각 데이터 포인트는 벡터 형태로 표현되며, SVM은 이 벡터들을 분류할 수 있는 초평면을 학습합니다. 지도학습에서 SVM은 특히 이진 분류 문제에서 높은 성능을 보입니다.

SVM의 개념

SVM은 주어진 데이터에서 두 클래스를 구분하는 최적의 초평면을 찾습니다. 이때, 각 클래스의 가장 가까운 데이터 포인트(즉, 서포트 벡터)와 초평면 사이의 거리를 최대화하는 것을 목표로 합니다.

  • 초평면(Hyperplane): 데이터를 분류하는 데 사용되는 경계입니다.
  • 마진(Margin): 각 클래스의 서포트 벡터와 초평면 사이의 거리입니다. SVM은 이 마진을 최대화하는 초평면을 찾습니다.
  • 서포트 벡터(Support Vectors): 각 클래스에서 초평면에 가장 가까운 데이터 포인트들입니다. 이 서포트 벡터는 최적의 초평면을 정의하는 데 중요한 역할을 합니다.

 

 

 

SVM의 수식 표현

SVM에서 최적의 초평면을 찾기 위해 다음과 같은 수식을 사용합니다:

회귀식과 비슷.

 

선을 그어서, 클래스 구분한다로 이해된다.

 

import cv2
import numpy as np
import os
from sklearn import svm
from sklearn.metrics import accuracy_score, roc_curve, roc_auc_score
from sklearn.model_selection import train_test_split
from skimage.feature import hog
import matplotlib.pyplot as plt

# 1. HOG 특징 추출 함수
def extract_hog_features(image):
    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 흑백 변환
    hog_features, _ = hog(gray_image, pixels_per_cell=(8, 8),
                          cells_per_block=(2, 2), block_norm='L2-Hys', visualize=True)
    return hog_features

# 2. 고양이(cat)와 개(dog) 데이터 로드
def load_images_from_folders(cat_folder, dog_folder):
    images = []
    labels = []

    # 고양이 이미지 로드
    for filename in os.listdir(cat_folder):
        img_path = os.path.join(cat_folder, filename)
        img = cv2.imread(img_path)

        if img is None:
            print(f"Warning: Unable to read {filename}")
            continue

        img = cv2.resize(img, (64, 64))
        features = extract_hog_features(img)

        if features.shape[0] != 1764:  # HOG 벡터 크기 체크
            print(f"Error: Unexpected HOG feature size {features.shape} for {filename}")
            continue

        images.append(features)
        labels.append(0)  # 고양이 = 0

    # 개 이미지 로드
    for filename in os.listdir(dog_folder):
        img_path = os.path.join(dog_folder, filename)
        img = cv2.imread(img_path)

        if img is None:
            print(f"Warning: Unable to read {filename}")
            continue

        img = cv2.resize(img, (64, 64))
        features = extract_hog_features(img)

        if features.shape[0] != 1764:
            print(f"Error: Unexpected HOG feature size {features.shape} for {filename}")
            continue

        images.append(features)
        labels.append(1)  # 개 = 1

    if len(images) == 0:
        raise ValueError("Error: No valid images found in the folders.")

    return np.array(images), np.array(labels)

# 3. 데이터 로드 (cat과 dog 경로 분리)
cat_folder_path = '/content/data/cat'   # 고양이 데이터 경로
dog_folder_path = '/content/data/dog'   # 개 데이터 경로

X, y = load_images_from_folders(cat_folder_path, dog_folder_path)

# 4. 데이터 확인 (정확도 0% 방지)
print(f"Total samples: {len(X)}, Labels: {len(y)}")

if X.shape[0] == 0:
    raise ValueError("No images found. Please check the dataset path.")

# 5. 데이터셋 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 6. SVM 모델 학습
model = svm.SVC(kernel='linear')
model.fit(X_train, y_train)

# 7. 예측 및 정확도 평가
y_pred = model.predict(X_test)
print(f'Accuracy: {accuracy_score(y_test, y_pred) * 100:.2f}%')

# 8. 테스트 이미지 예측 및 시각화
def predict_image(img_path):
    img = cv2.imread(img_path)
    if img is None:
        print(f"Error: Unable to read image {img_path}")
        return

    img_resized = cv2.resize(img, (64, 64))
    features = extract_hog_features(img_resized)
    features = features.reshape(1, -1)

    prediction = model.predict(features)

    if prediction == 0:
        print("It's a cat!")
    else:
        print("It's a dog!")

    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    plt.title("Prediction: Cat" if prediction == 0 else "Prediction: Dog")
    plt.show()

# 9. 예측 예시
predict_image('/content/data/dog/dog.jpeg')

# 10. ROC 곡선 및 AUC 계산
y_scores = model.decision_function(X_test)
fpr, tpr, _ = roc_curve(y_test, y_scores)
auc_score = roc_auc_score(y_test, y_scores)

plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, color='blue', label=f'ROC Curve (AUC = {auc_score:.2f})')
plt.plot([0, 1], [0, 1], color='gray', linestyle='--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve for SVM Model')
plt.legend()
plt.grid()
plt.show()

개와 고양이 사진을 학습시킨뒤, SVM을 사용하여 주어진 사진을 개인지 고양이인지 구분하는 것.

그리고 ROC곡선으로 시각화(역으로된 ㄱ이 완벽한 ROC 곡선형태)

 

출력결과, 학습데이터가 적어서 잘 구분하지 못하는 것 같다.

 

이런걸 활용해서 공장에서 양불 판정을 한다고 하심(납땜, 음료수 정량체크 등)

 

 

 

로지스틱 회귀 개념과 활용

1. 비즈니스 시나리오

구독 기간 예측 (회귀 모델 적용)

C사는 온라인 구독 서비스를 운영하고 있으며, 신규 가입자의 초기 사용 패턴을 바탕으로 얼마나 오랫동안 구독을 유지할지를 예측하고자 한다. 이를 통해 구독 기간이 짧을 가능성이 높은 고객을 사전에 파악하여 맞춤형 혜택(할인 쿠폰, 추가 콘텐츠 제공 등)을 제공할 수 있다.

목표

  • 신규 가입자의 초기 사용 데이터를 바탕으로 구독 기간(일)을 예측
  • 회귀 모델(선형 회귀)을 활용하여 특정 고객이 평균적으로 몇 일 동안 구독할지를 예측
  • 예측된 결과를 기반으로 고객 유지 전략을 최적화

2. 데이터 설명

사용할 데이터 예시

  • 고객 특성 데이터
    • age (나이)
    • num_logins (가입 후 첫 7일 동안 로그인 횟수)
    • num_watched_videos (첫 7일 동안 시청한 영상 수)
    • avg_watch_time (평균 시청 시간(분))
    • subscription_length (실제 구독 유지 기간(일), 회귀 모델의 타겟 변수)

 

3. 코드 작성 (회귀 모델 적용 및 예측 예제)

필요 라이브러리 설치 및 데이터 준비

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

# 가상의 신규 구독자 데이터 생성
data = {
    'age': [22, 45, 25, 33, 50, 41, 29, 39, 48, 23, 31, 36, 27, 40, 53, 44, 26, 38, 51, 30],
    'num_logins': [2, 15, 3, 10, 20, 12, 5, 9, 18, 4,
                   8, 11, 6, 13, 22, 14, 7, 10, 19, 5],
    'num_watched_videos': [1, 10, 2, 7, 15, 9, 3, 6, 13, 2,
                            5, 8, 3, 9, 18, 11, 4, 7, 14, 4],
    'avg_watch_time': [5, 40, 8, 30, 60, 35, 12, 28, 50, 6,
                       18, 32, 10, 33, 70, 45, 9, 29, 55, 14],
    'subscription_length': [10, 45, 14, 30, 60, 50, 21, 35, 55, 12,
                            28, 40, 18, 42, 70, 48, 15, 37, 58, 20]  # 타겟 변수
}

df = pd.DataFrame(data)

# 데이터 분할 (독립변수 X, 종속변수 y)
X = df[['age', 'num_logins', 'num_watched_videos', 'avg_watch_time']]
y = df['subscription_length']

# 훈련 데이터와 테스트 데이터로 분할 (80% 훈련, 20% 테스트)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 데이터 정규화 (회귀 모델의 입력값을 표준화)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

 

선형 회귀 모델 훈련 및 평가

# 선형 회귀 모델 생성 및 학습
model = LinearRegression()
model.fit(X_train, y_train)

# 예측 수행
y_pred = model.predict(X_test)

# 성능 평가
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_test, y_pred)

# 결과 출력
print(f"MAE (평균 절대 오차): {mae:.2f}")
print(f"MSE (평균 제곱 오차): {mse:.2f}")
print(f"RMSE (제곱근 평균 제곱 오차): {rmse:.2f}")
print(f"R² (결정 계수): {r2:.2f}")

 

 

예측 결과 시각화

# 실제 값 vs 예측 값 비교 시각화
plt.figure(figsize=(8, 6))
plt.scatter(y_test, y_pred, color='blue', alpha=0.6, label='예측 값')
plt.plot(y_test, y_test, color='red', linestyle='--', label='완벽한 예측선')
plt.xlabel("실제 구독 기간 (일)")
plt.ylabel("예측된 구독 기간 (일)")
plt.title("실제 vs 예측된 구독 기간")
plt.legend()
plt.show()

 

 

 

 

 

그래프 분석 및 전략 제안

 

MAE: 평균과의 절대 오차로 평균에서 해당 값만큼 차이 난다. 1.40으로 적은편

MSE: 평균 제곱 오차로 오차값이 클수록 MSE 값도 크게 증가한다. 이 모델의 MSE는 3.32로 작은편

RMSE: 제곱근 평균 제곱 오차, 오차의 크기를 실제값과 같은 단위로 보여줌. 오차에 더 큰 가중치를 보여줌.

R2의 값이 0.99로 모델 설명력이 매우 높다. 모델이 예측하는 구독기간과 실제 구독 기간은 거의 동일하고 매우 신뢰할 만한다고 볼 수 있다. 독립변수로 사용된 NUM_LOGINS, NUM_WATCHED_VIDEO, AVG_WATCH_TIME의 값을 높일 수 있는 방법으로 마케팅 캠페인을 진행 할 것을 추천

 

전략 제안

-  각 독립변수들이 첫 7일동안 발생한 행동 분석으로 가입 후 첫 7일 동안 해당 서비스에 빠르게 적응 할 수 있도록 UI/UX 개선을 통해 사용성을 개선한다면 상위 플랜 선택할 가능성이 높아진다고 보임.

- 가입 후 출석 이벤트를 진행하여 보상 제공(7일 동안 14시간 이상 사용 등의 조건.) 이벤트 달성하기 위해 첫 7일 동안 해당 서비스를 사용할 동기 부여 제공.

- 가입 후 첫 7일간 플랜 업그레이드 서비스 제공을 통해 7일동안 상위 플랜을 사용하여 만족시 업그레이드 할 수 있도록 유도.

 

 

 

 

기분 좋게 풀수 있는 문제

문제 1. 대입 수험생의 성적 데이터를 가상으로 생성하고 합격 여부(합격/추합/불합격)를 예측하는 서비스를 위 코드를 이용해 구현하세요.

 

 

 

 

오늘도 많은 예제를 다룬것 같다.

반복~