| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- """
- 营销策略模拟模块
- """
- import numpy as np
- import pandas as pd
- from .utils import ensure_native_type
- from .lifecycle_analyzer_service import enhanced_data_preprocessing
- def simulate_marketing_strategy(revenue_series, quantity_series, date_series, stages_map, stage_statistics, strategy_type, strategy_params):
- """模拟营销策略对SKU生命周期的影响"""
- # 转换为可修改的列表
- simulated_revenue = list(revenue_series)
- simulated_quantity = list(quantity_series)
-
- # 解析策略参数
- start_date = strategy_params.get('start_date')
- end_date = strategy_params.get('end_date')
- intensity = float(strategy_params.get('intensity', 0.5))
- price_change = float(strategy_params.get('price_change', 0))
-
- # 找到策略作用的日期范围索引
- start_idx = None
- end_idx = None
-
- for i, date_str in enumerate(date_series):
- if start_date and date_str == start_date:
- start_idx = i
- if end_date and date_str == end_date:
- end_idx = i
-
- # 如果未找到精确匹配,尝试模糊匹配
- if start_idx is None and start_date:
- for i, date_str in enumerate(date_series):
- if start_date in date_str:
- start_idx = i
- break
-
- if end_idx is None and end_date:
- for i, date_str in enumerate(date_series):
- if end_date in date_str:
- end_idx = i
- break
-
- # 默认范围
- if start_idx is None:
- start_idx = 0
- if end_idx is None:
- end_idx = len(simulated_revenue) - 1
-
- # 确保范围有效
- start_idx = max(0, min(start_idx, len(simulated_revenue) - 1))
- end_idx = max(start_idx, min(end_idx, len(simulated_revenue) - 1))
-
- # 根据策略类型应用不同的影响
- strategy_effects = {
- 'promotion': { # 促销活动
- 'quantity_boost': 1.3 + (intensity * 0.5),
- 'revenue_boost': 1.15 + (intensity * 0.25),
- },
- 'advertising': { # 广告宣传
- 'quantity_boost': 1.2 + (intensity * 0.6),
- 'revenue_boost': 1.25 + (intensity * 0.6),
- },
- 'price_cut': { # 降价
- 'quantity_boost': 1.4 + (abs(price_change) / 100 * 1.5),
- 'revenue_boost': 1.0 + (price_change / 100),
- },
- 'price_increase': { # 涨价
- 'quantity_boost': 1.0 - (price_change / 100 * 0.3),
- 'revenue_boost': 1.0 + (price_change / 100),
- },
- }
-
- effect = strategy_effects.get(strategy_type, {'quantity_boost': 1.0, 'revenue_boost': 1.0})
-
- # 应用策略影响(考虑渐进式影响和衰减)
- for i in range(start_idx, end_idx + 1):
- progress = (i - start_idx) / max(1, end_idx - start_idx)
-
- # 使用钟形曲线模拟影响强度
- impact_factor = np.exp(-((progress - 0.5) ** 2) / 0.1)
-
- # 应用影响
- quantity_multiplier = 1.0 + (effect['quantity_boost'] - 1.0) * impact_factor
- revenue_multiplier = 1.0 + (effect['revenue_boost'] - 1.0) * impact_factor
-
- simulated_quantity[i] *= quantity_multiplier
- simulated_revenue[i] *= revenue_multiplier
-
- # 计算策略影响的后续效应
- carryover_length = min(20, (end_idx - start_idx) // 2)
- for i in range(end_idx + 1, min(end_idx + 1 + carryover_length, len(simulated_revenue))):
- decay_factor = 1.0 - ((i - end_idx) / carryover_length)
- carryover_boost = 0.1 * intensity * decay_factor
- simulated_quantity[i] *= (1.0 + carryover_boost)
- simulated_revenue[i] *= (1.0 + carryover_boost * 0.5)
-
- # 平滑处理
- smoothed_simulated_revenue, smoothed_simulated_quantity = enhanced_data_preprocessing(
- pd.Series(simulated_revenue), pd.Series(simulated_quantity)
- )
-
- # 计算对比指标
- original_total_revenue = sum(revenue_series)
- original_total_quantity = sum(quantity_series)
- simulated_total_revenue = sum(simulated_revenue)
- simulated_total_quantity = sum(simulated_quantity)
-
- revenue_increase = simulated_total_revenue - original_total_revenue
- quantity_increase = simulated_total_quantity - original_total_quantity
- revenue_increase_pct = (revenue_increase / original_total_revenue * 100) if original_total_revenue > 0 else 0
- quantity_increase_pct = (quantity_increase / original_total_quantity * 100) if original_total_quantity > 0 else 0
-
- # 计算策略期间的增量
- strategy_period_original_revenue = sum(revenue_series[start_idx:end_idx + 1])
- strategy_period_simulated_revenue = sum(simulated_revenue[start_idx:end_idx + 1])
- strategy_period_revenue_increase = strategy_period_simulated_revenue - strategy_period_original_revenue
- strategy_period_revenue_increase_pct = (
- (strategy_period_revenue_increase / strategy_period_original_revenue * 100)
- if strategy_period_original_revenue > 0 else 0
- )
-
- return {
- 'simulated_revenue': [ensure_native_type(v, decimal_places=2) for v in simulated_revenue],
- 'simulated_quantity': [ensure_native_type(v, decimal_places=2) for v in simulated_quantity],
- 'smoothed_simulated_revenue': [ensure_native_type(v, decimal_places=2) for v in smoothed_simulated_revenue.tolist()],
- 'smoothed_simulated_quantity': [ensure_native_type(v, decimal_places=2) for v in smoothed_simulated_quantity.tolist()],
- 'comparison': {
- 'original_total_revenue': ensure_native_type(original_total_revenue, decimal_places=2),
- 'simulated_total_revenue': ensure_native_type(simulated_total_revenue, decimal_places=2),
- 'revenue_increase': ensure_native_type(revenue_increase, decimal_places=2),
- 'revenue_increase_pct': ensure_native_type(revenue_increase_pct, decimal_places=2),
- 'original_total_quantity': ensure_native_type(original_total_quantity, decimal_places=2),
- 'simulated_total_quantity': ensure_native_type(simulated_total_quantity, decimal_places=2),
- 'quantity_increase': ensure_native_type(quantity_increase, decimal_places=2),
- 'quantity_increase_pct': ensure_native_type(quantity_increase_pct, decimal_places=2),
- 'strategy_period_revenue_increase': ensure_native_type(strategy_period_revenue_increase, decimal_places=2),
- 'strategy_period_revenue_increase_pct': ensure_native_type(strategy_period_revenue_increase_pct, decimal_places=2),
- },
- 'strategy_range': {
- 'start_idx': start_idx,
- 'end_idx': end_idx,
- 'start_date': date_series[start_idx],
- 'end_date': date_series[end_idx],
- }
- }
|