Peer Session Badge Retrospectives Badge

1. assingment#3 풀이

저작권 문제를 피할 수 있도록 제가 수정한 코드입니다. 코드의 구조와 기능은 동일하게 유지하면서, 변수명과 함수명을 조금 변경하고, 설명을 추가해 주석을 수정했습니다.

먼저 “Cars - Purchase Decision” 데이터셋을 불러오고 전처리합니다.

  • User ID: 각 사용자를 고유하게 식별하는 ID
  • Gender: 성별 (Male 또는 Female)
  • Age: 사용자의 나이
  • EstimatedSalary: 예상 연봉
  • Purchased: 구매 여부 (1: 구매, 0: 미구매)

이 데이터를 모델에 적합하게 변환해야 합니다. 특히, Gender는 숫자로 변환하고, AgeEstimatedSalary는 정규화를 해야 합니다.

1단계: 데이터셋 이해 및 전처리

import pandas as pd
import torch
from torch.utils.data import Dataset
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

class CarPurchaseDataset(Dataset):
    def __init__(self, file_path="car_data.csv", mode="train"):
        # CSV 파일을 읽어들여 DataFrame으로 변환
        data = pd.read_csv(file_path)
        
        # 특성과 레이블을 분리하고 필요 없는 열 제거
        X = data.drop(columns=['User ID', 'Purchased'])
        y = data['Purchased']
        
        # 성별 데이터를 숫자로 변환 (Male=0, Female=1)
        X['Gender'] = X['Gender'].apply(lambda x: 0 if x == "Male" else 1)
        
        # 나이와 예상 연봉 데이터를 정규화
        scaler = StandardScaler()
        X[['Age', 'EstimatedSalary']] = scaler.fit_transform(X[['Age', 'EstimatedSalary']])
        
        # 학습과 평가용 데이터로 분할
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
        
        # 모드에 따라 데이터 선택
        if mode == "train":
            self.X = torch.tensor(X_train.values, dtype=torch.float32)
            self.y = torch.tensor(y_train.values, dtype=torch.float32).view(-1, 1)
        else:
            self.X = torch.tensor(X_test.values, dtype=torch.float32)
            self.y = torch.tensor(y_test.values, dtype=torch.float32).view(-1, 1)
        
    def __len__(self):
        # 데이터셋의 크기를 반환
        return len(self.X)
    
    def __getitem__(self, idx):
        # 주어진 인덱스의 데이터를 반환
        return self.X[idx], self.y[idx]

2단계: 로지스틱 회귀 모델 구현 및 학습

import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader

class LogisticRegressor(nn.Module):
    def __init__(self, input_dim):
        super(LogisticRegressor, self).__init__()
        # 선형 변환 레이어 정의
        self.linear = nn.Linear(input_dim, 1)
    
    def forward(self, x):
        # 모델의 출력값 계산 및 활성화 함수 적용
        return torch.sigmoid(self.linear(x))

# 데이터 로더 정의
train_dataset = CarPurchaseDataset(mode="train")
test_dataset = CarPurchaseDataset(mode="test")

train_loader = DataLoader(dataset=train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)

# 모델, 손실 함수, 옵티마이저 정의
input_dim = 3  # 성별, 나이, 예상 연봉 3개의 입력 특성
model = LogisticRegressor(input_dim)
loss_function = nn.BCELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 학습 함수 정의
def train_model(model, loss_function, optimizer, dataloader, device, epochs=100):
    model.to(device)
    for epoch in range(epochs):
        model.train()
        total_loss = 0.0
        for inputs, labels in dataloader:
            inputs, labels = inputs.to(device), labels.to(device)
            optimizer.zero_grad()
            predictions = model(inputs)
            loss = loss_function(predictions, labels)
            loss.backward()
            optimizer.step()
            total_loss += loss.item()
        print(f"Epoch {epoch+1}/{epochs}, Loss: {total_loss/len(dataloader):.4f}")

# GPU 또는 CPU 장치 선택
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 모델 학습
train_model(model, loss_function, optimizer, train_loader, device, epochs=100)

3단계: 통계적 방법을 통한 모델 학습 및 비교

import statsmodels.api as sm

# 데이터 준비 및 변환
data = pd.read_csv("car_data.csv")
X = data[['Gender', 'Age', 'EstimatedSalary']]
X['Gender'] = X['Gender'].apply(lambda x: 0 if x == "Male" else 1)
y = data['Purchased']

# 상수항 추가 (절편 항목 추가)
X = sm.add_constant(X)

# 통계적 로지스틱 회귀 모델 학습
logit_model = sm.Logit(y, X)
result = logit_model.fit()

# 모델 요약 출력
print(result.summary())

4단계: 모델 평가 및 비교

def evaluate_model(model, dataloader, device):
    model.eval()
    correct_predictions = 0
    total_samples = 0
    with torch.no_grad():
        for inputs, labels in dataloader:
            inputs, labels = inputs.to(device), labels.to(device)
            outputs = model(inputs)
            predicted_classes = (outputs >= 0.5).float()
            correct_predictions += (predicted_classes == labels).sum().item()
            total_samples += labels.size(0)
    print(f"Accuracy: {correct_predictions / total_samples:.4f}")

evaluate_model(model, test_loader, device)

# statsmodels를 사용한 모델 평가
y_pred_stats = result.predict(X)
y_pred_class_stats = (y_pred_stats >= 0.5).astype(int)
accuracy_stats = (y_pred_class_stats == y).mean()
print(f"Statsmodels accuracy: {accuracy_stats:.4f}")

회고

PyTorch와 statsmodels를 사용하여 각각 로지스틱 회귀 모델을 학습하고, 두 모델의 성능을 비교했다.