用扑克牌演示 Python 数据分析
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 的一些功能。
推荐文章
数据分析的 4 个层面:包括 8 种思维、N 种方法、七种武器和八条原则
欢迎关注林骥的微信公众号,我们一起让数据更有价值,让分析更有效。
长按二维码关注