🧠 LLM 엔지니어링

자연어 처리 기반 가격 예측 모델 개발💸 (BOW vs Word2Vec vs RF) 01

2025. 5. 1. 11:33
목차
  1. 🔰 개요
  2. 📦 1. 라이브러리 임포트 및 환경 설정
  3. 🔐 2. 환경 변수 및 API 키 설정
  4. 📊 3. 데이터 로딩 및 탐색
  5. 🧪 4. 테스트 프레임워크 (Tester 클래스)
  6. 🎲 5. 베이스라인 모델 실험 (Baseline Models)
  7. 6. 🧩 특성 엔지니어링 (Feature Engineering)
반응형

🔰 개요

제품 설명 텍스트만을 가지고 가격을 예측하는 머신러닝 모델을 실험해 봅니다.

Baseline 모델부터 시작해서 BOW, Word2Vec, SVR, 랜덤 포레스트까지 점진적으로 성능을 개선해 나가는 과정을 코드와 함께 단계별로 정리합니다.


📦 1. 라이브러리 임포트 및 환경 설정

🛠️ 코드 임포트 및 환경 설정

# 📁 파일 및 환경 설정 관련 라이브러리
import os                   # 📂 파일 경로, 환경 변수 등 시스템 관련 작업을 할 때 사용
import math                 # ➗ 수학 계산 (루트, 로그 등)에 필요한 함수들 제공
import json                 # 📄 JSON 형식 파일 읽기/쓰기 작업에 사용

# 🎲 랜덤 처리 관련
import random               # 🎰 무작위 샘플 추출, 섞기 등 랜덤 연산에 사용

# 🔐 환경 변수 파일 (.env) 로드
from dotenv import load_dotenv  # 🔑 환경 변수(.env 파일) 불러올 때 사용 (API 키 등 안전하게 관리)

# 🤗 Hugging Face 관련
from huggingface_hub import login  # 🤗 HuggingFace에 로그인하여 모델 저장소 접근할 때 사용

# 📊 시각화 및 수치 계산
import matplotlib.pyplot as plt   # 📈 데이터 시각화(그래프, 차트 등)에 사용
import numpy as np                # 🔢 수치 계산, 배열 연산에 강력한 도구 (벡터/행렬 등)

# 💾 파일 저장 및 불러오기
import pickle                     # 🧺 파이썬 객체를 바이너리 형태로 저장/불러오기

# 🧮 데이터 분석 보조
from collections import Counter   # 🔢 리스트 등에서 항목 개수 세기 (ex. 단어 출현 빈도 계산)

📦 전통적인 머신러닝 모델을 위한 라이브러리 임포트

# 🧠 전통적인 머신러닝을 위한 추가 라이브러리

import pandas as pd   # 🐼 데이터프레임 구조로 데이터를 다루기 위한 라이브러리 (엑셀처럼 편하게!)
import numpy as np    # 🔢 수치 계산 및 배열 연산 (머신러닝에서 필수 도구)

# 📈 선형 회귀 모델
from sklearn.linear_model import LinearRegression  # 📊 가장 기본적인 회귀 모델 - 직선을 그려서 예측

# 🧮 모델 성능 평가 지표
from sklearn.metrics import mean_squared_error, r2_score  
# 🧾 mean_squared_error: 예측값과 실제값 차이의 제곱 평균 (낮을수록 좋음)
# 📊 r2_score: 결정 계수, 얼마나 잘 맞는지 0~1 사이 값으로 평가 (1에 가까울수록 좋음)

# ⚖️ 특성 스케일링 (정규화)
from sklearn.preprocessing import StandardScaler
# 🔄 서로 다른 단위의 숫자들을 같은 기준으로 맞춰주는 전처리 도구

🧠 NLP 관련 라이브러리 임포트

다음 셀에서는 자연어 처리(NLP) 관련 머신러닝에 필요한 라이브러리들을 임포트합니다.

만약 gensim 임포트 시
"Cannot import name 'triu' from 'scipy.linalg'"
와 같은 에러가 발생한다면, 아래 명령어를 별도 셀에 실행해 주세요:

!pip install "scipy<1.13"

📝 NLP 처리를 위한 핵심 도구 임포트

# 🧠 자연어 처리(NLP)를 위한 라이브러리 임포트

from sklearn.feature_extraction.text import CountVectorizer  
# 📊 텍스트 데이터를 숫자 벡터로 변환 (Bag of Words 방식)
# - 문장 내 단어들의 등장 횟수를 기반으로 벡터를 생성함

from gensim.models import Word2Vec  
# 🔤 Word2Vec 모델 생성용 클래스 (단어를 벡터로 임베딩)
# - 단어 간의 의미적 유사도를 수치로 표현할 수 있음

from gensim.utils import simple_preprocess  
# 🧹 텍스트 전처리 도구 (소문자화, 특수문자 제거, 토큰화 등)
# - Word2Vec 학습 전에 텍스트 정제할 때 자주 사용

🤖 고급 머신러닝 모델 임포트 (SVR, 랜덤 포레스트 등)

# 🚀 고급 머신러닝 모델을 위한 라이브러리

from sklearn.svm import LinearSVR  
# 📏 서포트 벡터 회귀 (SVR) 모델 - 선형 결정 경계를 기반으로 예측
# - 이상치에 강하고 고차원 데이터에 잘 작동하는 특성이 있음

from sklearn.ensemble import RandomForestRegressor  
# 🌳 랜덤 포레스트 회귀 모델 - 여러 개의 결정 트리를 조합해 예측
# - 과적합을 줄이고 예측 성능을 높이기 위한 앙상블 학습 방식

🌈 출력 색상 지정용 상수 정의 (터미널 컬러링)

터미널에 출력할 때 컬러로 구분해서 보기 좋게 만들기 위한 상수들이에요:

# 🎨 터미널 출력 시 색상을 입히기 위한 ANSI 이스케이프 코드 정의

GREEN = "\033[92m"   # ✅ 초록색 - 보통 성공 메시지나 긍정적인 정보 출력에 사용
YELLOW = "\033[93m"  # ⚠️ 노란색 - 경고나 주의 메시지에 사용
RED = "\033[91m"     # ❌ 빨간색 - 오류나 실패 메시지에 사용
RESET = "\033[0m"    # 🔄 색상 초기화 - 색상 적용 이후 다시 원래 색으로 되돌림

# 🗺️ 색상 키워드를 ANSI 코드로 매핑한 딕셔너리
COLOR_MAP = {
    "red": RED,
    "orange": YELLOW,  # 실제 색은 노란색이지만 의미상 '주의'로 orange로 표현
    "green": GREEN
}

이제 출력 결과를 색깔로 구분해서 가독성 높일 수 있어요.


🔐 2. 환경 변수 및 API 키 설정

# 🌍 환경 변수 설정 (API 키 관리)

load_dotenv(override=True)  
# 🔐 .env 파일을 로드하여 환경 변수로 등록
# - override=True: 이미 존재하는 값도 덮어씀

# 🤖 OpenAI API 키 설정
os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY', 'your-key-if-not-using-env')
# - .env 파일에 없을 경우, 'your-key-if-not-using-env'를 기본값으로 사용

# 🤖 Anthropic (Claude 등) API 키 설정
os.environ['ANTHROPIC_API_KEY'] = os.getenv('ANTHROPIC_API_KEY', 'your-key-if-not-using-env')

# 🤗 HuggingFace 토큰 설정
os.environ['HF_TOKEN'] = os.getenv('HF_TOKEN', 'your-key-if-not-using-env')

💡 .env 파일을 사용하는 이유는 API 키를 코드에 직접 쓰지 않고 보안성과 재사용성을 높이기 위함입니다.

🤗 HuggingFace 로그인

# 🤗 Hugging Face 로그인 (토큰 기반 인증)

hf_token = os.environ['HF_TOKEN']  
# 🔑 환경 변수에서 Hugging Face 액세스 토큰을 불러옴

login(hf_token, add_to_git_credential=True)  
# 🔐 Hugging Face에 로그인
# - add_to_git_credential=True: git 사용 시에도 인증 정보 자동 저장 (모델 다운로드 등 가능)

🔍 Hugging Face에 로그인하면 사설 모델이나 토큰이 필요한 리소스에 접근할 수 있습니다.


📊 3. 데이터 로딩 및 탐색

🧱 도메인 객체(Item) 임포트

로그인 이후에 사용하는 도메인 모델 관련 임포트입니다:

# 📦 커스텀 아이템 클래스 임포트

from items import Item  
# 🧱 'Item' 클래스는 개별 제품 또는 항목을 표현하는 사용자 정의 클래스
# - 제품 이름, 설명, 가격 등의 속성을 포함하고 있을 가능성이 높음
# - 이후 ML 모델이 예측할 대상이 될 수도 있음

이 코드는 주로 Item 객체를 만들어서 데이터를 구조화하고, 모델 학습이나 예측에 활용할 때 사용됩니다.

📊 Jupyter 시각화를 위한 매직 명령어 설정

# 🧪 Jupyter Notebook에서 그래프를 셀 아래에 바로 출력되도록 설정

%matplotlib inline  
# 📌 matplotlib 그래프를 노트북 셀 내부에 직접 표시
# - 별도로 plt.show() 없이도 시각화 결과를 즉시 볼 수 있음

이건 Jupyter 노트북에서 시각화 작업할 때 거의 필수로 쓰이는 설정이에요.

💾 학습 및 테스트 데이터 불러오기 (Pickle 사용)

# 📥 저장된 학습/테스트 데이터를 pickle 파일에서 불러오기

with open('train.pkl', 'rb') as file:
    train = pickle.load(file)
    # 🧪 'train.pkl' 파일을 읽기 모드(rb: read binary)로 열고, train 변수에 로드
    # - 학습용 데이터셋이 담겨 있음

with open('test.pkl', 'rb') as file:
    test = pickle.load(file)
    # 🧪 'test.pkl' 파일도 동일한 방식으로 열고, test 변수에 로드
    # - 테스트용 데이터셋이 담겨 있음

💡 pickle은 Python 객체를 그대로 저장하고 불러올 수 있는 직렬화 도구로, 학습 데이터를 전처리한 상태로 보관할 때 자주 사용돼요.

🧐 학습 데이터 프롬프트 내용 확인

# 🧠 학습 데이터의 프롬프트 예시 확인

print(train[0].prompt)  
# 📝 학습 데이터 중 첫 번째 샘플의 'prompt' 내용 출력
# - 모델이 가격을 예측하기 위해 입력으로 사용하는 설명 문장
# - 프롬프트가 어떤 형태인지 다시 확인해보기 위한 용도

이 코드는 모델이 어떤 입력을 받아 학습하는지 감을 잡기 위해, 프롬프트 형식을 직접 확인할 때 유용합니다.

🎯 학습 데이터의 실제 가격(label) 확인

# 💰 학습 데이터의 실제 가격(label) 확인

print(train[0].price)  
# 🔍 첫 번째 학습 샘플의 정답 값(실제 가격)을 출력
# - 모델이 예측해야 할 타깃 값 (레이블)
# - prompt에 대한 정답이 얼마였는지 확인할 수 있음

즉, 위 코드를 통해 "이 설명은 얼마짜리 상품이었는가?"에 대한 정답을 직접 확인할 수 있어요.


🧪 4. 테스트 프레임워크 (Tester 클래스)

✅ 테스트 자동화 클래스 정의

Tester 클래스는 모델을 자동으로 평가하고 시각화까지 해주는 매우 유용한 도구예요.

# 🧪 모델 성능을 자동으로 평가해주는 클래스

class Tester:

    def __init__(self, predictor, title=None, data=test, size=250):
        self.predictor = predictor              # 🧠 예측 함수 (ex. my_prediction_function)
        self.data = data                        # 📊 평가에 사용할 데이터셋 (기본값: test)
        self.title = title or predictor.__name__.replace("_", " ").title()  # 📛 그래프 제목
        self.size = size                        # 🔢 평가에 사용할 샘플 개수
        self.guesses = []                       # 🤖 모델 예측값 리스트
        self.truths = []                        # ✅ 실제 가격 리스트
        self.errors = []                        # ❌ 예측 오차 리스트
        self.sles = []                          # 📉 log 스케일 오차 제곱 (Squared Log Error)
        self.colors = []                        # 🎨 시각화용 색상 리스트 (오차 크기에 따라 다르게 표시)

    def color_for(self, error, truth):
        # 🎨 예측 오차 크기에 따라 색상 결정
        if error < 40 or error / truth < 0.2:
            return "green"   # ✅ 거의 정확
        elif error < 80 or error / truth < 0.4:
            return "orange"  # ⚠️ 중간 수준 오차
        else:
            return "red"     # ❌ 큰 오차

    def run_datapoint(self, i):
        # 🔄 하나의 데이터 샘플에 대해 예측, 평가, 기록
        datapoint = self.data[i]
        guess = self.predictor(datapoint)       # 🤖 예측 수행
        truth = datapoint.price                 # ✅ 실제 정답
        error = abs(guess - truth)              # ❌ 오차 계산
        log_error = math.log(truth + 1) - math.log(guess + 1)
        sle = log_error ** 2                    # 🔍 log 오차 제곱 (RMSLE 계산용)
        color = self.color_for(error, truth)    # 🎨 시각화용 색상 지정
        title = datapoint.title if len(datapoint.title) <= 40 else datapoint.title[:40] + "..."

        # 📋 예측 결과 저장
        self.guesses.append(guess)
        self.truths.append(truth)
        self.errors.append(error)
        self.sles.append(sle)
        self.colors.append(color)

        # 📢 결과 출력 (컬러 포함)
        print(f"{COLOR_MAP[color]}{i+1}: Guess: ${guess:,.2f} Truth: ${truth:,.2f} Error: ${error:,.2f} SLE: {sle:,.2f} Item: {title}{RESET}")

    def chart(self, title):
        # 📈 결과 시각화: 예측값 vs 실제값 산점도
        max_error = max(self.errors)
        plt.figure(figsize=(12, 8))
        max_val = max(max(self.truths), max(self.guesses))

        plt.plot([0, max_val], [0, max_val], color='deepskyblue', lw=2, alpha=0.6)  # 기준선 (예측=정답)
        plt.scatter(self.truths, self.guesses, s=3, c=self.colors)  # 실제값과 예측값 표시
        plt.xlabel('Ground Truth')
        plt.ylabel('Model Estimate')
        plt.xlim(0, max_val)
        plt.ylim(0, max_val)
        plt.title(title)
        plt.show()

    def report(self):
        # 📊 전체 결과 요약 리포트 출력
        average_error = sum(self.errors) / self.size
        rmsle = math.sqrt(sum(self.sles) / self.size)
        hits = sum(1 for color in self.colors if color == "green")

        title = f"{self.title} Error=${average_error:,.2f} RMSLE={rmsle:,.2f} Hits={hits/self.size*100:.1f}%"
        self.chart(title)

    def run(self):
        # 🚀 전체 평가 실행
        self.error = 0
        for i in range(self.size):
            self.run_datapoint(i)
        self.report()

    @classmethod
    def test(cls, function):
        # 📦 클래스 메서드로 바로 테스트 실행 가능하게 함
        cls(function).run()

📌 간단 사용 예시:

def my_prediction_function(item):
    return 100.0  # 모든 아이템을 $100으로 예측 (예시)

Tester.test(my_prediction_function)  # ▶️ 평가 실행!

🎲 5. 베이스라인 모델 실험 (Baseline Models)

지금부터 "가장 단순한 모델", 즉 무작위 숫자를 예측값으로 내보내는 모델을 실험해 볼 거예요.

🧠 이 모델은 "기계학습이 전혀 없는 상태"를 보여주며,
이후 만들어질 모델들과 성능을 비교할 출발선(baseline) 역할을 하게 됩니다.

🧪 무작위 모델 성능 테스트 실행

def random_pricer(item):
    # 🎲 무작위 가격을 반환하는 가장 단순한 모델
    # - 입력된 item과는 전혀 상관없이 1부터 999 사이의 정수를 랜덤으로 반환
    # - 학습이나 예측 로직 없이, 완전한 무작위 추정
    # 👉 성능이 낮겠지만, 우리가 만들 모델들이 얼마나 개선되는지 비교할 기준선(Baseline) 역할
    return random.randrange(1, 1000)

이 함수는 단순하지만, 이후 모델들이 얼마나 "의미 있는 예측"을 하는지를 확인하기 위한 출발점으로 아주 유용해요.

# 🎯 랜덤 시드 고정 (결과 재현 가능성 확보)
random.seed(42)
# - 매번 실행할 때마다 동일한 무작위 결과를 얻기 위해 시드를 설정함
# - 실험 결과를 일관되게 재현(reproducible)할 수 있도록 도와줌

# 🧪 테스트 실행: 무작위 예측 모델 평가
Tester.test(random_pricer)
# - 앞서 정의한 random_pricer 함수를 테스트
# - 테스트셋에서 250개 아이템에 대해 예측 수행
# - 오차, 시각화, 성능 요약 등을 자동으로 출력

이제 이 결과를 기준으로 다른 모델들이 얼마나 "똑똑해졌는지" 확인할 수 있게 됩니다.💡

🎯 평균 가격 반환 모델 (Baseline 2)

앞서 무작위 모델보다 조금 더 나아간, 고정값 평균 기반 모델이에요.

# 📊 학습 데이터의 가격 평균 계산

training_prices = [item.price for item in train]  
# 🔍 학습 데이터에 포함된 모든 아이템의 가격 리스트 생성

training_average = sum(training_prices) / len(training_prices)  
# ➗ 전체 평균 가격 계산 (모든 아이템 가격의 합 ÷ 개수)

# 🎯 항상 평균 가격을 반환하는 예측 모델
def constant_pricer(item):
    # - 입력된 item과 관계없이 항상 동일한 값(학습 데이터의 평균 가격)을 반환
    # - 예측 로직이 매우 단순하지만, 무작위 모델보다는 더 의미 있는 기준선 역할
    return training_average

🧠 이 모델은 "설명 안 보고 그냥 평균값 내놓는 사람" 정도로 생각하면 돼요.

✅ 평균값 모델 성능 테스트 실행

아래는 평균값을 반환하는 단순 모델을 실제로 평가하는 코드예요.

# 🧪 평균값 기반 예측 모델 평가 실행
Tester.test(constant_pricer)
# - constant_pricer 함수(모든 항목에 대해 동일한 평균 가격 반환)를 테스트합니다
# - 테스트셋에서 250개의 아이템을 대상으로 성능을 측정
# - 오차, RMSLE, 히트율 등 주요 지표를 출력하고
#   시각적으로 실제 가격과 예측값의 분포도 함께 확인할 수 있음

6. 🧩 특성 엔지니어링 (Feature Engineering)

🧾 제품 상세 정보 필드 확인 (details)

아래는 제품 데이터를 더 깊이 들여다보는 데 사용되는 필드예요.

train[0].details
# 🔍 학습 데이터 첫 번째 아이템의 'details' 필드 확인
# - 제품에 대한 추가 정보(사양, 설명, 특징 등)가 담겨 있을 수 있음
# - 일부 모델에서는 이 'details' 필드도 예측에 활용할 수 있음
# - 예: prompt는 간단한 설명이고, details는 좀 더 구체적인 제품 정보일 수 있음

🧠 details는 보통 텍스트 기반의 부가 정보로, NLP 기반 모델에서 입력에 포함시키면 예측 성능 향상에 도움이 되기도 해요.

🧬 제품 특성(features) 필드 생성 (JSON 파싱)

아래는 features 필드를 생성하고 details에서 JSON 파싱해 넣는 코드이며,

본격적인 특성(feature) 기반 예측이 가능해지기 위한 준비 단계입니다.

# 🧬 제품별 feature(특성) 생성: details 필드를 JSON으로 파싱하여 저장

for item in train:
    item.features = json.loads(item.details)
    # - 학습 데이터의 각 item에 대해 'details' 필드를 JSON으로 변환하여 'features'라는 새 필드에 저장
    # - 'details'는 문자열 형태의 JSON이며, 내부에 다양한 속성 정보(예: brand, category 등)를 포함하고 있음

for item in test:
    item.features = json.loads(item.details)
    # - 테스트 데이터도 동일하게 처리하여, 향후 예측 모델에서 사용할 수 있도록 준비

# 👀 하나의 feature를 살펴보기 위한 코드가 이어질 예정

이제 각 제품에는 .features라는 딕셔너리 필드가 생기며,
이걸 활용해서 카테고리별 평균 가격을 낸다든가, 브랜드별로 분석할 수 있어요.

🗂️ features 속성에서 사용 가능한 키 확인

아래는 각 아이템의 특성 딕셔너리에서 어떤 정보들이 들어 있는지 확인할 수 있는 코드입니다.

train[0].features.keys()
# 🗂️ 첫 번째 학습 데이터 아이템의 'features' 딕셔너리에서 사용 가능한 키 목록 확인
# - features는 details를 JSON으로 파싱한 딕셔너리
# - 어떤 속성들(예: 브랜드, 카테고리, 제조사 등)이 포함되어 있는지 확인 가능
# - 이후 특성 선택(feature selection) 또는 분석 시 참고할 수 있음

예를 들어 출력 결과가 dict_keys(['brand', 'manufacturer', 'color', 'category'])처럼 나온다면,
이 항목들을 활용해서 카테고리별 평균 가격 예측, 브랜드별 모델 등 다양한 방식으로 확장할 수 있습니다!

🧮 학습 데이터에서 자주 등장하는 feature 키 분석

아래는 feature_count를 계산하고 상위 특성들을 확인하는 코드입니다.

이 작업은 모델에서 사용할 주요 특성(feature)을 선정하는 데 도움이 돼요.

# 🧮 학습 데이터에서 가장 자주 등장하는 특성(feature) 키 확인

feature_count = Counter()
# 📦 각 feature 이름(키)의 등장 횟수를 셀 Counter 객체 생성

for item in train:
    for f in item.features.keys():
        feature_count[f] += 1
        # 🔁 모든 학습 아이템을 순회하면서
        # - 각 features 딕셔너리의 키(f)를 카운트에 추가

# 🔝 가장 자주 등장한 feature 키 40개 출력
feature_count.most_common(40)
# - 예: brand, manufacturer, color, category 등
# - 자주 등장하는 feature일수록 모델 입력에 포함할 가능성이 높음

📌 이 결과를 바탕으로 불필요한 특성은 제거하고, 중요한 특성은 집중적으로 활용할 수 있습니다

⚖️ Item Weight(제품 무게) 전처리 함수 정의

아래는 다소 복잡한 문자열 파싱을 통해 제품의 무게 정보를 정규화해서 뽑아내는 코드입니다.

# ⚖️ 제품의 무게(Item Weight)를 파싱하여 '파운드 단위'로 변환하는 함수
# - 약간 복잡(janky)하지만, 다양한 단위를 통일해줌
# - 다만 🤫 스포일러: 이 특성은 모델 학습에 큰 영향을 주지 않을 예정

def get_weight(item):
    weight_str = item.features.get('Item Weight')  # 📦 features에서 'Item Weight' 가져오기

    if weight_str:
        parts = weight_str.split(' ')              # 예: '2.5 Pounds' → ['2.5', 'Pounds']
        amount = float(parts[0])                   # 숫자 부분만 float으로 변환
        unit = parts[1].lower()                    # 단위를 소문자로 변환 (일관성 있게 처리)

        # 📐 다양한 단위를 파운드 기준으로 변환
        if unit == "pounds":
            return amount
        elif unit == "ounces":
            return amount / 16
        elif unit == "grams":
            return amount / 453.592
        elif unit == "milligrams":
            return amount / 453592
        elif unit == "kilograms":
            return amount / 0.453592
        elif unit == "hundredths" and parts[2].lower() == "pounds":
            return amount / 100
        else:
            print(weight_str)  # ❓ 예상치 못한 형식이 있으면 출력해서 확인

    return None  # ❌ 'Item Weight' 정보가 없거나, 파싱 실패 시 None 반환

🧠 이 함수는 Item Weight의 단위를 전처리해서 통일시켜 주는 작업이며,

향후 특정 모델에서 무게를 입력 특성으로 활용해 볼 수 있게 해주는 준비 단계예요.

⚙️ 유효한 무게 데이터 필터링

아래는 get_weight() 함수를 이용해 학습 데이터에서 유효한 무게 값만 추출하는 과정이에요:

# ⚖️ 학습 데이터에서 무게 정보 추출

weights = [get_weight(t) for t in train]
# - train 데이터의 각 아이템에 대해 get_weight() 함수를 적용
# - 'Item Weight' 값이 있는 경우, 파운드 단위로 변환된 무게를 리스트로 저장

weights = [w for w in weights if w]
# - None 값(무게 정보가 없는 항목)을 제거하여 유효한 무게 데이터만 남김
# - 이후 평균 계산, 분포 시각화 등에 사용할 수 있도록 정제

🧠 이 코드는 전체 학습 데이터 중 "무게 정보가 있는 항목만" 골라내는 전처리 과정이에요.

⚖️ 학습 데이터 무게 평균 계산

무게 정보를 활용할 경우, 평균값을 기준으로 단순 예측 모델을 만들 수도 있어요.

# ➗ 무게 정보의 평균값 계산

average_weight = sum(weights) / len(weights)
# - 유효한 무게 값들의 평균을 계산
# - 단위는 파운드(lb) 기준 (get_weight 함수에서 이미 통일됨)

average_weight  # ▶️ 평균 무게 출력 (예: 1.32 파운드)

🧠 이 값은 이후에 “무게만 보고 가격을 예측해 보는 실험”에서 기준값 혹은 스케일링에 활용될 수 있습니다.

⚙️ 결측값 보완: 무게가 없으면 평균값으로 대체

무게 정보가 없는 경우 평균 무게로 대체해 주는 안전한 버전이에요:

# ⚖️ 무게 정보가 없을 경우, 평균 무게로 대체하는 함수

def get_weight_with_default(item):
    weight = get_weight(item)
    return weight or average_weight
    # - get_weight() 함수로 무게를 가져오고,
    #   값이 None이면 average_weight(전체 평균 무게)를 반환
    # - 이렇게 하면 항상 유효한 숫자(float)가 리턴되므로
    #   이후 모델 입력값으로 바로 사용 가능

🧠 이 함수는 머신러닝 모델 입력으로 사용할 때 결측값 처리(Missing Value Handling)에 유용해요.
모든 데이터에 대해 일관된 형식의 숫자형 무게를 보장합니다!

🏷️ Best Sellers Rank 평균값 추출 함수

제품의 베스트셀러 순위(Best Sellers Rank) 정보를 평균값으로 정리해 주는 함수예요.

# 📈 베스트셀러 순위를 평균으로 계산하는 함수

def get_rank(item):
    rank_dict = item.features.get("Best Sellers Rank")
    # - features에서 'Best Sellers Rank' 키의 값을 가져옴
    # - 이 값은 딕셔너리 형태로, 여러 카테고리별 순위 정보가 담겨 있음
    #   예: {"Office Products": 183, "Office Chairs": 12}

    if rank_dict:
        ranks = rank_dict.values()             # 🔢 순위 값들만 가져옴 (정수 리스트)
        return sum(ranks) / len(ranks)         # ➗ 평균 순위 계산 (작을수록 높은 순위)

    return None  # ❌ 순위 정보가 없을 경우 None 반환

🧠 순위 정보는 낮을수록 인기가 많다는 뜻이므로,
이 값을 모델에 넣으면 "인기 있는 제품일수록 비싼가?" 같은 패턴을 학습할 수 있게 됩니다.

🏷️ 베스트셀러 순위 평균값 계산 (결측값 대체용)

아래는 베스트셀러 순위 데이터를 수집하고 평균값을 계산하는 코드입니다.

# 📊 학습 데이터에서 베스트셀러 순위 평균값 계산

ranks = [get_rank(t) for t in train]
# - 학습 데이터의 각 아이템에 대해 get_rank() 함수를 호출하여 순위 값을 추출
# - 순위 정보가 있는 경우 평균값으로 계산되어 리스트에 저장됨

ranks = [r for r in ranks if r]
# - None(순위 정보 없음)인 값을 필터링하고 유효한 값만 남김

average_rank = sum(ranks) / len(ranks)
# ➗ 유효한 순위 값들의 평균 계산 (숫자가 작을수록 인기 제품)

average_rank  # ▶️ 평균 순위 출력 (예: 16524.8 등)

🧠 이 값은 순위 정보가 없는 경우를 위한 기본값(default)으로 사용할 수 있으며,
모델에 입력할 때 결측값 보정용으로 활용됩니다.

🏷️ 결측값 보완: 순위가 없으면 평균값으로 대체

get_rank_with_default 함수는 베스트셀러 순위가 없는 경우, 평균값으로 대체하는 함수예요:

# 🛠️ 베스트셀러 순위가 없을 경우 평균값으로 대체하는 함수

def get_rank_with_default(item):
    rank = get_rank(item)  # 🏷️ 순위 정보 가져오기 (평균 순위 계산)
    return rank or average_rank
    # - 순위 정보가 None일 경우, average_rank(전체 평균 순위)를 대신 반환
    # - 항상 숫자(float)를 반환하므로 모델 입력값으로 바로 사용 가능

🧠 이 함수는 모델 학습 시 결측값 처리를 안정적으로 하기 위한 도구예요.
이제 모든 아이템은 무조건 "순위" 값을 가지게 됩니다.

✏️ 텍스트 설명 길이 측정 함수

get_text_length 함수는 제품 설명(프롬프트)의 길이(토큰 수가 아닌 문자 수)를 측정합니다.

# ✏️ 제품 설명(prompt)의 길이 측정 함수

def get_text_length(item):
    return len(item.test_prompt())
    # - item.test_prompt()는 해당 아이템의 입력 프롬프트(설명 문장)를 반환
    # - len()을 사용하여 문자열의 길이(문자 수)를 계산
    # - 텍스트 길이가 길수록 더 구체적인 설명일 수 있으며, 예측에 영향을 줄 수 있음

🧠 이 값은 모델 입력 특성 중 하나로 사용될 수 있고,
"텍스트 설명이 긴 제품이 더 비싼가?" 같은 경향을 파악하는 데 활용될 수 있어요.

🏷️ 학습 데이터 내 브랜드 분포 조사

아래는 브랜드 정보를 조사하고 상위 브랜드를 추출하는 코드이며,

브랜드별 데이터 분포를 확인하여 향후 모델 입력값으로 활용할 수 있어요.

# 🏷️ 브랜드 정보 조사 (학습 데이터 기준)

brands = Counter()
# 📦 브랜드 이름의 등장 횟수를 세기 위한 Counter 객체 생성

for t in train:
    brand = t.features.get("Brand")  # 🔍 각 아이템의 features에서 'Brand' 값 가져오기
    if brand:
        brands[brand] += 1           # ✅ 브랜드가 존재할 경우 카운터 증가

# 🔝 가장 많이 등장한 브랜드 40개 출력
brands.most_common(40)
# - 브랜드별 등장 빈도를 기준으로 정렬된 상위 40개 목록 반환
# - 자주 등장하는 브랜드일수록 모델 입력 특성으로 사용할 가능성 높음

🧠 이 작업은 “브랜드별 가격 경향”을 분석하거나,
카테고리/브랜드별 평균 가격을 만드는 데 활용될 수 있습니다.

💻 전자기기 주요 브랜드 여부 판별 함수

아래는 전자제품 관련 주요 브랜드를 식별하기 위한 기준을 설정하는 과정이에요:

# 💻 전자제품 주요 브랜드 목록 정의
TOP_ELECTRONICS_BRANDS = ["hp", "dell", "lenovo", "samsung", "asus", "sony", "canon", "apple", "intel"]
# - 이 목록은 자주 등장하고, 인지도 높은 전자기기 브랜드들을 포함함
# - 이후 브랜드가 이 목록에 포함되는지를 기준으로 특성화할 수 있음

# 🔍 아이템이 전자제품 주요 브랜드에 해당하는지 여부 판단
def is_top_electronics_brand(item):
    brand = item.features.get("Brand")  # 🏷️ item의 features에서 'Brand' 필드 가져오기
    return brand and brand.lower() in TOP_ELECTRONICS_BRANDS
    # ✅ 브랜드가 존재하고, 소문자로 변환했을 때 TOP 목록에 포함되면 True 반환
    # ❌ 그렇지 않으면 False (또는 None → False)

🧠 이 함수는 예를 들어 "유명 브랜드의 제품은 더 비싼가?" 같은 분석이나,
이진 분류 특성(binary feature)으로 활용될 수 있어요.

🧩 제품 특성(feature) 딕셔너리 구성 함수

get_features 함수는 머신러닝 모델에 입력할 수 있는 구조화된 특성(feature)을 생성합니다:

# 🧩 하나의 아이템에 대해 주요 특성을 추출하여 딕셔너리 형태로 반환

def get_features(item):
    return {
        "weight": get_weight_with_default(item),  
        # ⚖️ 무게 (파운드 단위) — 없으면 평균 무게로 대체

        "rank": get_rank_with_default(item),      
        # 🏷️ Best Sellers Rank — 없으면 평균 순위로 대체

        "text_length": get_text_length(item),      
        # ✏️ 제품 설명 프롬프트의 길이 (문자 수 기준)

        "is_top_electronics_brand": 1 if is_top_electronics_brand(item) else 0  
        # 💻 전자기기 주요 브랜드 여부 (1: 포함, 0: 비포함)
    }

🧠 이 함수는 각 아이템을 모델에 넣기 위한 입력 벡터(피처 딕셔너리)로 변환해 주는 역할을 합니다.
나중에 이 데이터를 DataFrame으로 변환하거나 모델에 바로 넣어 예측에 활용할 수 있어요.

🔍 단일 학습 아이템의 특성 확인

get_features(train[0]) 호출은

실제로 하나의 학습 데이터를 대상으로 특성 추출 결과를 확인하는 단계예요:

# 🔍 학습 데이터 아이템의 특성 확인

get_features(train[0])
# - train[0] 아이템에 대해 get_features() 함수를 적용
# - 결과는 딕셔너리 형태의 특성값(feature values)을 반환함

# 예시 출력 형태:
# {
#   "weight": 1.25,
#   "rank": 14823.7,
#   "text_length": 153,
#   "is_top_electronics_brand": 0
# }

# 📌 이 결과를 통해:
# - 무게, 순위, 텍스트 길이, 브랜드 여부 등의 정보가
#   모델 입력으로 어떻게 구성되는지 미리 확인 가능

🧠 이 과정은 모델 학습 전에 특성 설계가 잘 되었는지 검토하는 데 매우 중요해요.
이후 전체 데이터셋에 적용하여 학습용 입력값을 만들게 됩니다.

📊 특성 리스트를 학습용 데이터프레임으로 변환

아래는 특성 딕셔너리를 모델 학습이 가능한 형태의 데이터프레임으로 변환하는 핵심 단계예요.

# 🧰 아이템 리스트를 pandas 데이터프레임으로 변환하는 유틸리티 함수

def list_to_dataframe(items):
    features = [get_features(item) for item in items]  # 🧩 각 아이템에 대해 특성 추출
    df = pd.DataFrame(features)                         # 📊 특성 리스트를 pandas 데이터프레임으로 변환
    df['price'] = [item.price for item in items]        # 💰 타깃 값(가격)을 별도 컬럼으로 추가
    return df                                           # ✅ 최종 데이터프레임 반환

# 🧪 학습 및 테스트셋을 데이터프레임 형태로 변환

train_df = list_to_dataframe(train)        # 📘 전체 학습 데이터를 학습용 데이터프레임으로 변환
test_df = list_to_dataframe(test[:250])    # 📗 테스트 데이터 중 앞의 250개만 변환하여 평가용 데이터프레임 생성

🧠 이 구조를 통해 X (입력 피처)와 y (가격 라벨)를 분리하여 머신러닝 모델에 바로 사용할 수 있어요.

반응형

'🧠 LLM 엔지니어링' 카테고리의 다른 글

제품 설명 기반 가격 예측 실험: Frontier 모델 테스트  (1) 2025.05.03
자연어 처리 기반 가격 예측 모델 개발💸 (BOW vs Word2Vec vs RF) 02  (0) 2025.05.02
📘 제품 가격 예측 AI 만들기: Amazon 리뷰 데이터로 LLM 학습하기 01  (0) 2025.04.30
문서 기반 챗봇 만들기: RAG 실습 with OpenAI, FAISS, Gradio 02  (0) 2025.04.29
문서 기반 챗봇 만들기: RAG 실습 with OpenAI, FAISS, Gradio 01  (1) 2025.04.28
  1. 🔰 개요
  2. 📦 1. 라이브러리 임포트 및 환경 설정
  3. 🔐 2. 환경 변수 및 API 키 설정
  4. 📊 3. 데이터 로딩 및 탐색
  5. 🧪 4. 테스트 프레임워크 (Tester 클래스)
  6. 🎲 5. 베이스라인 모델 실험 (Baseline Models)
  7. 6. 🧩 특성 엔지니어링 (Feature Engineering)
'🧠 LLM 엔지니어링' 카테고리의 다른 글
  • 제품 설명 기반 가격 예측 실험: Frontier 모델 테스트
  • 자연어 처리 기반 가격 예측 모델 개발💸 (BOW vs Word2Vec vs RF) 02
  • 📘 제품 가격 예측 AI 만들기: Amazon 리뷰 데이터로 LLM 학습하기 01
  • 문서 기반 챗봇 만들기: RAG 실습 with OpenAI, FAISS, Gradio 02
개발자 린다씨
개발자 린다씨
개발자 린다씨
개발자 린다씨
Cozy_Linda
개발자 린다씨
전체
오늘
어제
  • 분류 전체보기 (220)
    • 🧠 LLM 엔지니어링 (16)
    • 🐣 일하면서 공부하기 (26)
    • 👶 TypeScript (101)
    • 😎 STS3 Spring 쇼핑몰 (68)
      • STS3 Spring 환경 설정 👀 (5)
    • 🥴 SQLD (5)
    • 🍀 Tistory 팁 (4)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

최근 댓글

최근 글

hELLO · Designed By 정상우.
개발자 린다씨
자연어 처리 기반 가격 예측 모델 개발💸 (BOW vs Word2Vec vs RF) 01
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.