🔰 개요
제품 설명 텍스트만을 가지고 가격을 예측하는 머신러닝 모델을 실험해 봅니다.
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 |