Nasdaq Data Link를 활용한 데이터 수집

개요

  • Nasdaq Data Link은 금융 및 경제 데이터를 제공하는 플랫폼으로, 특히 투자자, 연구자, 그리고 데이터 애널리스트들에게 유용
  • 기존 quandl에서 2018년에 Nasdaq에 인수되었으며, 주식, 채권, 선물, 외환, 경제 지표 등 다양한 데이터를 제공
  • 그러나 Free 데이터에서 유의미한 데이터를 찾기에는 부족함을 느낌

Nasdaq Data Link의 주요 기능

  • 데이터 제공
    • 금융 시장 데이터 (주식, 상품, 금리 등)
    • 경제 데이터 (GDP, 실업률, 소비자 물가 지수 등)
    • 대체 데이터 (소셜미디어 트렌드, 위성 이미지 분석, 물류 데이터 등)
  • API 기반 접근
    • Python, R, Excel 등 다양한 도구에서 API를 사용해 데이터를 불러올 수 있음.
  • 데이터 품질
    • 검증된 데이터를 제공하며, 여러 프리미엄 데이터와 함께 무료 데이터도 사용할 수 있음.
  • 데이터 다운로드
    • CSV, Excel, JSON, XML 포맷으로 다운로드 가능하며, 시계열 분석에 최적화되어 있음.

회원가입

image.png

Kaggle ML Submission 클래스 만들기

개요

  • 취업 준비생 들에게 필요한 캐글 연습 코드 클래스로 구현함
    • 학습에서 제출까지 자동화하는 것에 목적을 둠
  • 클래스에 대한 기본적인 이해가 있다는 전제하에 작성
  • 전체 코드는 다음과 같다.
import numpy as np
import pandas as pd
import shap
import matplotlib.pyplot as plt

# 데이터 처리 및 모델링 라이브러리
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler, LabelEncoder, OrdinalEncoder
from sklearn.impute import SimpleImputer
from sklearn.metrics import (
    mean_squared_error, mean_absolute_error, 
    r2_score, mean_absolute_percentage_error
)
from sklearn.ensemble import RandomForestRegressor

# 부스팅 모델
import xgboost as xgb
import lightgbm as lgb
from catboost import CatBoostRegressor

# Matplotlib 설정 
plt.rcParams.update({'font.size': 9})  # 원하는 크기로 설정 (예: 10)

class DataPreprocessor:
    """
    데이터 전처리 클래스
    """
    def __init__(self, train_path, test_path):
        self.train_data = pd.read_csv(train_path)
        self.test_data = pd.read_csv(test_path)
    
    def preprocess(self, target_column):
        """
        데이터 전처리 메서드
        - 결측치 처리 전략 개선
        - 문자열 컬럼 Ordinal Encoding
        """
        # 타겟 분리
        X = self.train_data.drop(columns=[target_column])
        y = self.train_data[target_column]
        X_test = self.test_data.copy()
        
        # 결측치 처리 전략 개선
        def handle_missing_values(df):
            # 숫자형 변수 - 중앙값 대체
            numeric_columns = df.select_dtypes(include=['int64', 'float64']).columns
            df[numeric_columns] = df[numeric_columns].fillna(df[numeric_columns].median())
            
            # 범주형 변수 - 최빈값 대체
            categorical_columns = df.select_dtypes(include=['object']).columns
            df[categorical_columns] = df[categorical_columns].fillna(df[categorical_columns].mode().iloc[0])
            
            return df
        
        # 결측치 처리
        X = handle_missing_values(X)
        X_test = handle_missing_values(X_test)
        
        # 문자열 컬럼 식별
        categorical_columns = X.select_dtypes(include=['object']).columns
        
        # Ordinal Encoder 초기화
        ordinal_encoder = OrdinalEncoder(
            handle_unknown='use_encoded_value', 
            unknown_value=-1
        )
        
        # 훈련 및 테스트 데이터에 인코딩 적용
        if len(categorical_columns) > 0:
            # 전체 데이터 결합하여 인코딩
            combined_categorical = pd.concat([X[categorical_columns], X_test[categorical_columns]])
            
            # 인코더 훈련
            ordinal_encoder.fit(combined_categorical)
            
            # 훈련 데이터 인코딩
            X[categorical_columns] = ordinal_encoder.transform(X[categorical_columns])
            
            # 테스트 데이터 인코딩
            X_test[categorical_columns] = ordinal_encoder.transform(X_test[categorical_columns])
        
        return X, y, X_test, ordinal_encoder

class EvaluationMetrics:
    """
    모델 평가 지표 클래스
    """
    @staticmethod
    def rmse(y_true, y_pred):
        return np.sqrt(mean_squared_error(y_true, y_pred))
    
    @staticmethod
    def mae(y_true, y_pred):
        return mean_absolute_error(y_true, y_pred)
    
    @staticmethod
    def r2(y_true, y_pred):
        return r2_score(y_true, y_pred)
    
    @staticmethod
    def mape(y_true, y_pred):
        return mean_absolute_percentage_error(y_true, y_pred)

class SHAPExplainer:
    """
    SHAP 설명 및 시각화 클래스
    """
    def __init__(self, model, X):
        self.model = model
        self.X = X
    
    def tree_explainer(self):
        """트리 기반 모델용 SHAP 설명"""
        explainer = shap.TreeExplainer(self.model)
        shap_values = explainer.shap_values(self.X)
        return explainer, shap_values
    
    def plot_feature_importance(self, shap_values, feature_names):
        """특성 중요도 플롯"""
        plt.figure(figsize=(10, 6))
        shap.summary_plot(shap_values, self.X, feature_names=feature_names)
        plt.title("SHAP Feature Importance")
        plt.tight_layout()
        plt.show()

class BaseMLDL:
    """
    기본 ML/DL 모델 베이스 클래스
    """
    def __init__(self, X, y, test_size=0.2, random_state=42):
        # 데이터 분할
        self.X_train, self.X_val, self.y_train, self.y_val = train_test_split(
            X, y, test_size=test_size, random_state=random_state
        )
        
        # 스케일링
        self.scaler = StandardScaler()
        self.X_train_scaled = self.scaler.fit_transform(self.X_train)
        self.X_val_scaled = self.scaler.transform(self.X_val)
        
        self.model = None
        self.predictions = None
    
    def train(self):
        raise NotImplementedError("하위 클래스에서 구현해야 합니다.")
    
    def predict(self):
        raise NotImplementedError("하위 클래스에서 구현해야 합니다.")
    
    def evaluate(self):
        """모델 평가"""
        self.predictions = self.predict()
        return {
            'RMSE': EvaluationMetrics.rmse(self.y_val, self.predictions),
            'MAE': EvaluationMetrics.mae(self.y_val, self.predictions),
            'R2': EvaluationMetrics.r2(self.y_val, self.predictions),
            'MAPE': EvaluationMetrics.mape(self.y_val, self.predictions)
        }

# 각 모델 클래스 구현 (RandomForest, XGBoost, LightGBM, CatBoost 등)
class RandomForestModel(BaseMLDL):
    def train(self, n_estimators=100, **kwargs):
        self.model = RandomForestRegressor(n_estimators=n_estimators, **kwargs)
        self.model.fit(self.X_train_scaled, self.y_train)
    
    def predict(self):
        return self.model.predict(self.X_val_scaled)

class XGBoostModel(BaseMLDL):
    def train(self, n_estimators=100, **kwargs):
        self.model = xgb.XGBRegressor(n_estimators=n_estimators, **kwargs)
        self.model.fit(self.X_train_scaled, self.y_train)
    
    def predict(self):
        return self.model.predict(self.X_val_scaled)

class LightGBMModel(BaseMLDL):
    def train(self, n_estimators=100, **kwargs):
        self.model = lgb.LGBMRegressor(n_estimators=n_estimators, **kwargs)
        self.model.fit(self.X_train_scaled, self.y_train)
    
    def predict(self):
        return self.model.predict(self.X_val_scaled)

class CatBoostModel(BaseMLDL):
    def train(self, iterations=100, **kwargs):
        self.model = CatBoostRegressor(iterations=iterations, **kwargs)
        self.model.fit(self.X_train_scaled, self.y_train)
    
    def predict(self):
        return self.model.predict(self.X_val_scaled)

class KaggleSubmission:
    """
    Kaggle 제출 자동화 클래스
    """
    def __init__(self, preprocessor):
        self.preprocessor = preprocessor
    
    def submit(self, model, X_test, submission_path, id_column, target_column):
        """제출 파일 생성"""
        # 테스트 데이터 스케일링
        X_test_scaled = model.scaler.transform(X_test)
        
        # 예측
        predictions = model.model.predict(X_test_scaled)
        
        # 제출 파일 생성
        submission = pd.DataFrame({
            'id' : X_test['id'],
            'Premium Amount' : predictions
        })
        submission.to_csv(submission_path, index=False)
        print(f"제출 파일 생성: {submission_path}")

def compare_shap_feature_importance(models, X, save_path='shap_comparison.png'):
    """
    여러 모델의 SHAP 디테일 특성 중요도를 한 그래프에 시각화 및 저장
    
    Args:
        models (list): 비교할 모델 리스트
        X (pd.DataFrame): 특성 데이터
        save_path (str): 저장할 파일 경로
    """
    # 모델별 SHAP 값 저장할 딕셔너리
    model_shap_values = {}
    
    # 각 모델의 SHAP 값 계산
    for model_info in models:
        model = model_info['model']
        model_name = model_info['name']
        
        try:
            # SHAP 설명자 생성
            shap_explainer = SHAPExplainer(model.model, X)
            _, shap_values = shap_explainer.tree_explainer()
            
            # SHAP 값 저장
            model_shap_values[model_name] = shap_values
        
        except Exception as e:
            print(f"{model_name} SHAP 분석 중 오류: {e}")
    
    # 모델 수에 따른 동적 서브플롯 설정
    n_models = len(model_shap_values)
    
    # 행과 열 계산 (정사각형에 가깝게)
    import math
    n_cols = math.ceil(math.sqrt(n_models))
    n_rows = math.ceil(n_models / n_cols)
    
    # 큰 피규어 생성 (디테일 플롯만)
    plt.figure(figsize=(20*n_cols, 5*n_rows))
    
    # 각 모델의 SHAP 특성 중요도 시각화
    for idx, (model_name, shap_values) in enumerate(model_shap_values.items(), 1):
        plt.subplot(n_rows, n_cols, idx)
        
        # SHAP 디테일 플롯
        shap.summary_plot(
            shap_values, 
            X, 
            show=False,
        )
        plt.gca().set_xlabel('') 
        
        # 제목 추가
        plt.title(f"SHAP Detail - {model_name}", fontsize=11)
    
    plt.tight_layout()
    
    # 피규어 저장 (디테일 플롯만)
    plt.savefig(save_path, dpi=1000, bbox_inches='tight')
    print(f"SHAP 디테일 비교 그래프가 {save_path}에 저장되었습니다.")
    
    # 선택적으로 화면에 표시
    plt.show()

def main():
    # 데이터 전처리
    preprocessor = DataPreprocessor('playground-series-s4e12/train.csv', 'playground-series-s4e12/test.csv')
    X, y, X_test, ordinal_encoder = preprocessor.preprocess('Premium Amount')
    
    # 모델 학습 및 평가
    models = [
        RandomForestModel(X, y),
        XGBoostModel(X, y),
        LightGBMModel(X, y),
        CatBoostModel(X, y),
    ]
    
    # Kaggle 제출 클래스 초기화
    submission_handler = KaggleSubmission(preprocessor)
    
    # 모델별 성능 저장할 딕셔너리
    model_performances = {}
    model_shap_info = []
    
    # 모델별 성능 평가 및 SHAP 분석
    for model in models:
        try:
            # 모델 학습
            model.train()
            
            # 성능 평가
            metrics = model.evaluate()
            print(f"{model.__class__.__name__} 성능:")
            for metric, value in metrics.items():
                print(f"{metric}: {value}")
            
            # 모델 성능 저장 (RMSE를 기준으로)
            model_performances[model.__class__.__name__] = {
                'model': model,
                'rmse': metrics['RMSE']
            }
            
            # SHAP 정보 저장
            model_shap_info.append({
                'name': model.__class__.__name__,
                'model': model
            })
        
        except Exception as model_error:
            print(f"{model.__class__.__name__} 처리 중 오류: {model_error}")
            continue
    
    # 모델 간 SHAP 특성 중요도 비교
    compare_shap_feature_importance(model_shap_info, X)
    
    # 최적 모델 선택 (RMSE 기준 최소값)
    if model_performances:
        best_model_name = min(model_performances, key=lambda k: model_performances[k]['rmse'])
        best_model = model_performances[best_model_name]['model']
        
        print(f"\n최적 모델: {best_model_name}")
        print(f"최적 모델 RMSE: {model_performances[best_model_name]['rmse']}")
        
        # 최적 모델로 Kaggle 제출
        submission_handler.submit(
            best_model, 
            X_test, 
            'best_model_submission.csv', 
            'id', 
            'Premium Amount'
        )
        
        # 모든 모델의 성능 비교 CSV로 저장
        performance_df = pd.DataFrame.from_dict(
            {name: {'RMSE': data['rmse']} for name, data in model_performances.items()}, 
            orient='index'
        )
        performance_df.to_csv('model_performance_comparison.csv')
        print("\n모델 성능 비교 결과가 'model_performance_comparison.csv'에 저장되었습니다.")
    else:
        print("모델 학습에 실패했습니다.")

if __name__ == "__main__":
    main()
  • 코드의 주요 기능은 다음과 같음
    • 데이터 전처리
    • 다양항 모델 학습 및 평가 (Random Forest, XGBoost, LightGBM, CatBoost)
    • SHAP(Shapley Additive Explanations)을 활용한 특성 중요도 분석
    • 모델 성능 비교 및 최적 모델 선택
    • 최적 모델 기반 Kaggle 제출 파일 생성

주요 클래스 설명

DataPreprocessor

  • 데이터 전처리를 담당하는 클래스입니다.
  • 주요 기능:
    • 결측치 처리: 숫자형 데이터는 중앙값, 범주형 데이터는 최빈값으로 대체.
    • Ordinal Encoding: 문자열 데이터를 수치형으로 변환.
    • 훈련 데이터(train.csv)와 테스트 데이터(test.csv)를 받아 전처리 후 반환.
class DataPreprocessor:
    """
    데이터 전처리 클래스
    """
    def __init__(self, train_path, test_path):
        self.train_data = pd.read_csv(train_path)
        self.test_data = pd.read_csv(test_path)
    
    def preprocess(self, target_column):
        """
        데이터 전처리 메서드
        - 결측치 처리 전략 개선
        - 문자열 컬럼 Ordinal Encoding
        """
        # 타겟 분리
        X = self.train_data.drop(columns=[target_column])
        y = self.train_data[target_column]
        X_test = self.test_data.copy()
        
        # 결측치 처리 전략 개선
        def handle_missing_values(df):
            # 숫자형 변수 - 중앙값 대체
            numeric_columns = df.select_dtypes(include=['int64', 'float64']).columns
            df[numeric_columns] = df[numeric_columns].fillna(df[numeric_columns].median())
            
            # 범주형 변수 - 최빈값 대체
            categorical_columns = df.select_dtypes(include=['object']).columns
            df[categorical_columns] = df[categorical_columns].fillna(df[categorical_columns].mode().iloc[0])
            
            return df
        
        # 결측치 처리
        X = handle_missing_values(X)
        X_test = handle_missing_values(X_test)
        
        # 문자열 컬럼 식별
        categorical_columns = X.select_dtypes(include=['object']).columns
        
        # Ordinal Encoder 초기화
        ordinal_encoder = OrdinalEncoder(
            handle_unknown='use_encoded_value', 
            unknown_value=-1
        )
        
        # 훈련 및 테스트 데이터에 인코딩 적용
        if len(categorical_columns) > 0:
            # 전체 데이터 결합하여 인코딩
            combined_categorical = pd.concat([X[categorical_columns], X_test[categorical_columns]])
            
            # 인코더 훈련
            ordinal_encoder.fit(combined_categorical)
            
            # 훈련 데이터 인코딩
            X[categorical_columns] = ordinal_encoder.transform(X[categorical_columns])
            
            # 테스트 데이터 인코딩
            X_test[categorical_columns] = ordinal_encoder.transform(X_test[categorical_columns])
        
        return X, y, X_test, ordinal_encoder

EvaluationMetrics

  • 모델 성능을 평가하기 위한 지표를 제공합니다.
  • 값이 작을수록 모델의 예측이 실제 값과 더 가까움을 의미합니다.
  • 제공되는 지표:
    • RMSE (Root Mean Squared Error)
    • MAE (Mean Absolute Error) : 예측값과 실제값 간 절대 오차의 평균
    • R² Score (결정 계수) : 모델의 예측이 실제 데이터를 얼마나 잘 설명하는지
    • MAPE (Mean Absolute Percentage Error) : 예측값과 실제값 간의 상대적인 오차를 백분율
class EvaluationMetrics:
    """
    모델 평가 지표 클래스
    """
    @staticmethod
    def rmse(y_true, y_pred):
        return np.sqrt(mean_squared_error(y_true, y_pred))
    
    @staticmethod
    def mae(y_true, y_pred):
        return mean_absolute_error(y_true, y_pred)
    
    @staticmethod
    def r2(y_true, y_pred):
        return r2_score(y_true, y_pred)
    
    @staticmethod
    def mape(y_true, y_pred):
        return mean_absolute_percentage_error(y_true, y_pred)
  • @staticmethod 적용 이유
    • EvaluationMetrics 클래스의 메서드는 입력값 y_true, y_pred만 필요하며, 클래스의 상태(속성)와 무관.
    • 따라서 이 메서드를 정적 메서드로 정의하여 클래스의 다른 부분과 독립적으로 동작할 수 있도록 설계
    • 직접 호출 가능 클래스명.메서드명() 형태로 호출

SHAPExplainer

  • SHAP 분석 및 시각화를 담당
  • 주요 기능
    • tree_explainer(): 트리 기반 모델(XGBoost, LightGBM, Random Forest)에서 SHAP 값을 계산.
class SHAPExplainer:
    """
    SHAP 설명 및 시각화 클래스
    """
    def __init__(self, model, X):
        self.model = model
        self.X = X
    
    def tree_explainer(self):
        """트리 기반 모델용 SHAP 설명"""
        explainer = shap.TreeExplainer(self.model)
        shap_values = explainer.shap_values(self.X)
        return explainer, shap_values

BaseMLDL

  • 머신러닝 및 딥러닝 모델의 공통 동작을 정의하는 베이스 클래스
  • 주요 메서드:
    • train(): 모델 학습. (하위 클래스에서 구현)
    • predict(): 모델 예측. (하위 클래스에서 구현)
    • evaluate(): 평가 지표를 계산.
class BaseMLDL:
    """
    기본 ML/DL 모델 베이스 클래스
    """
    def __init__(self, X, y, test_size=0.2, random_state=42):
        # 데이터 분할
        self.X_train, self.X_val, self.y_train, self.y_val = train_test_split(
            X, y, test_size=test_size, random_state=random_state
        )
        
        # 스케일링
        self.scaler = StandardScaler()
        self.X_train_scaled = self.scaler.fit_transform(self.X_train)
        self.X_val_scaled = self.scaler.transform(self.X_val)
        
        self.model = None
        self.predictions = None
    
    def train(self):
        raise NotImplementedError("하위 클래스에서 구현해야 합니다.")
    
    def predict(self):
        raise NotImplementedError("하위 클래스에서 구현해야 합니다.")
    
    def evaluate(self):
        """모델 평가"""
        self.predictions = self.predict()
        return {
            'RMSE': EvaluationMetrics.rmse(self.y_val, self.predictions),
            'MAE': EvaluationMetrics.mae(self.y_val, self.predictions),
            'R2': EvaluationMetrics.r2(self.y_val, self.predictions),
            'MAPE': EvaluationMetrics.mape(self.y_val, self.predictions)
        }

주요 모델 클래스 정의

  • BaseMLDL을 상속받아 각 알고리즘에 맞게 동작을 구현한 클래스.
    • RandomForestModel: Random Forest Regressor 모델.
    • XGBoostModel: XGBoost Regressor 모델.
    • LightGBMModel: LightGBM Regressor 모델.
    • CatBoostModel: CatBoost Regressor 모델.
  • 각 클래스의 train을 재정의할 수 있습니다. 하이퍼파라미터 튜닝을 시행할 수 있다.
# 각 모델 클래스 구현 (RandomForest, XGBoost, LightGBM, CatBoost 등)
class RandomForestModel(BaseMLDL):
    def train(self, n_estimators=100, **kwargs):
        self.model = RandomForestRegressor(n_estimators=n_estimators, **kwargs)
        self.model.fit(self.X_train_scaled, self.y_train)
    
    def predict(self):
        return self.model.predict(self.X_val_scaled)

class XGBoostModel(BaseMLDL):
    def train(self, n_estimators=100, **kwargs):
        self.model = xgb.XGBRegressor(n_estimators=n_estimators, **kwargs)
        self.model.fit(self.X_train_scaled, self.y_train)
    
    def predict(self):
        return self.model.predict(self.X_val_scaled)

class LightGBMModel(BaseMLDL):
    def train(self, n_estimators=100, **kwargs):
        self.model = lgb.LGBMRegressor(n_estimators=n_estimators, **kwargs)
        self.model.fit(self.X_train_scaled, self.y_train)
    
    def predict(self):
        return self.model.predict(self.X_val_scaled)

class CatBoostModel(BaseMLDL):
    def train(self, iterations=100, **kwargs):
        self.model = CatBoostRegressor(iterations=iterations, **kwargs)
        self.model.fit(self.X_train_scaled, self.y_train)
    
    def predict(self):
        return self.model.predict(self.X_val_scaled)

KaggleSubmission

  • 최적 모델을 사용해 Kaggle 제출 파일을 생성

Windows Microsoft C++ Build Tools 설정

개요

  • Python 라이브러리 설치 시, 가끔 C++ 라이브러리 설치가 필요할 수 있다.

image.png

  • 위와 같이 에러가 발생할 때 C++ 라이브러리를 설치를 한다.

설치방법

image.png

  • Build Tools 다운로드 버튼 클릭 후 관리자 권한으로 실행

image.png

  • 아래와 같이 C++를 사용한 데스크톱 개발 선택 후, 설치

image.png

  • 설치하는 데 다소 시간이 필요함

image.png

  • 설치가 완료되면 재부팅을 한다.

image.png

파이썬 라이브러리 다시 설치

  • 중간에 보면 cp312가 보이는데, C++을 활용해서 설치가 되었다는 것을 의미한다.

image.png

Cursor AI 소개 및 설치

웹사이트

image.png

회원가입

image.png

Settings

image.png

가격정책(Pricing)

image.png

프로그램 설치 (Windows)

  • 기존에 Visual Studio Code가 설치가 되어 있어야 한다.

image.png

  • 실행 또는 (관리자 권한)으로 실행

image.png

  • Continue 버튼 선택

image.png

  • Use Extensions 선택

image.png

  • Data Preferences는 독자 취향에 맞게 선택한다. 필자는 Help Improve Cursor를 선택한다.

image.png

Login

image.png

  • 개인 계정 확인 후, Yes, Log in 버튼 클릭

커서화면.png

image.png

Visual Studio Code 확인

  • 이제 Visual Studio Code에 Cursor AI가 업데이트가 되었는지 확인해본다.
  • 그러기 위해서는, 먼저 Github에서 새로운 Repository를 하나 생성한다. 필자는 cursor_ai_project로 명명했다.
  • 해당 Repo를 생성한 후, git clone으로 다운로드 받는다.
  • Visual Studio Code에서 해당 Repository를 열면, 다음과 같은 화면이 나올 것이다.

image.png

Crontab으로 Git Commit Automation with sh 파일 on M1

개요

  • Mac Crontab으로 SH 파일을 실행하도록 한다.

SH 파일 작성

  • 주요 내용은 아래와 같이 작성한다. (파일명 : deploy.sh)
#!/bin/bash
echo "Git Push Starting..."

cd /Users/evan/Desktop/alphaco_test

# Check out repo
git add -A
git commit -m "Automated commit on $(date '+%Y-%m-%d %H:%M:%S')"
git push                                                             

수동 업로드

  • 수동으로 업로드 하기 위해 파일 권한을 열어준다.
    • 777은 소유자, 그룹, 다른 모든 사용자에게 읽기, 쓰기, 실행 권한 부여하는 명령어를 말한다.
chmod 777 deploy.sh

실행

  • 해당 파일이 있는 경로에서 deploy.sh 파일을 실행한다.
~$ ./deploy.sh 

Crontab 등록

Screenshot 2024-09-28 at 4.05.42 PM.png

Deep Learning Loss Function

딥러닝 손실 함수 (Loss Function) 개요

딥러닝에서 손실 함수는 모델의 예측과 실제 값 사이의 차이를 측정하는 중요한 요소. 다양한 종류의 손실 함수가 있으며, 문제의 특성에 따라 적절한 함수를 선택해야 함.

주요 손실 함수 설명

평균 제곱 오차 (Mean Squared Error, MSE)

  • 유형 : 회귀

  • 공식 :

    $$ \text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 $$

  • 설명:

    • $y_i$ : 실제 값
    • $\hat{y}_i$ : 예측 값
    • $n$ : 데이터 포인트의 수
  • 사용 용도

Docker-Compose와 Dockerfile을 활용한 Flask-MySQL 연동 예제

개요

  • Docker-Compose와 Dockerfile의 주요 기능을 이해한다.
  • 각 파일의 위치와 주요 기능을 이해한다.

전체 프로젝트 파일 디렉터리

  • 본 프로젝트의 전체 코드는 다음과 같다.
  • 실제 코드 작성을 해야하는 곳은 다음과 같다.
    • app.py
    • requirements.txt
    • init.sql
    • docker-compose.yml
    • Dockerfile
docker_kubernetes_flask/
├── app/
│   ├── __init__.py
│   ├── app.py
│   └── requirements.txt
├── db/
│   ├── init.sql
│   └── data/ (This will be created by Docker)
├── docker-compose.yml
└── Dockerfile

사전준비

  • 사전에 Docker는 Desktop 설치가 되어 있다고 가정한다.
  • 코드 편집을 위해서는 Visual Studio Code를 활용한다.

Docker가 익숙하지 않은 사람들을 위한 1줄 요약

  • MySQL 설치하고, Python 설치하고, 두개 또 연동해야 하고, CLI 명령어 또 각각 입력하는거 다 자동화 해줄게요!!
  • 즉, 자동화에 익숙해지자!

docker-compose와 Dockerfile 간단 비교

  • docker-compose.yml : python 컨테이너와 mysql 컨테이너를 각각 한꺼번에 구성하도록 스크립트를 작성함
  • Dockerfile : 여기에서는 python 개발환경을 구성함
  • docker-compose.yml에서 Dockerfile을 호출하여 개발환경을 만들도록 지시할 수 있음

전체 코드 흐름 1줄 요약

  • From MySQL to Python Flask

init.sql과 app.py 간단 설명

  • 각 두개의 파일은 사전에 미리 작성을 해둔다.

MySQL : init.sql

  • SQL 코드는 데이터베이스와 테이블을 생성하고, 테이블에 데이터를 삽입하는 작업을 수행.
    • test_db 데이터베이스 생성
    • users 테이블 생성
    • 간단하게 이름 생성
CREATE DATABASE IF NOT EXISTS test_db;

USE test_db;

CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL
);

INSERT INTO users (name) VALUES ('Evan');
INSERT INTO users (name) VALUES ('Sara');
INSERT INTO users (name) VALUES ('Lotto');

Python : app.py

  • Python 코드는 Flask 웹 애플리케이션을 설정하여 MySQL 데이터베이스에 연결하고, 사용자 데이터를 JSON 형식으로 반환하는 작업을 수행.
from flask import Flask, jsonify
import mysql.connector
import os

app = Flask(__name__)

def get_db_connection():
    connection = mysql.connector.connect(
        host='mysql',
        user='root',
        password='example',
        database='test_db'
    )
    return connection

@app.route('/')
def index():
    connection = get_db_connection()
    cursor = connection.cursor()
    cursor.execute('SELECT * FROM users')
    users = cursor.fetchall()
    cursor.close()
    connection.close()
    users_list = [{"id": user[0], "name": user[1]} for user in users]
    return jsonify(users_list)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
  • 좀더 구체적으로 살펴본다.

step 01 - 라이브러리 불러오기

  • Flask: Flask 웹 애플리케이션 프레임워크를 불러오기
  • jsonify: 데이터를 JSON 형식으로 변환하여 HTTP 응답으로 반환하는 데 사용
  • mysql.connector: MySQL 데이터베이스에 연결하기 위해 사용
from flask import Flask, jsonify
import mysql.connector
import os

step 02 - Flask Application Setup

  • Flask 애플리케이션 인스턴스를 생성. __name__은 현재 모듈의 이름을 전달하여 Flask 애플리케이션을 생성하는 데 사용.
app = Flask(__name__)

step 03 - Database Connection Function

  • get_db_connection 함수는 MySQL 데이터베이스에 연결하고, 연결 객체를 반환.
  • host, user, password, database 매개변수는 데이터베이스에 연결하기 위한 정보
def get_db_connection():
    connection = mysql.connector.connect(
        host='mysql',
        user='root',
        password='example',
        database='test_db'
    )
    return connection

step 04 - Index Route

  • @app.route('/'): 해당 Decorator는 URL (’/’)에 대한 요청을 처리하는 index 함수를 정의.
  • index 함수의 내용은 다음과 같이 구성됨
    • get_db_connection을 호출하여 데이터베이스에 연결.
    • 연결 객체에서 커서를 생성하고, SELECT * FROM users 쿼리를 실행하여 users 테이블의 모든 데이터를 가져오기
    • 데이터를 가져온 후 커서와 연결을 닫기
    • users 데이터를 List Comprehension을 사용하여 딕셔너리 형태로 변환합니다. 각 사용자에 대해 idname 키를 가지는 딕셔너리를 생성.
      • 이 부분은 별도의 HTML 소스코드를 넣지 않기 위해서 진행한 것이니, 해당 자세한 내용을 보기를 원한다면 Flask 웹개발로 더 공부할 것 권장
    • 변환된 리스트를 jsonify를 사용하여 JSON 형식으로 반환.
@app.route('/')
def index():
    connection = get_db_connection()
    cursor = connection.cursor()
    cursor.execute('SELECT * FROM users')
    users = cursor.fetchall()
    cursor.close()
    connection.close()
    users_list = [{"id": user[0], "name": user[1]} for user in users]
    return jsonify(users_list)

step 05 - Running the Application

  • 모듈이 직접 실행될 때만 Flask 애플리케이션을 실행
    • app.run 메소드를 호출하여 애플리케이션을 시작.
    • host='0.0.0.0': 애플리케이션이 모든 네트워크 인터페이스에서 접근 가능하도록 설정.
    • port=5000: 애플리케이션이 5000번 포트에서 실행되도록 설정.
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Python : requirements.txt

  • 주요 라이브러리 설치 위해 필요한 라이브러리 2개만 설치
  • 추후에 독자가 라이브러리 추가 가능
Flask
mysql-connector-python

Docker: Dockerfile

  • Dockerfile은 Python 애플리케이션을 컨테이너화하기 위한 스크립트
  • 다른 파일과 달리 확장자명이 없다는 것에 주의
  • 다양한 옵션에 대해 설명하도록 한다.
FROM python:3.10-slim

WORKDIR /app

COPY app/requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY app/ .

EXPOSE 5000

CMD ["python", "app.py"]

step 01 - FROM

FROM python:3.10-slim
  • Base Image를 선택한다. 해당 이미지를 선택하려면 Docker Hub 검색창에서 확인 (Login 필수)
  • 각 Base Image를 선택하면 관련 Tag가 존재하며 여기에서 Tags 확인해서 입력하도록 한다.
  • Docker Official Image 를 선택한다.

Screenshot 2024-07-01 at 8.16.09 AM.png

Streamlit on Google Colab

개요

  • 개발환경설정이 어려운 환경에서 Google Colab 상에서 Streamlit 설치 및 실행을 익히고자 한다.
  • 주로 강의 목적으로 사용하기를 바란다.

Streamlit 라이브러리 설치

  • 아래 코드를 활용하여 streamlit 라이브러리 설치
!pip install -q streamlit

Untitled

Streamlit 코드 작성 샘플

%%writefile app.py

import streamlit as st
import plotly.graph_objs as go
from plotly.subplots import make_subplots
import seaborn as sns

@st.cache_data
def load_data():
    df = sns.load_dataset('tips')
    return df

def main():
    st.title("Streamlit with Plotly")   
    tips = load_data()

    # 데이터가공
    m_tips = tips.loc[tips['sex'] == 'Male', :]
    f_tips = tips.loc[tips['sex'] == 'Female', :]

    # 시각화 차트
    fig = make_subplots(rows = 1,
                        cols = 2,
                        subplot_titles=('Male', 'Female'),
                        shared_yaxes=True,
                        shared_xaxes=True,
                        x_title='Total Bill($)'
                        )
    fig.add_trace(go.Scatter(x = m_tips['total_bill'], y = m_tips['tip'], mode='markers'), row=1, col=1)
    fig.add_trace(go.Scatter(x = f_tips['total_bill'], y = f_tips['tip'], mode='markers'), row=1, col=2)
    fig.update_yaxes(title_text="Tip($)", row=1, col=1)
    fig.update_xaxes(range=[0, 60])
    fig.update_layout(showlegend=False)
    
    # 중요포인트
    # fig.show()
    st.plotly_chart(fig, use_container_width=True)

if __name__ == "__main__":
    main()

Untitled

Oracle VM Box 양방향 복사 붙이기

개요

  • VirtualBox를 통해 복사 붙이기 등을 하려고 함

사전작업 1 - 우분투 패키지 업그레이드

  • 터미널을 열고 아래 코드를 순차적으로 입력
sudo apt update

Untitled

  • 업그레이 명령어 입력
sudo apt upgrade

Untitled

사전작업 2 - 게스트 확장 설치

  • 우선 주요 라이브러리 설치 진행
sudo apt install gcc make perl

Untitled

  • 게스트 확장 CD 이미지 삽입 메뉴 클릭

Untitled

  • 해당 디렉터리를 열고, 마우스 우클릭 > 터미널에서 열기 실행

Untitled

  • ls 명령어 실행
    • VBoxLinuxAdditions.run 파일이 있는지 확인
ls

Untitled

Ubuntu install on M1

개요

  • M1에서 Ubuntu를 설치하는 방법에 대해 기술한다.

Ubuntu 24.04 LTS 다운로드

  • Ubuntu Download를 진행한다.
    • 다운로드 받을 시, arm으로 다운로드 받아야 한다.
    • 다른 아키텍처로 다운로드 받을 시 리눅스가 활성화가 되지 않는다.
  • 사이트 : https://ubuntu.com/download/server/arm

Screenshot 2024-05-21 at 9.43.12 AM.png

Screenshot 2024-05-21 at 10.46.43 AM.png

UTM 다운로드

Screenshot 2024-05-21 at 9.29.15 AM.png

UTM 가상머신 생성

  • UTM을 실행하면 아래와 같은 화면이 나온다.
  • Create a New Virtual Machine을 선택한다.

Screenshot 2024-05-21 at 9.30.52 AM.png