一、为什么要学销量预测?
想象你是某连锁奶茶店的运营:
备货太少 → 顾客喝不到,差评 😡
备货太多 → 过期倒掉,亏钱 😭
销量预测(Sales Forecasting) 就是为了解决这个“黄金平衡点”。
在本教程中,我们将用Python + 真实逻辑,完成一次完整的销量预测项目。
二、准备工作:环境与数据
1️⃣ 安装必备库
pip install pandas numpy matplotlib scikit-learn statsmodels2️⃣ 构造示例数据
假设我们有某店铺过去 90 天的销量数据:
import pandas as pd import numpy as np # 构造日期 date_rng = pd.date_range(start='2024-01-01', end='2024-03-30', freq='D') np.random.seed(42) # 构造销量(含趋势 + 波动) sales = ( 100 + 0.5 * np.arange(len(date_rng)) + 10 * np.sin(2 * np.pi * date_rng.dayofyear / 7) + np.random.normal(0, 5, len(date_rng)) ) df = pd.DataFrame({ 'date': date_rng, 'sales': sales }) df.set_index('date', inplace=True) print(df.head())三、第一步:数据可视化(EDA)
永远先看图,再建模。
import matplotlib.pyplot as plt plt.figure(figsize=(12, 5)) plt.plot(df.index, df['sales'], label='Daily Sales') plt.title("Daily Sales Trend") plt.xlabel("Date") plt.ylabel("Sales") plt.legend() plt.show()🔍观察要点:
是否有上升趋势?
是否有周期性(周几卖得好)?
是否有异常值?
四、方法一:线性回归(初学者必学)
1️⃣ 特征工程:给时间编号
机器不懂“日期”,只懂数字。
df['day_index'] = np.arange(len(df))2️⃣ 划分训练集 & 测试集
from sklearn.model_selection import train_test_split X = df[['day_index']] y = df['sales'] X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, shuffle=False )3️⃣ 训练模型
from sklearn.linear_model import LinearRegression model = LinearRegression() model.fit(X_train, y_train)4️⃣ 预测 & 评估
from sklearn.metrics import mean_absolute_error y_pred = model.predict(X_test) mae = mean_absolute_error(y_test, y_pred) print(f"MAE(平均绝对误差):{mae:.2f}")📌线性回归适合:
✅ 趋势明显
❌ 忽略季节性
五、方法二:时间序列(Prophet 实战)
Facebook 开源的Prophet 非常适合业务人员。
1️⃣ 安装 Prophet
pip install prophet2️⃣ 数据格式转换
Prophet 要求两列:
ds:日期y:数值
from prophet import Prophet prophet_df = df.reset_index().rename(columns={'date': 'ds', 'sales': 'y'})3️⃣ 训练 & 预测
model = Prophet( yearly_seasonality=False, weekly_seasonality=True, daily_seasonality=False ) model.fit(prophet_df)4️⃣ 生成未来 30 天预测
future = model.make_future_dataframe(periods=30) forecast = model.predict(future) model.plot(forecast) plt.show()✅ Prophet 自动识别:
周规律(周末爆单)
节假日效应
趋势变化
六、模型对比:哪个更好?
模型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
线性回归 | 简单、快 | 忽略周期 | 稳定趋势 |
Prophet | 自动处理周期 | 黑盒 | 商业预测 |
神经网络 | 精度高 | 数据要求高 | 大规模预测 |
七、落地建议(非常重要)
7.1 不要只看 MAE
- 还要看 RMSE、MAPE
7.2 业务解释性 > 精度
- 老板要听得懂
7.3 定期重训模型
- 每月更新一次
7.4 做区间预测
- 给出“乐观 / 中性 / 悲观”
八、完整项目结构推荐
sales_forecast/ ├── notebooks/ │ └── 01_EDA.ipynb ├── .gitignore ├── main.py ├── requirements.txt ├── models/ │ ├── prophet_model.py │ └── linear_regression_model.py ├── data/ │ └── sales.csv └── utils/ └── metrics.py1️⃣requirements.txt
(放在项目根目录,用于一键安装依赖)
pandas>=1.5.0 numpy>=1.21.0 matplotlib>=3.5.0 scikit-learn>=1.0.0 prophet>=1.1.0 jupyter>=1.0.02️⃣data/sales.csv
(这是我们的原始数据源,你可以手动创建,也可以用代码生成)
date,sales 2024-01-01,105.2 2024-01-02,108.7 2024-01-03,112.4 2024-01-04,115.1 2024-01-05,118.9 2024-01-06,122.3 2024-01-07,119.8 2024-01-08,125.6 2024-01-09,128.4 2024-01-10,130.2 2024-01-11,127.5 2024-01-12,135.8 2024-01-13,138.2 2024-01-14,142.7 2024-01-15,140.1 2024-01-16,145.3 2024-01-17,148.9 2024-01-18,152.4 2024-01-19,149.7 2024-01-20,155.2 2024-01-21,158.6 2024-01-22,162.1 2024-01-23,165.8 2024-01-24,168.3 2024-01-25,172.9 2024-01-26,175.4 2024-01-27,178.8 2024-01-28,182.3 2024-01-29,179.6 2024-01-30,185.1✅提示:真实项目中这里通常是几十万行的数据,这里仅做演示。
3️⃣notebooks/01_EDA.ipynb
(Jupyter Notebook 文件,用于探索性分析)
# %% import pandas as pd import matplotlib.pyplot as plt # 读取数据 df = pd.read_csv('../data/sales.csv', parse_dates=['date']) df.set_index('date', inplace=True) # 查看前5行 print(df.head()) # %% # 基础统计信息 print(df.describe()) # %% # 销量趋势图 plt.figure(figsize=(12, 6)) plt.plot(df.index, df['sales'], marker='o', linestyle='-') plt.title('Daily Sales Trend') plt.xlabel('Date') plt.ylabel('Sales') plt.grid(True) plt.show() # %% # 按周聚合查看周期性 weekly_sales = df.resample('W').mean() print(weekly_sales.tail())4️⃣utils/metrics.py
(工具函数:专门用于评估模型好坏)
from sklearn.metrics import mean_absolute_error, mean_squared_error import numpy as np def evaluate_model(y_true, y_pred): """ 计算回归模型的常用评估指标 """ mae = mean_absolute_error(y_true, y_pred) rmse = np.sqrt(mean_squared_error(y_true, y_pred)) # 避免除以0 if y_true.mean() != 0: mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100 else: mape = np.nan return { "MAE": round(mae, 2), "RMSE": round(rmse, 2), "MAPE": f"{round(mape, 2)}%" }5️⃣models/prophet_model.py
(封装 Prophet 模型,便于主程序调用)
from prophet import Prophet import pandas as pd class SalesProphet: def __init__(self): self.model = None def train(self, df: pd.DataFrame): """ df 必须包含两列:ds (日期), y (销量) """ self.model = Prophet( yearly_seasonality=False, weekly_seasonality=True, daily_seasonality=False ) self.model.fit(df) def predict(self, periods=30): """ 预测未来 N 天 """ future = self.model.make_future_dataframe(periods=periods) forecast = self.model.predict(future) return forecast def plot(self, forecast): fig = self.model.plot(forecast) return fig6️⃣models/linear_regression_model.py
(备选模型:线性回归)
from sklearn.linear_model import LinearRegression import numpy as np class LinearSalesModel: def __init__(self): self.model = LinearRegression() def train(self, X, y): self.model.fit(X, y) def predict(self, X): return self.model.predict(X) def get_coefficients(self): return { "intercept": self.model.intercept_, "coefficient": self.model.coef_[0] }7️⃣main.py
(项目的主入口文件,串联整个流程)
import pandas as pd from utils.metrics import evaluate_model from models.prophet_model import SalesProphet def main(): print("🚀 启动销量预测项目...") # 1. 加载数据 df = pd.read_csv('data/sales.csv', parse_dates=['date']) df_prophet = df.rename(columns={'date': 'ds', 'sales': 'y'}) # 2. 训练模型 model = SalesProphet() model.train(df_prophet) # 3. 预测未来 30 天 forecast = model.predict(periods=30) # 4. 评估(使用历史数据进行回测) y_true = df_prophet['y'].values[-30:] y_pred = forecast['yhat'].values[-30:] metrics = evaluate_model(y_true, y_pred) print("📊 模型评估结果:") for k, v in metrics.items(): print(f"{k}: {v}") # 5. 可视化 model.plot(forecast) import matplotlib.pyplot as plt plt.show() if __name__ == "__main__": main()8️⃣.gitignore(可选但推荐)
# Python __pycache__/ *.pyc *.pyo # Jupyter .ipynb_checkpoints/ # 数据文件(如果是敏感数据) # data/*.csv # 虚拟环境 venv/ .env✅ 运行顺序
安装依赖:
pip install -r requirements.txt打开 Notebook:
jupyter notebook notebooks/01_EDA.ipynb运行主程序:
python main.py
九、总结一句话
销量预测不是“算命”,而是用历史数据 + 数学模型,降低经营的不确定性。