marketing_strategy_service.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. """
  2. 营销策略模拟模块
  3. """
  4. import numpy as np
  5. import pandas as pd
  6. from .utils import ensure_native_type
  7. from .lifecycle_analyzer_service import enhanced_data_preprocessing
  8. def simulate_marketing_strategy(revenue_series, quantity_series, date_series, stages_map, stage_statistics, strategy_type, strategy_params):
  9. """模拟营销策略对SKU生命周期的影响"""
  10. # 转换为可修改的列表
  11. simulated_revenue = list(revenue_series)
  12. simulated_quantity = list(quantity_series)
  13. # 解析策略参数
  14. start_date = strategy_params.get('start_date')
  15. end_date = strategy_params.get('end_date')
  16. intensity = float(strategy_params.get('intensity', 0.5))
  17. price_change = float(strategy_params.get('price_change', 0))
  18. # 找到策略作用的日期范围索引
  19. start_idx = None
  20. end_idx = None
  21. for i, date_str in enumerate(date_series):
  22. if start_date and date_str == start_date:
  23. start_idx = i
  24. if end_date and date_str == end_date:
  25. end_idx = i
  26. # 如果未找到精确匹配,尝试模糊匹配
  27. if start_idx is None and start_date:
  28. for i, date_str in enumerate(date_series):
  29. if start_date in date_str:
  30. start_idx = i
  31. break
  32. if end_idx is None and end_date:
  33. for i, date_str in enumerate(date_series):
  34. if end_date in date_str:
  35. end_idx = i
  36. break
  37. # 默认范围
  38. if start_idx is None:
  39. start_idx = 0
  40. if end_idx is None:
  41. end_idx = len(simulated_revenue) - 1
  42. # 确保范围有效
  43. start_idx = max(0, min(start_idx, len(simulated_revenue) - 1))
  44. end_idx = max(start_idx, min(end_idx, len(simulated_revenue) - 1))
  45. # 根据策略类型应用不同的影响
  46. strategy_effects = {
  47. 'promotion': { # 促销活动
  48. 'quantity_boost': 1.3 + (intensity * 0.5),
  49. 'revenue_boost': 1.15 + (intensity * 0.25),
  50. },
  51. 'advertising': { # 广告宣传
  52. 'quantity_boost': 1.2 + (intensity * 0.6),
  53. 'revenue_boost': 1.25 + (intensity * 0.6),
  54. },
  55. 'price_cut': { # 降价
  56. 'quantity_boost': 1.4 + (abs(price_change) / 100 * 1.5),
  57. 'revenue_boost': 1.0 + (price_change / 100),
  58. },
  59. 'price_increase': { # 涨价
  60. 'quantity_boost': 1.0 - (price_change / 100 * 0.3),
  61. 'revenue_boost': 1.0 + (price_change / 100),
  62. },
  63. }
  64. effect = strategy_effects.get(strategy_type, {'quantity_boost': 1.0, 'revenue_boost': 1.0})
  65. # 应用策略影响(考虑渐进式影响和衰减)
  66. for i in range(start_idx, end_idx + 1):
  67. progress = (i - start_idx) / max(1, end_idx - start_idx)
  68. # 使用钟形曲线模拟影响强度
  69. impact_factor = np.exp(-((progress - 0.5) ** 2) / 0.1)
  70. # 应用影响
  71. quantity_multiplier = 1.0 + (effect['quantity_boost'] - 1.0) * impact_factor
  72. revenue_multiplier = 1.0 + (effect['revenue_boost'] - 1.0) * impact_factor
  73. simulated_quantity[i] *= quantity_multiplier
  74. simulated_revenue[i] *= revenue_multiplier
  75. # 计算策略影响的后续效应
  76. carryover_length = min(20, (end_idx - start_idx) // 2)
  77. for i in range(end_idx + 1, min(end_idx + 1 + carryover_length, len(simulated_revenue))):
  78. decay_factor = 1.0 - ((i - end_idx) / carryover_length)
  79. carryover_boost = 0.1 * intensity * decay_factor
  80. simulated_quantity[i] *= (1.0 + carryover_boost)
  81. simulated_revenue[i] *= (1.0 + carryover_boost * 0.5)
  82. # 平滑处理
  83. smoothed_simulated_revenue, smoothed_simulated_quantity = enhanced_data_preprocessing(
  84. pd.Series(simulated_revenue), pd.Series(simulated_quantity)
  85. )
  86. # 计算对比指标
  87. original_total_revenue = sum(revenue_series)
  88. original_total_quantity = sum(quantity_series)
  89. simulated_total_revenue = sum(simulated_revenue)
  90. simulated_total_quantity = sum(simulated_quantity)
  91. revenue_increase = simulated_total_revenue - original_total_revenue
  92. quantity_increase = simulated_total_quantity - original_total_quantity
  93. revenue_increase_pct = (revenue_increase / original_total_revenue * 100) if original_total_revenue > 0 else 0
  94. quantity_increase_pct = (quantity_increase / original_total_quantity * 100) if original_total_quantity > 0 else 0
  95. # 计算策略期间的增量
  96. strategy_period_original_revenue = sum(revenue_series[start_idx:end_idx + 1])
  97. strategy_period_simulated_revenue = sum(simulated_revenue[start_idx:end_idx + 1])
  98. strategy_period_revenue_increase = strategy_period_simulated_revenue - strategy_period_original_revenue
  99. strategy_period_revenue_increase_pct = (
  100. (strategy_period_revenue_increase / strategy_period_original_revenue * 100)
  101. if strategy_period_original_revenue > 0 else 0
  102. )
  103. return {
  104. 'simulated_revenue': [ensure_native_type(v, decimal_places=2) for v in simulated_revenue],
  105. 'simulated_quantity': [ensure_native_type(v, decimal_places=2) for v in simulated_quantity],
  106. 'smoothed_simulated_revenue': [ensure_native_type(v, decimal_places=2) for v in smoothed_simulated_revenue.tolist()],
  107. 'smoothed_simulated_quantity': [ensure_native_type(v, decimal_places=2) for v in smoothed_simulated_quantity.tolist()],
  108. 'comparison': {
  109. 'original_total_revenue': ensure_native_type(original_total_revenue, decimal_places=2),
  110. 'simulated_total_revenue': ensure_native_type(simulated_total_revenue, decimal_places=2),
  111. 'revenue_increase': ensure_native_type(revenue_increase, decimal_places=2),
  112. 'revenue_increase_pct': ensure_native_type(revenue_increase_pct, decimal_places=2),
  113. 'original_total_quantity': ensure_native_type(original_total_quantity, decimal_places=2),
  114. 'simulated_total_quantity': ensure_native_type(simulated_total_quantity, decimal_places=2),
  115. 'quantity_increase': ensure_native_type(quantity_increase, decimal_places=2),
  116. 'quantity_increase_pct': ensure_native_type(quantity_increase_pct, decimal_places=2),
  117. 'strategy_period_revenue_increase': ensure_native_type(strategy_period_revenue_increase, decimal_places=2),
  118. 'strategy_period_revenue_increase_pct': ensure_native_type(strategy_period_revenue_increase_pct, decimal_places=2),
  119. },
  120. 'strategy_range': {
  121. 'start_idx': start_idx,
  122. 'end_idx': end_idx,
  123. 'start_date': date_series[start_idx],
  124. 'end_date': date_series[end_idx],
  125. }
  126. }