个人编程网站

进销存(JXC)软件开发技术积累与分享

进销存系统智能需求预测与供应链协同

引言

需求预测是进销存系统的核心功能之一,准确的需求预测可以优化库存水平、减少资金占用、提高供货及时率。本文将介绍如何利用机器学习算法构建智能需求预测系统,实现供应链的协同优化。

需求预测框架

智能需求预测的整体架构:

层次 组件 职责
数据层 销售数据、库存数据、外部数据 数据采集、清洗、存储
特征层 时间特征、统计特征、外部特征 特征工程、特征选择
模型层 ARIMA、Prophet、LSTM、XGBoost 预测模型训练与推理
应用层 采购建议、库存优化、预警提醒 预测结果应用

时间序列预测模型

基于历史销售数据的时间序列预测:

// 时间序列预测器
class TimeSeriesForecaster {
  constructor(config) {
    this.predictionHorizon = config.predictionHorizon || 30;  // 预测天数
    this.confidenceLevel = config.confidenceLevel || 0.95;
    this.seasonality = config.seasonality || { weekly: 7, yearly: 365 };
  }

  // 预测主方法
  async forecast(productId, historicalData) {
    // 数据预处理
    const cleanData = this.preprocess(historicalData);

    // 多个模型预测
    const predictions = await Promise.all([
      this.arimaForecast(cleanData),
      this.prophetForecast(cleanData),
      this.exponentialSmoothing(cleanData)
    ]);

    // 模型融合
    const ensembleResult = this.ensemblePredictions(predictions);

    // 计算置信区间
    const confidenceInterval = this.calculateConfidenceInterval(
      cleanData,
      ensembleResult
    );

    return {
      productId,
      predictions: ensembleResult,
      confidenceLower: confidenceInterval.lower,
      confidenceUpper: confidenceInterval.upper,
      accuracy: this.calculateAccuracy(cleanData, ensembleResult)
    };
  }

  // ARIMA 模型预测
  async arimaForecast(data) {
    // 差分处理使序列平稳
    const d = this.calculateDifferencingOrder(data);
    const differenced = this.difference(data, d);

    // ACF 和 PACF 分析确定参数
    const { p, q } = this.identifyOrders(differenced);

    // 拟合 ARIMA 模型
    const model = this.fitARIMA(data, p, d, q);

    // 多步预测
    return this.forecastSteps(model, this.predictionHorizon);
  }

  // 指数平滑预测
  exponentialSmoothing(data) {
    const alpha = 0.3;  // 平滑系数
    const beta = 0.1;   // 趋势平滑系数
    const gamma = 0.2;  // 季节性平滑系数

    let level = data[0];
    let trend = 0;
    const seasonal = new Array(this.seasonality.weekly).fill(1);

    const fitted = [];
    const residuals = [];

    for (let i = 0; i < data.length; i++) {
      const season = seasonal[i % this.seasonality.weekly];

      // 计算预测值
      const yhat = (level + trend) * season;
      fitted.push(yhat);

      // 计算残差
      residuals.push(data[i] - yhat);

      // 更新参数
      const newLevel = alpha * (data[i] / season) + (1 - alpha) * (level + trend);
      const newTrend = beta * (newLevel - level) + (1 - beta) * trend;
      const newSeason = gamma * (data[i] / newLevel) + (1 - gamma) * season;

      level = newLevel;
      trend = newTrend;
      seasonal[i % this.seasonality.weekly] = newSeason;
    }

    // 未来预测
    const forecasts = [];
    for (let h = 1; h <= this.predictionHorizon; h++) {
      const futureSeason = seasonal[h % this.seasonality.weekly];
      forecasts.push((level + h * trend) * futureSeason);
    }

    return { forecasts, weight: 0.3 };
  }

  // Prophet 模型预测
  async prophetForecast(data) {
    // 将数据转换为 Prophet 格式
    const df = this.toProphetFormat(data);

    // 拟合模型
    const model = {
      trend: this.fitTrend(df),
      seasonality: this.extractSeasonality(df),
      holidays: this.extractHolidays(df)
    };

    // 生成未来日期
    const futureDates = this.generateFutureDates(this.predictionHorizon);

    // 预测
    const forecasts = futureDates.map(date => {
      let prediction = model.trend.predict(date);

      // 叠加季节性
      prediction += model.seasonality.weekly(date);
      prediction += model.seasonality.yearly(date);

      // 叠加节假日效应
      prediction += model.holidays.effect(date);

      return Math.max(0, prediction);
    });

    return { forecasts, weight: 0.4 };
  }

  // 模型融合
  ensemblePredictions(predictions) {
    const weights = predictions.map(p => p.weight);
    const totalWeight = weights.reduce((a, b) => a + b, 0);

    const normalizedWeights = weights.map(w => w / totalWeight);

    const ensemble = [];

    for (let i = 0; i < this.predictionHorizon; i++) {
      let sum = 0;
      for (let j = 0; j < predictions.length; j++) {
        sum += predictions[j].forecasts[i] * normalizedWeights[j];
      }
      ensemble.push(sum);
    }

    return ensemble;
  }

  // 置信区间计算
  calculateConfidenceInterval(data, predictions) {
    // 计算历史预测误差
    const errors = this.calculatePredictionErrors(data, predictions.slice(0, data.length));

    const meanError = errors.reduce((a, b) => a + b, 0) / errors.length;
    const stdError = Math.sqrt(
      errors.reduce((sum, e) => sum + Math.pow(e - meanError, 2), 0) / errors.length
    );

    // z 值查表(95%置信度)
    const zValue = 1.96;

    const lower = predictions.map(p => Math.max(0, p - zValue * stdError));
    const upper = predictions.map(p => p + zValue * stdError);

    return { lower, upper };
  }
}

特征工程

构建丰富的预测特征:

// 特征工程
class FeatureEngineering {
  constructor() {
    this.featureCache = new Map();
  }

  // 生成完整特征集
  generateFeatures(productId, date, context) {
    const features = {
      // 时间特征
      ...this.extractTimeFeatures(date),

      // 历史销售特征
      ...this.extractSalesFeatures(productId, date),

      // 库存特征
      ...this.extractInventoryFeatures(productId, date),

      // 外部特征
      ...this.extractExternalFeatures(date, context),

      // 交互特征
      ...this.extractInteractionFeatures(productId, date)
    };

    return features;
  }

  // 时间特征提取
  extractTimeFeatures(date) {
    const d = new Date(date);

    return {
      year: d.getFullYear(),
      month: d.getMonth() + 1,
      day: d.getDate(),
      dayOfWeek: d.getDay(),
      dayOfYear: this.getDayOfYear(d),
      weekOfYear: this.getWeekOfYear(d),
      isWeekend: d.getDay() === 0 || d.getDay() === 6,
      isMonthStart: d.getDate() === 1,
      isMonthEnd: d.getDate() === this.getMonthEnd(d),
      isQuarterStart: this.isQuarterStart(d),
      isQuarterEnd: this.isQuarterEnd(d),
      isYearStart: d.getMonth() === 0 && d.getDate() === 1,
      isYearEnd: d.getMonth() === 11 && d.getDate() === 31,
      season: this.getSeason(d),
      // 节假日特征
      isHoliday: this.isHoliday(d),
      isPreHoliday: this.isPreHoliday(d),
      isPostHoliday: this.isPostHoliday(d),
      daysToHoliday: this.daysToHoliday(d),
      holidayDuration: this.getHolidayDuration(d)
    };
  }

  // 历史销售特征
  extractSalesFeatures(productId, date) {
    const history = this.getSalesHistory(productId, date);

    return {
      // 移动平均
      sales_ma_7: this.calculateMA(history, 7),
      sales_ma_14: this.calculateMA(history, 14),
      sales_ma_30: this.calculateMA(history, 30),

      // 指数移动平均
      sales_ema_7: this.calculateEMA(history, 7),
      sales_ema_14: this.calculateEMA(history, 14),

      // 变化率
      sales_change_7: this.calculateChangeRate(history, 7),
      sales_change_14: this.calculateChangeRate(history, 14),
      sales_change_30: this.calculateChangeRate(history, 30),

      // 波动性
      sales_std_7: this.calculateStd(history, 7),
      sales_std_14: this.calculateStd(history, 14),
      sales_std_30: this.calculateStd(history, 30),

      // 同比环比
      sales_yoy: this.calculateYoY(productId, date),   // 同比
      sales_mom: this.calculateMoM(productId, date),   // 环比

      // 累计销售
      cumulative_sales_30: this.calculateCumulative(history, 30),

      // 峰值特征
      sales_max_30: this.calculateMax(history, 30),
      sales_min_30: this.calculateMin(history, 30),

      // 季节性指标
      seasonal_index: this.calculateSeasonalIndex(productId, date)
    };
  }

  // 库存特征
  extractInventoryFeatures(productId, date) {
    const inventory = this.getInventoryLevel(productId, date);
    const safetyStock = this.getSafetyStock(productId);

    return {
      current_stock: inventory,
      safety_stock: safetyStock,
      stock_ratio: inventory / safetyStock,
      is_low_stock: inventory < safetyStock,
      stock_coverage_days: inventory / this.getAvgDailySales(productId),
      reorder_point: this.calculateReorderPoint(productId),
      is_need_reorder: inventory < this.calculateReorderPoint(productId)
    };
  }

  // 外部特征
  extractExternalFeatures(date, context = {}) {
    return {
      // 天气特征(如果有)
      weather: context.weather || 'unknown',
      temperature: context.temperature || 0,

      // 促销活动
      has_promotion: context.hasPromotion || false,
      promotion_discount: context.promotionDiscount || 0,
      promotion_type: context.promotionType || 'none',

      // 竞争对手
      competitor_price_change: context.competitorPriceChange || 0,

      // 经济指标
      consumer_confidence_index: context.cci || 50,

      // 特殊事件
      has_special_event: context.hasSpecialEvent || false,
      event_type: context.eventType || 'none'
    };
  }

  // 同比计算
  calculateYoY(productId, date) {
    const currentDate = new Date(date);
    const lastYearDate = new Date(date);
    lastYearDate.setFullYear(currentDate.getFullYear() - 1);

    const currentSales = this.getSales(productId, date, 30);
    const lastYearSales = this.getSales(productId, lastYearDate, 30);

    if (lastYearSales === 0) return 0;

    return (currentSales - lastYearSales) / lastYearSales;
  }

  // 环比计算
  calculateMoM(productId, date) {
    const currentDate = new Date(date);
    const lastMonthDate = new Date(date);
    lastMonthDate.setMonth(currentDate.getMonth() - 1);

    const currentSales = this.getSales(productId, date, 30);
    const lastMonthSales = this.getSales(productId, lastMonthDate, 30);

    if (lastMonthSales === 0) return 0;

    return (currentSales - lastMonthSales) / lastMonthSales;
  }

  // 季节性指数
  calculateSeasonalIndex(productId, date) {
    const d = new Date(date);
    const month = d.getMonth();

    // 获取该商品历史的月度销售数据
    const monthlySales = this.getMonthlySalesPattern(productId);

    // 计算季节性指数
    const monthlyAvg = monthlySales.reduce((a, b) => a + b, 0) / 12;
    return monthlySales[month] / monthlyAvg;
  }
}

库存优化策略

基于预测的库存优化:

// 库存优化器
class InventoryOptimizer {
  constructor(config) {
    this.serviceLevel = config.serviceLevel || 0.95;
    this.holdingCost = config.holdingCost || 0.2;  // 年持有成本率
    this.orderCost = config.orderCost || 100;      // 每次订货成本
    this.leadTime = config.leadTime || 7;          // 采购提前期(天)
  }

  // 计算安全库存
  calculateSafetyStock(productId, forecast, variability) {
    // 使用改进的安全库存公式
    const z = this.getZScore(this.serviceLevel);
    const sigma = this.calculateDemandVariability(forecast, variability);
    const leadTime = this.getLeadTime(productId);

    // 安全库存 = z * sigma * sqrt(Lead Time)
    return Math.ceil(z * sigma * Math.sqrt(leadTime));
  }

  // 计算需求变异性
  calculateDemandVariability(forecast, variability) {
    // 考虑预测误差
    const forecastError = variability.forecastError || 0.2;
    const demandStd = forecast * forecastError;

    // 考虑需求波动
    const demandVariation = variability.demandVariation || 0.3;

    return Math.max(demandStd, forecast * demandVariation);
  }

  // 计算再订货点
  calculateReorderPoint(productId, forecast, safetyStock) {
    const avgLeadTime = this.getAvgLeadTime(productId);
    const avgDailySales = forecast;

    // 再订货点 = 平均需求 * 平均交货期 + 安全库存
    return Math.ceil(avgDailySales * avgLeadTime + safetyStock);
  }

  // 计算最优订货量(EOQ)
  calculateEOQ(annualDemand, unitCost) {
    // 经济订货量公式
    const eoq = Math.sqrt(
      (2 * annualDemand * this.orderCost) /
      (unitCost * this.holdingCost)
    );

    return Math.ceil(eoq);
  }

  // 生成补货建议
  generateReplenishmentRecommendation(productId, forecast, currentStock) {
    const product = this.getProductInfo(productId);
    const leadTime = this.getLeadTime(productId);

    // 计算各期间预测需求
    const forecastedDemand = forecast.predictions.slice(0, leadTime + 30);
    const totalForecast = forecastedDemand.reduce((a, b) => a + b, 0);

    // 计算安全库存
    const variability = this.getDemandVariability(productId);
    const safetyStock = this.calculateSafetyStock(productId, forecast.predictions[0], variability);

    // 计算再订货点
    const reorderPoint = this.calculateReorderPoint(
      productId,
      forecast.predictions[0],
      safetyStock
    );

    // 检查是否需要补货
    const needsReorder = currentStock <= reorderPoint;
    const stockoutRisk = this.calculateStockoutRisk(currentStock, forecast, leadTime);

    // 计算建议订货量
    const targetStock = Math.ceil(
      forecast.predictions[0] * (leadTime + 30) + safetyStock
    );
    const recommendedOrderQty = Math.max(0, targetStock - currentStock);

    // 检查最小起订量
    const finalOrderQty = Math.max(
      recommendedOrderQty,
      product.minOrderQty || 0
    );

    return {
      productId,
      currentStock,
      safetyStock,
      reorderPoint,
      needsReorder,
      stockoutRisk,
      recommendedOrderQty: finalOrderQty,
      expectedStockAfterOrder: currentStock + finalOrderQty,
      stockoutDate: this.estimateStockoutDate(currentStock, forecast),
      optimalReorderDate: this.calculateOptimalReorderDate(
        currentStock,
        forecast,
        leadTime,
        reorderPoint
      )
    };
  }

  // 计算缺货风险
  calculateStockoutRisk(currentStock, forecast, leadTime) {
    const leadTimeDemand = forecast.predictions.slice(0, leadTime).reduce((a, b) => a + b, 0);
    const variance = this.calculateVariance(forecast.predictions.slice(0, leadTime));

    // 使用正态分布近似
    const z = (currentStock - leadTimeDemand) / Math.sqrt(variance);
    const probability = 1 - this.normalCDF(z);

    return probability;
  }

  // 计算最佳补货日期
  calculateOptimalReorderDate(currentStock, forecast, leadTime, reorderPoint) {
    const dailySales = forecast.predictions[0];

    // 计算多少天后会达到再订货点
    const daysToReorder = currentStock > reorderPoint
      ? (currentStock - reorderPoint) / dailySales
      : 0;

    // 考虑交货期,提前一些天数下单
    const optimalDate = new Date();
    optimalDate.setDate(optimalDate.getDate() + Math.max(0, daysToReorder - leadTime));

    return optimalDate.toISOString().split('T')[0];
  }
}

供应链协同

实现供应链上下游协同:

// 供应链协同平台
class SupplyChainCollaboration {
  constructor() {
    this.vendors = new Map();
    this.distributors = new Map();
  }

  // 需求共享
  async shareDemandForecast(vendorId, forecasts) {
    const vendor = this.vendors.get(vendorId);

    // 发送预测需求给供应商
    await this.sendToVendor(vendorId, {
      type: 'demand_forecast',
      forecasts: forecasts.map(f => ({
        productId: f.productId,
        date: f.date,
        quantity: f.quantity,
        confidence: f.confidence
      })),
      requestDate: new Date().toISOString()
    });

    // 记录共享历史
    await this.logDemandShare(vendorId, forecasts);
  }

  // 供应商响应
  async vendorResponse(vendorId, productId, response) {
    const {
      confirmedDate,
      confirmedQuantity,
      alternativeProducts,
      priceAdjustment,
      capacityConstraint
    } = response;

    // 更新预测的确定性
    await this.updateForecastCertainty(productId, {
      vendorId,
      confirmedDate,
      confirmedQuantity,
      reliability: this.calculateReliability(vendorId)
    });

    // 检查是否有产能约束
    if (capacityConstraint) {
      await this.handleCapacityConstraint(vendorId, productId, capacityConstraint);
    }

    return {
      accepted: confirmedQuantity > 0,
      leadTime: this.getLeadTimeDays(new Date(), confirmedDate),
      unitPrice: response.price
    };
  }

  // 库存可视化共享
  async shareInventoryLevel(partnerId, inventoryData) {
    return await this.syncToPartner(partnerId, {
      type: 'inventory_update',
      data: inventoryData.map(item => ({
        productId: item.productId,
        quantity: item.quantity,
        warehouse: item.warehouse,
        reserved: item.reserved,
        available: item.available
      })),
      timestamp: new Date().toISOString()
    });
  }

  // 自动补货协议
  async setupAutoReplenishment(customerId, vendorId, agreement) {
    const {
      productId,
      minStock,
      maxStock,
      reorderPoint,
      quantity,
      frequency
    } = agreement;

    // 创建自动补货规则
    const rule = {
      id: this.generateRuleId(),
      customerId,
      vendorId,
      productId,
      condition: `stock <= ${reorderPoint}`,
      action: {
        type: 'create_purchase_order',
        quantity: quantity,
        autoApprove: true
      },
      schedule: frequency,
      status: 'active'
    };

    await this.saveAutoReplenishmentRule(rule);

    return rule;
  }

  // 协同计划排产
  async collaborativePlanning(orders, constraints) {
    // 收集所有参与者的能力和约束
    const participants = await this.getAllParticipants();

    // 运行协同计划算法
    const plan = await this.optimizeProductionPlan(
      orders,
      participants,
      constraints
    );

    // 分发计划给各参与者
    for (const participant of participants) {
      const participantPlan = this.extractParticipantPlan(plan, participant.id);
      await this.sendPlanToParticipant(participant.id, participantPlan);
    }

    return plan;
  }

  // 订单状态同步
  async syncOrderStatus(orderId) {
    const order = await this.getOrder(orderId);
    const statusHistory = [];

    // 追踪订单在各环节的状态
    for (const step of order.steps) {
      const status = await this.getStepStatus(orderId, step);
      statusHistory.push({
        step: step.name,
        status: status.state,
        timestamp: status.timestamp,
        location: status.location
      });
    }

    return statusHistory;
  }
}

最佳实践建议

总结

智能需求预测与供应链协同是提升企业运营效率的关键:

通过智能预测与协同,企业可以实现供需匹配,降低运营成本。

← 下一篇:进销存系统智能推荐引擎设计与实现