查看全课大纲(第 39 / 51 节)
  1. 1.为什么人人都该学点编程?
  2. 2.计算机与程序设计:你的电脑到底在“想”什么?
  3. 3.Python 这门语言,到底有什么魔力?
  4. 4.Python 开发环境配置:如何拥有你的第一个“编程工具箱”?
  5. 5.如何安装一个更强大的代码编辑器?
  6. 6.汇率兑换1.0:你的第一个“钱生钱”小程序
  7. 7.你的第一行代码,藏着哪些秘密?
  8. 8.汇率兑换2.0(上):让程序看懂“CNY”和“USD”
  9. 9.汇率兑换程序,如何让它“聪明”地判断币种?
  10. 10.汇率兑换程序能一直运行,直到我喊停吗?
  11. 11.汇率兑换4.0:如何把“算钱”功能打包成积木?
  12. 12.汇率兑换5.0:给你的程序穿上“结构化”的西装
  13. 13.怎么用 Python 画一个会动的五角星?
  14. 14.如何让程序自动画出不同大小的五角星?
  15. 15.函数自己调用自己,会发生什么?
  16. 16.用递归画出神奇的分形树
  17. 17.Python 怎么计算你一天躺着不动能消耗多少热量?
  18. 18.如何让程序“活”起来,持续为你服务?
  19. 19.如何让 BMR 计算器更“聪明”?
  20. 20.当程序遇到“不按套路出牌”的用户怎么办?
  21. 21.怎么用 Python 模拟一个“滚雪球”式的存钱计划?
  22. 22.如何用列表记录每一周的存款?
  23. 23.如何让程序自己数数?—— 用 for 循环解放你的双手
  24. 24.52周存钱挑战4.0:你的存款计算器能有多灵活?
  25. 25.52周存钱挑战:怎么根据日期自动查存款?
  26. 26.Python 怎么判断一年中的第几天?
  27. 27.列表 vs 元组:哪个更适合存储月份天数?
  28. 28.用集合给月份分个队,换个思路算天数
  29. 29.把月份和天数“锁”在一起:用字典给数据配个对
  30. 30.Python 怎么判断密码强弱?
  31. 31.Python 怎么给密码设置“防沉迷”系统?
  32. 32.Python 怎么把密码保存到文件里?
  33. 33.Python 怎么读取文件里的密码?
  34. 34.Python 怎么把密码检查工具“打包”起来?
  35. 35.Python 怎么把文件操作也“打包”起来?
  36. 36.计算机怎么“扔骰子”?——用Python模拟随机事件
  37. 37.如何用 Python 模拟掷两个骰子?
  38. 38.怎么用 Python 把骰子轨迹画出来?
  39. 39.骰子点数分布长啥样?用直方图一眼看穿!
  40. 40.用科学计算库让骰子程序“起飞”
  41. 41.空气质量指数怎么算?手把手教你写一个AQI计算器
  42. 42.空气质量指数计算:从零开始,让程序看懂空气
  43. 43.如何读取空气质量数据文件并找出空气质量最好的五个监测点?
  44. 44.JSON 数据怎么变成 Excel 表格?—— 让数据换个“马甲”
  45. 45.Python 怎么让程序自己判断文件类型?
  46. 46.如何让程序自己上网查空气质量?
  47. 47.用美味的汤来解析网页:Beautiful Soup 入门
  48. 48.如何让爬虫自动抓取全国所有城市的空气质量?
  49. 49.爬到的数据怎么存下来?—— 把全国空气质量数据保存为CSV文件
  50. 50.用 pandas 玩转空气质量数据:找出全国空气最好和最差的城市
  51. 51.空气质量数据怎么“洗”干净,还能画成图?

骰子点数分布长啥样?用直方图一眼看穿!

约 14 分钟

小象实战讲义 · Python 入门:8 个小项目边玩边学

欢迎回来,骰子模拟师!上一节我们用 matplotlib 画出了骰子点数的散点图,看到了随机性的“散漫”。但这还不够,我们更想知道:投掷一万次,点数7到底出现了多少次?点数2和12是不是真的那么稀有?这一节,我们将用一种更强大的可视化工具——直方图,来直接“看穿”数据的分布规律。学完这一节,你就能一键生成清晰、专业的统计图表,用数据说话!

💡 核心导读

  • 直方图是什么:一种展示数据分布情况的“分组统计图”,能直观看出哪个区间数据最多、哪个最少。
  • plt.hist() 的魔力:一行代码,自动完成数据分组、计数和绘图,解放你的双手。
  • 让图表更专业:调整柱子样式、显示频率、解决中文乱码,让你的图表既好看又好懂。
  • 本节唯一新增:引入 plt.hist() 函数绘制直方图,并对图表进行基础美化。

直方图:数据分布的“显微镜”

在上一节,我们手动统计了每个点数出现的次数。但如果数据量很大,或者我们想快速了解整体分布,手动统计就太麻烦了。这时候,直方图就是我们的好帮手。

你可以把直方图想象成一个“数据显微镜”。它先把所有可能的数据值(比如我们骰子的点数2到12)分成几个连续的“区间”(也叫“分组”或“桶”),然后数一数落在每个区间里的数据有多少个,最后用柱子的高低把这个数量直观地画出来。

生活中的直方图:人口的身高调查。特别高和特别矮的人都比较少,中等身高的人最多,画出来的直方图就会是中间高、两边低的“小山包”形状(统计学里叫“正态分布”)。我们的两个骰子点数之和,理论上也是中间的点数(如7)出现概率最高,两边的点数(如2和12)概率最低。

用 plt.hist() 一键生成分布图

matplotlib 为我们提供了超级简单的直方图绘制函数 plt.hist()。它的核心参数就两个:

  • data: 你的数据列表,比如我们记录的所有骰子点数之和。
  • bins: 分组的边界。比如 [2, 3, 4, ..., 13] 表示分组是 [2,3), [3,4), …, [12,13)。

让我们直接升级程序,用直方图来展示结果。为了让代码更专注于核心功能,我们把之前手动统计的部分都去掉,只保留记录每次投掷结果的列表。

import random
import matplotlib.pyplot as plt
random.seed(42)  # 固定随机种子,让示例输出可复现

# 解决中文显示问题(稍后解释)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号

def roll_dice():
    """模拟掷一次骰子,返回1到6的随机整数"""
    return random.randint(1, 6)

# 主逻辑
total_times = 10000  # 模拟投掷总次数
roll_list = []       # 用于记录每次投掷两个骰子的点数之和

for i in range(total_times):
    roll1 = roll_dice()
    roll2 = roll_dice()
    roll_list.append(roll1 + roll2)  # 记录和

# 数据可视化:绘制直方图
# bins=range(2, 14) 创建了 [2,3), [3,4), ..., [12,13) 这些分组
plt.hist(roll_list, bins=range(2, 14))
plt.title('骰子点数统计')  # 图表标题
plt.xlabel('点数')         # X轴标签
plt.ylabel('出现次数')     # Y轴标签
plt.show()

运行上面的代码,你会立刻看到一张图表!柱子最高的地方,对应的就是出现次数最多的点数(很可能是7)。看,我们不需要任何额外的统计代码,plt.hist() 帮我们全搞定了!

美化图表:从“能看”到“好看”

生成的图表可能看起来有点“简陋”,柱子之间没有缝隙。我们可以通过 plt.hist() 的更多参数来美化它。

import random
import matplotlib.pyplot as plt
random.seed(42)  # 固定随机种子,让示例输出可复现

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

def roll_dice():
    return random.randint(1, 6)

total_times = 10000
roll_list = []

for i in range(total_times):
    roll_list.append(roll_dice() + roll_dice())

# 绘制美化后的直方图
plt.hist(roll_list,
         bins=range(2, 14),
         edgecolor='black',  # 柱子边缘为黑色
         linewidth=1)        # 边缘线宽度为1
plt.title('骰子点数统计')
plt.xlabel('点数')
plt.ylabel('出现次数')
plt.show()

现在柱子之间有了清晰的黑边,看起来是不是更专业、更易读了?

显示概率:更直观的洞察

“出现1600次”这个数字,不如“概率是16%”来得直观。我们想让Y轴直接显示频率(概率)。plt.hist() 有一个超好用的参数 density,设置 density=True,它就会自动将次数转换为频率密度,使得所有柱子的面积之和为1。

小知识:很早以前的 matplotlib(2.x 时代)这个参数叫 normed,但它在 matplotlib 2.1 被弃用、3.0 起彻底移除,现在统一用 density。如果你在很老的教程里看到 normed=True,知道它就是今天的 density=True 即可——现在写 normed 会直接报错。

import random
import matplotlib.pyplot as plt
random.seed(42)  # 固定随机种子,让示例输出可复现

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

def roll_dice():
    return random.randint(1, 6)

total_times = 10000
roll_list = []

for i in range(total_times):
    roll_list.append(roll_dice() + roll_dice())

# 绘制显示频率的直方图
plt.hist(roll_list,
         bins=range(2, 14),
         density=True,          # 归一化,显示频率
         edgecolor='black',
         linewidth=1)
plt.title('骰子点数统计')
plt.xlabel('点数')
plt.ylabel('频率')
plt.show()

运行后,看看Y轴,是不是变成了0.00, 0.05, 0.10…?最高点对应的频率,就是点数7出现的近似概率。这下,数据分布一目了然!

关于中文显示的小窍门

你可能注意到了代码开头的两行“魔法”:

import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

这是因为 matplotlib 默认的字体不支持中文,直接使用中文会显示成小方框 □□□。

  • 第一行:将字体设置为支持中文的“黑体”(SimHei)。
  • 第二行:解决负号(-)可能显示异常的问题。

记住它:以后只要在用 matplotlib 画图并且要用到中文,把这两行代码放在 import matplotlib.pyplot as plt 之后,其他画图代码之前,就万事大吉了。

📝 动手练一练

  1. 改变实验规模:将模拟投掷次数 total_times 分别改为 100、1000、100000 次,运行程序观察直方图的变化。随着次数增加,图形的形状有什么趋势?它是否越来越接近一个稳定的、对称的“小山包”形状?

  2. 模拟三个骰子:如果一次投掷三个骰子,点数之和的范围是3到18。请你修改程序,模拟投掷三个骰子10000次,并用直方图展示结果。猜一猜,哪个点数出现的概率会最高?

👉 点击查看第2题参考答案

思路:需要模拟三个骰子,所以循环内要生成三个随机数并求和。直方图的分组边界 bins 也要相应调整为从3到19(range(3, 20))。

import random
import matplotlib.pyplot as plt
random.seed(42)  # 固定随机种子,让示例输出可复现

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

def roll_dice():
    return random.randint(1, 6)

total_times = 10000
roll_list_three = []  # 记录三个骰子的和

for i in range(total_times):
    # 投掷三个骰子并记录和
    roll_list_three.append(roll_dice() + roll_dice() + roll_dice())

# 绘制直方图,分组边界为3到19
plt.hist(roll_list_three,
         bins=range(3, 20),
         density=True,
         edgecolor='black',
         linewidth=1)
plt.title('三个骰子点数统计')
plt.xlabel('点数')
plt.ylabel('频率')
plt.show()

运行后,你会发现图形仍然是对称的,但最高点对应的点数变成了 10或11(因为3到18的中间值是10.5)。这就是概率论的魅力!

本章小结

恭喜!你成功地为骰子模拟项目装上了“数据分析之眼”。通过直方图,我们不再需要费力地数数,就能一眼看清数据的分布规律,甚至能读出精确的概率。plt.hist() 这个工具,在未来的数据分析工作中会经常用到。

📋 行动清单

  • 运行本节最终代码,观察骰子点数的频率分布直方图。
  • 修改total_times参数,感受“大数定律”——实验次数越多,结果越接近理论概率。
  • 挑战一下“动手练一练”的第2题,看看三个骰子的世界有什么不同。

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 第8章代码包:模拟掷骰子(含全部版本 5 个 .py)
    ZIP · 3KB
    下载
看图文没弄懂?展开看本节视频讲解(约 14 分钟)
📺 正在播放小象学院官方高清录播(支持倍速与清晰度调节)