本章通过模拟掷骰子计算的5案例来进行学习基础的Python程序
案例描述
通过计算机程序模拟抛掷骰子,并显示各点数的出现次数及频率
比如:抛掷2个骰子50次,出现点数为7的次数是8,频率是0.16
案例分析
根据以下函数判断密码强度并输出:
1.设置一个变量strength_level用于记录密码的强度,初始为0。满足一个条件,对其加1;
2.长度判断:使用len()方法;
3.包含数字判断:对密码字符串遍历,使用isnumeric()方法;
4.包含字母判断:对密码字符串遍历,使用isalpha()方法;
5.如果strength_level等于3,密码强度合格,否则不合格
v1.0
新建一个简单的Python程序,1.0功能:模拟抛掷1个骰子,并输出其结果;通过Python的random模块模拟随机事件或者生成随机数;遍历列表时,使用enumerate()函数同时获取每个元素的索引号及其元素值。首先掷骰子编写成一个函数,然后编写主函数设置参数并开始掷骰子,最后输出结果。
知识点:
1.random模块
(1)random模块用于生成随机数,包含整数,浮点数,获取列表中的随机元素
(2)常用函数,random库里面有几个常用的函数,分别如下:
2.enumerate()函数
(1)enumerate()函数用于将可遍历的组合转换为一个索引序列
(2)一般用于for循环中,同时列出元素和元素的索引号
random模块函数示例:
enumerate函数示例:
PS:更多random模块的方法请参考:https://docs.python.org/3/library/random.html
扔骰子函数,先引入ramdom库,randint(1,6)返回的是1 - 6的整数赋值给dice_num,最后返回该结果:
import random
def roll_dice():
"""
掷骰子
"""
dice_num = random.randint(1, 6)
return dice_num
主体代码,里面先初始化主要的参数是total_time次数和result_list次数统计列表,for循环迭代range(total_times)对象,计算每次掷骰子的结果然后再for循环给统计列表计数,若符合则+1,最后enumerate()会返回两个参数,第1个给i,第2个给result再进行for循环迭代,因为列表下标是从0开始的,所以format的i需要+1正确显示0:
# 掷骰子次数
total_times = 1000
# 初始化结果列表[0,0,0,0,0,0]
result_list = [0] * 6
# 开始掷骰子
for i in range(total_times):
roll = roll_dice()
# 给列表计数
for j in range(1, 7):
if roll == j:
result_list[j - 1] += 1
# 输出结果
for i, result in enumerate(result_list):
print("计数为{}的骰子出现次数{},频率:{}".format(i + 1, result, result / total_times))
结果如图所示:
v2.0
在v1.0的基础上,2.0功能:模拟抛掷2个骰子,并输出其结果。由于要2个骰子,因此骰子的点数要新建列表,然后使用字典将对应的点数和次数关联起来。zip()函数的作用就是把骰子列表和统计列表组合成元组,然后用dict()转换成字典。
知识点:
1.zip()函数:
(1)zip()函数用于将对应的元素打包成一个个元组
(2)注意:元组中的元素是不可修改的,若要修改元素值可转换成字典类型;如:dict(zip(l1, l2))
(3)Python2.x版本和Python3版本的zip()函数返回结果不同,示例如下:
zip函数示例:
投掷子函数之前相同,不展示了。
具体代码,首先新建结果列表,因为2个骰子的结果有11种,所以要[0]*11,而点数列表对应也有11种,并且是2 - 12。dict(zip(roll_list, result_list))返回的结果是key为点数,value为结果计数的字典:
# 掷骰子次数
total_times = 1000
# 初始化结果列表[0,0,0,0,0,0]
result_list = [0] * 11
# 初始化点数列表
roll_list = list(range(2, 13))
roll_dict = dict(zip(roll_list, result_list))
print(roll_dict)
# 开始掷骰子
for i in range(total_times):
roll1 = roll_dice()
roll2 = roll_dice()
# 给列表计数
for j in range(2, 13):
if (roll1 + roll2) == j:
roll_dict[j] += 1
# 输出结果
for i, result in roll_dict.items():
print("计数为{}出现的次数为{},频率:{}".format(i, result, result / total_times))
运行结果:v3.0
在2.0的基础上,3.0功能:可视化抛掷2个骰子的结果;通过绘制散点图图像,简单分析数据的分布情况,使用到matploylib库。
知识点:
1.Python数据可视化:matplotlib模块
(1)matplotlib是一个数据可视化函数库
(2)matplotlib的子模块pyplot提供了2D图表制作的基本函数
(3)例子:https://matplotlib.org/gallery.html
(4)散点图绘制操作
import matplotlib.pyplot as plt
plt.scatter(x, y) # x, y分别是x坐标和y坐标的列表
plt.show()
2.scatter()参数详解
matplotlib.pyplot.scatter(x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, verts=None, edgecolors=None, *, data=None, **kwargs)
参数的解释:
x,y:表示的是大小为(n,)的数组,也就是我们即将绘制散点图的数据点
s:是一个实数或者是一个数组大小为(n,),这个是一个可选的参数。
c:表示的是颜色,也是一个可选项。默认是蓝色'b',表示的是标记的颜色,或者可以是一个表示颜色的字符,或者是一个长度为n的表示颜色的序列等等,感觉还没用到过现在不解释了。但是c不可以是一个单独的RGB数字,也不可以是一个RGBA的序列。可以是他们的2维数组(只有一行)。
marker:表示的是标记的样式,默认的是'o'。
cmap:Colormap实体或者是一个colormap的名字,cmap仅仅当c是一个浮点数数组的时候才使用。如果没有申明就是image.cmap
norm:Normalize实体来将数据亮度转化到0-1之间,也是只有c是一个浮点数的数组的时候才使用。如果没有申明,就是默认为colors.Normalize。
vmin,vmax:实数,当norm存在的时候忽略。用来进行亮度数据的归一化。
alpha:实数,0-1之间。
主要代码,骰子的计数方式和之前相同,新增绘制散点图。散点图绘制要先import引入库,在用scatter()设置骰子1和2的显示方式,参数包含x轴坐标,y轴坐标,颜色和透明度,最后显示:
# 掷骰子次数
total_times = 1000
# 初始化结果列表[0,0,0,0,0,0]
result_list = [0] * 11
# 初始化点数列表
roll_list = list(range(2, 13))
roll_dict = dict(zip(roll_list, result_list))
# 初始化骰子结果列表
roll1_result = []
roll2_result = []
# 开始掷骰子
for i in range(total_times):
roll1 = roll_dice()
roll2 = roll_dice()
roll1_result.append(roll1)
roll2_result.append(roll2)
# 给列表计数
for j in range(2, 13):
if (roll1 + roll2) == j:
roll_dict[j] += 1
# 输出结果
for i, result in roll_dict.items():
print("计数为{}出现的次数为{},频率:{}".format(i, result, result / total_times))
# 绘制散点图
x = range(1, total_times + 1)
plt.scatter(x, roll1_result, c="red", alpha=0.5)
plt.scatter(x, roll2_result, c="blue", alpha=0.5)
plt.show()
代码部分运行结果:
v4.0
在v3.0的基础上,4.0功能:对结果进行简单的数据统计和分析。使用matplotlib直方图做简单的数据统计分析。直方图可以直接看到分布情况,简单易懂。在做数据分析或机器学习时会经常用到。
知识点:
1.matplotlib直方图
(1)直方图是一种对数据分布情况的图形表示
(2)首先要对数据进行分组,然后统计每个分组内数据的数量。
(3)作用:
• 显示各分组频率或数量分布的情况
• 易于显示各组之间频率或数量的差别
(4)matplotlib绘制直方图
plt.hist(data, bins)
data: 数据列表
bins: 分组边界
2.hist()参数和返回值:
调用方式:
n, bins, patches = plt.hist(arr, bins=10, normed=0, facecolor='black', edgecolor='black',alpha=1,histtype='bar')
hist的参数非常多,但常用的就这六个,只有第一个是必须的,后面四个可选
arr: 需要计算直方图的一维数组
bins: 直方图的柱数,可选项,默认为10
normed: 是否将得到的直方图向量归一化。默认为0
facecolor: 直方图颜色
edgecolor: 直方图边框颜色
alpha: 透明度
histtype: 直方图类型,‘bar’, ‘barstacked’, ‘step’, ‘stepfilled’
返回值 :
n: 直方图向量,是否归一化由参数normed设定
bins: 返回各个bin的区间范围
patches: 返回每个bin里面包含的数据,是一个list
hist()函数参数详解:https://matplotlib.org/api/_as_gen/matplotlib.pyplot.hist.html
https://blog.csdn.net/qq_41940950/article/details/82937966
3.hist示例和中文显示错误解决方法
plt.rcParams[]详解参考:http://www.cnblogs.com/pacino12134/p/9776882.html
主要代码,骰子的计数方式和之前相同,新增绘制直方图。直方图绘制要先import引入库,在用hist()设置直方图的显示形状,参数包含x轴坐标,y轴坐标,归一化即y轴数据修改为频率,边框颜色(间隔开方便观察);title()设置直方图标题,xlabel()设置x轴标题,ylabel设置y轴标题,这3个都用size更改字体大小。最后显示::
# 掷骰子次数
total_times = 100000
# 初始化结果列表[0,0,0,0,0,0]
result_list = [0] * 11
# 初始化点数列表
roll_list = list(range(2, 13))
roll_dict = dict(zip(roll_list, result_list))
# 掷骰子结果初始化
roll_list = []
# 开始掷骰子
for i in range(total_times):
roll1 = roll_dice()
roll2 = roll_dice()
roll_list.append(roll1 + roll2)
# 给列表计数
for j in range(2, 13):
if (roll1 + roll2) == j:
roll_dict[j] += 1
# 输出结果
for i, result in roll_dict.items():
print("计数为{}出现的次数为{},频率:{}".format(i, result, result / total_times))
# 绘制散点图
plt.hist(roll_list, bins=range(2, 14), density=1, edgecolor="yellow", rwidth=3) # normed=1
plt.title("骰子点数统计",size=16)
plt.xlabel("点数", size=10)
plt.ylabel("频率", size=10)
plt.show()
执行结果:
v5.0
在v4.0的基础上,5.0功能:使用科学计算库简化程序,完善数据可视化结果。使用科学计算库NumPy简化程序。numpy可以直接生成大量的随机数对象数组,不需要再每次生成1个再加入列表中了,除此之外numpy还包含其他处理多维数组的方法。
知识点:
- NumPy
(1)NumPy (Numeric Python):用Python实现的科学计算库
(2)包括:
a.强大的N维数组对象array
b.成熟的科学函数库
c.实用的线性代数、随机数生成函数等
(3)NumPy的操作对象是多维数组ndarray
(4)ndarray.shape 数组的维度;操作方法如下:
创建数组:np.array(<list>),np.arrange() …
改变数组形状 reshape()
2.histogram()详解
umpy.histogram(a, bins=10, range=None, normed=False, weights=None, density=None)
参数:
a : array_like
输入数据。直方图在平顶阵列上计算。
bin : int或scalars或str的序列,可选
如果bin是int,则它定义给定范围内的等宽bin的数量(默认为10)。如果bin是一个序列,它定义了一个单调增加的bin边缘数组,包括最右边的边,允许不均匀的bin宽度。
range :( float,float),可选
箱子的下部和上部范围。如果没有提供,范围很简单。超出范围的值将被忽略。范围的第一个元素必须小于或等于第二个元素。range也会影响自动bin计算。虽然基于范围内的实际数据计算箱宽度是最佳的,但箱计数将填充整个范围,包括不包含数据的部分。(a.min(), a.max())
normed : bool,可选
从版本1.6.0开始不推荐使用。
这相当于density参数,但是对于不相等的bin宽度产生不正确的结果。不应该使用它。
weights : array_like,可选
一系列重量,形状与a相同。中的每个值 一个不仅有助于其相关联的权重对所述的箱数(而不是1)。如果密度为True,则将权重归一化,以使密度在整个范围内的积分保持为1。
density : bool,可选
如果False,结果将包含每个bin中的样本数。如果True,结果是bin处的概率密度函数的值,则归一化使得该范围上的积分为1.注意,除非选择单位宽度的区间,否则直方图值的总和将不等于1; 它不是概率质量函数。
返回值,有两个,
hist : array
bin_edges : array of dtype float,bin edges 的长度要是 hist 的长度加1,bin edges (length(hist)+1),也即 (bin_edges[0], bin_edges[1]) ⇒ hist[0],….,(bin_edges[-2], bin_edges[-1]) ⇒ hist[-1],bin_edges 参数与输入参数的 bins 保持一致;
PS:numpy详细教程参考:https://blog.csdn.net/a373595475/article/details/79580734
数组维度详解:https://www.cnblogs.com/Allen-rg/p/9592590.html
np.arange()函数详解:https://jingyan.baidu.com/article/e6c8503c1e89d6e54f1a188c.html
reshape()函数详解:https://blog.csdn.net/qq_28618765/article/details/78083895
数组的使用:http://www.cnblogs.com/dwnblogs/archive/2012/07/15/2592714.html
histogram()详解参考:https://docs.scipy.org/doc/numpy/reference/generated/numpy.histogram.html
主函数代码,先导入numpy库,调用里面的random.randint()直接生成含有大量随机数的对象数组,方法函数包含起始数,终结数,数据数量;然后调用np.histogram统计结果,返回2-12点数的出现次数和对应的区间;然后hist绘制直方图,参数包含y轴数据,x轴数据,归一化,边框颜色,边框宽度,方条间隔;xticks()设置x轴坐标点的显示,参数包含显示坐标(这里+0.5居中显示方便观看)和坐标点显示的标题;接着设置标题,y和x的标题,最后显示。
# 掷骰子次数
total_times = 1000000
# 使用array操作随机数
roll1_arr = np.random.randint(1, 7, size=total_times)
roll2_arr = np.random.randint(1, 7, size=total_times)
# 统计结果、
result_arr = (roll1_arr + roll2_arr)
hist, bins = np.histogram(result_arr, bins=range(2, 14))
print(hist)
print(bins)
# 绘制散点图
plt.hist(result_arr, bins=range(2, 14), density=1, edgecolor="yellow", linewidth=1, rwidth=0.8) # normed=1
# 设置x轴坐标点显示
tick_labels = ["2点", "3点", "4点", "5点",
"6点", "7点", "8点", "9点", "10点", "11点", "12点"]
tick_pos = np.arange(2, 13) + 0.5
plt.xticks(tick_pos, tick_labels)
plt.title("骰子点数统计", size=16)
plt.xlabel("点数", size=10)
plt.ylabel("频率", size=10)
plt.show()
执行结果:
总结
模拟掷骰子的5个例子,知识点归纳如下:
重点是Numpy库的知识点和相关操作和matplotlib库的操作
完整代码查看码云