服饰流行周期计算程序 —— 预判款式衰退与清仓最佳时间点一、实际应用场景描述在《时尚产业与品牌创新》课程中服饰流行周期Fashion Cycle 是一个核心理论框架。从 引入期 → 成长期 → 成熟期 → 衰退期 → 滞销期 的完整生命周期决定了品牌每一个关键决策的时间窗口阶段 典型表现 品牌动作引入期 (Introduction) 首批 KOL 穿搭曝光小红书/抖音种草开始 小批量试水观察数据成长期 (Growth) 搜索量攀升竞品跟进销量周环比 15% 追单补货加大投放成熟期 (Maturity) 销量 plateau周环比 ±5% 波动 维持曝光准备新品衔接衰退期 (Decline) 销量周环比持续下滑 3 周退货率上升 启动折扣减少新流量投入滞销期 (Obsolescence) 库存周转率 0.5仓储成本 边际贡献 清仓退出回收现金流核心决策问题一款衣服上架后什么时候开始打折什么时候必须清仓晚一周可能多赚但也多压一周库存早一周可能损失利润。这个最佳清仓时间点就是本程序要解决的核心问题。二、引入痛点2.1 行业现状的三拍决策痛点 真实表现 后果拍脑袋定折扣 卖了一个月了该打折了吧 要么打折太早损失毛利要么太晚变死库存看总量不看趋势 只看累计销量不看周环比斜率 成熟期误判为衰退或衰退期误判为季节性波动统一折扣节奏 所有款一起 618 打折、双 11 打折 不同款的生命周期阶段完全不同一刀切效率低缺乏量化预警 等发现卖不动了已经晚了 库存积压 → 折价 70% 才能清掉 → 吞噬前期利润不懂品类差异 连衣裙和羽绒服用同一套节奏 连衣裙衰退以周计羽绒服以月计2.2 一个典型损失场景某独立品牌一款 ¥899 的碎花连衣裙第 1~3 周周销量 120 → 150 → 180成长期✅ 不打折第 4~6 周周销量 185 → 178 → 170成熟期 临界区第 7~9 周周销量 152 → 130 → 105衰退期❌ 应该打 8 折但实际决策等到第 10 周才打 7 折结果库存 200 件 × 折价损失 ¥180/件 ¥36,000 利润蒸发核心矛盾不是要不要打折而是在哪一周打折能使总利润最大化——这就是流行周期量化的价值。三、核心逻辑讲解3.1 流行周期曲线模型本程序采用 修正的 Bass 扩散模型 指数衰减叠加将单款销量拟合为周销量(t) 基础扩散曲线(t) × 季节衰减因子(t) × 随机噪声(t)其中基础扩散曲线Bass 模型S(t) p (q − p) × F(t) − p × F(t)²p 创新系数KOL/种草驱动约 0.03~0.08q 模仿系数大众跟风驱动约 0.15~0.40F(t) 累积采纳比例季节衰减因子品类差异连衣裙快衰减 λ 0.12生命周期 8~12 周羽绒服慢衰减 λ 0.05生命周期 16~24 周T恤 中衰减 λ 0.08生命周期 12~16 周衰减公式e^(−λ × t)3.2 衰退判定算法程序通过三重判定确认衰退起点判定条件需同时满足① 连续 N 周默认 3 周周环比 0② 最近一周销量 峰值 × 衰退阈值默认 70%③ 斜率线性回归显著为负p 0.053.3 最佳清仓时间点算法核心思路比较继续持有vs立即清仓的期望利润持有策略再等 w 周E[利润(w)] Σ[P(t) × (1−d(t)) × M] − C_hold × w − C_risk其中P(t) 第 t 周预测销量d(t) 第 t 周自然折扣率季节性加深M 每件边际贡献售价 × 毛利率 − 单件可变成本C_hold 周库存持有成本仓储 资金占用 贬值C_risk 滞销风险成本概率 × 最终折价损失清仓策略第 T 周立即打折E[利润(T)] P(T) × (1−d_clear) × M − C_clear_cost其中d_clear 清仓折扣率如 0.30 7 折C_clear_cost 清仓执行成本额外推广/直播坑位费最优清仓周 argmax E[利润(w)] over all w3.4 折扣策略建议衰退期折扣阶梯动态定价衰退早期销量降至峰值 70% 9 折轻微刺激衰退中期销量降至峰值 50% 8 折主动去库存衰退晚期销量降至峰值 30% 6.5~7 折清仓价滞销期 库存周转率 0.3 5 折以下回收现金流四、项目结构fashion_cycle_tracker/├── config.py # 品类参数配置衰减率/周期阶段阈值├── data_models.py # 数据模型单品/周销量/生命周期事件├── curve_fitter.py # 曲线拟合器Bass模型 季节衰减├── decline_detector.py # 衰退检测器三重判定算法├── clearance_optimizer.py # 清仓优化器利润最大化├── discount_strategy.py # 折扣策略生成器├── report.py # 报告生成表格 可视化├── main.py # 主程序入口含完整示例数据├── README.md # 项目说明└── requirements.txt # 依赖声明五、代码模块化实现requirements.txtnumpy1.24.0scipy1.10.0matplotlib3.7.0config.py#!/usr/bin/env python3# -*- coding: utf-8 -*-config.py品类参数配置中心不同服饰品类的生命周期特征参数from typing import Dictimport numpy as np# 品类生命周期参数 # 基于时尚产业研究的典型值CATEGORY_PARAMS {# 连衣裙春夏核心品类生命周期短衰减快dress: {bass_p: 0.06, # 创新系数种草敏感度bass_q: 0.35, # 模仿系数跟风效应强decay_lambda: 0.12, # 衰减速率快typical_weeks: 10, # 典型总生命周期周peak_week_range: (3, 6), # 峰值通常出现在第几周seasonal_strength: 0.8, # 季节性强度高},# 羽绒服秋冬核心品类生命周期长衰减慢down_jacket: {bass_p: 0.04,bass_q: 0.25,decay_lambda: 0.05,typical_weeks: 20,peak_week_range: (5, 10),seasonal_strength: 0.9,},# T恤/基础款全年可穿生命周期中等tshirt: {bass_p: 0.05,bass_q: 0.30,decay_lambda: 0.08,typical_weeks: 14,peak_week_range: (4, 8),seasonal_strength: 0.4,},# 牛仔裤经典款生命周期最长jeans: {bass_p: 0.03,bass_q: 0.20,decay_lambda: 0.04,typical_weeks: 24,peak_week_range: (6, 12),seasonal_strength: 0.3,},# 运动服/瑜伽裤功能驱动衰减中等偏快activewear: {bass_p: 0.07,bass_q: 0.38,decay_lambda: 0.10,typical_weeks: 12,peak_week_range: (3, 7),seasonal_strength: 0.5,},}# 衰退判定阈值 DECLINE_THRESHOLDS {min_consecutive_weeks: 3, # 至少连续 N 周下滑peak_ratio_threshold: 0.70, # 销量降至峰值的 X% 以下slope_p_value: 0.10, # 斜率显著性阈值min_weeks_data: 5, # 最少需要多少周数据才判定}# 清仓策略参数 CLEARANCE_PARAMS {holding_cost_per_unit_week: 8.0, # 每件每周持有成本仓储资金risk_discount_rate: 0.15, # 滞销风险折价率clearance_execution_cost: 500, # 清仓执行成本直播/推广discount_tiers: { # 折扣阶梯0.70: 衰退早期温和刺激,0.50: 衰退中期主动去库存,0.30: 衰退晚期清仓价,0.15: 滞销期回收现金流,},}# 可视化配色 COLORS {introduction: #4CAF50, # 绿 - 引入期growth: #2196F3, # 蓝 - 成长期maturity: #FF9800, # 橙 - 成熟期decline: #F44336, # 红 - 衰退期obsolescence: #9C27B0, # 紫 - 滞销期predicted: #BDBDBD, # 灰 - 预测区间clearance: #FF5722, # 深橙 - 清仓点peak: #E91E63, # 粉 - 峰值}data_models.py#!/usr/bin/env python3# -*- coding: utf-8 -*-data_models.py数据模型层单品定义、周销量数据、生命周期事件记录from dataclasses import dataclass, fieldfrom typing import Dict, List, Optional, Tupleimport numpy as npfrom datetime import date, timedeltadataclassclass Product:单品定义product_id: str # 商品编号如 DR-2024-001name: str # 商品名称category: str # 品类dress/down_jacket/tshirt/jeans/activewearprice: float # 售价元gross_margin: float # 毛利率0~1launch_date: date # 上架日期initial_stock: int # 初始库存件variable_cost_per_unit: float 0.0 # 单件可变成本包装/物流等def __post_init__(self):if self.category not in CATEGORY_PARAMS:raise ValueError(f未注册的品类: {self.category})if self.price 0:raise ValueError(售价必须大于零)if not (0 self.gross_margin 1):raise ValueError(毛利率必须在 0~1 之间)def marginal_contribution(self) - float:每件边际贡献 售价 × 毛利率 − 单件可变成本return self.price * self.gross_margin - self.variable_cost_per_unitdataclassclass WeeklySales:周销量数据支持逐步录入模拟真实追踪场景product_id: strsales: Dict[int, int] field(default_factorydict) # {周序号: 销量}weeks_recorded: int 0def add_week(self, week_num: int, units_sold: int) - None:录入一周销量if units_sold 0:raise ValueError(销量不能为负)self.sales[week_num] units_soldself.weeks_recorded max(self.weeks_recorded, week_num 1)def get_array(self, max_weeks: Optional[int] None) - np.ndarray:转为连续数组缺失周填 0if max_weeks is None:max_weeks self.weeks_recordedarr np.zeros(max_weeks)for w, v in self.sales.items():if w max_weeks:arr[w] vreturn arrdef get_peak(self) - Tuple[int, int]:返回 (峰值周序号, 峰值销量)if not self.sales:return (-1, 0)peak_w max(self.sales, keyself.sales.get)return (peak_w, self.sales[peak_w])def week_over_week(self) - np.ndarray:计算周环比增长率arr self.get_array()if len(arr) 2:return np.array([])return (arr[1:] - arr[:-1]) / np.where(arr[:-1] 0, arr[:-1], 1)dataclassclass LifecycleEvent:生命周期事件记录event_type: str # introduction/growth/maturity/decline/obsolescence/clearanceweek: int # 发生周次description: str metadata: Dict field(default_factorydict)curve_fitter.py#!/usr/bin/env python3# -*- coding: utf-8 -*-curve_fitter.py曲线拟合器用 Bass 扩散模型 指数衰减拟合/预测销量曲线import numpy as npfrom scipy.optimize import curve_fitfrom typing import Dict, Tuple, Optionalfrom config import CATEGORY_PARAMSfrom data_models import Product, WeeklySalesclass BassCurveFitter:Bass 扩散模型拟合器核心公式S(t) (p q × F(t)) × (1 − F(t))F(t) 1 − e^(−(pq)×t) / (1 (q/p) × e^(−(pq)×t))叠加季节衰减S_final(t) S(t) × e^(−λ×t)def __init__(self, product: Product, weekly_sales: WeeklySales):self.product productself.weekly_sales weekly_salesself.category_params CATEGORY_PARAMS[product.category]# 拟合结果缓存self.fitted_params: Optional[Tuple[float, float, float]] Noneself.fitted_curve: Optional[np.ndarray] Nonestaticmethoddef bass_function(t: np.ndarray, p: float, q: float, m: float) - np.ndarray:Bass 模型核心函数t: 时间数组p: 创新系数q: 模仿系数m: 市场总潜力最大累计采纳数# 累计采纳比例 F(t)if p q 0:f_t np.zeros_like(t, dtypefloat)else:exp_term np.exp(-(p q) * t)f_t (1 - exp_term) / (1 (q / p) * exp_term) if p 0 else np.zeros_like(t)# 当期采纳数即销量s_t m * (p q * f_t) * (1 - f_t)return s_tdef seasonal_decay(self, t: np.ndarray) - np.ndarray:季节衰减因子lam self.category_params[decay_lambda]strength self.category_params[seasonal_strength]# 基础衰减decay np.exp(-lam * t)# 叠加周期性波动模拟时尚周期的长尾seasonal 1 0.15 * strength * np.sin(2 * np.pi * t / 52)return decay * seasonaldef full_model(self, t: np.ndarray, p: float, q: float, m: float) - np.ndarray:完整模型 Bass 季节衰减bass self.bass_function(t, p, q, m)decay self.seasonal_decay(t)return bass * decaydef fit(self, max_weeks: int 30) - Dict:用已有数据拟合模型参数Returns:拟合结果字典包含参数、拟合曲线、预测曲线observed self.weekly_sales.get_array(max_weeks)t np.arange(len(observed))if len(observed) 4:raise ValueError(数据不足 4 周无法拟合)# 初始参数猜测p0 self.category_params[bass_p]q0 self.category_params[bass_q]m0 observed.max() * 3 # 市场潜力约为峰值的 3 倍try:popt, pcov curve_fit(self.full_model,t,observed,p0[p0, q0, m0],bounds([0, 0, 0], [1, 1, 1e6]),maxfev5000,)self.fitted_params tuple(popt)# 生成拟合曲线已有数据部分self.fitted_curve self.full_model(t, *popt)# 预测未来再预测 max_weeks 周t_future np.arange(max_weeks)future_curve self.full_model(t_future, *popt)return {status: success,params: {p (创新系数): round(popt[0], 4),q (模仿系数): round(popt[1], 4),m (市场潜力): round(popt[2], 1),},fitted_weeks: len(observed),fitted_curve: self.fitted_curve,predicted_curve: future_curve,predicted_weeks: max_weeks,rss: float(np.sum((observed - self.fitted_curve) ** 2)),}except Exception as e:return {status: failed,error: str(e),params: {p: p0, q: q0, m: m0},}def predict_future(self, total_weeks: int 20) - np.ndarray:预测未来销量if self.fitted_params is None:raise ValueError(请先调用 fit() 拟合模型)t np.arange(total_weeks)return self.full_model(t, *self.fitted_params)def identify_stage(self, week: int) - str:根据拟合曲线判断某周所处的生命周期阶段if self.fitted_params is None:return unknownt np.arange(max(week 1, 10))curve self.full_model(t, *self.fitted_params)if week len(curve):return obsolescence# 找到峰值位置peak_idx int(np.argmax(curve))peak_val curve[peak_idx]current_val curve[week]peak_ratio current_val / peak_val if peak_val 0 else 0if week peak_idx * 0.5:return introductionelif week peak_idx:return growthelif peak_ratio 0.70:return maturityelif peak_ratio 0.35:return declineelse:return obsolescencedecline_detector.py#!/usr/bin/env python3# -*- coding: utf-8 -*-decline_detector.py衰退检测器三重判定算法识别款式进入衰退期的精确时间点import numpy as npfrom typing import Dict, List, Tuplefrom scipy import statsfrom config import DECLINE_THRESHOLDSfrom data_models import WeeklySalesclass DeclineDetector:衰退检测算法三重判定① 连续 N 周销量环比下滑② 销量降至峰值 X% 以下③ 线性回归斜率显著为负def __init__(self, weekly_sales: WeeklySales):self.sales weekly_salesself.thresholds DECLINE_THRESHOLDSdef check_consecutive_decline(self, window: int 3) - Dict:判定①检查是否存在连续 N 周下滑Returns:{detected: bool, start_week: int, decline_weeks: int}arr self.sales.get_array()if len(arr) window:return {detected: False, reason: 数据不足}# 滑动窗口检测max_consecutive 0current_consecutive 0decline_start -1for i in range(1, len(arr)):if arr[i] arr[i - 1]:current_consecutive 1if current_consecutive 1:decline_start i - 1max_consecutive max(max_consecutive, current_consecutive)else:current_consecutive 0min_required self.thresholds[min_consecutive_weeks]detected max_consecutive min_requiredreturn {detected: detected,max_consecutive_decline: max_consecutive,decline_start_week: decline_start if detected else -1,reason: f最长连续下滑 {max_consecutive} 周 if detected else 未检测到连续下滑,}def check_peak_ratio(self) - Dict:判定②当前销量是否降至峰值的 X% 以下Returns:{detected: bool, current_ratio: float, peak_week: int, peak_value: int}peak_week, peak_val self.sales.get_peak()if peak_week 0:return {detected: False, reason: 无销量数据}arr self.sales.get_array()threshold self.thresholds[peak_ratio_threshold]# 检查最近几周是否低于阈值recent_weeks 3detected Falsefor i in range(max(0, len(arr) - recent_weeks), len(arr)):ratio arr[i] / peak_val if peak_val 0 else 0if ratio threshold:detected Truebreakcurrent_ratio arr[-1] / peak_val if peak_val 0 and len(arr) 0 else 0return {detected: detected,current_ratio: round(current_ratio, 3),peak_week: peak_week,peak_value: peak_val,threshold: threshold,reason: f当前销量是峰值的 {current_ratio*100:.1f}% if detected else 仍在峰值以上,}def check_slope_significance(self, window: int 5) - Dict:判定③线性回归斜率是否显著为负Returns:{detected: bool, slope: float, p_value: float}arr self.sales.get_array()if len(arr) window:return {detected: False, reason: 数据不足}# 取最近 window 周做线性回归recent arr[-window:]t np.arange(window)slope, intercept, r_value, p_value, std_err stats.linregress(t, recent)alpha self.thresholds[slope_p_value]detected slope 0 and p_value alphareturn {detected: detected,slope: round(slope, 2),r_squared: round(r_value ** 2, 3),p_value: round(p_value, 4),reason: f斜率{slope:.1f}, p{p_value:.3f} if detected else 斜率不显著,}def detect_decline(self) - Dict:三重判定汇总Returns:综合判定结果包含各子判定详情和最终结论if self.sales.weeks_recorded self.thresholds[min_weeks_data]:return {status: insufficient_data,weeks_recorded: self.sales.weeks_recorded,min_required: self.thresholds[min_weeks_data],decline_detected: False,}result_1 self.check_consecutive_decline()result_2 self.check_peak_ratio()result_3 self.check_slope_significance()# 三重判定汇总count sum([result_1[detected],result_2[detected],result_3[detected],])# 至少满足 2/3 才判定为衰退decline_detected count 2# 衰退起点 最严格的判定连续下滑起点decline_week -1if decline_detected:candidates []if result_1[detected]:candidates.append(result_1[decline_start_week])if result_2[detected]:candidates.append(result_2.get(peak_week, -1))if result_3[detected]:candidates.append(self.sales.weeks_recorded - 1)decline_week min(c for c in candidates if c 0)return {status: analyzed,decline_detected: decline_detected,decline_week: decline_week,confidence: f{count}/3 条件满足,checks: {连续下滑检测: result_1,峰值比例检测: result_2,斜率显著性检测: result_3,},recommendation: self._get_recommendation(decline_detected, count, decline_week),}def _get_recommendation(self, detected: bool, count: int, week: int) - str:根据判定结果给出建议if not detected:if count 0:return 款式仍处于健康销售期维持正常运营elif count 1:return 出现早期衰退信号建议密切关注后续 1~2 周数据else:return 数据矛盾建议人工复核else:return f⚠️ 衰退已确认第 {week} 周起建议启动折扣/清仓评估class LifecycleTracker:生命周期阶段追踪器基于销量曲线的形态特征自动标注每个阶段staticmethoddef identify_stages(sales_array: np.ndarray) - List[Tuple[int, str]]:基于销量曲线的二阶导数识别阶段转换点Returns:[(week, stage_name), ...] 按时间排序的阶段列表if len(sales_array) 4:return [(0, introduction)]stages []arr sales_array.copy()# 一阶导数变化率diff1 np.diff(arr)# 二阶导数加速度diff2 np.diff(diff1)# 找峰值peak_idx int(np.argmax(arr))# 找拐点二阶导数过零inflection_points []for i in range(1, len(diff2)):if diff2[i] * diff2[i - 1] 0:inflection_points.append(i 1)# 阶段划分逻辑# 引入期0 ~ 第一个拐点或峰值的 1/3intro_end inflection_points[0] if inflection_points else peak_idx // 3stages.append((0, introduction))# 成长期拐点 ~ 峰值if intro_end peak_idx:stages.append((intro_end, growth))# 成熟期峰值 ~ 峰值后第一个拐点decline_start peak_idx 1for ip in inflection_points:if ip peak_idx:decline_start ipbreakstages.append((peak_idx, maturity))# 衰退期拐点 ~ 低谷if decline_start len(arr) - 1:stages.append((decline_start, decline))利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛
服饰流行周期计算程序,输入单品上线数据,预判款式衰退清仓最佳时间点。
发布时间:2026/7/3 9:50:25
服饰流行周期计算程序 —— 预判款式衰退与清仓最佳时间点一、实际应用场景描述在《时尚产业与品牌创新》课程中服饰流行周期Fashion Cycle 是一个核心理论框架。从 引入期 → 成长期 → 成熟期 → 衰退期 → 滞销期 的完整生命周期决定了品牌每一个关键决策的时间窗口阶段 典型表现 品牌动作引入期 (Introduction) 首批 KOL 穿搭曝光小红书/抖音种草开始 小批量试水观察数据成长期 (Growth) 搜索量攀升竞品跟进销量周环比 15% 追单补货加大投放成熟期 (Maturity) 销量 plateau周环比 ±5% 波动 维持曝光准备新品衔接衰退期 (Decline) 销量周环比持续下滑 3 周退货率上升 启动折扣减少新流量投入滞销期 (Obsolescence) 库存周转率 0.5仓储成本 边际贡献 清仓退出回收现金流核心决策问题一款衣服上架后什么时候开始打折什么时候必须清仓晚一周可能多赚但也多压一周库存早一周可能损失利润。这个最佳清仓时间点就是本程序要解决的核心问题。二、引入痛点2.1 行业现状的三拍决策痛点 真实表现 后果拍脑袋定折扣 卖了一个月了该打折了吧 要么打折太早损失毛利要么太晚变死库存看总量不看趋势 只看累计销量不看周环比斜率 成熟期误判为衰退或衰退期误判为季节性波动统一折扣节奏 所有款一起 618 打折、双 11 打折 不同款的生命周期阶段完全不同一刀切效率低缺乏量化预警 等发现卖不动了已经晚了 库存积压 → 折价 70% 才能清掉 → 吞噬前期利润不懂品类差异 连衣裙和羽绒服用同一套节奏 连衣裙衰退以周计羽绒服以月计2.2 一个典型损失场景某独立品牌一款 ¥899 的碎花连衣裙第 1~3 周周销量 120 → 150 → 180成长期✅ 不打折第 4~6 周周销量 185 → 178 → 170成熟期 临界区第 7~9 周周销量 152 → 130 → 105衰退期❌ 应该打 8 折但实际决策等到第 10 周才打 7 折结果库存 200 件 × 折价损失 ¥180/件 ¥36,000 利润蒸发核心矛盾不是要不要打折而是在哪一周打折能使总利润最大化——这就是流行周期量化的价值。三、核心逻辑讲解3.1 流行周期曲线模型本程序采用 修正的 Bass 扩散模型 指数衰减叠加将单款销量拟合为周销量(t) 基础扩散曲线(t) × 季节衰减因子(t) × 随机噪声(t)其中基础扩散曲线Bass 模型S(t) p (q − p) × F(t) − p × F(t)²p 创新系数KOL/种草驱动约 0.03~0.08q 模仿系数大众跟风驱动约 0.15~0.40F(t) 累积采纳比例季节衰减因子品类差异连衣裙快衰减 λ 0.12生命周期 8~12 周羽绒服慢衰减 λ 0.05生命周期 16~24 周T恤 中衰减 λ 0.08生命周期 12~16 周衰减公式e^(−λ × t)3.2 衰退判定算法程序通过三重判定确认衰退起点判定条件需同时满足① 连续 N 周默认 3 周周环比 0② 最近一周销量 峰值 × 衰退阈值默认 70%③ 斜率线性回归显著为负p 0.053.3 最佳清仓时间点算法核心思路比较继续持有vs立即清仓的期望利润持有策略再等 w 周E[利润(w)] Σ[P(t) × (1−d(t)) × M] − C_hold × w − C_risk其中P(t) 第 t 周预测销量d(t) 第 t 周自然折扣率季节性加深M 每件边际贡献售价 × 毛利率 − 单件可变成本C_hold 周库存持有成本仓储 资金占用 贬值C_risk 滞销风险成本概率 × 最终折价损失清仓策略第 T 周立即打折E[利润(T)] P(T) × (1−d_clear) × M − C_clear_cost其中d_clear 清仓折扣率如 0.30 7 折C_clear_cost 清仓执行成本额外推广/直播坑位费最优清仓周 argmax E[利润(w)] over all w3.4 折扣策略建议衰退期折扣阶梯动态定价衰退早期销量降至峰值 70% 9 折轻微刺激衰退中期销量降至峰值 50% 8 折主动去库存衰退晚期销量降至峰值 30% 6.5~7 折清仓价滞销期 库存周转率 0.3 5 折以下回收现金流四、项目结构fashion_cycle_tracker/├── config.py # 品类参数配置衰减率/周期阶段阈值├── data_models.py # 数据模型单品/周销量/生命周期事件├── curve_fitter.py # 曲线拟合器Bass模型 季节衰减├── decline_detector.py # 衰退检测器三重判定算法├── clearance_optimizer.py # 清仓优化器利润最大化├── discount_strategy.py # 折扣策略生成器├── report.py # 报告生成表格 可视化├── main.py # 主程序入口含完整示例数据├── README.md # 项目说明└── requirements.txt # 依赖声明五、代码模块化实现requirements.txtnumpy1.24.0scipy1.10.0matplotlib3.7.0config.py#!/usr/bin/env python3# -*- coding: utf-8 -*-config.py品类参数配置中心不同服饰品类的生命周期特征参数from typing import Dictimport numpy as np# 品类生命周期参数 # 基于时尚产业研究的典型值CATEGORY_PARAMS {# 连衣裙春夏核心品类生命周期短衰减快dress: {bass_p: 0.06, # 创新系数种草敏感度bass_q: 0.35, # 模仿系数跟风效应强decay_lambda: 0.12, # 衰减速率快typical_weeks: 10, # 典型总生命周期周peak_week_range: (3, 6), # 峰值通常出现在第几周seasonal_strength: 0.8, # 季节性强度高},# 羽绒服秋冬核心品类生命周期长衰减慢down_jacket: {bass_p: 0.04,bass_q: 0.25,decay_lambda: 0.05,typical_weeks: 20,peak_week_range: (5, 10),seasonal_strength: 0.9,},# T恤/基础款全年可穿生命周期中等tshirt: {bass_p: 0.05,bass_q: 0.30,decay_lambda: 0.08,typical_weeks: 14,peak_week_range: (4, 8),seasonal_strength: 0.4,},# 牛仔裤经典款生命周期最长jeans: {bass_p: 0.03,bass_q: 0.20,decay_lambda: 0.04,typical_weeks: 24,peak_week_range: (6, 12),seasonal_strength: 0.3,},# 运动服/瑜伽裤功能驱动衰减中等偏快activewear: {bass_p: 0.07,bass_q: 0.38,decay_lambda: 0.10,typical_weeks: 12,peak_week_range: (3, 7),seasonal_strength: 0.5,},}# 衰退判定阈值 DECLINE_THRESHOLDS {min_consecutive_weeks: 3, # 至少连续 N 周下滑peak_ratio_threshold: 0.70, # 销量降至峰值的 X% 以下slope_p_value: 0.10, # 斜率显著性阈值min_weeks_data: 5, # 最少需要多少周数据才判定}# 清仓策略参数 CLEARANCE_PARAMS {holding_cost_per_unit_week: 8.0, # 每件每周持有成本仓储资金risk_discount_rate: 0.15, # 滞销风险折价率clearance_execution_cost: 500, # 清仓执行成本直播/推广discount_tiers: { # 折扣阶梯0.70: 衰退早期温和刺激,0.50: 衰退中期主动去库存,0.30: 衰退晚期清仓价,0.15: 滞销期回收现金流,},}# 可视化配色 COLORS {introduction: #4CAF50, # 绿 - 引入期growth: #2196F3, # 蓝 - 成长期maturity: #FF9800, # 橙 - 成熟期decline: #F44336, # 红 - 衰退期obsolescence: #9C27B0, # 紫 - 滞销期predicted: #BDBDBD, # 灰 - 预测区间clearance: #FF5722, # 深橙 - 清仓点peak: #E91E63, # 粉 - 峰值}data_models.py#!/usr/bin/env python3# -*- coding: utf-8 -*-data_models.py数据模型层单品定义、周销量数据、生命周期事件记录from dataclasses import dataclass, fieldfrom typing import Dict, List, Optional, Tupleimport numpy as npfrom datetime import date, timedeltadataclassclass Product:单品定义product_id: str # 商品编号如 DR-2024-001name: str # 商品名称category: str # 品类dress/down_jacket/tshirt/jeans/activewearprice: float # 售价元gross_margin: float # 毛利率0~1launch_date: date # 上架日期initial_stock: int # 初始库存件variable_cost_per_unit: float 0.0 # 单件可变成本包装/物流等def __post_init__(self):if self.category not in CATEGORY_PARAMS:raise ValueError(f未注册的品类: {self.category})if self.price 0:raise ValueError(售价必须大于零)if not (0 self.gross_margin 1):raise ValueError(毛利率必须在 0~1 之间)def marginal_contribution(self) - float:每件边际贡献 售价 × 毛利率 − 单件可变成本return self.price * self.gross_margin - self.variable_cost_per_unitdataclassclass WeeklySales:周销量数据支持逐步录入模拟真实追踪场景product_id: strsales: Dict[int, int] field(default_factorydict) # {周序号: 销量}weeks_recorded: int 0def add_week(self, week_num: int, units_sold: int) - None:录入一周销量if units_sold 0:raise ValueError(销量不能为负)self.sales[week_num] units_soldself.weeks_recorded max(self.weeks_recorded, week_num 1)def get_array(self, max_weeks: Optional[int] None) - np.ndarray:转为连续数组缺失周填 0if max_weeks is None:max_weeks self.weeks_recordedarr np.zeros(max_weeks)for w, v in self.sales.items():if w max_weeks:arr[w] vreturn arrdef get_peak(self) - Tuple[int, int]:返回 (峰值周序号, 峰值销量)if not self.sales:return (-1, 0)peak_w max(self.sales, keyself.sales.get)return (peak_w, self.sales[peak_w])def week_over_week(self) - np.ndarray:计算周环比增长率arr self.get_array()if len(arr) 2:return np.array([])return (arr[1:] - arr[:-1]) / np.where(arr[:-1] 0, arr[:-1], 1)dataclassclass LifecycleEvent:生命周期事件记录event_type: str # introduction/growth/maturity/decline/obsolescence/clearanceweek: int # 发生周次description: str metadata: Dict field(default_factorydict)curve_fitter.py#!/usr/bin/env python3# -*- coding: utf-8 -*-curve_fitter.py曲线拟合器用 Bass 扩散模型 指数衰减拟合/预测销量曲线import numpy as npfrom scipy.optimize import curve_fitfrom typing import Dict, Tuple, Optionalfrom config import CATEGORY_PARAMSfrom data_models import Product, WeeklySalesclass BassCurveFitter:Bass 扩散模型拟合器核心公式S(t) (p q × F(t)) × (1 − F(t))F(t) 1 − e^(−(pq)×t) / (1 (q/p) × e^(−(pq)×t))叠加季节衰减S_final(t) S(t) × e^(−λ×t)def __init__(self, product: Product, weekly_sales: WeeklySales):self.product productself.weekly_sales weekly_salesself.category_params CATEGORY_PARAMS[product.category]# 拟合结果缓存self.fitted_params: Optional[Tuple[float, float, float]] Noneself.fitted_curve: Optional[np.ndarray] Nonestaticmethoddef bass_function(t: np.ndarray, p: float, q: float, m: float) - np.ndarray:Bass 模型核心函数t: 时间数组p: 创新系数q: 模仿系数m: 市场总潜力最大累计采纳数# 累计采纳比例 F(t)if p q 0:f_t np.zeros_like(t, dtypefloat)else:exp_term np.exp(-(p q) * t)f_t (1 - exp_term) / (1 (q / p) * exp_term) if p 0 else np.zeros_like(t)# 当期采纳数即销量s_t m * (p q * f_t) * (1 - f_t)return s_tdef seasonal_decay(self, t: np.ndarray) - np.ndarray:季节衰减因子lam self.category_params[decay_lambda]strength self.category_params[seasonal_strength]# 基础衰减decay np.exp(-lam * t)# 叠加周期性波动模拟时尚周期的长尾seasonal 1 0.15 * strength * np.sin(2 * np.pi * t / 52)return decay * seasonaldef full_model(self, t: np.ndarray, p: float, q: float, m: float) - np.ndarray:完整模型 Bass 季节衰减bass self.bass_function(t, p, q, m)decay self.seasonal_decay(t)return bass * decaydef fit(self, max_weeks: int 30) - Dict:用已有数据拟合模型参数Returns:拟合结果字典包含参数、拟合曲线、预测曲线observed self.weekly_sales.get_array(max_weeks)t np.arange(len(observed))if len(observed) 4:raise ValueError(数据不足 4 周无法拟合)# 初始参数猜测p0 self.category_params[bass_p]q0 self.category_params[bass_q]m0 observed.max() * 3 # 市场潜力约为峰值的 3 倍try:popt, pcov curve_fit(self.full_model,t,observed,p0[p0, q0, m0],bounds([0, 0, 0], [1, 1, 1e6]),maxfev5000,)self.fitted_params tuple(popt)# 生成拟合曲线已有数据部分self.fitted_curve self.full_model(t, *popt)# 预测未来再预测 max_weeks 周t_future np.arange(max_weeks)future_curve self.full_model(t_future, *popt)return {status: success,params: {p (创新系数): round(popt[0], 4),q (模仿系数): round(popt[1], 4),m (市场潜力): round(popt[2], 1),},fitted_weeks: len(observed),fitted_curve: self.fitted_curve,predicted_curve: future_curve,predicted_weeks: max_weeks,rss: float(np.sum((observed - self.fitted_curve) ** 2)),}except Exception as e:return {status: failed,error: str(e),params: {p: p0, q: q0, m: m0},}def predict_future(self, total_weeks: int 20) - np.ndarray:预测未来销量if self.fitted_params is None:raise ValueError(请先调用 fit() 拟合模型)t np.arange(total_weeks)return self.full_model(t, *self.fitted_params)def identify_stage(self, week: int) - str:根据拟合曲线判断某周所处的生命周期阶段if self.fitted_params is None:return unknownt np.arange(max(week 1, 10))curve self.full_model(t, *self.fitted_params)if week len(curve):return obsolescence# 找到峰值位置peak_idx int(np.argmax(curve))peak_val curve[peak_idx]current_val curve[week]peak_ratio current_val / peak_val if peak_val 0 else 0if week peak_idx * 0.5:return introductionelif week peak_idx:return growthelif peak_ratio 0.70:return maturityelif peak_ratio 0.35:return declineelse:return obsolescencedecline_detector.py#!/usr/bin/env python3# -*- coding: utf-8 -*-decline_detector.py衰退检测器三重判定算法识别款式进入衰退期的精确时间点import numpy as npfrom typing import Dict, List, Tuplefrom scipy import statsfrom config import DECLINE_THRESHOLDSfrom data_models import WeeklySalesclass DeclineDetector:衰退检测算法三重判定① 连续 N 周销量环比下滑② 销量降至峰值 X% 以下③ 线性回归斜率显著为负def __init__(self, weekly_sales: WeeklySales):self.sales weekly_salesself.thresholds DECLINE_THRESHOLDSdef check_consecutive_decline(self, window: int 3) - Dict:判定①检查是否存在连续 N 周下滑Returns:{detected: bool, start_week: int, decline_weeks: int}arr self.sales.get_array()if len(arr) window:return {detected: False, reason: 数据不足}# 滑动窗口检测max_consecutive 0current_consecutive 0decline_start -1for i in range(1, len(arr)):if arr[i] arr[i - 1]:current_consecutive 1if current_consecutive 1:decline_start i - 1max_consecutive max(max_consecutive, current_consecutive)else:current_consecutive 0min_required self.thresholds[min_consecutive_weeks]detected max_consecutive min_requiredreturn {detected: detected,max_consecutive_decline: max_consecutive,decline_start_week: decline_start if detected else -1,reason: f最长连续下滑 {max_consecutive} 周 if detected else 未检测到连续下滑,}def check_peak_ratio(self) - Dict:判定②当前销量是否降至峰值的 X% 以下Returns:{detected: bool, current_ratio: float, peak_week: int, peak_value: int}peak_week, peak_val self.sales.get_peak()if peak_week 0:return {detected: False, reason: 无销量数据}arr self.sales.get_array()threshold self.thresholds[peak_ratio_threshold]# 检查最近几周是否低于阈值recent_weeks 3detected Falsefor i in range(max(0, len(arr) - recent_weeks), len(arr)):ratio arr[i] / peak_val if peak_val 0 else 0if ratio threshold:detected Truebreakcurrent_ratio arr[-1] / peak_val if peak_val 0 and len(arr) 0 else 0return {detected: detected,current_ratio: round(current_ratio, 3),peak_week: peak_week,peak_value: peak_val,threshold: threshold,reason: f当前销量是峰值的 {current_ratio*100:.1f}% if detected else 仍在峰值以上,}def check_slope_significance(self, window: int 5) - Dict:判定③线性回归斜率是否显著为负Returns:{detected: bool, slope: float, p_value: float}arr self.sales.get_array()if len(arr) window:return {detected: False, reason: 数据不足}# 取最近 window 周做线性回归recent arr[-window:]t np.arange(window)slope, intercept, r_value, p_value, std_err stats.linregress(t, recent)alpha self.thresholds[slope_p_value]detected slope 0 and p_value alphareturn {detected: detected,slope: round(slope, 2),r_squared: round(r_value ** 2, 3),p_value: round(p_value, 4),reason: f斜率{slope:.1f}, p{p_value:.3f} if detected else 斜率不显著,}def detect_decline(self) - Dict:三重判定汇总Returns:综合判定结果包含各子判定详情和最终结论if self.sales.weeks_recorded self.thresholds[min_weeks_data]:return {status: insufficient_data,weeks_recorded: self.sales.weeks_recorded,min_required: self.thresholds[min_weeks_data],decline_detected: False,}result_1 self.check_consecutive_decline()result_2 self.check_peak_ratio()result_3 self.check_slope_significance()# 三重判定汇总count sum([result_1[detected],result_2[detected],result_3[detected],])# 至少满足 2/3 才判定为衰退decline_detected count 2# 衰退起点 最严格的判定连续下滑起点decline_week -1if decline_detected:candidates []if result_1[detected]:candidates.append(result_1[decline_start_week])if result_2[detected]:candidates.append(result_2.get(peak_week, -1))if result_3[detected]:candidates.append(self.sales.weeks_recorded - 1)decline_week min(c for c in candidates if c 0)return {status: analyzed,decline_detected: decline_detected,decline_week: decline_week,confidence: f{count}/3 条件满足,checks: {连续下滑检测: result_1,峰值比例检测: result_2,斜率显著性检测: result_3,},recommendation: self._get_recommendation(decline_detected, count, decline_week),}def _get_recommendation(self, detected: bool, count: int, week: int) - str:根据判定结果给出建议if not detected:if count 0:return 款式仍处于健康销售期维持正常运营elif count 1:return 出现早期衰退信号建议密切关注后续 1~2 周数据else:return 数据矛盾建议人工复核else:return f⚠️ 衰退已确认第 {week} 周起建议启动折扣/清仓评估class LifecycleTracker:生命周期阶段追踪器基于销量曲线的形态特征自动标注每个阶段staticmethoddef identify_stages(sales_array: np.ndarray) - List[Tuple[int, str]]:基于销量曲线的二阶导数识别阶段转换点Returns:[(week, stage_name), ...] 按时间排序的阶段列表if len(sales_array) 4:return [(0, introduction)]stages []arr sales_array.copy()# 一阶导数变化率diff1 np.diff(arr)# 二阶导数加速度diff2 np.diff(diff1)# 找峰值peak_idx int(np.argmax(arr))# 找拐点二阶导数过零inflection_points []for i in range(1, len(diff2)):if diff2[i] * diff2[i - 1] 0:inflection_points.append(i 1)# 阶段划分逻辑# 引入期0 ~ 第一个拐点或峰值的 1/3intro_end inflection_points[0] if inflection_points else peak_idx // 3stages.append((0, introduction))# 成长期拐点 ~ 峰值if intro_end peak_idx:stages.append((intro_end, growth))# 成熟期峰值 ~ 峰值后第一个拐点decline_start peak_idx 1for ip in inflection_points:if ip peak_idx:decline_start ipbreakstages.append((peak_idx, maturity))# 衰退期拐点 ~ 低谷if decline_start len(arr) - 1:stages.append((decline_start, decline))利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛