未记录事实核验 · 状态:维护中

记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。

warning 适用边界与维护说明

本文适用于中位数基础计算、模拟数据分组分析及扩展算法学习,不构成真实业务结论或完整生产实现。本次仅作全文结构审阅,未运行代码或进行外部事实、链接核验。深度房价模拟未定义金额单位,输出和图表中的“万元/平米”不能用于解释真实城市价格水平。数值计算应使用非空、有限数值输入;有序分类数据不能直接套用偶数样本取算术平均的规则。分组插值要求区间有序、无重叠、宽度为正,频数与区间匹配且非负、总频数为正,并采用组内均匀近似。MAD检测中的阈值是示例规则,MAD为零时会列出所有偏离中位数的值,不能据此证明异常。平滑窗口限正奇数,边缘窗口会截短;加权计算要求非空、等长、非负权重且总权重为正,累计权重恰好达到一半时返回当前值,不采用两个边界值取平均的约定。双堆实现仅支持持续加入数据并保留全部历史观测,不支持固定内存或滑动窗口;部分代码块依赖前文导入,需按顺序执行或自行准备相应依赖。

📊 中位数(Median)

abstract 📋 本节概览

  • 🎯 学习目标:深入理解中位数的本质、计算方法和在数据分析中的重要作用
  • 📚 前置知识:描述性统计 | 集中趋势指标
  • ⏱️ 预计用时:15分钟
  • 🔧 实践技能:掌握Python中位数计算和实际应用分析

🤔 什么是中位数?

note 📖 **中位数的定义**

中位数是将一组数据按大小顺序排列后,位于中间位置的数值。至少一半数据不大于中位数,至少一半数据不小于中位数;存在重复值或奇数个观测时,严格小于和严格大于中位数的数据不一定各占一半。

生活例子:

  • 班级里11个同学的身高排队,站在中间的那个同学的身高就是中位数
  • 5个朋友的工资:3000, 4000, 5000, 8000, 20000,中位数是5000元(不受20000这个高收入影响)

🔢 中位数的计算方法

奇数个数据

公式:$\text{中位数} = X_{(\frac{n+1}{2})}$

步骤:

  1. 将数据按从小到大排序
  2. 找到第 $\frac{n+1}{2}$ 个位置的数值

例子:数据 [3, 1, 4, 1, 5]

  • 排序后:[1, 1, 3, 4, 5]
  • n=5,中位数位置:$\frac{5+1}{2} = 3$
  • 中位数 = 第3个数 = 3

偶数个数据

公式:$\text{中位数} = \frac{X_{(\frac{n}{2})} + X_{(\frac{n}{2}+1)}}{2}$

步骤:

  1. 将数据按从小到大排序
  2. 找到第 $\frac{n}{2}$ 和第 $\frac{n}{2}+1$ 个位置的数值
  3. 取两个数值的平均值

例子:数据 [2, 4, 1, 3]

  • 排序后:[1, 2, 3, 4]
  • n=4,中位数位置:第2和第3个数
  • 中位数 = $\frac{2 + 3}{2} = 2.5$

💻 Python实现

import numpy as np
import statistics

# 方法1:使用numpy
data = [3, 1, 4, 1, 5, 9, 2, 6]
median_np = np.median(data)
print(f"NumPy方法: {median_np}")

# 方法2:使用statistics模块
median_stat = statistics.median(data)
print(f"Statistics方法: {median_stat}")

# 方法3:手动计算
def calculate_median(data):
    sorted_data = sorted(data)
    n = len(sorted_data)
    
    if n % 2 == 1:  # 奇数个数据
        return sorted_data[n // 2]
    else:  # 偶数个数据
        mid1 = sorted_data[n // 2 - 1]
        mid2 = sorted_data[n // 2]
        return (mid1 + mid2) / 2

median_manual = calculate_median(data)
print(f"手动计算: {median_manual}")

🆚 中位数 vs 均值

特征 中位数 均值
定义 中间位置的值 所有值的平均
抗异常值 ✅ 强 ❌ 弱
计算方式 本文基础实现采用排序,也可使用选择算法或双堆维护 求和后除以数据个数
适用数据 数值型、有序分类 数值型
受分布影响 偏态分布下通常比均值更少受尾部极端数值牵引,但仍随分布变化 易受尾部极端数值牵引
import numpy as np
import matplotlib.pyplot as plt

# 正常分布数据
normal_data = [2, 3, 4, 4, 5, 5, 5, 6, 6, 7]
print("正常分布数据:")
print(f"均值: {np.mean(normal_data):.2f}")
print(f"中位数: {np.median(normal_data):.2f}")

# 包含异常值的数据
outlier_data = [2, 3, 4, 4, 5, 5, 5, 6, 6, 50]  # 50是异常值
print("\n包含异常值的数据:")
print(f"均值: {np.mean(outlier_data):.2f}")  # 被异常值拉高
print(f"中位数: {np.median(outlier_data):.2f}")  # 不受影响

🎯 中位数的应用场景

1. 收入分析

为什么用中位数? 收入分布通常右偏,少数高收入者会拉高平均值

# 某公司员工月薪(元)
salaries = [4000, 4500, 5000, 5500, 6000, 6500, 7000, 25000, 30000]

print(f"平均工资: {np.mean(salaries):,.0f}元")      # 被高薪拉高
print(f"中位数工资: {np.median(salaries):,.0f}元")    # 更代表普通员工
print(f"众数工资: 无单一众数")

# 结论:中位数更能反映普通员工的收入水平

2. 房价分析

# 某小区房价(万元/平米)
house_prices = [3.5, 3.8, 4.0, 4.2, 4.5, 4.8, 5.0, 8.0, 12.0]

print(f"平均房价: {np.mean(house_prices):.1f}万/平米")
print(f"中位数房价: {np.median(house_prices):.1f}万/平米")

# 中位数更适合描述"大多数房子的价格水平"

3. 考试成绩分析

# 班级考试成绩
scores = [65, 70, 75, 78, 80, 82, 85, 88, 90, 95]

print(f"平均分: {np.mean(scores):.1f}")
print(f"中位数分数: {np.median(scores):.1f}")

# 中位数表示有一半学生高于此分数,一半低于此分数

📊 中位数的变体和扩展

1. 分位数系列

data = np.random.normal(100, 15, 1000)  # 生成正态分布数据

# 常用分位数
percentiles = [25, 50, 75, 90, 95, 99]
for p in percentiles:
    value = np.percentile(data, p)
    print(f"第{p}百分位数: {value:.2f}")

# 四分位数
Q1 = np.percentile(data, 25)   # 第一四分位数
Q2 = np.percentile(data, 50)   # 第二四分位数(中位数)
Q3 = np.percentile(data, 75)   # 第三四分位数

print(f"\nQ1: {Q1:.2f}, Q2(中位数): {Q2:.2f}, Q3: {Q3:.2f}")

2. 分组数据的中位数

def grouped_median(intervals, frequencies):
    """计算分组数据的中位数"""
    total = sum(frequencies)
    cumulative = 0
    median_position = total / 2
    
    for i, freq in enumerate(frequencies):
        cumulative += freq
        if cumulative >= median_position:
 # 找到中位数所在组
            lower_bound = intervals[i][0]
            upper_bound = intervals[i][1]
            cf_before = cumulative - freq  # 组前累积频数
            
 # 线性插值估算
            median = lower_bound + ((median_position - cf_before) / freq) * (upper_bound - lower_bound)
            return median
    
    return None

# 示例:年龄分组数据
age_groups = [(20, 30), (30, 40), (40, 50), (50, 60)]
frequencies = [15, 25, 30, 10]

median_age = grouped_median(age_groups, frequencies)
print(f"分组数据估算中位数: {median_age:.1f}岁")

🔍 中位数的优缺点分析

✅ 优点

  1. 抗异常值:相比均值,对少量极端值通常更稳健,但并非在所有数据变化下保持不变
  2. 直观易懂:"中间值"概念简单
  3. 适用性广:适用于偏斜分布
  4. 相对稳健:对少量尾部极端值的变化通常比均值更不敏感,但对一般数据变化及抽样波动的敏感程度取决于具体分布

❌ 缺点

  1. 信息损失:不使用所有数据信息
  2. 计算成本:排序实现通常比直接求均值成本高,但计算中位数并不一定需要完整排序
  3. 不适合代数运算:无法简单地合并多组中位数
  4. 采样变异性:小样本时变异较大

🛠️ 实际应用技巧

1. 异常值检测

def detect_outliers_median(data, threshold=2):
    """基于中位数的异常值检测"""
    median = np.median(data)
    mad = np.median(np.abs(data - median))  # 中位数绝对偏差
    
    outliers = []
    for x in data:
        if np.abs(x - median) > threshold * mad:
            outliers.append(x)
    
    return outliers

# 示例
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 100]  # 100是异常值
outliers = detect_outliers_median(data)
print(f"检测到的异常值: {outliers}")

2. 中位数平滑

def median_filter(data, window_size=3):
    """中位数滤波器"""
    filtered = []
    half_window = window_size // 2
    
    for i in range(len(data)):
        start = max(0, i - half_window)
        end = min(len(data), i + half_window + 1)
        window = data[start:end]
        filtered.append(np.median(window))
    
    return filtered

# 含噪声的时间序列
import random
noisy_data = [x + random.uniform(-2, 2) for x in range(20)]
smoothed = median_filter(noisy_data, 5)

print("原始数据前10个:", noisy_data[:10])
print("平滑数据前10个:", smoothed[:10])

🔬 中位数在大数据中的应用

📈 电商用户行为分析

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats

def ecommerce_median_analysis():
    """电商用户消费中位数分析"""
    np.random.seed(42)
    
    # 模拟电商用户数据(对数正态分布,模拟右偏分布)
    n_users = 10000
    
    # 不同用户群体
    normal_users = np.random.lognormal(mean=4.0, sigma=0.6, size=8000)  # 普通用户
    vip_users = np.random.lognormal(mean=5.5, sigma=0.4, size=1500)     # VIP用户  
    whale_users = np.random.lognormal(mean=7.0, sigma=0.3, size=500)    # 大客户
    
    all_spending = np.concatenate([normal_users, vip_users, whale_users])
    user_types = ['Normal'] * 8000 + ['VIP'] * 1500 + ['Whale'] * 500
    
    df = pd.DataFrame({
        'spending': all_spending,
        'user_type': user_types
    })
    
    print("=== 电商用户消费中位数分析 ===")
    
    # 总体统计
    overall_mean = df['spending'].mean()
    overall_median = df['spending'].median()
    overall_std = df['spending'].std()
    
    print(f"\n总体消费统计:")
    print(f"  平均消费: ¥{overall_mean:.2f}")
    print(f"  中位数消费: ¥{overall_median:.2f}")
    print(f"  标准差: ¥{overall_std:.2f}")
    print(f"  均值/中位数比值: {overall_mean/overall_median:.2f}")
    
    # 分组统计
    group_stats = df.groupby('user_type')['spending'].agg([
        'count', 'mean', 'median', 'std', 
        lambda x: np.percentile(x, 25),  # Q1
        lambda x: np.percentile(x, 75),  # Q3
        'min', 'max'
    ]).round(2)
    
    group_stats.columns = ['Count', 'Mean', 'Median', 'Std', 'Q1', 'Q3', 'Min', 'Max']
    
    print(f"\n各用户类型消费统计:")
    print(group_stats)
    
    # 可视化分析
    fig, axes = plt.subplots(2, 2, figsize=(16, 12))
    
    # 1. 整体消费分布
    axes[0,0].hist(df['spending'], bins=100, alpha=0.7, color='skyblue', density=True)
    axes[0,0].axvline(overall_mean, color='red', linestyle='--', linewidth=2, label=f'均值: ¥{overall_mean:.0f}')
    axes[0,0].axvline(overall_median, color='green', linestyle='--', linewidth=2, label=f'中位数: ¥{overall_median:.0f}')
    axes[0,0].set_title('用户消费分布(显著右偏)')
    axes[0,0].set_xlabel('消费金额 (¥)')
    axes[0,0].set_ylabel('密度')
    axes[0,0].legend()
    axes[0,0].set_xlim(0, 1000)  # 限制x轴显示范围
    
    # 2. 不同用户类型箱线图
    sns.boxplot(data=df, x='user_type', y='spending', ax=axes[0,1])
    axes[0,1].set_title('不同用户类型消费分布')
    axes[0,1].set_ylabel('消费金额 (¥)')
    
    # 3. 对数变换后的分布(更接近正态)
    log_spending = np.log(df['spending'])
    axes[1,0].hist(log_spending, bins=50, alpha=0.7, color='lightcoral', density=True)
    axes[1,0].axvline(np.mean(log_spending), color='red', linestyle='--', linewidth=2, label=f'均值: {np.mean(log_spending):.2f}')
    axes[1,0].axvline(np.median(log_spending), color='green', linestyle='--', linewidth=2, label=f'中位数: {np.median(log_spending):.2f}')
    axes[1,0].set_title('对数消费分布(接近正态)')
    axes[1,0].set_xlabel('log(消费金额)')
    axes[1,0].set_ylabel('密度')
    axes[1,0].legend()
    
    # 4. 分位数分析
    percentiles = [10, 25, 50, 75, 90, 95, 99]
    pct_values = [np.percentile(df['spending'], p) for p in percentiles]
    
    axes[1,1].bar(range(len(percentiles)), pct_values, color='lightgreen')
    axes[1,1].set_xticks(range(len(percentiles)))
    axes[1,1].set_xticklabels([f'P{p}' for p in percentiles])
    axes[1,1].set_title('消费分位数分析')
    axes[1,1].set_ylabel('消费金额 (¥)')
    
    # 添加数值标签
    for i, v in enumerate(pct_values):
        axes[1,1].text(i, v + max(pct_values)*0.01, f'¥{v:.0f}', ha='center', fontsize=9)
    
    plt.tight_layout()
    plt.show()
    
    # 业务洞察
    print(f"\n=== 业务洞察分析 ===")
    print(f"1. 数据分布显著右偏,均值({overall_mean:.0f})明显高于中位数({overall_median:.0f})")
    print(f"2. 50%的用户消费低于¥{overall_median:.0f},中位数更代表典型用户")
    
    # 计算不同消费水平的用户占比
    below_median = (df['spending'] < overall_median).mean() * 100
    below_mean = (df['spending'] < overall_mean).mean() * 100
    high_spenders = (df['spending'] > overall_mean * 2).mean() * 100
    
    print(f"3. {below_median:.1f}%的用户消费低于中位数")
    print(f"4. {below_mean:.1f}%的用户消费低于平均值")
    print(f"5. 仅{high_spenders:.1f}%的用户是高消费用户(>平均消费的2倍)")
    
    # 中位数在不同组的稳定性
    print(f"\n=== 中位数稳定性分析 ===")
    for user_type in ['Normal', 'VIP', 'Whale']:
        group_data = df[df['user_type'] == user_type]['spending']
        group_mean = group_data.mean()
        group_median = group_data.median()
        skewness = stats.skew(group_data)
        
        print(f"{user_type}用户:")
        print(f"  均值: ¥{group_mean:.2f}, 中位数: ¥{group_median:.2f}")
        print(f"  偏度: {skewness:.3f} ({'Right-skewed' if skewness > 0 else 'Left-skewed' if skewness < 0 else 'Symmetric'})")
        print(f"  偏度绝对值是否超过示例阈值0.5: {'Yes' if abs(skewness) > 0.5 else 'No'};这不能单独证明中位数比均值更稳定")

ecommerce_median_analysis()

🏠 房价分析实战

def housing_price_median_analysis():
    """房价中位数深度分析"""
    np.random.seed(123)
    
    # 模拟不同地区房价数据
    regions = {
        '市中心': np.random.lognormal(mean=9.5, sigma=0.3, size=500),   # 高房价区
        '内环': np.random.lognormal(mean=9.0, sigma=0.4, size=800),     # 中高房价区  
        '外环': np.random.lognormal(mean=8.5, sigma=0.5, size=1200),    # 中等房价区
        '郊区': np.random.lognormal(mean=8.0, sigma=0.6, size=1500)     # 相对低房价区
    }
    
    # 合并数据
    all_prices = []
    all_regions = []
    
    for region, prices in regions.items():
        all_prices.extend(prices)
        all_regions.extend([region] * len(prices))
    
    df = pd.DataFrame({
        'price': all_prices,
        'region': all_regions
    })
    
    print("=== 房价中位数深度分析 ===")
    
    # 整体统计
    overall_stats = {
        '平均房价': df['price'].mean(),
        '中位房价': df['price'].median(),
        '最低房价': df['price'].min(),
        '最高房价': df['price'].max(),
        'Q1': df['price'].quantile(0.25),
        'Q3': df['price'].quantile(0.75)
    }
    
    print(f"\n全市房价概况 (万元/平米):")
    for key, value in overall_stats.items():
        print(f"  {key}: {value:.2f}")
    
    # 分地区统计
    regional_stats = df.groupby('region')['price'].agg([
        'count', 'mean', 'median', 'std',
        lambda x: np.percentile(x, 10),
        lambda x: np.percentile(x, 90)
    ]).round(2)
    
    regional_stats.columns = ['Sample_Size', 'Mean', 'Median', 'Std', 'P10', 'P90']
    regional_stats = regional_stats.sort_values('Median', ascending=False)
    
    print(f"\n各地区房价统计 (万元/平米):")
    print(regional_stats)
    
    # 可视化分析
    fig, axes = plt.subplots(2, 2, figsize=(16, 12))
    
    # 1. 各地区房价箱线图
    sns.boxplot(data=df, x='region', y='price', ax=axes[0,0], 
                order=regional_stats.index)  # 按中位数排序
    axes[0,0].set_title('各地区房价分布对比')
    axes[0,0].set_ylabel('房价 (万元/平米)')
    axes[0,0].tick_params(axis='x', rotation=45)
    
    # 2. 中位数 vs 均值对比
    x_pos = np.arange(len(regional_stats))
    width = 0.35
    
    axes[0,1].bar(x_pos - width/2, regional_stats['Mean'], width, label='平均价', alpha=0.7)
    axes[0,1].bar(x_pos + width/2, regional_stats['Median'], width, label='中位数', alpha=0.7)
    axes[0,1].set_xlabel('地区')
    axes[0,1].set_ylabel('房价 (万元/平米)')
    axes[0,1].set_title('各地区平均价 vs 中位数')
    axes[0,1].set_xticks(x_pos)
    axes[0,1].set_xticklabels(regional_stats.index, rotation=45)
    axes[0,1].legend()
    
    # 3. 全市房价分位数分析
    percentiles = [5, 10, 25, 50, 75, 90, 95]
    pct_values = [df['price'].quantile(p/100) for p in percentiles]
    
    axes[1,0].plot(percentiles, pct_values, 'bo-', linewidth=2, markersize=8)
    axes[1,0].set_xlabel('百分位数')
    axes[1,0].set_ylabel('房价 (万元/平米)')
    axes[1,0].set_title('全市房价分位数曲线')
    axes[1,0].grid(True, alpha=0.3)
    
    # 标注关键点
    axes[1,0].axhline(overall_stats['中位房价'], color='red', linestyle='--', alpha=0.7, label='中位数')
    axes[1,0].legend()
    
    # 4. 不同价位房子占比
    price_ranges = {
        '低价位(<P25)': (df['price'] < overall_stats['Q1']).mean() * 100,
        '中低价位(P25-P50)': ((df['price'] >= overall_stats['Q1']) & (df['price'] < overall_stats['中位房价'])).mean() * 100,
        '中高价位(P50-P75)': ((df['price'] >= overall_stats['中位房价']) & (df['price'] < overall_stats['Q3'])).mean() * 100,
        '高价位(>P75)': (df['price'] >= overall_stats['Q3']).mean() * 100
    }
    
    axes[1,1].pie(price_ranges.values(), labels=price_ranges.keys(), autopct='%1.1f%%', startangle=90)
    axes[1,1].set_title('不同价位房子占比')
    
    plt.tight_layout()
    plt.show()
    
    # 业务洞察
    print(f"\n=== 业务洞察与建议 ===")
    print(f"1. 中位房价 {overall_stats['中位房价']:.2f}万/平米,代表了全市房价的中间水平")
    print(f"2. 本模拟样本约50%的房子价格低于中位数;是否适合刚需人群还取决于收入、总价、区位等条件")
    print(f"3. 本模拟样本约25%的房子价格低于 {overall_stats['Q1']:.2f}万/平米,仅表示样本内价格较低,不能据此认定为经济适用房")
    
    # 不同地区的性价比分析
    print(f"\n=== 地区性价比分析 ===")
    for region in regional_stats.index:
        region_data = regional_stats.loc[region]
        affordability_score = (overall_stats['Q1'] - region_data['Median']) / overall_stats['Q1'] * 100
        
        print(f"{region}:")
        print(f"  中位房价: {region_data['Median']:.2f}万/平米")
        print(f"  相对全市Q1的价格差异评分: {affordability_score:+.1f}% ({'High' if affordability_score > 0 else 'Low' if affordability_score < -20 else 'Medium'};仅为示例分档,不代表综合性价比)")

housing_price_median_analysis()

⚙️ 高级中位数技术

🔄 动态中位数计算

import heapq
from collections import deque

class StreamingMedian:
    """流式数据中位数计算器"""
    
    def __init__(self):
        self.small_heap = []  # 大根堆,存放较小的一半数据
        self.large_heap = []  # 小根堆,存放较大的一半数据
        self.count = 0
    
    def add_number(self, num):
        """添加新数字"""
        self.count += 1
        
        # 添加到小数堆(使用负数模拟大根堆)
        heapq.heappush(self.small_heap, -num)
        
        # 将小数堆的最大值移到大数堆
        heapq.heappush(self.large_heap, -heapq.heappop(self.small_heap))
        
        # 平衡两个堆的大小
        if len(self.small_heap) < len(self.large_heap):
            heapq.heappush(self.small_heap, -heapq.heappop(self.large_heap))
    
    def get_median(self):
        """获取当前中位数"""
        if self.count == 0:
            return None
        
        if len(self.small_heap) > len(self.large_heap):
            return -self.small_heap[0]  # 奇数个元素
        else:
            return (-self.small_heap[0] + self.large_heap[0]) / 2  # 偶数个元素

# 测试流式中位数
def test_streaming_median():
    """测试流式中位数计算器"""
    print("=== 流式数据中位数计算 ===")
    
    stream_median = StreamingMedian()
    data_stream = [5, 15, 1, 3, 8, 7, 9, 6, 12, 2]
    
    print("Data Stream Processing:")
    all_data = []
    
    for i, num in enumerate(data_stream):
        all_data.append(num)
        stream_median.add_number(num)
        
        # 对比流式算法和简单算法的结果
        stream_result = stream_median.get_median()
        simple_result = np.median(all_data)
        
        print(f"  Step {i+1}: Add {num} -> Streaming: {stream_result}, Simple: {simple_result}")
        
        # 验证结果一致性
        assert abs(stream_result - simple_result) < 1e-10, f"Results don't match at step {i+1}"
    
    print("\n流式算法验证成功!")
    print(f"最终数据: {sorted(all_data)}")
    print(f"最终中位数: {stream_median.get_median()}")

test_streaming_median()

📊 加权中位数

def weighted_median(values, weights):
    """计算加权中位数"""
    if len(values) != len(weights):
        raise ValueError("Values and weights must have the same length")
    
    # 按值排序,并带上权重
    sorted_pairs = sorted(zip(values, weights))
    sorted_values, sorted_weights = zip(*sorted_pairs)
    
    # 计算累积权重
    total_weight = sum(sorted_weights)
    cumulative_weight = 0
    
    for i, (value, weight) in enumerate(sorted_pairs):
        cumulative_weight += weight
        
        # 当累积权重超过一半时,当前值就是加权中位数
        if cumulative_weight >= total_weight / 2:
            return value
    
    return sorted_values[-1]  # 安全返回

def weighted_median_example():
    """加权中位数应用示例"""
    print("=== 加权中位数应用 ===")
    
    # 示例1:学生成绩的加权中位数(以学分为权重)
    subjects = ['数学', '物理', '化学', '英语', '语文']
    scores = [85, 92, 78, 88, 90]
    credits = [4, 3, 2, 3, 2]  # 学分作为权重
    
    simple_median = np.median(scores)
    weighted_median_score = weighted_median(scores, credits)
    weighted_mean = np.average(scores, weights=credits)
    
    print(f"学生成绩分析:")
    for subject, score, credit in zip(subjects, scores, credits):
        print(f"  {subject}: {score}分 (学分: {credit})")
    
    print(f"\n简单中位数: {simple_median}分")
    print(f"加权中位数: {weighted_median_score}分")
    print(f"加权平均数: {weighted_mean:.1f}分")
    
    # 示例2:公司薪资的加权中位数(以人数为权重)
    print(f"\n公司薪资的加权中位数分析:")
    
    departments = ['技术部', '销售部', '市场部', '人事部', '财务部']
    avg_salaries = [12000, 8000, 9000, 7000, 10000]  # 各部门平均薪资
    employee_counts = [50, 30, 15, 10, 8]  # 各部门人数
    
    simple_dept_median = np.median(avg_salaries)
    weighted_salary_median = weighted_median(avg_salaries, employee_counts)
    weighted_salary_mean = np.average(avg_salaries, weights=employee_counts)
    
    for dept, salary, count in zip(departments, avg_salaries, employee_counts):
        print(f"  {dept}: ¥{salary:,} (人数: {count})")
    
    print(f"\n简单中位数 (不考虑人数): ¥{simple_dept_median:,}")
    print(f"加权中位数 (考虑人数): ¥{weighted_salary_median:,}")
    print(f"加权平均数 (考虑人数): ¥{weighted_salary_mean:,.0f}")
    
    print(f"\n这里计算的是以人数为权重的部门平均薪资中位数;只有假设每位员工薪资都等于所在部门均薪时,才可将其视为该假设下的员工薪资中位数,真实员工薪资中位数需要个体数据或部门内部薪资分布")

weighted_median_example()

🔗 学习路径与相关知识

📚 核心概念链接

🔬 进阶应用

  • 分位数 - 中位数的扩展概念
  • 四分位距 - 利用中位数的离散度量
  • 箱线图 - 中位数在数据可视化中的应用
  • 异常值检测 - 中位数在异常值检测中的作用

🎨 实战应用

  • 非参数统计 - 中位数在非参数方法中的应用
  • 时间序列 - 中位数滤波和平滑

tip 💡 **学习建议**

中位数是抗异常值的重要统计量,建议:

  1. 理解本质:中位数代表排序后的“中间值”,相比均值对少量极端值通常更稳健
  2. 掌握适用场景:偏态分布、包含异常值的数据
  3. 结合其他指标:与均值、众数等结合使用
  4. 实践应用:在实际业务分析中灵活运用

#统计学 #集中趋势 #描述性统计 #基础