kshs33_emotion_predict / utils /prediction_utils.py
leewatson's picture
Upload 2 files
d445415 verified
# utils/prediction_utils.py
import warnings
warnings.filterwarnings("ignore")
import numpy as np
# Prophet ์‹œ๋„, ์‹คํŒจ ์‹œ Holt(์ง€์ˆ˜ ํ‰ํ™œ) ํด๋ฐฑ
try:
from prophet import Prophet
_HAS_PROPHET = True
except Exception:
_HAS_PROPHET = False
try:
from statsmodels.tsa.holtwinters import ExponentialSmoothing
_HAS_HOLT = True
except Exception:
_HAS_HOLT = False
import pandas as pd
def prophet_emotion_forecast(scores, steps=3):
"""
Prophet ๊ธฐ๋ฐ˜ ์˜ˆ์ธก. ์ž…๋ ฅ: ์ ์ˆ˜ ๋ฆฌ์ŠคํŠธ(0~100)
๋ฐ˜ํ™˜: ์˜ˆ์ธก ์ ์ˆ˜ ๋ฆฌ์ŠคํŠธ ๊ธธ์ด=steps (float)
์ฐธ๊ณ : Taylor & Letham (2018) 'Forecasting at Scale'
"""
if not _HAS_PROPHET or len(scores) < 5:
return None
df = pd.DataFrame({
'ds': pd.date_range(start='2023-01-01', periods=len(scores), freq='D'),
'y': scores
})
model = Prophet(
daily_seasonality=False, weekly_seasonality=False, yearly_seasonality=False,
changepoint_prior_scale=0.2 # ๋ณ€ํ™”์  ๋ฏผ๊ฐ๋„
)
model.fit(df)
future = model.make_future_dataframe(periods=steps)
forecast = model.predict(future)
tail = forecast[['yhat']].tail(steps)['yhat'].to_list()
# ์•ˆ์ „ ํด๋ฆฌํ•‘
return [float(np.clip(x, 0, 100)) for x in tail]
def holt_fallback_forecast(scores, steps=3):
"""
Holt ์ง€์ˆ˜ํ‰ํ™œ(์ถ”์„ธํ˜•) ํด๋ฐฑ ์˜ˆ์ธก.
Prophet ์‚ฌ์šฉ ๋ถˆ๊ฐ€ ํ™˜๊ฒฝ์—์„œ ๊ฐ„๋‹จํ•˜๊ณ  ์•ˆ์ •์ .
"""
if not _HAS_HOLT or len(scores) < 4:
return None
try:
model = ExponentialSmoothing(
np.array(scores, dtype=float),
trend='add', seasonal=None
).fit()
fcast = model.forecast(steps)
return [float(np.clip(x, 0, 100)) for x in fcast.tolist()]
except Exception:
return None
def forecast_scores(scores, steps=3):
"""
ํ†ตํ•ฉ ์˜ˆ์ธก ์—”์ง„:
1) Prophet ์„ฑ๊ณต ์‹œ Prophet ์‚ฌ์šฉ
2) ์•„๋‹ˆ๋ฉด Holt ํด๋ฐฑ
3) ๊ทธ๋ž˜๋„ ์•ˆ ๋˜๋ฉด, ๋งˆ์ง€๋ง‰ ๊ธฐ์šธ๊ธฐ ์„ ํ˜• ์™ธ์‚ฝ(๊ทน๋‹จ ํด๋ฐฑ)
"""
if len(scores) < 2:
return [scores[-1]] * steps if scores else [0.0]*steps
yhat = prophet_emotion_forecast(scores, steps=steps)
if yhat is not None:
return yhat
yhat = holt_fallback_forecast(scores, steps=steps)
if yhat is not None:
return yhat
# ๋งˆ์ง€๋ง‰ ๋‘ ์ ์˜ ๊ธฐ์šธ๊ธฐ๋กœ ์™ธ์‚ฝ
slope = scores[-1] - scores[-2]
return [float(np.clip(scores[-1] + slope*(i+1), 0, 100)) for i in range(steps)]