背景为物流行业,箱成本需区分仓储/物流/管理三类成本,计算复合成本指数。
运行环境:jupyter notebook(python 3.12.7)
1.复合成本计算公式解读
2.设定权重值,用示例数据运行python代码
3.根据成本波动率自动调整权重
4.整合2和3的代码,根据成本波动率自动调整权重并运行出复合成本指数的结果
步骤1:公式理解
步骤2:示例数据的python运行
代码:
import pandas as pd import numpy as np import matplotlib.pyplot as plt import matplotlib.ticker as mtick # 设置中文显示 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False # 生成示例数据(2023年月度数据) np.random.seed(2023) dates = pd.date_range('2023-01', periods=12, freq='ME') data = { "仓储成本(元/箱)": np.round(np.random.uniform(2.5, 3.5, 12) + np.sin(np.arange(12)*0.5)*0.3, 2), "物流成本(元/箱)": np.round(np.random.uniform(8.0, 12.0, 12) + np.cos(np.arange(12)*0.4)*1.2, 2), "管理成本(元/箱)": np.round(np.linspace(1.8, 2.3, 12) + np.random.normal(0, 0.1, 12), 2) } df = pd.DataFrame(data, index=dates) # 计算复合成本指数(权重系数:仓储1 : 物流2 : 管理0.5) weights = np.array([1, 2, 0.5]) df["复合成本指数"] = df.apply(lambda x: np.dot(x.values, weights)/weights.sum(), axis=1) # 成本构成分析可视化 fig, axes = plt.subplots(2, 2, figsize=(16, 12)) # 1. 成本趋势分析 ax = axes[0,0] df[['仓储成本(元/箱)', '物流成本(元/箱)', '管理成本(元/箱)']].plot(ax=ax, marker='o') ax.set_title("单箱成本分项趋势", fontsize=14) ax.set_ylabel("成本(元)") ax.yaxis.set_major_formatter(mtick.FormatStrFormatter('%.1f')) ax.grid(True, alpha=0.3) # 2. 复合指数趋势 ax = axes[0,1] df['复合成本指数'].plot(ax=ax, color='purple', marker='s') ax.set_title("复合成本指数变化趋势", fontsize=14) ax.set_ylabel("指数值") ax.axhline(df['复合成本指数'].mean(), color='r', linestyle='--', label=f'年度均值({df["复合成本指数"].mean():.2f})') ax.legend() ax.grid(True, alpha=0.3) # 3. 成本构成堆叠图 ax = axes[1,0] components = df[['仓储成本(元/箱)', '物流成本(元/箱)', '管理成本(元/箱)']].T ax.stackplot(df.index, components, labels=['仓储', '物流', '管理'], colors=['#4CAF50', '#2196F3', '#FF9800']) ax.set_title("成本构成堆叠分析", fontsize=14) ax.set_ylabel("累计成本(元)") ax.legend(loc='upper left') ax.xaxis.set_tick_params(rotation=45) ax.grid(True, alpha=0.3) # 4. 年度成本占比 ax = axes[1,1] total = df[['仓储成本(元/箱)', '物流成本(元/箱)', '管理成本(元/箱)']].sum() ax.pie(total, labels=total.index, autopct='%1.1f%%', colors=['#4CAF50', '#2196F3', '#FF9800'], startangle=90, wedgeprops=dict(width=0.4)) ax.set_title("年度成本结构占比", fontsize=14) plt.tight_layout() plt.show() # 打印详细数据报告 print("月度成本明细报告:") print(df) print("\n年度成本汇总:") print(df[['仓储成本(元/箱)', '物流成本(元/箱)', '管理成本(元/箱)']].sum().to_string())运行结果:
对比表格计算结果做验证:
Tips:
| 参数 | 说明 |
|---|---|
| 'ME' | 每月最后一天(Month End) |
| 'ME-S' | 每月第一天(Month Start) |
| 'QE' | 季度最后一天 |
| 'YE' | 年度最后一天 |
步骤3:根据成本波动率自动调整权重,
- 波动率越低 → 权重越高
- 波动率越高 → 权重越低
示例数据与代码:
import numpy as np import pandas as pd import matplotlib.pyplot as plt # 设置中文显示 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False # ====================== # 生成示例数据(2023年季度数据) # ====================== np.random.seed(2023) dates = pd.date_range('2023-Q1', periods=8, freq='QE') # 生成8个季度末日期 data = { # 仓储成本 - 低波动性(标准差0.3) '仓储成本': np.round(50 + np.cumsum(np.random.normal(0, 0.3, 8)), 2), # 物流成本 - 高波动性(标准差1.5) '物流成本': np.round(80 + np.cumsum(np.random.normal(0, 1.5, 8)), 2), # 管理成本 - 中波动性(标准差0.8) '管理成本': np.round(30 + np.cumsum(np.random.normal(0, 0.8, 8)), 2) } df = pd.DataFrame(data, index=dates) # ====================== # 动态权重计算 # ====================== # 计算波动率(标准差) volatility = df.std() # 计算动态权重(波动率越小权重越高) epsilon = 1e-6 # 防止除零 weights = (1 / (volatility + epsilon)).round(2) weights /= weights.sum() # 标准化为总和1 # ====================== # 可视化分析 # ====================== fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8)) # 1. 成本趋势图 df.plot(ax=ax1, marker='o') ax1.set_title('成本项目趋势分析(单位:万元)') ax1.set_ylabel('成本金额') ax1.grid(True, alpha=0.3) # 2. 波动率与权重对比 ax2.bar(volatility.index, volatility, alpha=0.7, label='波动率(标准差)') ax2_twin = ax2.twinx() ax2_twin.plot(weights.index, weights, 'ro-', markersize=8, label='动态权重') ax2.set_title('波动率与动态权重关系') ax2.set_ylabel('波动率') ax2_twin.set_ylabel('权重系数', color='r') ax2_twin.tick_params(axis='y', labelcolor='r') # 合并图例 lines, labels = ax2.get_legend_handles_labels() lines2, labels2 = ax2_twin.get_legend_handles_labels() ax2.legend(lines + lines2, labels + labels2, loc='upper left') plt.tight_layout() plt.show() # 打印计算结果 print("波动率分析报告:") print(volatility.to_string()) print("\n动态权重分配:") print(weights.to_string())运行结果:
步骤4:整合以上代码,根据成本波动率自动调整权重并运行出复合成本指数的结果
代码:
import pandas as pd import numpy as np import matplotlib.pyplot as plt import matplotlib.ticker as mtick from matplotlib.gridspec import GridSpec # 设置中文显示 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False # ====================== # 数据生成(带时间序列特征) # ====================== np.random.seed(2023) dates = pd.date_range('2022-01', periods=24, freq='ME') # 生成24个月数据用于滚动计算 data = { "仓储成本": np.round(3 + np.sin(np.arange(24)*0.5)*0.3 + np.random.normal(0, 0.1, 24), 2), "物流成本": np.round(10 + np.cos(np.arange(24)*0.4)*1.2 + np.random.normal(0, 0.5, 24), 2), "管理成本": np.round(2 + np.linspace(0, 0.5, 24) + np.random.normal(0, 0.2, 24), 2) } df = pd.DataFrame(data, index=dates) # ====================== # 动态权重计算(滚动窗口) # ====================== def calculate_dynamic_weights(df, window=12): """滚动计算动态权重""" weights = pd.DataFrame(index=df.index, columns=df.columns) for i in range(window-1, len(df)): # 提取滚动窗口数据 window_data = df.iloc[i-window+1:i+1] # 计算波动率 volatility = window_data.std() # 计算动态权重(波动率越小权重越高) epsilon = 1e-6 adjusted_weights = 1 / (volatility + epsilon) normalized_weights = adjusted_weights / adjusted_weights.sum() weights.iloc[i] = normalized_weights return weights[window-1:] # 去除前window-1个空值 # 计算动态权重(12个月滚动) dynamic_weights = calculate_dynamic_weights(df, window=12) # 计算复合成本指数(仅计算有效窗口期) def calculate_composite_index(row, weights): """根据动态权重计算复合指数""" try: valid_weights = weights.loc[row.name] return np.dot(row.values, valid_weights.values) except KeyError: return np.nan # 对无权重数据返回空值 df['复合成本指数'] = df.apply(lambda x: calculate_composite_index(x, dynamic_weights), axis=1) # ====================== # 可视化分析(调整数据范围) # ====================== valid_data = df[df.index >= dynamic_weights.index[0]] # 仅展示有效数据 fig = plt.figure(figsize=(18, 16)) gs = GridSpec(3, 2, figure=fig) # 1. 成本趋势分析 ax1 = fig.add_subplot(gs[0, :]) valid_data[['仓储成本', '物流成本', '管理成本']].plot(ax=ax1, marker='o', linewidth=2) ax1.set_title("单箱成本分项趋势(有效数据范围)", fontsize=14) ax1.set_ylabel("成本(元)") ax1.yaxis.set_major_formatter(mtick.FormatStrFormatter('%.1f')) ax1.grid(True, alpha=0.3) ax1.legend(bbox_to_anchor=(1.02, 1), loc='upper left') # 2. 权重动态变化 ax2 = fig.add_subplot(gs[1, 0]) dynamic_weights.plot(ax=ax2, style=['o-', 's--', 'D:'], markersize=6) ax2.set_title("动态权重变化趋势(12个月滚动窗口)", fontsize=14) ax2.set_ylabel("权重系数") ax2.grid(True, alpha=0.3) ax2.legend(bbox_to_anchor=(1.02, 1), loc='upper left') # 3. 复合指数分析 ax3 = fig.add_subplot(gs[1, 1]) valid_data['复合成本指数'].plot(ax=ax3, color='purple', marker='s', linewidth=2) ax3.axhline(valid_data['复合成本指数'].mean(), color='r', linestyle='--', label=f'均值({valid_data["复合成本指数"].mean():.2f})') ax3.set_title("复合成本指数动态变化", fontsize=14) ax3.set_ylabel("指数值") ax3.grid(True, alpha=0.3) ax3.legend() # 4. 波动率矩阵 ax4 = fig.add_subplot(gs[2, 0]) volatility = df.rolling(12).std().dropna() volatility.plot(ax=ax4, colormap='coolwarm', linewidth=2) ax4.set_title("12个月滚动波动率趋势", fontsize=14) ax4.set_ylabel("波动率") ax4.grid(True, alpha=0.3) # 5. 成本结构占比(末月) ax5 = fig.add_subplot(gs[2, 1]) last_month = valid_data.iloc[-1][['仓储成本', '物流成本', '管理成本']] ax5.pie(last_month, labels=last_month.index, autopct='%1.1f%%', colors=['#4CAF50', '#2196F3', '#FF9800'], startangle=90, wedgeprops=dict(width=0.4)) ax5.set_title(f"末月成本结构占比 ({last_month.name.strftime('%Y-%m')})", fontsize=14) plt.tight_layout() plt.show() # ====================== # 数据报告输出 # ====================== print("动态权重示例(最近3个月):") print(dynamic_weights.tail(3).to_string()) print("\n复合成本指数描述统计:") print(valid_data['复合成本指数'].describe().to_string())运行结果: