23 KiB
23 KiB
🔮 药店销售预测结果分析增强方案
一、预测结果解释系统设计 📊
1. 预测解释功能概述
在现有的预测系统基础上,增加预测结果解释功能,不仅返回预测值,还提供对预测结果的分析解释,帮助用户理解"为什么会得到这样的预测结果"和"哪些因素影响了这个预测"。
2. 核心功能模块
A. 特征重要性分析
def analyze_feature_importance(model, X_test, feature_names):
"""
分析各个特征对预测结果的重要性
Args:
model: 训练好的模型
X_test: 测试数据特征
feature_names: 特征名称列表
Returns:
feature_importance_dict: 特征重要性字典
"""
# 根据不同模型类型实现特征重要性计算
if hasattr(model, 'feature_importances_'): # 如GBDT等树模型
importances = model.feature_importances_
else: # 对于深度学习模型,使用排列重要性或SHAP值
importances = calculate_permutation_importance(model, X_test)
# 将特征名称与重要性值匹配
feature_importance_dict = dict(zip(feature_names, importances))
return feature_importance_dict
B. 预测因素分解
def decompose_prediction_factors(prediction, feature_values, feature_importance):
"""
将预测结果分解为各个因素的贡献
Args:
prediction: 预测结果
feature_values: 输入特征值
feature_importance: 特征重要性
Returns:
factor_contributions: 各因素对预测的贡献
"""
# 计算每个特征的贡献
factor_contributions = {}
for feature, value in feature_values.items():
if feature in feature_importance:
contribution = value * feature_importance[feature]
factor_contributions[feature] = {
'value': value,
'importance': feature_importance[feature],
'contribution': contribution
}
# 按贡献大小排序
sorted_factors = sorted(factor_contributions.items(),
key=lambda x: abs(x[1]['contribution']),
reverse=True)
return sorted_factors
C. 历史模式匹配
def find_similar_historical_patterns(current_prediction, historical_data, window_size=7):
"""
查找历史数据中与当前预测模式相似的时间段
Args:
current_prediction: 当前预测结果序列
historical_data: 历史数据
window_size: 比较窗口大小
Returns:
similar_patterns: 相似的历史模式列表
"""
similar_patterns = []
# 计算当前预测的特征(如趋势、周期性等)
current_features = extract_pattern_features(current_prediction)
# 在历史数据中滑动窗口寻找相似模式
for i in range(len(historical_data) - window_size):
window = historical_data[i:i+window_size]
window_features = extract_pattern_features(window)
# 计算相似度
similarity = calculate_similarity(current_features, window_features)
if similarity > SIMILARITY_THRESHOLD:
similar_patterns.append({
'period': (i, i+window_size),
'data': window,
'similarity': similarity
})
# 按相似度排序
similar_patterns.sort(key=lambda x: x['similarity'], reverse=True)
return similar_patterns[:5] # 返回前5个最相似的模式
D. 异常值检测与解释
def detect_and_explain_anomalies(predictions, historical_stats):
"""
检测预测结果中的异常值并提供解释
Args:
predictions: 预测结果序列
historical_stats: 历史数据统计信息
Returns:
anomalies: 异常值及其解释
"""
anomalies = []
# 计算预测值的统计特性
mean = historical_stats['mean']
std = historical_stats['std']
# 检测异常值(例如超过2个标准差)
for i, value in enumerate(predictions):
z_score = (value - mean) / std
if abs(z_score) > 2:
# 异常值检测
anomaly = {
'day': i,
'value': value,
'z_score': z_score,
'severity': 'high' if abs(z_score) > 3 else 'medium',
'explanation': generate_anomaly_explanation(value, z_score, i)
}
anomalies.append(anomaly)
return anomalies
二、预测结果解释API设计 🔌
1. API接口扩展
@app.route('/api/prediction/explain', methods=['POST'])
def explain_prediction():
"""
提供预测结果的详细解释
---
tags:
- 预测分析
parameters:
- name: body
in: body
required: true
schema:
type: object
properties:
product_id:
type: string
example: P001
model_type:
type: string
enum: [mlstm, transformer, kan, optimized_kan]
future_days:
type: integer
default: 7
include_factors:
type: boolean
default: true
include_similar_patterns:
type: boolean
default: true
include_anomaly_detection:
type: boolean
default: true
responses:
200:
description: 预测结果及其解释
"""
data = request.json
product_id = data.get('product_id')
model_type = data.get('model_type')
future_days = data.get('future_days', 7)
# 获取预测结果
predictions, features = load_model_and_predict_with_features(
product_id, model_type, future_days
)
# 准备响应数据
response = {
'status': 'success',
'predictions': predictions.tolist(),
'explanation': {}
}
# 根据请求参数添加不同类型的解释
if data.get('include_factors', True):
# 添加特征重要性分析
model = load_model(product_id, model_type)
feature_importance = analyze_feature_importance(model, features, FEATURE_NAMES)
factor_contributions = decompose_prediction_factors(
predictions, features, feature_importance
)
response['explanation']['factors'] = factor_contributions
if data.get('include_similar_patterns', True):
# 添加历史模式匹配
historical_data = load_historical_data(product_id)
similar_patterns = find_similar_historical_patterns(
predictions, historical_data
)
response['explanation']['similar_patterns'] = similar_patterns
if data.get('include_anomaly_detection', True):
# 添加异常值检测
historical_stats = calculate_historical_stats(product_id)
anomalies = detect_and_explain_anomalies(predictions, historical_stats)
response['explanation']['anomalies'] = anomalies
# 生成总体解释文本
response['explanation']['summary'] = generate_explanation_summary(
predictions, response['explanation']
)
return jsonify(response)
2. 前端展示组件
A. 预测结果解释面板
// Vue组件示例
<template>
<div class="prediction-explanation">
<el-card class="explanation-card">
<div slot="header">
<span>预测结果解释</span>
</div>
<!-- 总体解释摘要 -->
<div class="explanation-summary">
<h4>预测分析摘要</h4>
<p>{{ explanation.summary }}</p>
</div>
<!-- 关键影响因素 -->
<div v-if="explanation.factors" class="key-factors">
<h4>关键影响因素</h4>
<el-table :data="explanation.factors.slice(0, 5)" style="width: 100%">
<el-table-column prop="factor" label="因素"></el-table-column>
<el-table-column prop="contribution" label="贡献度">
<template slot-scope="scope">
<el-progress
:percentage="Math.abs(scope.row.contribution * 100)"
:color="scope.row.contribution > 0 ? '#67C23A' : '#F56C6C'"
></el-progress>
</template>
</el-table-column>
<el-table-column prop="impact" label="影响">
<template slot-scope="scope">
<span :class="scope.row.contribution > 0 ? 'positive' : 'negative'">
{{ scope.row.contribution > 0 ? '增加' : '减少' }}
</span>
</template>
</el-table-column>
</el-table>
</div>
<!-- 异常值提示 -->
<div v-if="explanation.anomalies && explanation.anomalies.length > 0" class="anomalies">
<h4>异常值提示</h4>
<el-alert
v-for="(anomaly, index) in explanation.anomalies"
:key="index"
:title="`第${anomaly.day + 1}天: ${anomaly.value} (${anomaly.severity}级异常)`"
:type="anomaly.severity === 'high' ? 'error' : 'warning'"
:description="anomaly.explanation"
show-icon
></el-alert>
</div>
<!-- 相似历史模式 -->
<div v-if="explanation.similar_patterns && explanation.similar_patterns.length > 0" class="similar-patterns">
<h4>相似历史模式</h4>
<el-collapse>
<el-collapse-item
v-for="(pattern, index) in explanation.similar_patterns"
:key="index"
:title="`相似模式 #${index + 1} (相似度: ${(pattern.similarity * 100).toFixed(1)}%)`"
>
<div class="pattern-chart">
<line-chart :chart-data="prepareChartData(pattern.data)"></line-chart>
</div>
<div class="pattern-period">
<p>历史时段: {{ formatDateRange(pattern.period) }}</p>
</div>
</el-collapse-item>
</el-collapse>
</div>
</el-card>
</div>
</template>
三、预测解释生成器实现 🧩
1. 解释文本生成器
def generate_explanation_summary(predictions, explanation_data):
"""
根据预测结果和解释数据生成人类可读的解释摘要
Args:
predictions: 预测结果序列
explanation_data: 包含各种解释数据的字典
Returns:
summary: 人类可读的解释摘要
"""
summary = []
# 分析预测趋势
trend = analyze_trend(predictions)
if trend == 'increasing':
summary.append("预测显示未来销量呈上升趋势。")
elif trend == 'decreasing':
summary.append("预测显示未来销量呈下降趋势。")
else:
summary.append("预测显示未来销量相对稳定。")
# 添加关键影响因素解释
if 'factors' in explanation_data:
top_factors = explanation_data['factors'][:3] # 取前三个最重要的因素
factor_text = "主要影响因素包括: "
for i, (factor, data) in enumerate(top_factors):
direction = "增加" if data['contribution'] > 0 else "减少"
if i > 0:
factor_text += "、"
factor_text += f"{factor}({direction})"
summary.append(factor_text)
# 添加异常值解释
if 'anomalies' in explanation_data and explanation_data['anomalies']:
anomaly_count = len(explanation_data['anomalies'])
summary.append(f"预测中发现{anomaly_count}个异常值,可能需要特别关注。")
# 添加历史模式参考
if 'similar_patterns' in explanation_data and explanation_data['similar_patterns']:
top_pattern = explanation_data['similar_patterns'][0]
similarity = top_pattern['similarity'] * 100
summary.append(f"当前预测模式与历史数据中的某些时段有{similarity:.1f}%的相似度,可参考历史表现。")
# 生成建议
recommendations = generate_recommendations(predictions, explanation_data)
if recommendations:
summary.append("建议: " + recommendations)
return " ".join(summary)
2. 特定场景解释生成
def generate_anomaly_explanation(value, z_score, day_index):
"""
为异常值生成解释
Args:
value: 异常预测值
z_score: Z分数(标准差倍数)
day_index: 异常值所在的天数索引
Returns:
explanation: 异常值解释文本
"""
weekday = (datetime.now() + timedelta(days=day_index)).strftime("%A")
if z_score > 0:
if weekday in ['Saturday', 'Sunday']:
return f"该值异常偏高,可能与周末效应有关。周末通常客流量增加,销量上升。"
else:
return f"该值异常偏高,可能受到促销活动、季节性因素或特殊事件影响。"
else:
if weekday in ['Saturday', 'Sunday']:
return f"该值在周末异常偏低,与典型周末销售模式不符,可能有特殊原因导致客流减少。"
else:
return f"该值异常偏低,可能受到库存问题、竞争对手活动或外部因素影响。"
3. 建议生成器
def generate_recommendations(predictions, explanation_data):
"""
基于预测结果和解释数据生成行动建议
Args:
predictions: 预测结果序列
explanation_data: 解释数据字典
Returns:
recommendations: 建议文本
"""
recommendations = []
# 分析预测趋势
trend = analyze_trend(predictions)
# 基于趋势的库存建议
if trend == 'increasing':
recommendations.append("考虑增加采购量,确保库存充足")
elif trend == 'decreasing':
recommendations.append("考虑减少采购,避免库存积压")
# 基于异常值的建议
if 'anomalies' in explanation_data and explanation_data['anomalies']:
high_anomalies = [a for a in explanation_data['anomalies'] if a['severity'] == 'high']
if high_anomalies:
recommendations.append("关注高度异常的预测日期,制定应对预案")
# 基于特征重要性的建议
if 'factors' in explanation_data:
weather_factors = [f for f, _ in explanation_data['factors'] if 'temperature' in f or 'weather' in f]
if weather_factors:
recommendations.append("密切关注天气变化对销量的影响")
promotion_factors = [f for f, _ in explanation_data['factors'] if 'promotion' in f]
if promotion_factors:
recommendations.append("促销活动对销量影响显著,可考虑优化促销策略")
return ",".join(recommendations) + "。" if recommendations else ""
四、实施与集成方案 🔧
1. 系统集成步骤
-
后端API实现:
- 在
pharmacy_predictor.py
中添加预测解释相关函数 - 在
api.py
中添加新的API端点
- 在
-
数据存储扩展:
- 添加特征重要性存储
- 保存历史预测与实际销量对比数据
-
前端集成:
- 在
UI/src/views/PredictionView.vue
中添加解释面板组件 - 添加可视化图表展示影响因素
- 在
2. 代码实现示例
A. 后端实现
# 在pharmacy_predictor.py中添加
def explain_model_prediction(product_id, model_type, predictions, features):
"""
为模型预测结果提供解释
"""
# 加载模型
model_path = get_model_path(product_id, model_type)
model = torch.load(model_path)
# 获取特征重要性
feature_names = ['sales', 'price', 'weekday', 'month', 'is_holiday',
'is_weekend', 'is_promotion', 'temperature']
feature_importance = analyze_feature_importance(model, features, feature_names)
# 获取历史数据
historical_data = load_historical_sales_data(product_id)
# 生成解释
explanation = {
'feature_importance': feature_importance,
'similar_patterns': find_similar_historical_patterns(predictions, historical_data),
'anomalies': detect_and_explain_anomalies(predictions, calculate_historical_stats(historical_data))
}
# 生成总结
explanation['summary'] = generate_explanation_summary(predictions, explanation)
return explanation
B. API端点实现
# 在api.py中添加
@app.route('/api/prediction/explain', methods=['POST'])
def explain_prediction():
"""
提供预测结果的详细解释
"""
try:
data = request.json
product_id = data.get('product_id')
model_type = data.get('model_type')
future_days = data.get('future_days', 7)
# 验证参数
if not product_id or not model_type:
return jsonify({"status": "error", "error": "缺少必要参数"}), 400
# 获取预测结果和特征
predictions, features = load_model_and_predict_with_features(
product_id, model_type, future_days
)
# 生成解释
explanation = explain_model_prediction(
product_id, model_type, predictions, features
)
return jsonify({
"status": "success",
"product_id": product_id,
"model_type": model_type,
"predictions": predictions.tolist(),
"explanation": explanation
})
except Exception as e:
return jsonify({"status": "error", "error": str(e)}), 500
3. UI实现示例
<!-- 在PredictionView.vue中添加 -->
<template>
<div>
<!-- 现有预测结果展示 -->
<div class="prediction-results">
<!-- ... 现有代码 ... -->
</div>
<!-- 新增预测解释面板 -->
<el-collapse v-if="predictionExplanation">
<el-collapse-item title="预测结果解释" name="explanation">
<div class="explanation-summary">
<el-alert
:title="predictionExplanation.summary"
type="info"
:closable="false"
show-icon
></el-alert>
</div>
<!-- 关键影响因素 -->
<div class="key-factors-section">
<h4>关键影响因素</h4>
<el-table
:data="keyFactors"
style="width: 100%"
>
<el-table-column prop="factor" label="因素名称"></el-table-column>
<el-table-column prop="importance" label="重要性">
<template slot-scope="scope">
<el-progress :percentage="scope.row.importance * 100"></el-progress>
</template>
</el-table-column>
<el-table-column prop="impact" label="影响方向">
<template slot-scope="scope">
<span :class="scope.row.impact > 0 ? 'positive-impact' : 'negative-impact'">
{{ scope.row.impact > 0 ? '正面影响' : '负面影响' }}
</span>
</template>
</el-table-column>
</el-table>
</div>
<!-- 异常值检测 -->
<div v-if="predictionExplanation.anomalies && predictionExplanation.anomalies.length > 0" class="anomalies-section">
<h4>异常值检测</h4>
<el-card v-for="(anomaly, index) in predictionExplanation.anomalies" :key="index" class="anomaly-card">
<div slot="header">
<span>第{{ anomaly.day + 1 }}天异常: {{ anomaly.value }}</span>
</div>
<p>{{ anomaly.explanation }}</p>
</el-card>
</div>
<!-- 相似历史模式 -->
<div v-if="predictionExplanation.similar_patterns && predictionExplanation.similar_patterns.length > 0" class="similar-patterns-section">
<h4>相似历史模式</h4>
<el-tabs>
<el-tab-pane
v-for="(pattern, index) in predictionExplanation.similar_patterns.slice(0, 3)"
:key="index"
:label="`模式 ${index + 1} (相似度: ${(pattern.similarity * 100).toFixed(1)}%)`"
>
<div class="pattern-chart">
<line-chart :chart-data="getPatternChartData(pattern)"></line-chart>
</div>
</el-tab-pane>
</el-tabs>
</div>
</el-collapse-item>
</el-collapse>
</div>
</template>
<script>
export default {
// ... 现有代码 ...
data() {
return {
// ... 现有数据 ...
predictionExplanation: null,
keyFactors: []
};
},
methods: {
// ... 现有方法 ...
async getPrediction() {
// 获取预测结果
const response = await this.fetchPrediction();
// 获取预测解释
this.fetchPredictionExplanation();
},
async fetchPredictionExplanation() {
try {
const response = await fetch('/api/prediction/explain', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
product_id: this.form.product_id,
model_type: this.form.model_type,
future_days: this.form.future_days
})
});
const data = await response.json();
if (data.status === 'success') {
this.predictionExplanation = data.explanation;
this.keyFactors = this.formatKeyFactors(data.explanation.feature_importance);
}
} catch (error) {
console.error('获取预测解释失败:', error);
}
},
formatKeyFactors(featureImportance) {
// 将特征重要性数据转换为表格数据
return Object.entries(featureImportance)
.map(([factor, value]) => ({
factor,
importance: Math.abs(value),
impact: value
}))
.sort((a, b) => b.importance - a.importance)
.slice(0, 5); // 只显示前5个最重要的因素
},
getPatternChartData(pattern) {
// 准备图表数据
return {
labels: Array.from({length: pattern.data.length}, (_, i) => `Day ${i+1}`),
datasets: [{
label: '历史销量',
data: pattern.data,
borderColor: '#409EFF',
fill: false
}]
};
}
}
};
</script>
五、应用场景与优势 🌟
1. 应用场景
- 库存管理决策支持:解释预测结果背后的原因,帮助制定更精准的库存计划
- 销售策略优化:理解影响销量的关键因素,优化促销和定价策略
- 异常情况预警:提前识别可能的销售异常,制定应对措施
- 多模型比较分析:解释不同模型预测结果的差异原因,选择最适合的模型
2. 系统优势
- 提高可解释性:将"黑盒"模型转变为可理解的决策支持工具
- 增强用户信任:通过解释预测背后的逻辑,增强用户对预测结果的信任
- 辅助决策制定:提供数据支持的建议,帮助用户做出更明智的决策
- 持续学习优化:通过解释系统,识别模型的不足和改进方向
3. 未来扩展方向
- 交互式解释:允许用户通过调整输入参数,实时观察对预测结果的影响
- 场景模拟:基于不同假设条件(如天气变化、促销力度)模拟预测结果
- 自动化建议系统:根据预测解释自动生成库存管理和销售策略建议
- 多维度可视化:提供更丰富的可视化工具,展示预测结果与各因素的关系 </rewritten_file>