查看原文
其他

用扑克牌演示 Python 数据分析

林骥 林骥 2022-10-26

1. 序言


扑克牌是我们常见一种娱乐工具,玩法千变万化,为了提高学习 Python 知识的趣味性,我构建了一个扑克牌的数据框,将用它来演示一些 Python 数据分析的功能。


畅想一下,假设利用人工智能的算法,让机器人学会各种扑克牌的玩法,比如说,德州扑克、桥牌、斗地主等等,把机器人训练成玩扑克牌游戏的高手,最终能否实现无人能敌?就像 Alpha Go 战胜人类围棋冠军一样。


说明一下,理解下面的文章,需要你先学习一些 Python 语言的基础知识,我先是看了《利用 Python 进行数据分析》这本书,并把学到的知识应用到了实际的工作中。为了让文章尽可能更加通俗易懂,我下面用一个扑克牌游戏来进行演示。


首先,安装好 Python 的运行环境,建议安装最新版本的 Anaconda,其中默认包含了数据分析所需的大部分库。


为了方便演示和分析,我安装了最新版本的 Jupyter Lab,在命令行输入:jupyter lab,就可以在浏览器中打开和新建 Notebook 文件。


2. 构建一副扑克牌的数据框


在 Jupyter Notebook 中输入以下代码,其中有比较详细的解释说明,如果有不懂或发现不对的地方,欢迎在文章下面留言。

# 导入相关 Python 库
import numpy as np
import pandas as pd
import datetime
from datetime import datetime
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns

# 设置最大行列数
pd.set_option('max_rows', 20)
pd.set_option('max_columns', 10)

# 显示两位小数
pd.set_option('display.float_format', lambda x: '%.2f' % x)

# 在 Jupyter Notebook 中显示图形
%matplotlib inline

# 构建扑克牌的数据框
nums = list(range(2, 11))
faces = DataFrame(['A'] + nums + ['J', 'Q', 'K'])
values = DataFrame([np.arange(1, 14)] * 4).T

# 定义列名
faces.columns = ['牌面']
values.columns = ['红心♥️', '黑桃♠️', '梅花♣️', '方块♦️']

# 合并两个数据框
poker = pd.merge(faces, values,
left_index=True, right_index=True)

# 定义大小王
poker.loc[13] = ['小王'] + [np.NaN]*4
poker.loc[14] = ['大王'] + [np.NaN]*4

poker

运行结果如下:



3. 描述性数据分析


我们用一行代码,对扑克牌数据框做一个简单的数据分析:

# 描述性数据分析
poker.describe()

运行结果如下:



从上面的结果可以看出,大小王的缺失值 nan 没有统计在内,每种花色有 13 张扑克牌,平均值为 7,标准差为 3.89,最小值为 1,最大值为 13。其中 25% 代表第一个四分位数,50% 代表第二个四分位数,其实就是中位数,75% 代表第三个四分位数。


这里稍微解释一下四分位数的概念,就是在数据排序后,处于某个位置上的值,比如说,中位数的位置在 1/2 的地方,去掉大小王之后,每种花色有 13 张牌,7 刚好处于正中间,它的前面和后面都有 6 张牌。


好好理解四分位数,这对我们做数据分析非常重要。


4. 数据可视化


我以前写过一篇《Python编程实践(2):数据可视化》,其中用的画图库是 pyecharts,在 Python 语言下,数据可视化的库有很多,是一个比较热门的领域,如果你有兴趣,可以试着去探索更多数据可视化的生态系统。


本文将使用的数据可视化库是 matplotlib 和 seaborn,具体代码如下:

# 先设置字体格式,防止中文乱码
sns.set_style("whitegrid",
{"font.sans-serif": ['simhei', 'Arial']})
matplotlib.rcParams.update({'font.size': 16})

# 绘制箱形图,设置标题和标签的字体大小
poker.plot.box(title='扑克牌点数的箱形图')

# 显示网格线并设置样式
plt.grid(linestyle='--', alpha=0.5)

运行得到的下面这个图形,它把四分位数比较直观地展现了出来,让人对数据的整体分布状况有个整体的把握,如果其中有异常值,那么能够快速地发现。


接下来,我们进一步探索,看看数据的相关性和分布情况:

# 绘制成对的散点图矩阵,在对角线上显示密度估计值
sns.pairplot(poker.iloc[:13],
diag_kind='kde',
markers='+',
height=2,
plot_kws=dict(edgecolor="b"),
diag_kws=dict(shade=True))

运行结果如下:



5. 一个诈金花小游戏


诈金花,又叫三张牌,是一种比较流行的多人纸牌游戏,具有独特的规则,需要考验玩家的胆略和智慧。


从表面上看,诈金花是一种自己可以掌握自己命运的游戏。如果你的牌不好,那么你可以跑,但是别人的牌可能比你更不好,你可能因此懊恼不已。相反,你可能以为自己的牌很好,但是别人的牌可能更好。就像古龙小说《七杀手》中描述的那样,有一个叫杜七的武林高手,一只手长了七根手指,他出现后不久杀了几个人,但转眼就被人灭了,这就叫人外有人,天外有天。


我用 Python 写了一段代码,实现了简单的发牌功能。假设有两个人,去掉扑克牌中的大小王后,每个人随机发 3 张牌,将两个人拿到的牌分别保存到 Excel 文件中,具体代码如下:

# 去掉大小王
poker_no_joker = poker.iloc[:13, 1:].unstack().reset_index()

# 把数据框变成只有 1 列
poker_no_joker = pd.DataFrame(poker_no_joker)

# 设置列名
poker_no_joker.columns = ['花色', '索引', '点数']

# 删除不用的列
del poker_no_joker['索引']

# 总共 52 张牌的索引
poker_index = np.r_[0:52]
person_num = 2
poker_num = 3
poker_choice = None

# 循环发牌
for i in range(person_num):
for j in range(poker_num):
# 随机选 1 张牌
num = np.random.choice(poker_index, 1)

# 刚开始没有牌
if poker_choice is None:
poker_choice = poker_no_joker.iloc[num]
else:
poker_choice = poker_choice.append(poker_no_joker.iloc[num])

# 排除已发过的牌
poker_index = poker_index[poker_index != num[0]]

# 第 1、3、5 张牌给第一个人
person1 = poker_choice.iloc[list(np.arange(0, 6, 2))]

# 第 2、4、6 张牌给第二个人
person2 = poker_choice.iloc[list(np.arange(1, 6, 2))]

# 将两个人拿到的牌分别保存到 Excel 文件中
dt_now = datetime.now().strftime('%Y-%m-%d %H%M%S')
person1.to_excel('第一个人的三张牌-' + dt_now + '.xlsx')
person2.to_excel('第二个人的三张牌-' + dt_now + '.xlsx')


6. 总结


这篇文章,我们试着用娱乐的精神,和大家一起学习 Python,首先,我们构建了一副扑克牌的数据框。然后,我们对其做了一个简单的描述性数据分析。接着,我们对数据进行可视化。最后,我们用了一个诈金花的小游戏,演示了 Python 的一些功能。


推荐文章


Python 数据分析精选

Python编程实践(2):数据可视化

Python编程实践(1)

数据分析的 4 个层面:包括 8 种思维、N 种方法、七种武器和八条原则

数据分析的 8 种思维

数据分析的思维与工具


欢迎关注林骥的微信公众号,我们一起让数据更有价值,让分析更有效。


长按二维码关注

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存