未记录事实核验 · 状态:维护中
记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。
warning 适用边界与维护说明
本文适用于学习多种均值及其在模拟订单分组、异常值比较和时间序列趋势展示中的计算方法,不构成真实业务增收或投资绩效验证。几何平均收益率示例要求增长因子为正;简单调和平均速度适用于等距离路段,不等距离时按距离加权。股票示例采用252日年化约定,等权组合隐含每日再平衡;均线交易仅统计模拟序列中的完整买卖配对,假定信号当日成交,未计费用、滑点及执行延迟。电商分组均值先行四舍五入后再加权,可能与原始总体均值存在微小舍入差异。股票示例的多列收益率直方图传入单个子图轴,存在重建图形、破坏预设四宫格布局的问题,不宜将该部分视为完整可靠的排版示范。本次仅作结构审阅,未运行代码或进行外部事实及链接核验。
📊 均值(Mean/Average)
abstract 📋 本节概览
🌟 均值的本质与定义
note 📖 **什么是均值?**
均值是所有数据值的总和除以数据个数得到的值,它代表了数据的"平衡点"或"重心",是描述数据集中趋势最常用的统计量。
🎯 均值的直观理解
想象你有一个天平,把所有数据点都放在数轴上对应的位置,均值就是让这个天平保持平衡的支点位置。
import numpy as np
import matplotlib.pyplot as plt
# 模拟数据点
data = [2, 4, 6, 8, 10, 12, 14]
mean_value = np.mean(data)
plt.figure(figsize=(12, 6))
# 绘制数据点
plt.scatter(data, [0]*len(data), s=100, alpha=0.7, color='blue', label='数据点')
# 绘制均值线
plt.axvline(x=mean_value, color='red', linestyle='--', linewidth=2, label=f'均值 = {mean_value:.1f}')
# 显示每个点到均值的距离
for i, value in enumerate(data):
distance = abs(value - mean_value)
plt.plot([value, mean_value], [0.1, 0.1], 'gray', alpha=0.5)
plt.text(value, 0.2, f'{value}', ha='center', fontsize=10)
plt.text((value + mean_value)/2, 0.15, f'{distance:.1f}', ha='center', fontsize=8, color='gray')
plt.ylim(-0.1, 0.4)
plt.xlabel('数值')
plt.title('均值作为数据的平衡点')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
print(f"数据集: {data}")
print(f"均值: {mean_value:.2f}")
print(f"离差平方和: {sum([(x - mean_value)**2 for x in data]):.2f}")
print('这个值是所有可能“中心点”中离差平方和最小的!')
📐 均值的数学定义与公式
🔢 算术平均数(Arithmetic Mean)
总体均值(μ): $$\mu = \frac{1}{N} \sum_{i=1}^{N} x_i = \frac{x_1 + x_2 + ... + x_N}{N}$$
样本均值(x̄): $$\bar{x} = \frac{1}{n} \sum_{i=1}^{n} x_i = \frac{x_1 + x_2 + ... + x_n}{n}$$
import numpy as np
import pandas as pd
def calculate_mean_manually(data):
"""手动计算均值"""
return sum(data) / len(data)
def demonstrate_mean_calculation():
# 示例数据:学生考试成绩
scores = [85, 92, 78, 96, 88, 91, 84, 89, 93, 87]
print("=== 均值计算演示 ===")
print(f"原始数据: {scores}")
print(f"数据个数: {len(scores)}")
print(f"数据总和: {sum(scores)}")
print()
# 方法1:手动计算
manual_mean = calculate_mean_manually(scores)
print(f"手动计算均值: {manual_mean:.2f}")
# 方法2:NumPy
numpy_mean = np.mean(scores)
print(f"NumPy计算均值: {numpy_mean:.2f}")
# 方法3:Pandas
df = pd.DataFrame({'scores': scores})
pandas_mean = df['scores'].mean()
print(f"Pandas计算均值: {pandas_mean:.2f}")
# 方法4:Python内置statistics模块
import statistics
builtin_mean = statistics.mean(scores)
print(f"Statistics模块均值: {builtin_mean:.2f}")
return scores, manual_mean
scores, mean_value = demonstrate_mean_calculation()
🔄 加权平均数(Weighted Mean)
当数据中不同值的重要性不同时,使用加权平均数:
$$\bar{x}_w = \frac{\sum_{i=1}^{n} w_i x_i}{\sum_{i=1}^{n} w_i}$$import numpy as np
import pandas as pd
def weighted_mean_example():
"""加权平均数实际应用案例"""
print("=== 学生期末成绩计算(加权平均)===")
# 学生成绩数据
grades_data = {
'考试类型': ['平时作业', '期中考试', '期末考试', '课程项目'],
'成绩': [88, 92, 85, 94],
'权重': [0.2, 0.3, 0.4, 0.1] # 权重总和为1
}
df = pd.DataFrame(grades_data)
print(df)
print()
# 计算加权平均
weighted_avg = np.average(df['成绩'], weights=df['权重'])
simple_avg = np.mean(df['成绩'])
print(f"简单算术平均: {simple_avg:.2f}")
print(f"加权平均成绩: {weighted_avg:.2f}")
print(f"差异: {abs(weighted_avg - simple_avg):.2f}分")
# 详细计算过程
print("\n详细计算过程:")
weighted_sum = 0
weight_sum = 0
for i, row in df.iterrows():
contribution = row['成绩'] * row['权重']
weighted_sum += contribution
weight_sum += row['权重']
print(f"{row['考试类型']}: {row['成绩']} × {row['权重']} = {contribution:.1f}")
print(f"加权总和: {weighted_sum:.1f}")
print(f"权重总和: {weight_sum:.1f}")
print(f"加权平均: {weighted_sum:.1f} ÷ {weight_sum:.1f} = {weighted_avg:.2f}")
weighted_mean_example()
📏 几何平均数(Geometric Mean)
适用于比率、增长率等数据:
$$\bar{x}_g = \sqrt[n]{x_1 \times x_2 \times ... \times x_n} = \left(\prod_{i=1}^{n} x_i\right)^{1/n}$$import numpy as np
from scipy.stats import gmean
import matplotlib.pyplot as plt
def geometric_mean_example():
"""几何平均数在投资收益率中的应用"""
print("=== 投资收益率的几何平均(复合年增长率)===")
# 假设5年的投资收益率(百分比形式)
annual_returns = [8.5, -2.1, 15.3, 6.8, -0.7] # 年收益率(%)
# 转换为增长倍数(1 + 收益率)
growth_factors = [1 + r/100 for r in annual_returns]
print(f"年收益率 (%): {annual_returns}")
print(f"增长倍数: {[f'{x:.3f}' for x in growth_factors]}")
# 计算几何平均数
geometric_mean_factor = gmean(growth_factors)
geometric_mean_return = (geometric_mean_factor - 1) * 100
# 对比算术平均数
arithmetic_mean_return = np.mean(annual_returns)
print(f"\n几何平均收益率: {geometric_mean_return:.2f}%")
print(f"算术平均收益率: {arithmetic_mean_return:.2f}%")
print(f"差异: {abs(geometric_mean_return - arithmetic_mean_return):.2f}%")
# 验证复合增长的正确性
final_value_geometric = (1 + geometric_mean_return/100) ** len(annual_returns)
final_value_actual = np.prod(growth_factors)
print(f"\n验证:")
print(f"使用几何平均的最终价值倍数: {final_value_geometric:.4f}")
print(f"实际复合增长的最终价值倍数: {final_value_actual:.4f}")
print(f"差异: {abs(final_value_geometric - final_value_actual):.6f}")
# 可视化对比
plt.figure(figsize=(12, 8))
# 实际增长路径
years = list(range(len(annual_returns) + 1))
actual_values = [1.0] # 初始投资1元
for factor in growth_factors:
actual_values.append(actual_values[-1] * factor)
# 几何平均增长路径
geometric_values = [1.0]
for i in range(1, len(years)):
geometric_values.append(geometric_values[0] * (geometric_mean_factor ** i))
# 算术平均增长路径(错误的复合方式)
arithmetic_factor = 1 + arithmetic_mean_return/100
arithmetic_values = [1.0]
for i in range(1, len(years)):
arithmetic_values.append(arithmetic_values[0] * (arithmetic_factor ** i))
plt.plot(years, actual_values, 'bo-', linewidth=2, label='实际增长路径', markersize=8)
plt.plot(years, geometric_values, 'r--', linewidth=2, label=f'几何平均({geometric_mean_return:.2f}%/年)')
plt.plot(years, arithmetic_values, 'g:', linewidth=2, label=f'算术平均({arithmetic_mean_return:.2f}%/年,错误!)')
plt.xlabel('年份')
plt.ylabel('投资价值倍数')
plt.title('几何平均 vs 算术平均在复合增长中的差异')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
geometric_mean_example()
🎵 调和平均数(Harmonic Mean)
适用于比率的平均(如速度、效率等):
$$\bar{x}_h = \frac{n}{\sum_{i=1}^{n} \frac{1}{x_i}} = \frac{n}{\frac{1}{x_1} + \frac{1}{x_2} + ... + \frac{1}{x_n}}$$from scipy.stats import hmean
import numpy as np
def harmonic_mean_example():
"""调和平均数在速度计算中的应用"""
print("=== 平均速度计算(调和平均数)===")
# 场景:往返旅行,去程60km/h,回程40km/h,求平均速度
speed_going = 60 # km/h
speed_returning = 40 # km/h
distance = 120 # 单程距离 km
print(f"去程速度: {speed_going} km/h")
print(f"回程速度: {speed_returning} km/h")
print(f"单程距离: {distance} km")
# 错误的算术平均计算
arithmetic_avg_speed = (speed_going + speed_returning) / 2
# 正确的调和平均计算
harmonic_avg_speed = hmean([speed_going, speed_returning])
# 验证:通过总时间计算实际平均速度
time_going = distance / speed_going
time_returning = distance / speed_returning
total_time = time_going + time_returning
total_distance = 2 * distance
actual_avg_speed = total_distance / total_time
print(f"\n去程用时: {time_going:.2f} 小时")
print(f"回程用时: {time_returning:.2f} 小时")
print(f"总用时: {total_time:.2f} 小时")
print(f"总距离: {total_distance} km")
print(f"\n算术平均速度(错误): {arithmetic_avg_speed:.2f} km/h")
print(f"调和平均速度(正确): {harmonic_avg_speed:.2f} km/h")
print(f"实际平均速度: {actual_avg_speed:.2f} km/h")
print(f"调和平均与实际的差异: {abs(harmonic_avg_speed - actual_avg_speed):.6f} km/h")
# 更复杂的例子:多段不同速度的旅程
print("\n=== 多段旅程的平均速度 ===")
segments = [
{'distance': 50, 'speed': 80}, # 高速路段
{'distance': 30, 'speed': 40}, # 城市路段
{'distance': 20, 'speed': 60} # 郊区路段
]
total_distance = sum(seg['distance'] for seg in segments)
total_time = sum(seg['distance'] / seg['speed'] for seg in segments)
true_avg_speed = total_distance / total_time
# 加权调和平均(以距离为权重)
distances = [seg['distance'] for seg in segments]
speeds = [seg['speed'] for seg in segments]
weighted_harmonic_avg = total_distance / sum(d/s for d, s in zip(distances, speeds))
print(f"各路段情况:")
for i, seg in enumerate(segments, 1):
time_needed = seg['distance'] / seg['speed']
print(f" 路段{i}: {seg['distance']}km, {seg['speed']}km/h, 用时{time_needed:.2f}h")
print(f"\n总距离: {total_distance} km")
print(f"总用时: {total_time:.2f} 小时")
print(f"实际平均速度: {true_avg_speed:.2f} km/h")
print(f"加权调和平均速度: {weighted_harmonic_avg:.2f} km/h")
print(f"差异: {abs(true_avg_speed - weighted_harmonic_avg):.6f} km/h")
harmonic_mean_example()
🎯 均值在实际业务中的应用
📊 电商业务分析
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
def ecommerce_average_analysis():
"""电商业务中的均值分析"""
np.random.seed(42)
# 模拟电商订单数据
n_orders = 5000
# 不同用户群体的订单
vip_orders = np.random.lognormal(mean=5.0, sigma=0.5, size=500) # VIP用户,高客单价
regular_orders = np.random.lognormal(mean=4.0, sigma=0.6, size=3000) # 普通用户
new_orders = np.random.lognormal(mean=3.5, sigma=0.8, size=1500) # 新用户,低客单价
all_orders = np.concatenate([vip_orders, regular_orders, new_orders])
# 创建数据框
user_types = ['VIP'] * 500 + ['Regular'] * 3000 + ['New'] * 1500
df = pd.DataFrame({
'order_amount': all_orders,
'user_type': user_types
})
print("=== 电商客单价分析 ===")
# 总体统计
overall_mean = df['order_amount'].mean()
overall_median = df['order_amount'].median()
print(f"总体客单价均值: ¥{overall_mean:.2f}")
print(f"总体客单价中位数: ¥{overall_median:.2f}")
print(f"均值与中位数差异: ¥{abs(overall_mean - overall_median):.2f}")
# 分用户类型分析
group_stats = df.groupby('user_type')['order_amount'].agg([
'count', 'mean', 'median', 'std'
]).round(2)
print(f"\n各用户群体客单价统计:")
print(group_stats)
# 加权平均客单价(按订单量加权)
weighted_mean = np.average(
group_stats['mean'],
weights=group_stats['count']
)
print(f"\n加权平均客单价: ¥{weighted_mean:.2f}")
print(f"与总体均值差异: ¥{abs(weighted_mean - overall_mean):.2f}")
# 可视化分析
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
# 1. 客单价分布直方图
axes[0,0].hist(df['order_amount'], bins=50, alpha=0.7, color='skyblue', edgecolor='black')
axes[0,0].axvline(overall_mean, color='red', linestyle='--', linewidth=2, label=f'均值: ¥{overall_mean:.2f}')
axes[0,0].axvline(overall_median, color='green', linestyle='--', linewidth=2, label=f'中位数: ¥{overall_median:.2f}')
axes[0,0].set_title('客单价分布')
axes[0,0].set_xlabel('客单价 (¥)')
axes[0,0].set_ylabel('频数')
axes[0,0].legend()
# 2. 不同用户类型的客单价箱线图
sns.boxplot(data=df, x='user_type', y='order_amount', ax=axes[0,1])
axes[0,1].set_title('不同用户类型客单价分布')
axes[0,1].set_ylabel('客单价 (¥)')
# 3. 用户类型占比饼图
user_counts = df['user_type'].value_counts()
axes[1,0].pie(user_counts.values, labels=user_counts.index, autopct='%1.1f%%')
axes[1,0].set_title('用户类型分布')
# 4. 各用户类型贡献的收入
revenue_by_type = df.groupby('user_type')['order_amount'].sum()
axes[1,1].bar(revenue_by_type.index, revenue_by_type.values, color=['gold', 'lightblue', 'lightcoral'])
axes[1,1].set_title('各用户类型总收入贡献')
axes[1,1].set_ylabel('总收入 (¥)')
for i, v in enumerate(revenue_by_type.values):
axes[1,1].text(i, v + max(revenue_by_type.values)*0.01, f'¥{v:.0f}', ha='center')
plt.tight_layout()
plt.show()
# 业务洞察
print(f"\n=== 业务洞察 ===")
vip_avg = group_stats.loc['VIP', 'mean']
regular_avg = group_stats.loc['Regular', 'mean']
new_avg = group_stats.loc['New', 'mean']
print(f"1. VIP用户客单价比普通用户高 {((vip_avg/regular_avg - 1)*100):.1f}%")
print(f"2. 新用户客单价比普通用户低 {((1 - new_avg/regular_avg)*100):.1f}%")
# 计算如果提升新用户客单价的潜在收益
new_user_count = len(df[df['user_type'] == 'New'])
potential_increase = (regular_avg - new_avg) * new_user_count
print(f"3. 如果新用户客单价提升至普通用户水平,可增收: ¥{potential_increase:.0f}")
ecommerce_average_analysis()
📈 股票投资分析
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
def stock_return_analysis():
"""股票收益率的均值分析"""
np.random.seed(42)
# 模拟股票价格数据(随机游走)
days = 252 # 一年交易日
initial_price = 100
# 模拟三只股票的价格走势
stocks = {
'STOCK_A': {'drift': 0.08/252, 'volatility': 0.2/np.sqrt(252)}, # 年化8%收益,20%波动率
'STOCK_B': {'drift': 0.12/252, 'volatility': 0.3/np.sqrt(252)}, # 年化12%收益,30%波动率
'STOCK_C': {'drift': 0.05/252, 'volatility': 0.15/np.sqrt(252)} # 年化5%收益,15%波动率
}
price_data = {}
return_data = {}
for stock, params in stocks.items():
# 生成价格序列
returns = np.random.normal(params['drift'], params['volatility'], days)
prices = [initial_price]
for ret in returns:
prices.append(prices[-1] * (1 + ret))
price_data[stock] = prices[1:] # 排除初始价格
return_data[stock] = returns
# 创建日期索引
dates = pd.date_range(start='2023-01-01', periods=days, freq='B')
# 创建DataFrame
price_df = pd.DataFrame(price_data, index=dates)
return_df = pd.DataFrame(return_data, index=dates)
print("=== 股票收益率均值分析 ===")
# 计算各种均值
stats_summary = pd.DataFrame(index=stocks.keys())
for stock in stocks.keys():
returns = return_df[stock]
# 各种均值计算
arithmetic_mean = returns.mean()
geometric_mean = (1 + returns).prod() ** (1/len(returns)) - 1
# 年化收益率
annual_arithmetic = arithmetic_mean * 252
annual_geometric = ((1 + returns).prod()) ** (252/len(returns)) - 1
# 波动率
volatility = returns.std() * np.sqrt(252)
# 风险调整收益(夏普比率,假设无风险利率3%)
risk_free_rate = 0.03
daily_risk_free_rate = (1 + risk_free_rate) ** (1 / 252) - 1
excess_returns = returns - daily_risk_free_rate
sharpe_ratio = excess_returns.mean() / excess_returns.std() * np.sqrt(252)
stats_summary.loc[stock, 'Daily_Arithmetic_Mean'] = arithmetic_mean
stats_summary.loc[stock, 'Daily_Geometric_Mean'] = geometric_mean
stats_summary.loc[stock, 'Annual_Arithmetic_Return'] = annual_arithmetic
stats_summary.loc[stock, 'Annual_Geometric_Return'] = annual_geometric
stats_summary.loc[stock, 'Annual_Volatility'] = volatility
stats_summary.loc[stock, 'Sharpe_Ratio'] = sharpe_ratio
stats_summary.loc[stock, 'Final_Price'] = price_df[stock].iloc[-1]
stats_summary.loc[stock, 'Total_Return'] = (price_df[stock].iloc[-1] / initial_price - 1)
print("股票收益率统计汇总:")
print(stats_summary.round(4))
# 可视化分析
fig, axes = plt.subplots(2, 2, figsize=(16, 12))
# 1. 价格走势图
price_df.plot(ax=axes[0,0], linewidth=2)
axes[0,0].set_title('股票价格走势')
axes[0,0].set_ylabel('价格')
axes[0,0].grid(True, alpha=0.3)
# 2. 日收益率分布
return_df.hist(bins=30, ax=axes[0,1], alpha=0.7)
axes[0,1].set_title('日收益率分布')
axes[0,1].set_xlabel('日收益率')
# 3. 累计收益率
cumulative_returns = (1 + return_df).cumprod() - 1
cumulative_returns.plot(ax=axes[1,0], linewidth=2)
axes[1,0].set_title('累计收益率')
axes[1,0].set_ylabel('累计收益率')
axes[1,0].grid(True, alpha=0.3)
# 4. 风险-收益散点图
axes[1,1].scatter(stats_summary['Annual_Volatility'], stats_summary['Annual_Geometric_Return'],
s=100, alpha=0.7)
for stock in stocks.keys():
axes[1,1].annotate(stock,
(stats_summary.loc[stock, 'Annual_Volatility'],
stats_summary.loc[stock, 'Annual_Geometric_Return']),
xytext=(5, 5), textcoords='offset points')
axes[1,1].set_xlabel('年化波动率')
axes[1,1].set_ylabel('年化几何收益率')
axes[1,1].set_title('风险-收益关系')
axes[1,1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 投资组合分析
print(f"\n=== 投资组合分析 ===")
# 等权重组合
portfolio_returns = return_df.mean(axis=1)
portfolio_annual_return = ((1 + portfolio_returns).prod()) ** (252/len(portfolio_returns)) - 1
portfolio_volatility = portfolio_returns.std() * np.sqrt(252)
portfolio_daily_risk_free_rate = (1 + 0.03) ** (1 / 252) - 1
portfolio_excess_returns = portfolio_returns - portfolio_daily_risk_free_rate
portfolio_sharpe = portfolio_excess_returns.mean() / portfolio_excess_returns.std() * np.sqrt(252)
print(f"等权重组合年化收益率: {portfolio_annual_return:.2%}")
print(f"等权重组合年化波动率: {portfolio_volatility:.2%}")
print(f"等权重组合夏普比率: {portfolio_sharpe:.3f}")
# 与单只股票对比
print(f"\n单只股票 vs 组合:")
for stock in stocks.keys():
individual_sharpe = stats_summary.loc[stock, 'Sharpe_Ratio']
print(f"{stock} 夏普比率: {individual_sharpe:.3f}")
print(f"组合夏普比率: {portfolio_sharpe:.3f}")
print(f"分散投资的好处: 组合相比最差单股提升了 {(portfolio_sharpe - stats_summary['Sharpe_Ratio'].min()):.3f}")
stock_return_analysis()
⚠️ 均值的局限性与注意事项
🎭 异常值对均值的影响
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats
def outlier_impact_demo():
"""演示异常值对均值的影响"""
print("=== 异常值对均值的影响分析 ===")
# 正常数据
np.random.seed(42)
normal_data = np.random.normal(50, 10, 100)
# 添加异常值
data_with_outliers = np.append(normal_data, [150, 200, 250])
# 计算各种统计量
stats_comparison = pd.DataFrame({
'统计量': ['均值', '中位数', '众数', '标准差'],
'正常数据': [
np.mean(normal_data),
np.median(normal_data),
stats.mode(normal_data.round(), keepdims=True)[0][0],
np.std(normal_data, ddof=1)
],
'含异常值数据': [
np.mean(data_with_outliers),
np.median(data_with_outliers),
stats.mode(data_with_outliers.round(), keepdims=True)[0][0],
np.std(data_with_outliers, ddof=1)
]
})
stats_comparison['变化幅度'] = (
(stats_comparison['含异常值数据'] - stats_comparison['正常数据']) /
stats_comparison['正常数据'] * 100
).round(2)
print(stats_comparison.round(2))
# 可视化对比
fig, axes = plt.subplots(1, 2, figsize=(15, 6))
# 正常数据分布
axes[0].hist(normal_data, bins=20, alpha=0.7, color='lightblue', edgecolor='black')
axes[0].axvline(np.mean(normal_data), color='red', linestyle='--',
label=f'均值: {np.mean(normal_data):.1f}')
axes[0].axvline(np.median(normal_data), color='green', linestyle='--',
label=f'中位数: {np.median(normal_data):.1f}')
axes[0].set_title('正常数据分布')
axes[0].set_xlabel('数值')
axes[0].set_ylabel('频数')
axes[0].legend()
# 含异常值数据分布
axes[1].hist(data_with_outliers, bins=25, alpha=0.7, color='lightcoral', edgecolor='black')
axes[1].axvline(np.mean(data_with_outliers), color='red', linestyle='--',
label=f'均值: {np.mean(data_with_outliers):.1f}')
axes[1].axvline(np.median(data_with_outliers), color='green', linestyle='--',
label=f'中位数: {np.median(data_with_outliers):.1f}')
axes[1].set_title('含异常值数据分布')
axes[1].set_xlabel('数值')
axes[1].set_ylabel('频数')
axes[1].legend()
plt.tight_layout()
plt.show()
print(f"\n关键观察:")
print(f"1. 异常值使均值从 {np.mean(normal_data):.1f} 增加到 {np.mean(data_with_outliers):.1f}")
print(f"2. 中位数相对稳定,仅从 {np.median(normal_data):.1f} 变为 {np.median(data_with_outliers):.1f}")
print(f"3. 标准差大幅增加 {stats_comparison.iloc[3, 3]:.1f}%,表明数据变异性增大")
outlier_impact_demo()
📊 偏态分布中的均值问题
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import pandas as pd
def skewed_distribution_analysis():
"""偏态分布中均值的问题"""
print("=== 偏态分布中的均值分析 ===")
np.random.seed(42)
# 生成不同偏态的数据
normal_data = np.random.normal(50, 15, 1000)
right_skewed = np.random.exponential(20, 1000) + 30 # 右偏
left_skewed = 100 - np.random.exponential(20, 1000) # 左偏
datasets = {
'正态分布': normal_data,
'右偏分布': right_skewed,
'左偏分布': left_skewed
}
# 计算统计量
stats_df = pd.DataFrame(index=['均值', '中位数', '众数', '偏度', '峰度'])
for name, data in datasets.items():
mean_val = np.mean(data)
median_val = np.median(data)
mode_val = stats.mode(data.round(), keepdims=True)[0][0]
skewness = stats.skew(data)
kurtosis = stats.kurtosis(data)
stats_df[name] = [mean_val, median_val, mode_val, skewness, kurtosis]
print("各分布的统计量对比:")
print(stats_df.round(3))
# 可视化
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
colors = ['skyblue', 'lightcoral', 'lightgreen']
for i, (name, data) in enumerate(datasets.items()):
# 直方图
axes[0, i].hist(data, bins=30, alpha=0.7, color=colors[i], edgecolor='black', density=True)
mean_val = np.mean(data)
median_val = np.median(data)
mode_val = stats.mode(data.round(), keepdims=True)[0][0]
axes[0, i].axvline(mean_val, color='red', linestyle='--', linewidth=2, label=f'均值: {mean_val:.1f}')
axes[0, i].axvline(median_val, color='green', linestyle='--', linewidth=2, label=f'中位数: {median_val:.1f}')
axes[0, i].axvline(mode_val, color='blue', linestyle='--', linewidth=2, label=f'众数: {mode_val:.1f}')
axes[0, i].set_title(f'{name}\n偏度: {stats.skew(data):.2f}')
axes[0, i].set_xlabel('数值')
axes[0, i].set_ylabel('密度')
axes[0, i].legend()
# 箱线图
axes[1, i].boxplot(data, vert=True)
axes[1, i].set_title(f'{name} 箱线图')
axes[1, i].set_ylabel('数值')
# 添加统计量标记
axes[1, i].axhline(mean_val, color='red', linestyle='--', alpha=0.7, label='均值')
axes[1, i].axhline(median_val, color='green', linestyle='--', alpha=0.7, label='中位数')
plt.tight_layout()
plt.show()
# 分析均值的代表性
print(f"\n=== 均值代表性分析 ===")
for name, data in datasets.items():
mean_val = np.mean(data)
median_val = np.median(data)
# 计算有多少数据点小于均值
below_mean_pct = (data < mean_val).mean() * 100
below_median_pct = (data < median_val).mean() * 100
print(f"\n{name}:")
print(f" 小于均值的数据占比: {below_mean_pct:.1f}%")
print(f" 小于中位数的数据占比: {below_median_pct:.1f}%")
print(f" 均值与中位数差异: {abs(mean_val - median_val):.2f}")
if abs(stats.skew(data)) > 0.5:
print(f" ⚠️ 该分布偏度较大,均值可能不是最佳的中心趋势代表")
skewed_distribution_analysis()
🔍 均值的高级应用
📈 移动平均与趋势分析
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
def moving_average_analysis():
"""移动平均在时间序列分析中的应用"""
print("=== 移动平均趋势分析 ===")
# 生成模拟时间序列数据(股价)
np.random.seed(42)
dates = pd.date_range('2023-01-01', periods=252, freq='D')
# 基础趋势 + 周期性 + 随机噪声
trend = np.linspace(100, 120, 252)
seasonal = 5 * np.sin(2 * np.pi * np.arange(252) / 30) # 30天周期
noise = np.random.normal(0, 2, 252)
price = trend + seasonal + noise
df = pd.DataFrame({'price': price}, index=dates)
# 计算不同期间的移动平均
df['MA_5'] = df['price'].rolling(window=5).mean() # 5日均线
df['MA_20'] = df['price'].rolling(window=20).mean() # 20日均线
df['MA_60'] = df['price'].rolling(window=60).mean() # 60日均线
# 指数移动平均
df['EMA_20'] = df['price'].ewm(span=20).mean()
# 布林带(基于20日移动平均)
df['BB_upper'] = df['MA_20'] + 2 * df['price'].rolling(window=20).std()
df['BB_lower'] = df['MA_20'] - 2 * df['price'].rolling(window=20).std()
print(f"数据时间范围: {df.index[0].date()} 到 {df.index[-1].date()}")
print(f"价格范围: {df['price'].min():.2f} - {df['price'].max():.2f}")
# 可视化
plt.figure(figsize=(16, 10))
# 主图:价格和移动平均线
plt.subplot(2, 1, 1)
plt.plot(df.index, df['price'], label='价格', linewidth=1, alpha=0.7)
plt.plot(df.index, df['MA_5'], label='5日均线', linewidth=1.5)
plt.plot(df.index, df['MA_20'], label='20日均线', linewidth=2)
plt.plot(df.index, df['MA_60'], label='60日均线', linewidth=2)
plt.plot(df.index, df['EMA_20'], label='20日指数均线', linewidth=1.5, linestyle='--')
# 布林带
plt.fill_between(df.index, df['BB_upper'], df['BB_lower'], alpha=0.2, color='gray', label='布林带')
plt.title('价格与移动平均线分析')
plt.ylabel('价格')
plt.legend()
plt.grid(True, alpha=0.3)
# 子图:移动平均线的交叉信号
plt.subplot(2, 1, 2)
# 计算均线交叉信号
df['signal'] = 0
df.loc[df['MA_5'] > df['MA_20'], 'signal'] = 1 # 金叉:短期均线上穿长期均线
df.loc[df['MA_5'] <= df['MA_20'], 'signal'] = -1 # 死叉:短期均线下穿长期均线
# 找出交叉点
df['signal_change'] = df['signal'].diff()
golden_cross = df[df['signal_change'] == 2].index # 死叉转金叉
death_cross = df[df['signal_change'] == -2].index # 金叉转死叉
plt.plot(df.index, df['price'], label='价格', color='black', linewidth=1)
plt.scatter(golden_cross, df.loc[golden_cross, 'price'],
color='gold', s=100, marker='^', label=f'金叉信号({len(golden_cross)}次)', zorder=5)
plt.scatter(death_cross, df.loc[death_cross, 'price'],
color='red', s=100, marker='v', label=f'死叉信号({len(death_cross)}次)', zorder=5)
plt.title('移动平均线交叉信号')
plt.xlabel('日期')
plt.ylabel('价格')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 交易信号分析
print(f"\n=== 交易信号分析 ===")
print(f"观察期内金叉信号: {len(golden_cross)} 次")
print(f"观察期内死叉信号: {len(death_cross)} 次")
# 计算信号的盈利性(简化分析)
if len(golden_cross) > 0 and len(death_cross) > 0:
# 匹配买入卖出信号
trades = []
for i, buy_date in enumerate(golden_cross):
# 找到下一个卖出信号
next_sell = death_cross[death_cross > buy_date]
if len(next_sell) > 0:
sell_date = next_sell[0]
buy_price = df.loc[buy_date, 'price']
sell_price = df.loc[sell_date, 'price']
return_pct = (sell_price - buy_price) / buy_price * 100
trades.append({
'buy_date': buy_date,
'sell_date': sell_date,
'buy_price': buy_price,
'sell_price': sell_price,
'return_pct': return_pct,
'days_held': (sell_date - buy_date).days
})
if trades:
trades_df = pd.DataFrame(trades)
print(f"\n完整交易次数: {len(trades_df)}")
print(f"平均收益率: {trades_df['return_pct'].mean():.2f}%")
print(f"胜率: {(trades_df['return_pct'] > 0).mean()*100:.1f}%")
print(f"平均持仓天数: {trades_df['days_held'].mean():.1f}天")
print(f"最大单次收益: {trades_df['return_pct'].max():.2f}%")
print(f"最大单次亏损: {trades_df['return_pct'].min():.2f}%")
moving_average_analysis()
🔗 学习路径与推荐资源
📚 后续学习建议
- 深入理解:
- 实际应用:
- 高级技术:
- 时间序列 - 动态均值分析
- 贝叶斯统计 - 后验均值估计
🛠️ 实践建议
# 实践任务清单
practice_tasks = [
"1. 分析你最近一个月的支出数据,计算日均消费",
"2. 比较算术平均和几何平均在投资收益计算中的差异",
"3. 使用移动平均分析某只股票的价格趋势",
"4. 计算加权平均分(以学分为权重)",
"5. 分析异常值对班级平均分的影响",
"6. 使用调和平均计算往返旅行的平均速度"
]
print("=== 均值学习实践任务 ===")
for task in practice_tasks:
print(task)
print("\n完成这些任务将帮助你深入理解均值在实际中的应用!")
#统计学 #均值 #平均数 #描述性统计 #集中趋势 #Python #数据分析