데이터 분석 part

k-NN 알고리즘, 서포트 벡터 머신(SVM), flask 웹실습

bleufonce 2025. 3. 13. 02:47

k-NN 알고리즘

k-NN은 새로운 데이터가 들어왔을 때, 그 주변에 있는 가까운 데이터(k개)를 참고하여 값을 예측하는 방법.
'비슷한 데이터는 서로 가까이 모여 있다'는 개념을 이용하는 알고리즘.

 

작동 방식

1. 거리 측정

  • 새로운 데이터가 들어오면, 기존에 있던 모든 데이터와의 거리를 계산.
  • 보통 유클리드 거리(Euclidean Distance) 를 많이 쓰는데, 쉽게 말하면 '두 점 사이의 직선 거리'이다.

 

  • 맨해튼 거리(Manhattan Distance) 같은 다른 방식도 사용가능.
    (맨해튼 거리는 '직선이 아닌 격자형 길을 따라 이동하는 거리'라고 생각하면 됨.)

2. 이웃 선택

  • 모든 데이터와의 거리를 구한 뒤, 가장 가까운 k개의 데이터를 선택.
  • 여기서 k는 미리 정한 숫자. (예: k=3이면, 가장 가까운 3개의 데이터를 참고함.)

3. 분류 or 회귀 수행

  • 분류 (Classification):
    • k개의 이웃 중에서 가장 많은 클래스(분류)를 선택해서 새로운 데이터의 클래스를 정한다.
    • 예를 들어, 주변에 고양이 2마리, 강아지 1마리가 있다면, 새로운 데이터는 고양이로 분류됨.
    • "다수결 투표(Majority Voting)" 방식
  • 회귀 (Regression):
    • k개의 이웃들의 값을 평균 내서 예측 값으로 사용.
    • 예를 들어, 주변에 온도가 23°C, 25°C, 22°C인 3개의 데이터가 있다면, 새로운 데이터의 온도를 (23+25+22)/3=23.3°C 로 예측하는 식이다.
새로운 데이터가 들어오면 → 기존 데이터와 거리 비교 → 가까운 k개 이웃 찾기 → 다수결(분류) or 평균(회귀)으로 예측!

 

 

k-NN 그래프 설명:

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

작동방식:

  1. 새로운 데이터 포인트(초록색 별)와 모든 기존 데이터 포인트(빨간색 원과 파란색 삼각형) 사이의 거리를 계산.
  2. 가장 가까운 k=3개의 이웃을 선택. 
  3. 선택된 이웃 중 다수결에 따라 새로운 데이터 포인트의 클래스를 결정.

k-NN 알고리즘 장단점

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

k-NN의 활용 예

  • 이미지 분류: 특정 이미지가 어떤 카테고리에 속하는지 분류.
  • 추천 시스템: 사용자 간의 유사성을 측정하여 비슷한 선호도를 가진 사용자들에게 유사한 콘텐츠를 추천.
  • 의료 진단: 특정 증상을 가진 환자가 어떤 질병에 걸렸는지 예측.

 

* 한국 청소년들의 의류 구매패턴을 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.")

 

 

* K-NN 알고리즘을 이용한 MBTI 분석 코드

※ 데이터를 추후에 좀 더 추가해야함. 데이터가 많아질수록 예측 정확도가 높아짐.

 

 

mbti계산 외부 모듈 생성하여 업로드 (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)}')

 

MBTI 분석하고 예측하는 코드

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 코드를 Flask를 통해 웹서비스로 구현해보는 실습

 

MBTI 예측.zip
0.00MB

 

터미널을 이용해 폴더를 만들고 파일질라를 이용해 파일을 옮긴다.

index.html과 result.html파일은 templates 폴더에, app.py는 templates의 상위폴더에 놓는다.

터미널에서 python3 app.py 입력하여 실행후 'http://vm인스턴스 외부ip주소:포트번호' 로 접속 후 확인.

 

 

 

* 신규고객에 대한 의류 고객 추천시스템 코드

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

# 데이터셋 로드
file_path = '/content/sales.csv'
df = pd.read_csv(file_path)

# 'PurchaseAmount (원)' 컬럼명을 'PurchaseAmount'로 변경
df.rename(columns={'PurchaseAmount (원)': 'PurchaseAmount'}, inplace=True)

# 필요한 데이터 전처리
# 'Age', 'Gender', 'ClothingCategory', 'Brand', 'PurchaseLocation' 등의 열을 사용
X = df[['Age', 'Gender', 'ClothingCategory', 'Brand', 'PurchaseAmount']]  # 필요한 특성만 선택
y = df['Email']  # 타겟 변수 (Email)

# 범주형 데이터를 수치형으로 변환
X = pd.get_dummies(X)

# 데이터셋을 학습과 테스트 세트로 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

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

# 새로운 고객 데이터로 예측
new_customer = pd.DataFrame({
    'Age': [30],
    'Gender': ['Female'],
    'ClothingCategory': ['Casual'],
    'Brand': ['Nike'],
    'PurchaseAmount': [150000]  # 구매 금액
})

# 새로운 고객 데이터에 대해 One-Hot Encoding 적용
new_customer = pd.get_dummies(new_customer)
new_customer = new_customer.reindex(columns=X.columns, fill_value=0)

# 가장 유사한 고객의 Email 예측
predicted_customer = knn.predict(new_customer)[0]

# 예측된 고객과 유사한 다른 고객들의 구매 패턴을 확인하고 추천 내용 생성
similar_customers = df[df['Email'] == predicted_customer]

# 입력된 new_customer의 금액에 최대한 유사한 상품 추천
if not similar_customers.empty:
    input_amount = new_customer['PurchaseAmount'].values[0]

    # 입력 금액과 가장 유사한 상품을 찾기 위해 오차를 계산
    df['AmountDifference'] = abs(df['PurchaseAmount'] - input_amount)

    # 오차가 작은 상품을 추천 (여기서는 상위 5개의 유사한 상품을 추천)
    recommended_products = df.nsmallest(5, 'AmountDifference')

    if not recommended_products.empty:
        print("추천 상품 목록:")
        print(recommended_products[['Brand', 'ClothingCategory', 'PurchaseAmount', 'PurchaseLocation']])
    else:
        print("추천할 상품이 없습니다.")
else:
    print("유사한 고객을 찾을 수 없어 추천할 내용이 없습니다.")

 

# 위 코드를 Flask를 통해 웹서비스로 구현해보는 실습

의류구매추천.zip
0.00MB

 

* 직접 데이터셋을 만들어 코드 구성 후 Flask를 통해 웹서비스로 구현해보는 실습

# 고객 특성별 카드 추천 시스템을 만들어보자.

 

1. 카드추천에 도움이 될 만한 고객 특성들을 생각하여 독립변수로 잡고 데이터셋 생성

 

2. 고객 특성을 고려한 카드 추천시스템 코드 생성 (k-NN 알고리즘 활용)

# 내가 만든 Card 추천시스템

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

# 데이터셋 로드
data = {
    'Age': [21, 21, 31, 35, 55, 35, 33, 31, 35, 30],
    'Gender': ['Male', 'Male', 'Male', 'Male', 'Male', 'Male', 'Male', 'Male', 'Female', 'Female'],
    'Interest': ['Food', 'Technology', 'Technology', 'Food', 'Food', 'Food', 'Sports', 'Food', 'Technology', 'Technology'],
    'MonthlyPurchaseAmount': [700000, 850000, 1200000, 4000000, 1800000, 900000, 1500000, 1900000, 2500000, 1000000],
    'Occupation': ['Engineer', 'Student', 'Teacher', 'Doctor', 'Student', 'Student', 'Engineer', 'Student', 'Artist', 'Teacher'],
    'CreditCardProducts': ['Cashback Credit Card', 'Standard Credit Card', 'Travel Credit Card', 'Premium Credit Card', 'Standard Credit Card',
                           'Standard Credit Card', 'Premium Credit Card', 'Travel Credit Card', 'Premium Credit Card', 'Cashback Credit Card']
}

df = pd.DataFrame(data)

# 'MonthlyPurchaseAmount' 컬럼명을 'PurchaseAmount'로 변경
df.rename(columns={'MonthlyPurchaseAmount': 'PurchaseAmount'}, inplace=True)

# 필요한 데이터 전처리
# 'Age', 'Gender', 'Interest', 'Occupation', 'PurchaseAmount' 컬럼을 사용
X = df[['Age', 'Gender', 'Interest', 'Occupation', 'PurchaseAmount']]  # 필요한 특성만 선택
y = df['CreditCardProducts']  # 타겟 변수 (신용카드상품)

# 범주형 데이터를 수치형으로 변환
X = pd.get_dummies(X)

# 데이터셋을 학습과 테스트 세트로 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

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

# 새로운 고객 데이터로 예측
new_customer = pd.DataFrame({
    'Age': [30],
    'Gender': ['Female'],
    'Interest': ['Technology'],
    'Occupation': ['Teacher'],
    'PurchaseAmount': [1500000]  # 구매 금액
})

# 새로운 고객 데이터에 대해 One-Hot Encoding 적용
new_customer = pd.get_dummies(new_customer)
new_customer = new_customer.reindex(columns=X.columns, fill_value=0)

# 가장 유사한 고객의 신용카드 상품 예측
predicted_card = knn.predict(new_customer)[0]

# 예측된 신용카드 상품과 유사한 다른 고객들의 데이터를 확인하고 추천 내용 생성
similar_customers = df[df['CreditCardProducts'] == predicted_card]

# 입력된 new_customer의 금액에 최대한 유사한 상품 추천
if not similar_customers.empty:
    input_amount = new_customer['PurchaseAmount'].values[0]

    # 입력 금액과 가장 유사한 상품을 찾기 위해 오차를 계산
    df['AmountDifference'] = abs(df['PurchaseAmount'] - input_amount)

    # 오차가 작은 상품을 추천 (여기서는 상위 5개의 유사한 상품을 추천)
    recommended_products = df.nsmallest(5, 'AmountDifference')

    if not recommended_products.empty:
        print("추천 상품 목록:")
        print(recommended_products[['CreditCardProducts','Interest', 'Occupation', 'PurchaseAmount']])
    else:
        print("추천할 상품이 없습니다.")
else:
    print("유사한 고객을 찾을 수 없어 추천할 내용이 없습니다.")

 

3. Flask를 통해 웹서비스로 구현하기

 

카드상품추천.Zip
0.00MB

 

터미널을 이용해 폴더를 만들고 파일질라를 이용해 파일을 옮긴다.

index.html과 result.html파일은 templates 폴더에, app.py는 templates의 상위폴더에 놓는다.

터미널에서 python3 app.py 입력하여 실행후 'http://vm인스턴스 외부ip주소:포트번호' 로 접속 후 확인.

 

 

이번에는 데이터셋을 간단하게 만들었지만 추후에 데이터를 더 많이 생성하고 카드추천에 유용한 고객의 특성을 더 세부적으로 파악하여 독립변수에 추가한다면 좀 더 정확한 예측을 할 수 있는 추천시스템을 구축할 수 있을 것 같다.

 


 

서포트 벡터 머신(SVM)

  • 지도학습의 대표적인 분류 알고리즘 - 특히 이진 분류 문제에서 높은 성능을 보임.
  • 데이터를 가장 잘 구분하는 "최적의 경계선(초평면)"을 찾는 알고리즘
  • 분류(Classification)와 회귀(Regression)에 사용됨
  • 가장 가까운 데이터(서포트 벡터)와 초평면 사이의 거리(마진)를 최대화하는 것이 목표
  • 데이터가 선형적으로 구분되지 않을 때는 "커널 트릭"을 사용해서 차원을 확장

 

SVM이 하는 일 (분류 문제 기준)

# 최적의 초평면(Hyperplane) 찾기

  • 초평면(Hyperplane)은 데이터를 나누는 선(2D에서는 선, 3D에서는 평면, 고차원에서는 초평면)
  • 목표: 두 클래스 간의 마진(Margin) 을 최대화하는 초평면을 찾는 것
  • 마진(Margin): 서포트 벡터(Support Vector)와 초평면 사이의 거리

마진을 가장 크게 만드는 초평면이 최적의 결정 경계이다.

 

SVM의 공식

SVM은 초평면을 수식으로 이렇게 나타낸다:

 

  • = 초평면의 기울기를 나타내는 벡터
  • x = 데이터 포인트 (입력 값)
  • b = 절편

 

SVM 커널(Kernel)

- 데이터가 선형적으로 구분되지 않는다면 커널 트릭(Kernel Trick)" 을 사용해서 데이터를 고차원 공간으로 변환할 수 있음.

 

1. 선형 커널 (Linear Kernel)

  • 선형적으로 구분되는 데이터에 사용 - 주로 우리가 볼 것.

2. 다항 커널 (Polynomial Kernel)

  • 특징 간의 복잡한 상호작용이 중요한 경우 사용.

3. RBF 커널 (Radial Basis Function Kernel, 가우시안 커널)

  • 가장 많이 사용됨.
  • 비선형 데이터에 효과적.

4. 시그모이드 커널 (Sigmoid Kernel)

  • 신경망과 유사한 방식. 특수한 작업에 사용.

SVM의 활용 사례

  • 이미지 분류 (손글씨 숫자 인식, 얼굴 인식 등)
  • 텍스트 분류 (스팸 필터링, 감성 분석)
  • 의료 데이터 분석 (질병 진단)

 

그래프로 이해하기

SVM은 주어진 데이터에서 두 클래스를 구분하는 최적의 초평면을 찾는다.

각 클래스의 가장 가까운 데이터 포인트(즉, 서포트 벡터)와 초평면 사이의 거리를 최대화하는 것이 목표.

 

  • 초평면(Hyperplane): 데이터를 분류하는 데 사용되는 경계.
  • 마진(Margin): 각 클래스의 서포트 벡터와 초평면 사이의 거리. SVM은 이 마진을 최대화하는 초평면을 찾는다.
  • 서포트 벡터(Support Vectors): 각 클래스에서 초평면에 가장 가까운 데이터 포인트들. 이 서포트 벡터는 최적의 초평면을 정의하는 데 중요한 역할을 한다.
  • ※ 커널(Kernel): 데이터를 고차원으로 변환하는 함수 (비선형 데이터 처리 가능)

  • Decision Boundary: 검정색 선은 SVM이 학습한 초평면(결정 경계)을 나타낸. 이 선은 두 클래스 사이를 최대한 분리하는 역할을 한다.
  • Support Vectors: 노란색 점들은 서포트 벡터를 나타낸다. 이 점들은 결정 경계의 위치를 결정하는 데 중요한 역할을 한다.
  • Classes: 두 개의 클래스(파란색과 빨간색)로 나뉜 데이터 포인트들. SVM은 이 클래스들을 최대한 분리하는 초평면을 찾음.

 

# SVM을 이용해 개와 고양이 사진을 학습해 분류하는 예시

data.zip
0.17MB

※ 개와 고양이 사진 압축 파일

 

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

# 1. HOG 특징 추출 함수
def extract_hog_features(image):
    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 이미지를 흑백으로 변환
    hog_features, hog_image = hog(gray_image, pixels_per_cell=(8, 8),
                                  cells_per_block=(2, 2), visualize=True)
    return hog_features

# 2. 이미지 로드 및 전처리
def load_images_from_folder(folder):
    images = []
    labels = []
    for filename in os.listdir(folder):
        label = 0 if 'cat' in filename else 1  # 파일명에 'cat'이 포함된 이미지를 고양이로, 그렇지 않으면 개로 라벨링
        img = cv2.imread(os.path.join(folder, filename))
        if img is not None:
            img = cv2.resize(img, (64, 64))  # 이미지 크기를 통일
            images.append(extract_hog_features(img))
            labels.append(label)
    return np.array(images), np.array(labels)

# 3. 데이터 로드
folder_path = '/content/data'  # 구글 드라이브에 있는 데이터셋 폴더 경로
X, y = load_images_from_folder(folder_path)

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

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

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

# 7. 테스트 이미지 예측 및 시각화
def predict_image(img_path):
    img = cv2.imread(img_path)
    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()

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

import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, roc_auc_score

# 1. 예측 확률 계산 (SVM에서 결정 함수 사용)
y_scores = model.decision_function(X_test)

# 2. ROC 곡선 데이터 계산
fpr, tpr, thresholds = roc_curve(y_test, y_scores)

# 3. AUC 값 계산
auc_score = roc_auc_score(y_test, y_scores)

# 4. ROC 곡선 그리기
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 (1 - Specificity)')
plt.ylabel('True Positive Rate (Sensitivity)')
plt.title('ROC Curve for SVM Model')
plt.legend(loc='lower right')
plt.grid(True)
plt.show()

 

 

 

※ 여기서 ROC 곡선이란??

ROC 곡선은 분류 모델의 성능을 평가하는 그래프.
특히, 이진 분류(Binary Classification) 모델이 얼마나 잘 작동하는지 시각적으로 보여준다.

ROC 곡선은 True Positive Rate (TPR) vs False Positive Rate (FPR) 를 나타내는 그래프.

왼쪽 위에 가까울수록 성능이 좋은 모델. (그래프가 뒤집어진 기역자)

TPR (True Positive Rate, 민감도 Sensitivity) FPR (False Positive Rate)
  • 실제 양성(Positive) 데이터를 얼마나 잘 맞췄는지
  • TPR = (TP) / (TP + FN)
  • 높을수록 좋음.
  • 실제 음성(Negative) 데이터를 잘못 양성으로 예측한 비율
  • FPR = (FP) / (FP + TN)
  • 낮을수록 좋음.

 

 


복습 - 다중 클래스 로지스틱 회귀

# 로지스틱 회귀를 사용하여 고객 충성도 등급 예측하기

  • 0 (낮음): 구매 빈도가 낮고, 재방문 가능성이 낮음
  • 1 (중간): 일정 수준의 구매와 재방문 기록이 있음
  • 2 (높음): 높은 구매 빈도와 충성도를 보이며, 장기 고객이 될 가능성이 큼

고객의 연령, 월 평균 구매 횟수, 월 평균 구매 금액, 고객 서비스 문의 횟수 등의 정보를 바탕으로 충성도 등급을 예측하는 다중 클래스 분류 모델.

# 고객충성도 등급예측 - 다중 클래스 로지스틱 회귀 코드

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

# 가상의 고객 데이터 생성
data = {
    'age': [22, 45, 25, 33, 50, 41, 29, 39, 48, 23, 31, 36, 27, 40, 53, 44, 26, 38, 51, 30],
    'monthly_purchases': [1, 5, 2, 3, 6, 4, 2, 3, 5, 1, 3, 4, 2, 4, 6, 5, 2, 3, 5, 2],
    'monthly_spending': [50, 300, 80, 200, 400, 250, 100, 220, 380, 60, 180, 240, 90, 270, 420, 320, 75, 230, 390, 110],
    'customer_support_calls': [3, 1, 4, 2, 0, 1, 3, 2, 0, 4, 2, 1, 3, 1, 0, 1, 4, 2, 0, 3],
    'loyalty_level': [0, 2, 0, 1, 2, 1, 0, 1, 2, 0, 1, 1, 0, 1, 2, 1, 0, 1, 2, 0]  # 0=낮음, 1=중간, 2=높음
}

df = pd.DataFrame(data)

# 독립 변수(X)와 종속 변수(y) 분리
X = df[['age', 'monthly_purchases', 'monthly_spending', 'customer_support_calls']]
y = df['loyalty_level']

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

# 데이터 정규화
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# 다중 클래스 로지스틱 회귀 모델 학습
model = LogisticRegression(multi_class='multinomial', solver='lbfgs', max_iter=200)
model.fit(X_train, y_train)

# 예측 함수 정의
def predict_loyalty(age, monthly_purchases, monthly_spending, customer_support_calls):
    """ 입력값을 받아 고객 충성도 등급을 예측 """
    input_data = np.array([[age, monthly_purchases, monthly_spending, customer_support_calls]])
    input_scaled = scaler.transform(input_data)

    predicted_class = model.predict(input_scaled)[0]
    predicted_proba = model.predict_proba(input_scaled)

    loyalty_labels = {0: "낮음", 1: "중간", 2: "높음"}

    print(f"\n🔹 예측된 고객 충성도 등급: {loyalty_labels[predicted_class]}")
    print(f"🔹 각 등급 확률: 낮음={predicted_proba[0][0]:.2f}, 중간={predicted_proba[0][1]:.2f}, 높음={predicted_proba[0][2]:.2f}")

# 예측 예제 실행
predict_loyalty(30, 4, 200, 2)  # 나이=30, 월 평균 구매=4회, 월 평균 구매액=200, 고객센터 문의=2회

 

* 위 코드를 Flask를 통해 웹서비스로 구현하기

고객충성도 등급예측.Zip
0.00MB

 

터미널을 이용해 폴더를 만들고 파일질라를 이용해 파일을 옮긴다.

index.html파일은 templates 폴더에, app.py는 templates의 상위폴더에 놓는다.

터미널에서 python3 app.py 입력하여 실행후 'http://vm인스턴스 외부ip주소:포트번호' 로 접속 후 확인.

 

데이터셋이 많을수록 정확한 예측을 보이기 때문에 많은 데이터 확보가 관건이다.

 

 

# 로지스틱 회귀를 사용하여 대입 수험생 대학 합격 여부 예측 서비스 만들기

  • 대학 합격 여부 (0: 합격, 1: 추합, 2: 불합격)
# 대입 수험생 대학 합격 여부 예측 서비스 만들기 (웹에서도 구현)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

# 가상의 데이터 생성
data = {
    'Korean': [85, 92, 78, 88, 94, 75, 80, 95, 89, 93, 87, 91, 82, 78, 90, 85, 87, 93, 88, 91, 84, 80, 76, 77, 95, 83, 92, 85, 88, 80],
    'Mathematics': [90, 88, 85, 91, 89, 82, 87, 93, 86, 90, 92, 86, 83, 81, 89, 90, 85, 92, 87, 93, 91, 85, 84, 82, 92, 90, 91, 80, 85, 88],
    'English': [80, 85, 75, 90, 88, 70, 80, 85, 82, 88, 78, 82, 85, 75, 84, 83, 82, 87, 81, 84, 80, 85, 82, 78, 85, 80, 83, 87, 81, 79],
    'Korean_History': [95, 100, 90, 85, 98, 92, 89, 97, 94, 96, 93, 95, 92, 91, 90, 89, 94, 96, 88, 99, 97, 92, 95, 90, 93, 96, 94, 97, 95, 92],
    'Inquiry': [88, 92, 85, 91, 94, 80, 85, 89, 87, 90, 88, 90, 85, 92, 91, 86, 85, 87, 92, 89, 88, 91, 92, 90, 90, 87, 93, 85, 88, 89],
    'Second_Foreign_Language': [70, 80, 65, 85, 78, 72, 76, 90, 85, 80, 75, 78, 80, 76, 70, 85, 82, 80, 78, 75, 88, 80, 82, 76, 84, 79, 77, 82, 75, 80],
    'admission_status': [0, 1, 2, 0, 1, 2, 2, 0, 1, 0, 1, 0, 2, 1, 1, 2, 0, 2, 1, 0, 1, 0, 2, 2, 1, 0, 1, 1, 2, 0]  # 대학 합격 여부 (0: 합격, 1: 추합, 2: 불합격)
}

df = pd.DataFrame(data)

# 독립 변수(X)와 종속 변수(y) 분리
X = df[['Korean', 'Mathematics', 'English', 'Korean_History','Inquiry','Second_Foreign_Language']]
y = df['admission_status']

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

# 데이터 정규화
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# 다중 클래스 로지스틱 회귀 모델 학습
model = LogisticRegression(multi_class='multinomial', solver='lbfgs', max_iter=200)
model.fit(X_train, y_train)

# 예측 함수 정의
def predict_loyalty(Korean, Mathematics, English, Korean_History, Inquiry, Second_Foreign_Language):

    input_data = np.array([[Korean, Mathematics, English, Korean_History, Inquiry, Second_Foreign_Language]])
    input_scaled = scaler.transform(input_data)

    predicted_class = model.predict(input_scaled)[0]
    predicted_proba = model.predict_proba(input_scaled)

    loyalty_labels = {0: "합격", 1: "추합", 2: "불합격"}

    print(f"\n🔹 예측된 대학 합격 확인: {loyalty_labels[predicted_class]}")
    print(f"🔹 합격/추합/불합격 확률: 합격={predicted_proba[0][0]:.2f}, 추합={predicted_proba[0][1]:.2f}, 불합격={predicted_proba[0][2]:.2f}")

# 예측 예제 실행
predict_loyalty(100, 80, 70, 90, 70, 90)

 

* 위 코드를 Flask를 통해 웹서비스로 구현하기

대입 수험생 대학합격 예측.Zip
0.00MB