美文网首页
案例(7):模拟掷骰子

案例(7):模拟掷骰子

作者: hwang_zhic | 来源:发表于2019-03-23 16:46 被阅读0次

    本章通过模拟掷骰子计算的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库里面有几个常用的函数,分别如下:


    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))
    

    结果如图所示:


    1个骰子1000次结果统计

    v2.0

    在v1.0的基础上,2.0功能:模拟抛掷2个骰子,并输出其结果。由于要2个骰子,因此骰子的点数要新建列表,然后使用字典将对应的点数和次数关联起来。zip()函数的作用就是把骰子列表和统计列表组合成元组,然后用dict()转换成字典。

    知识点:

    1.zip()函数:
    (1)zip()函数用于将对应的元素打包成一个个元组
    (2)注意:元组中的元素是不可修改的,若要修改元素值可转换成字典类型;如:dict(zip(l1, l2))
    (3)Python2.x版本和Python3版本的zip()函数返回结果不同,示例如下:


    Python2 Python3示例

    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还包含其他处理多维数组的方法。

    知识点:
    1. 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库的操作
    完整代码查看码云

    相关文章

      网友评论

          本文标题:案例(7):模拟掷骰子

          本文链接:https://www.haomeiwen.com/subject/xnwdyqtx.html