文章目录[隐藏]
WordPress柔性供应链需求预测模块的开发与应用教程
引言:供应链数字化转型的必要性
在当今快速变化的商业环境中,供应链管理已成为企业竞争力的核心要素。传统供应链系统往往缺乏灵活性,难以应对市场需求波动、原材料供应不稳定等挑战。WordPress作为全球最流行的内容管理系统,不仅适用于网站建设,通过扩展开发也能成为强大的企业管理平台。本文将详细介绍如何在WordPress中开发一个柔性供应链需求预测模块,帮助企业实现数据驱动的智能决策。
模块架构设计
系统整体架构
我们的柔性供应链需求预测模块将采用分层架构设计:
- 数据层:负责收集和存储历史销售数据、库存数据、市场趋势数据等
- 处理层:包含数据清洗、特征工程和预测算法
- 应用层:提供用户界面和API接口
- 展示层:可视化预测结果和报表
技术栈选择
- WordPress作为基础平台
- PHP 7.4+ 作为后端语言
- MySQL 8.0+ 作为数据库
- Python 3.8+ 用于机器学习算法(通过REST API集成)
- JavaScript/Chart.js 用于数据可视化
- WooCommerce(可选)用于获取销售数据
数据库设计与实现
创建预测数据表
-- 创建需求预测主表
CREATE TABLE wp_supply_chain_forecast (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id INT NOT NULL,
forecast_date DATE NOT NULL,
predicted_demand DECIMAL(10, 2) NOT NULL,
confidence_interval_lower DECIMAL(10, 2),
confidence_interval_upper DECIMAL(10, 2),
algorithm_used VARCHAR(50),
actual_demand DECIMAL(10, 2) DEFAULT NULL,
forecast_error DECIMAL(10, 2) DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_product_date (product_id, forecast_date)
);
-- 创建历史销售数据表
CREATE TABLE wp_sales_history (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id INT NOT NULL,
sale_date DATE NOT NULL,
quantity_sold INT NOT NULL,
price DECIMAL(10, 2),
promotion_flag TINYINT(1) DEFAULT 0,
seasonality_factor DECIMAL(5, 2) DEFAULT 1.00,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_product_sale_date (product_id, sale_date)
);
-- 创建外部因素表
CREATE TABLE wp_external_factors (
id INT AUTO_INCREMENT PRIMARY KEY,
factor_date DATE NOT NULL,
weather_index DECIMAL(5, 2),
economic_indicator DECIMAL(8, 2),
competitor_activity_level DECIMAL(5, 2),
special_event_flag TINYINT(1) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY unique_date (factor_date)
);
核心预测算法实现
PHP预测引擎类
<?php
/**
* WordPress柔性供应链需求预测模块
* 预测引擎核心类
*/
class SupplyChainForecastEngine {
private $db;
private $table_prefix;
/**
* 构造函数
*/
public function __construct() {
global $wpdb;
$this->db = $wpdb;
$this->table_prefix = $wpdb->prefix;
}
/**
* 移动平均法预测
* @param int $product_id 产品ID
* @param int $periods 预测周期数
* @param int $window_size 移动窗口大小
* @return array 预测结果
*/
public function movingAverageForecast($product_id, $periods = 30, $window_size = 7) {
// 获取历史销售数据
$history_table = $this->table_prefix . 'sales_history';
$query = $this->db->prepare(
"SELECT sale_date, quantity_sold
FROM {$history_table}
WHERE product_id = %d
ORDER BY sale_date DESC
LIMIT %d",
$product_id,
$window_size * 3 // 获取足够的历史数据
);
$historical_data = $this->db->get_results($query, ARRAY_A);
if (empty($historical_data)) {
return ['error' => '没有足够的历史数据'];
}
// 提取销售量数据
$sales = array_column($historical_data, 'quantity_sold');
// 计算移动平均值
$forecasts = [];
for ($i = 0; $i < $periods; $i++) {
// 获取最近window_size个数据点
$recent_sales = array_slice($sales, $i, $window_size);
// 如果数据不足,使用可用数据
if (count($recent_sales) < $window_size) {
$recent_sales = array_slice($sales, 0, $window_size);
}
// 计算平均值
$average = array_sum($recent_sales) / count($recent_sales);
// 添加季节性调整(简化示例)
$seasonal_factor = $this->calculateSeasonalFactor($product_id, $i);
$adjusted_forecast = $average * $seasonal_factor;
$forecasts[] = [
'period' => $i + 1,
'forecast' => round($adjusted_forecast, 2),
'method' => 'moving_average',
'window_size' => $window_size
];
}
return $forecasts;
}
/**
* 指数平滑法预测
* @param int $product_id 产品ID
* @param int $periods 预测周期数
* @param float $alpha 平滑系数 (0-1)
* @return array 预测结果
*/
public function exponentialSmoothingForecast($product_id, $periods = 30, $alpha = 0.3) {
$history_table = $this->table_prefix . 'sales_history';
// 获取历史数据
$query = $this->db->prepare(
"SELECT quantity_sold
FROM {$history_table}
WHERE product_id = %d
ORDER BY sale_date DESC
LIMIT 100",
$product_id
);
$historical_data = $this->db->get_col($query);
if (count($historical_data) < 2) {
return ['error' => '需要至少2个历史数据点'];
}
// 反转数组使数据按时间顺序排列
$historical_data = array_reverse($historical_data);
// 初始化
$forecasts = [];
$last_forecast = $historical_data[0];
// 生成预测
for ($i = 0; $i < $periods; $i++) {
if ($i < count($historical_data)) {
// 使用历史数据更新预测
$last_forecast = $alpha * $historical_data[$i] + (1 - $alpha) * $last_forecast;
}
// 添加趋势调整(霍尔特线性趋势法简化版)
$trend_adjustment = $this->calculateTrendAdjustment($historical_data);
$adjusted_forecast = $last_forecast + $trend_adjustment * ($i + 1);
$forecasts[] = [
'period' => $i + 1,
'forecast' => round(max(0, $adjusted_forecast), 2), // 确保非负
'method' => 'exponential_smoothing',
'alpha' => $alpha
];
}
return $forecasts;
}
/**
* 计算季节性因子
* @param int $product_id 产品ID
* @param int $period_offset 周期偏移
* @return float 季节性因子
*/
private function calculateSeasonalFactor($product_id, $period_offset) {
// 简化版季节性因子计算
// 实际应用中应根据历史数据计算真实的季节性模式
$month = date('n', strtotime("+{$period_offset} days"));
// 示例季节性模式(可根据实际数据调整)
$seasonal_patterns = [
12 => 1.5, // 12月:节日季,需求增加50%
1 => 1.2, // 1月:需求增加20%
6 => 0.8, // 6月:需求减少20%
7 => 0.7, // 7月:需求减少30%
];
return $seasonal_patterns[$month] ?? 1.0;
}
/**
* 计算趋势调整
* @param array $historical_data 历史数据
* @return float 趋势值
*/
private function calculateTrendAdjustment($historical_data) {
if (count($historical_data) < 2) {
return 0;
}
// 简单线性趋势计算
$n = count($historical_data);
$sum_x = 0;
$sum_y = 0;
$sum_xy = 0;
$sum_x2 = 0;
for ($i = 0; $i < $n; $i++) {
$sum_x += $i;
$sum_y += $historical_data[$i];
$sum_xy += $i * $historical_data[$i];
$sum_x2 += $i * $i;
}
// 计算斜率(趋势)
$slope = ($n * $sum_xy - $sum_x * $sum_y) / ($n * $sum_x2 - $sum_x * $sum_x);
return $slope;
}
/**
* 保存预测结果到数据库
* @param int $product_id 产品ID
* @param array $forecasts 预测结果数组
* @return bool 保存是否成功
*/
public function saveForecasts($product_id, $forecasts) {
$forecast_table = $this->table_prefix . 'supply_chain_forecast';
foreach ($forecasts as $forecast) {
$forecast_date = date('Y-m-d', strtotime("+{$forecast['period']} days"));
$data = [
'product_id' => $product_id,
'forecast_date' => $forecast_date,
'predicted_demand' => $forecast['forecast'],
'algorithm_used' => $forecast['method'],
'confidence_interval_lower' => $forecast['forecast'] * 0.8, // 80%置信下限
'confidence_interval_upper' => $forecast['forecast'] * 1.2, // 80%置信上限
];
$format = ['%d', '%s', '%f', '%s', '%f', '%f'];
$this->db->insert($forecast_table, $data, $format);
}
return true;
}
}
?>
WordPress插件集成
主插件文件
<?php
/**
* Plugin Name: 柔性供应链需求预测模块
* Plugin URI: https://yourwebsite.com/
* Description: WordPress柔性供应链需求预测系统
* Version: 1.0.0
* Author: Your Name
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('SC_FORECAST_VERSION', '1.0.0');
define('SC_FORECAST_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('SC_FORECAST_PLUGIN_URL', plugin_dir_url(__FILE__));
// 包含核心类
require_once SC_FORECAST_PLUGIN_DIR . 'includes/class-forecast-engine.php';
require_once SC_FORECAST_PLUGIN_DIR . 'includes/class-forecast-admin.php';
require_once SC_FORECAST_PLUGIN_DIR . 'includes/class-data-collector.php';
/**
* 插件激活时创建数据库表
*/
register_activation_hook(__FILE__, 'sc_forecast_activate');
function sc_forecast_activate() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// 创建数据库表的SQL语句(同上文数据库设计部分)
// 这里应包含完整的建表语句
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 设置默认选项
add_option('sc_forecast_version', SC_FORECAST_VERSION);
}
/**
* 初始化插件
*/
function sc_forecast_init() {
// 初始化预测引擎
$forecast_engine = new SupplyChainForecastEngine();
// 初始化管理界面
if (is_admin()) {
$admin_interface = new ForecastAdminInterface();
}
// 初始化数据收集器
$data_collector = new DataCollector();
}
add_action('plugins_loaded', 'sc_forecast_init');
/**
* 添加管理菜单
*/
function sc_forecast_add_admin_menu() {
add_menu_page(
'供应链预测',
'供应链预测',
'manage_options',
'supply-chain-forecast',
'sc_forecast_admin_page',
'dashicons-chart-line',
30
);
add_submenu_page(
'supply-chain-forecast',
'预测设置',
'预测设置',
'manage_options',
'sc-forecast-settings',
'sc_forecast_settings_page'
);
add_submenu_page(
'supply-chain-forecast',
'预测报告',
'预测报告',
'manage_options',
'sc-forecast-reports',
'sc_forecast_reports_page'
);
}
add_action('admin_menu', 'sc_forecast_add_admin_menu');
/**
* 主管理页面
*/
function sc_forecast_admin_page() {
?>
<div class="wrap">
<h1>柔性供应链需求预测系统</h1>
<div class="sc-forecast-dashboard">
<div class="sc-row">
<div class="sc-col-6">
<div class="sc-card">
<h3>快速预测</h3>
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
<input type="hidden" name="action" value="run_forecast">
<?php wp_nonce_field('run_forecast_action', 'run_forecast_nonce'); ?>
<p>
<label for="product_id">选择产品:</label>
<select name="product_id" id="product_id" required>
<option value="">请选择产品</option>
<!-- 这里应动态加载产品选项 -->
</select>
</p>
<p>
<label for="forecast_method">预测方法:</label>
<select name="forecast_method" id="forecast_method">
<option value="moving_average">移动平均法</option>
<option value="exponential_smoothing">指数平滑法</option>
<option value="ensemble">组合预测</option>
</select>
</p>
<p>
<label for="forecast_periods">预测周期(天):</label>
<input type="number" name="forecast_periods" id="forecast_periods"
value="30" min="7" max="365">
</p>
<p>
<input type="submit" class="button button-primary" value="开始预测">
</p>
</form>
</div>
</div>
<div class="sc-col-6">
<div class="sc-card">
<h3>预测概览</h3>
<div id="forecast-chart-container">
<canvas id="forecast-chart"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// 使用Chart.js显示预测图表
document.addEventListener('DOMContentLoaded', function() {
var ctx = document.getElementById('forecast-chart').getContext('2d');
var forecastChart = new Chart(ctx, {
type: 'line',
data: {
labels: [], // 日期标签
datasets: [{
label: '预测需求',
data: [], // 预测数据
borderColor: 'rgb(75, 192, 192)',
tension: 0.1
}, {
label: '实际需求',
data: [], // 实际数据
borderColor: 'rgb(255, 99, 132)',
tension: 0.1
}]
},
options: {
responsive: true,
plugins: {
title: {
display: true,
text: '需求预测趋势图'
}
},
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: '需求量'
}
}
}
}
});
// 加载初始数据
loadForecastData();
function loadForecastData() {
jQuery.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'get_forecast_data',
product_id: 1 // 默认产品ID
},
success: function(response) {
if (response.success) {
forecastChart.data.labels = response.data.dates;
forecastChart.data.datasets[0].data = response.data.forecasts;
forecastChart.data.datasets[1].data = response.data.actuals;
forecastChart.update();
}
}
});
}
});
</script>
<?php
}
?>
数据可视化与报表
预测结果可视化
// 高级可视化组件 - 预测仪表板
class ForecastDashboard {
constructor(containerId) {
this.container = document.getElementById(containerId);
this.charts = {};
this.init();
}
init() {
this.createLayout();
this.loadData();
this.setupEventListeners();
}
createLayout() {
this.container.innerHTML = `
<div class="forecast-dashboard">
<div class="dashboard-header">
<h2>供应链需求预测仪表板</h2>
<div class="dashboard-controls">
<select id="timeRange" class="form-control">
<option value="7">最近7天</option>
<option value="30" selected>最近30天</option>
<option value="90">最近90天</option>
<option value="365">最近1年</option>
</select>
<select id="productFilter" class="form-control">
<option value="all">所有产品</option>
</select>
<button id="refreshBtn" class="btn btn-primary">刷新数据</button>
<button id="exportBtn" class="btn btn-secondary">导出报告</button>
</div>
</div>
<div class="dashboard-metrics">
<div class="metric-card">
<div class="metric-title">平均预测准确率</div>
<div class="metric-value" id="accuracyRate">--%</div>
<div class="metric-trend" id="accuracyTrend"></div>
</div>
<div class="metric-card">
<div class="metric-title">总预测需求</div>
<div class="metric-value" id="totalForecast">--</div>
<div class="metric-subtitle">未来30天</div>
</div>
<div class="metric-card">
<div class="metric-title">库存周转率</div>
<div class="metric-value" id="turnoverRate">--</div>
<div class="metric-trend" id="turnoverTrend"></div>
</div>
<div class="metric-card">
<div class="metric-title">预测置信度</div>
<div class="metric-value" id="confidenceLevel">--%</div>
<div class="metric-subtitle">平均置信区间</div>
</div>
</div>
<div class="dashboard-charts">
<div class="chart-container full-width">
<canvas id="forecastTrendChart"></canvas>
</div>
<div class="chart-container">
<canvas id="accuracyChart"></canvas>
</div>
<div class="chart-container">
<canvas id="productMixChart"></canvas>
</div>
</div>
<div class="dashboard-table">
<h3>详细预测数据</h3>
<table id="forecastTable" class="display">
<thead>
<tr>
<th>产品名称</th>
<th>预测日期</th>
<th>预测需求</th>
<th>实际需求</th>
<th>预测误差</th>
<th>置信区间</th>
<th>算法</th>
<th>建议采购量</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
`;
}
async loadData() {
try {
const response = await fetch(ajaxurl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
action: 'get_forecast_dashboard_data',
time_range: document.getElementById('timeRange').value,
product_id: document.getElementById('productFilter').value
})
});
const data = await response.json();
if (data.success) {
this.updateMetrics(data.data.metrics);
this.renderCharts(data.data.charts);
this.updateTable(data.data.table);
this.updateProductFilter(data.data.products);
}
} catch (error) {
console.error('加载数据失败:', error);
}
}
updateMetrics(metrics) {
document.getElementById('accuracyRate').textContent =
`${(metrics.accuracy * 100).toFixed(1)}%`;
document.getElementById('totalForecast').textContent =
metrics.total_forecast.toLocaleString();
document.getElementById('turnoverRate').textContent =
metrics.turnover_rate.toFixed(2);
document.getElementById('confidenceLevel').textContent =
`${(metrics.confidence * 100).toFixed(1)}%`;
// 更新趋势指示器
this.updateTrendIndicator('accuracyTrend', metrics.accuracy_trend);
this.updateTrendIndicator('turnoverTrend', metrics.turnover_trend);
}
updateTrendIndicator(elementId, trend) {
const element = document.getElementById(elementId);
if (trend > 0) {
element.innerHTML = `<span class="trend-up">↑ ${trend}%</span>`;
element.className = 'metric-trend trend-up';
} else if (trend < 0) {
element.innerHTML = `<span class="trend-down">↓ ${Math.abs(trend)}%</span>`;
element.className = 'metric-trend trend-down';
} else {
element.innerHTML = `<span class="trend-neutral">→ 持平</span>`;
element.className = 'metric-trend trend-neutral';
}
}
renderCharts(chartData) {
// 趋势图
if (!this.charts.trendChart) {
const ctx = document.getElementById('forecastTrendChart').getContext('2d');
this.charts.trendChart = new Chart(ctx, {
type: 'line',
data: {
labels: chartData.trend.labels,
datasets: [{
label: '预测需求',
data: chartData.trend.forecast,
borderColor: '#4CAF50',
backgroundColor: 'rgba(76, 175, 80, 0.1)',
fill: true,
tension: 0.4
}, {
label: '实际需求',
data: chartData.trend.actual,
borderColor: '#2196F3',
borderDash: [5, 5],
tension: 0.4
}, {
label: '置信区间上限',
data: chartData.trend.upper,
borderColor: 'rgba(76, 175, 80, 0.3)',
borderDash: [2, 2],
fill: false,
tension: 0.4
}, {
label: '置信区间下限',
data: chartData.trend.lower,
borderColor: 'rgba(76, 175, 80, 0.3)',
borderDash: [2, 2],
fill: '-1',
tension: 0.4
}]
},
options: {
responsive: true,
plugins: {
title: {
display: true,
text: '需求预测趋势与置信区间'
},
tooltip: {
mode: 'index',
intersect: false
}
},
scales: {
x: {
title: {
display: true,
text: '日期'
}
},
y: {
title: {
display: true,
text: '需求量'
},
beginAtZero: true
}
}
}
});
} else {
this.charts.trendChart.data = {
labels: chartData.trend.labels,
datasets: this.charts.trendChart.data.datasets.map((dataset, index) => ({
...dataset,
data: index === 0 ? chartData.trend.forecast :
index === 1 ? chartData.trend.actual :
index === 2 ? chartData.trend.upper : chartData.trend.lower
}))
};
this.charts.trendChart.update();
}
// 准确率图
if (!this.charts.accuracyChart) {
const ctx = document.getElementById('accuracyChart').getContext('2d');
this.charts.accuracyChart = new Chart(ctx, {
type: 'bar',
data: {
labels: chartData.accuracy.labels,
datasets: [{
label: '预测准确率',
data: chartData.accuracy.values,
backgroundColor: chartData.accuracy.values.map(value =>
value >= 90 ? '#4CAF50' :
value >= 80 ? '#FFC107' : '#F44336'
),
borderColor: '#333',
borderWidth: 1
}]
},
options: {
responsive: true,
plugins: {
title: {
display: true,
text: '各算法预测准确率对比'
}
},
scales: {
y: {
beginAtZero: true,
max: 100,
title: {
display: true,
text: '准确率 (%)'
}
}
}
}
});
}
// 产品结构图
if (!this.charts.productMixChart) {
const ctx = document.getElementById('productMixChart').getContext('2d');
this.charts.productMixChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: chartData.productMix.labels,
datasets: [{
data: chartData.productMix.values,
backgroundColor: [
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0',
'#9966FF', '#FF9F40', '#8AC926', '#1982C4'
]
}]
},
options: {
responsive: true,
plugins: {
title: {
display: true,
text: '预测需求产品结构'
},
legend: {
position: 'right'
}
}
}
});
}
}
updateTable(tableData) {
const tableBody = document.querySelector('#forecastTable tbody');
tableBody.innerHTML = '';
tableData.forEach(row => {
const tr = document.createElement('tr');
// 计算预测误差百分比
const errorPercent = row.actual_demand ?
((row.forecast_error / row.actual_demand) * 100).toFixed(1) : '--';
// 根据误差大小设置颜色
const errorClass = Math.abs(errorPercent) <= 10 ? 'error-low' :
Math.abs(errorPercent) <= 20 ? 'error-medium' : 'error-high';
tr.innerHTML = `
<td>${row.product_name}</td>
<td>${row.forecast_date}</td>
<td>${row.predicted_demand.toLocaleString()}</td>
<td>${row.actual_demand ? row.actual_demand.toLocaleString() : '--'}</td>
<td class="${errorClass}">
${row.forecast_error ? `${row.forecast_error.toLocaleString()} (${errorPercent}%)` : '--'}
</td>
<td>${row.confidence_lower.toLocaleString()} - ${row.confidence_upper.toLocaleString()}</td>
<td>${this.getAlgorithmName(row.algorithm_used)}</td>
<td>
<span class="recommended-qty">
${this.calculateRecommendedQuantity(row)}
</span>
</td>
`;
tableBody.appendChild(tr);
});
}
getAlgorithmName(algorithmCode) {
const algorithms = {
'moving_average': '移动平均',
'exponential_smoothing': '指数平滑',
'arima': 'ARIMA模型',
'ensemble': '组合预测',
'neural_network': '神经网络'
};
return algorithms[algorithmCode] || algorithmCode;
}
calculateRecommendedQuantity(row) {
// 基于预测需求、当前库存和安全库存计算建议采购量
const safetyStock = row.predicted_demand * 0.2; // 20%的安全库存
const recommended = Math.max(0,
row.predicted_demand + safetyStock - (row.current_stock || 0)
);
return Math.ceil(recommended).toLocaleString();
}
updateProductFilter(products) {
const filter = document.getElementById('productFilter');
filter.innerHTML = '<option value="all">所有产品</option>';
products.forEach(product => {
const option = document.createElement('option');
option.value = product.id;
option.textContent = product.name;
filter.appendChild(option);
});
}
setupEventListeners() {
document.getElementById('refreshBtn').addEventListener('click', () => this.loadData());
document.getElementById('timeRange').addEventListener('change', () => this.loadData());
document.getElementById('productFilter').addEventListener('change', () => this.loadData());
document.getElementById('exportBtn').addEventListener('click', () => this.exportReport());
}
async exportReport() {
try {
const response = await fetch(ajaxurl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
action: 'export_forecast_report',
time_range: document.getElementById('timeRange').value,
product_id: document.getElementById('productFilter').value,
report_type: 'detailed'
})
});
if (response.ok) {
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `供应链预测报告_${new Date().toISOString().split('T')[0]}.xlsx`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}
} catch (error) {
console.error('导出报告失败:', error);
alert('导出报告失败,请重试');
}
}
}
// 初始化仪表板
document.addEventListener('DOMContentLoaded', function() {
const dashboard = new ForecastDashboard('forecastDashboardContainer');
});
高级预测功能:机器学习集成
Python机器学习API服务
# ml_forecast_service.py
"""
WordPress供应链预测的机器学习API服务
使用Flask提供RESTful API接口
"""
import pandas as pd
import numpy as np
from flask import Flask, request, jsonify
from flask_cors import CORS
import joblib
import mysql.connector
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')
# 机器学习库
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import TimeSeriesSplit
import xgboost as xgb
from prophet import Prophet
app = Flask(__name__)
CORS(app)
class AdvancedForecastModel:
"""高级预测模型类"""
def __init__(self):
self.models = {}
self.scaler = StandardScaler()
self.db_config = {
'host': 'localhost',
'user': 'wordpress_user',
'password': 'your_password',
'database': 'wordpress_db'
}
def connect_db(self):
"""连接MySQL数据库"""
return mysql.connector.connect(**self.db_config)
def load_training_data(self, product_id, lookback_days=365):
"""加载训练数据"""
conn = self.connect_db()
query = """
SELECT
sh.sale_date,
sh.quantity_sold,
sh.price,
sh.promotion_flag,
sh.seasonality_factor,
ef.weather_index,
ef.economic_indicator,
ef.competitor_activity_level,
ef.special_event_flag,
DAYOFWEEK(sh.sale_date) as day_of_week,
MONTH(sh.sale_date) as month,
DAY(sh.sale_date) as day,
CASE
WHEN DAYOFWEEK(sh.sale_date) IN (1, 7) THEN 1
ELSE 0
END as is_weekend,
LAG(sh.quantity_sold, 1) OVER (ORDER BY sh.sale_date) as lag_1,
LAG(sh.quantity_sold, 7) OVER (ORDER BY sh.sale_date) as lag_7,
LAG(sh.quantity_sold, 30) OVER (ORDER BY sh.sale_date) as lag_30,
AVG(sh.quantity_sold) OVER (
ORDER BY sh.sale_date
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
) as moving_avg_7,
AVG(sh.quantity_sold) OVER (
ORDER BY sh.sale_date
ROWS BETWEEN 29 PRECEDING AND CURRENT ROW
) as moving_avg_30
FROM wp_sales_history sh
LEFT JOIN wp_external_factors ef ON sh.sale_date = ef.factor_date
WHERE sh.product_id = %s
AND sh.sale_date >= DATE_SUB(CURDATE(), INTERVAL %s DAY)
ORDER BY sh.sale_date
"""
df = pd.read_sql(query, conn, params=(product_id, lookback_days))
conn.close()
if df.empty:
return None
# 处理缺失值
df.fillna(method='ffill', inplace=True)
df.fillna(0, inplace=True)
return df
def prepare_features(self, df):
"""准备特征数据"""
# 分离特征和目标变量
features = df.drop(['sale_date', 'quantity_sold'], axis=1)
target = df['quantity_sold']
# 标准化数值特征
numeric_features = features.select_dtypes(include=[np.number]).columns
features[numeric_features] = self.scaler.fit_transform(features[numeric_features])
return features, target
def train_prophet_model(self, df, periods=30):
"""使用Facebook Prophet进行时间序列预测"""
# 准备Prophet数据格式
prophet_df = df[['sale_date', 'quantity_sold']].copy()
prophet_df.columns = ['ds', 'y']
# 添加节假日信息
holidays = pd.DataFrame({
'holiday': 'promotion',
'ds': pd.to_datetime(df[df['promotion_flag'] == 1]['sale_date']),
