当前位置:首页>python>一起学Python第113天:Matplotlib 直方图,给数据做"体检",一眼看穿分布与异常

一起学Python第113天:Matplotlib 直方图,给数据做"体检",一眼看穿分布与异常

  • 2026-10-11 07:03:00
一起学Python第113天:Matplotlib 直方图,给数据做"体检",一眼看穿分布与异常

📅 系列:一起学Python | 难度:⭐⭐⭐

🔗 上期回顾:第112天:饼图

一、直方图:数据的"体检报告"

柱状图对比的是不同类别的高低,而直方图(Histogram)看的是同一组数据的分布。

它能回答三个关键问题:

  • 📍 中心在哪? 数据集中在哪个区间?

  • 📐 偏不偏? 是左偏(长尾在左)还是右偏(长尾在右)?

  • 👀 有没有异常值? 有没有远离主体的"孤胆英雄"?

一句话:直方图是探索性数据分析(EDA)的必备武器。

二、核心 API:hist() 参数全解析

matplotlib.pyplot.hist(x, bins=None, range=None, density=False,                        cumulative=False, histtype='bar',                        align='mid', orientation='vertical',                        rwidth=None, color=None, alpha=None,                        stacked=False, label=None)
参数
作用
常用值
x
输入数据(一维数组/列表)
np.random.randn(1000)
bins
箱子数量
10
(默认)、30、50
range
值域范围
(0, 100)
,只统计这个区间
density
是否归一化为概率密度
False
(频数)/True(密度)
cumulative
是否累积
False
/True
histtype
直方图类型
'bar'
、'step'、'stepfilled'
align
箱子对齐方式
'left'
、'mid'(默认)、'right'
orientation
方向
'vertical'
(默认)、'horizontal'
rwidth
柱子相对宽度
0.8
(留间隙)、1.0(无缝)
color
填充颜色
'skyblue'
、'#2E86AB'
alpha
透明度
0.5
(多组叠加时用)
stacked
是否堆叠多组数据
False
/True
edgecolor
边框颜色
'white'
、'black'

三、从入门到精通:6个实战示例

示例 1:基础直方图——数据的"身材"

import numpy as npimport matplotlib.pyplot as pltimport matplotlib.font_manager as fmimport os# ================= 1. 字体加载(解决报错的核心) =================font_path = "simhei.ttf"  # 确保你已经在当前目录上传了 simhei.ttfif not os.path.exists(font_path):    font_path = "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc"  # 备用系统字体prop = fm.FontProperties(fname=font_path)plt.rcParams['axes.unicode_minus'] = False# 生成1000个标准正态分布随机数data = np.random.randn(1000)plt.figure(figsize=(10, 6))plt.hist(data, bins=30, color='skyblue', edgecolor='white', alpha=0.8)plt.title('标准正态分布直方图', fontproperties=prop, fontsize=16)plt.xlabel('数值', fontproperties=prop)plt.ylabel('频数', fontproperties=prop)plt.grid(True, alpha=0.3, linestyle='--')plt.show()

效果:经典的"钟形曲线"轮廓,中间高、两边低。

💡 bins 调参技巧:bins 太少会丢失细节(变成几座大山),太多会过于稀疏(变成刺猬)。数据量1000时,bins=20~40 最合适。

示例 2:多组数据对比——谁更"集中"?

# 三组不同分布的数据data1 = np.random.normal(0, 1, 1000)    # 均值0,标准差1data2 = np.random.normal(2, 1, 1000)    # 均值2,标准差1data3 = np.random.normal(-2, 1, 1000)   # 均值-2,标准差1plt.figure(figsize=(10, 6))plt.hist(data1, bins=30, alpha=0.5, label='A组(均值0)', color='#2E86AB')plt.hist(data2, bins=30, alpha=0.5, label='B组(均值2)', color='#E74C3C')plt.hist(data3, bins=30, alpha=0.5, label='C组(均值-2)', color='#27AE60')plt.title('三组数据分布对比', fontproperties=prop, fontsize=16)plt.xlabel('数值', fontproperties=prop)plt.ylabel('频数', fontproperties=prop)plt.legend(prop=prop)plt.grid(True, alpha=0.3)plt.show()
效果:三个"小山包"并排,均值差异一目了然。
🔥 alpha=0.5 是关键:多组直方图叠加时,透明度必须调低,否则颜色会糊成一团。

示例 3:概率密度直方图——面积 = 概率

data = np.random.normal(170, 10, 1000)  # 身高数据:均值170,标准差10plt.figure(figsize=(10, 6))# density=True:y轴变为概率密度,所有柱子面积之和 = 1plt.hist(data, bins=30, density=True,          color='#9B59B6', edgecolor='white', alpha=0.7)# 叠加理论正态分布曲线from scipy import statsxmin, xmax = plt.xlim()x = np.linspace(xmin, xmax, 100)plt.plot(x, stats.norm.pdf(x, 170, 10), 'r--', linewidth=2, label='理论曲线')plt.title('身高分布概率密度', fontproperties=prop, fontsize=16)plt.xlabel('身高(cm)', fontproperties=prop)plt.ylabel('概率密度', fontproperties=prop)plt.legend(prop=prop)plt.grid(True, alpha=0.3)plt.show()
效果:y轴不再是"有多少人",而是"概率密度"。配合理论曲线,一眼看出数据是否符合正态分布。

示例 4:累积分布直方图——"从小到大"的累加

data = np.random.randn(1000)plt.figure(figsize=(10, 6))# cumulative=True:累积频数/概率plt.hist(data, bins=30, cumulative=True, density=True,         color='#F39C12', edgecolor='white', alpha=0.8)plt.title('累积分布函数(CDF)', fontproperties=prop, fontsize=16)plt.xlabel('数值', fontproperties=prop)plt.ylabel('累积概率', fontproperties=prop)plt.grid(True, alpha=0.3)plt.show()

示例 5:阶梯图样式——更简洁的线条感

data = np.random.randn(1000)fig, axes = plt.subplots(1, 3, figsize=(15, 5))# bar(默认)axes[0].hist(data, bins=20, histtype='bar', color='#3498DB', edgecolor='white')axes[0].set_title('bar(默认)', fontproperties=prop)# step(无填充阶梯)axes[1].hist(data, bins=20, histtype='step', color='#E74C3C', linewidth=2)axes[1].set_title('step(线条)', fontproperties=prop)# stepfilled(填充阶梯)axes[2].hist(data, bins=20, histtype='stepfilled', color='#2ECC71', alpha=0.7)axes[2].set_title('stepfilled(填充阶梯)', fontproperties=prop)plt.suptitle('直方图样式对比', fontproperties=prop, fontsize=14)plt.tight_layout()plt.show()

示例 6:结合 Pandas——数据分析一条龙

import pandas as pd# 生成数据data = pd.Series(np.random.normal(170, 10, 250))plt.figure(figsize=(10, 6))# 直接用 plt.hist() 传入 Pandas Seriesplt.hist(data, bins=15, color='#1ABC9C', edgecolor='white', alpha=0.8)# 添加统计信息mean = data.mean()std = data.std()plt.axvline(mean, color='red', linestyle='--', linewidth=2, label=f'均值: {mean:.1f}')plt.axvline(mean + std, color='orange', linestyle=':', linewidth=2, label=f'±1σ')plt.axvline(mean - std, color='orange', linestyle=':', linewidth=2)plt.title('Pandas 数据直方图 + 统计标注', fontproperties=prop, fontsize=16)plt.xlabel('数值', fontproperties=prop)plt.ylabel('频数', fontproperties=prop)plt.legend(prop=prop)plt.grid(True, alpha=0.3)plt.show()

四、直方图 vs 柱状图:千万别混了!

五、避坑指南

六、参数速查卡

# 基础直方图plt.hist(data, bins=30)# 美化版plt.hist(data, bins=30, color='skyblue', edgecolor='white', alpha=0.8)# 概率密度plt.hist(data, bins=30, density=True)# 累积分布plt.hist(data, bins=30, cumulative=True, density=True)# 多组对比plt.hist(data1, bins=30, alpha=0.5, label='A组')plt.hist(data2, bins=30, alpha=0.5, label='B组')plt.legend()# 阶梯样式plt.hist(data, bins=30, histtype='step', linewidth=2)

七、今日练习

  1. 基础题:生成500个均值为50、标准差为15的随机数,绘制直方图,bins=25

  2. 进阶题:绘制两组学生成绩的直方图(A班均值75,B班均值82),用透明度叠加对比

  3. 挑战题:绘制概率密度直方图,并叠加正态分布理论曲线,标注均值和标准差线

八、总结

今天我们掌握了 Matplotlib 直方图的核心技能:

  • ✅ plt.hist() —— 基础直方图,探索数据分布

  • ✅ bins —— 控制粒度,太少丢细节,太多变稀疏

  • ✅ density=True —— 概率密度,面积=概率

  • ✅ cumulative=True —— 累积分布,看"从小到大"的累加

  • ✅ histtype —— bar/step/stepfilled,风格切换

  • ✅ 多组叠加 —— alpha 透明度是关键

  • ✅ 与 Pandas 结合 —— 数据分析流程无缝衔接

关键记忆:直方图看分布,柱状图看对比;bins 是分辨率,density 是概率尺。

🎯 今日金句:直方图是数据的X光片——它不告诉你谁高谁低,而是照出数据的骨骼与脾气:是匀称、偏瘦,还是藏着一颗"肿瘤"(异常值)。

最新文章

随机文章