Price_Pulse/analysis/app.py

172 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import numpy as np
import pandas as pd
from datetime import timedelta
from tensorflow.keras.models import load_model
from sklearn.preprocessing import MinMaxScaler
import matplotlib.pyplot as plt
import io
import joblib
from flask import Flask, request, jsonify, Blueprint, send_file
from flasgger import Swagger
app = Flask(__name__)
api = Blueprint('api', __name__)
Swagger(app)
# Загружаем модель и scaler
model = load_model("my_model_1H.keras")
scaler = MinMaxScaler(feature_range=(0, 1))
# Загружаем данные
column_names = ['product_url', 'price', 'datetime']
df1 = pd.read_csv('parsed_data_public_price_history_1.csv')
df2 = pd.read_csv('parsed_data_public_price_history.csv', names=column_names, )
df3 = pd.read_csv('price_history.csv', names=column_names,)
df = pd.concat([df1, df2, df3])
# Преобразуем колонку 'datetime' в тип данных datetime
df['datetime'] = pd.to_datetime(df['datetime'], format='mixed', utc=True)
df['price'] = df['price'].astype(float)
q_low = df['price'].quantile(0.55)
q_hi = df['price'].quantile(0.75)
q_range = q_hi - q_low
df = df[(df['price'] < q_hi + 1.5 * q_range) & (df['price'] > q_low - 1.5 * q_range)]
df_hourly_avg = df[['price', 'datetime']]
df_hourly_avg['datetime'] = df_hourly_avg['datetime'].dt.floor('1H')
df_hourly_avg = df_hourly_avg.groupby('datetime').agg({'price': 'mean'}).reset_index()
df_hourly_avg.set_index('datetime', inplace=True)
# Подготовка данных для прогнозирования
def prepare_data(df, days_forward=7):
last_date = df.index[-1]
scaled_data = scaler.fit_transform(df[['price']].values)
n = 3 # число временных шагов (можно менять)
X_test = []
# Формируем X_test на основе последних n значений
for i in range(n, len(scaled_data)):
X_test.append(scaled_data[i - n:i, 0])
X_test = np.array(X_test)
X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))
# Предсказание на 7 дней вперед
predictions = []
current_input = X_test[-1] # начальное состояние для прогноза
for _ in range(days_forward):
pred = model.predict(np.expand_dims(current_input, axis=0))
predictions.append(pred[0, 0])
# Обновляем current_input, добавляя новое предсказание и удаляя старое
current_input = np.append(current_input[1:], pred).reshape(n, 1)
# Масштабируем предсказания обратно
predictions = scaler.inverse_transform(np.array(predictions).reshape(-1, 1)).flatten()
future_dates = [last_date + timedelta(days=i) for i in range(1, days_forward + 1)]
forecast_df = pd.DataFrame({'date': future_dates, 'predicted_price': predictions})
return forecast_df
# Построение графика
def plot_price(forecast_df):
plt.figure(figsize=(14, 7))
plt.plot(df_hourly_avg.index, df_hourly_avg['price'], label='Actual Price', color='blue')
plt.plot(forecast_df['date'], forecast_df['predicted_price'], label='Predicted Price', color='orange')
plt.title("Price Prediction")
plt.xlabel("Date")
plt.ylabel("Price")
plt.legend()
plt.grid(True)
img = io.BytesIO()
plt.savefig(img, format='png')
img.seek(0)
plt.close()
return img
@api.route('/predict_price', methods=['GET'])
def predict_price():
"""
Предсказание цены на 7 дней вперед
---
responses:
200:
description: JSON с предсказаниями цен и днем минимальной цены
schema:
type: object
properties:
forecast:
type: array
items:
type: object
properties:
date:
type: string
format: date
predicted_price:
type: number
min_price_day:
type: object
properties:
date:
type: string
format: date
price:
type: number
"""
forecast_df = prepare_data(df_hourly_avg)
forecast_list = forecast_df.to_dict(orient='records') # Преобразование в список словарей
# Преобразуем значения 'predicted_price' в float
for record in forecast_list:
record['predicted_price'] = float(record['predicted_price'])
# Определяем день с минимальной предсказанной ценой
min_price_day = forecast_df.loc[forecast_df['predicted_price'].idxmin()]
# Преобразуем минимальную цену в float
min_price_day_price = float(min_price_day['predicted_price'])
# Формируем ответ
return jsonify({
'forecast': forecast_list,
'min_price_day': {
'date': min_price_day['date'].strftime('%Y-%m-%d'),
'price': min_price_day_price
}
})
# Эндпоинт для получения графика
@api.route('/plot', methods=['GET'])
def plot():
"""
Получение графика предсказанных и фактических цен
---
responses:
200:
description: Возвращает график предсказанных и фактических цен в формате PNG
content:
image/png:
schema:
type: string
format: binary
"""
forecast_df = prepare_data(df_hourly_avg)
img = plot_price(forecast_df)
return send_file(img, mimetype='image/png')
app.register_blueprint(api, url_prefix='/api')
if __name__ == "__main__":
app.run(debug=True)