EM 是聚类方法的一种. EM 分为两个步骤: E 步相当于通过初始化的参数来估计隐含变量, M 步是通过隐含变量来反推优化参数. 最后通过EM 步骤的迭代得到最终的模型参数.
GMM 模型中文名为高斯混合模型, 是EM 算法的一种.
在python 的机器学习工具包sklearn中, 通过 from sklearn.mixture import GaussianMixture 引入GMM模型.
首先使用model = GaussianMixture(n_components=1, covariance_type=‘full’, max_iter=100) 来创建GMM 聚类, 再使用fit 函数传入样本特征矩阵, 模型会自动生成聚类器, 然后使用prediction=model.predict(data) 来对数据进行聚类, 传入你想进行聚类的数据, 可以得到聚类结果 prediction.
在创建GMM 模型时, 使用的主要参数如下:
1. n_components: 即高斯混合模型的个数, 也就是我们要聚类的个数, 默认值为 1. 如果不指定n_components, 最终的聚类结果都会为同一个值.
2. covariance_type: 代表协方差类型. 一个高斯混合模型的分布是由均值向量和协方差矩阵决定的, 所以协方差的类型也代表了不同的高斯混合模型的特征. 协方差类型有 4 种取值:
(1) covariance_type='full', 代表完全协方差, 也就是元素都不为0 , 默认值;
(2) covariance_type='tied', 代表相同的完全协方差;
(3) covariance_type='diag', 代表对角协方差, 也就是对角不为0, 其余为0 ;
(4) covariance_type='spherical', 代表球面协方差, 非对角为0, 对角完全相同, 呈现球面的特性.
3. max_iter: 代表最大迭代次数, EM 算法是由E 步和M 步迭代求得最终的模型参数, 这里可以指定最大迭代次数, 默认值为 100.
使用pandas 加载hero.csv 文件, 通过查看数据的描述性统计可以发现, 数据一共有69 行, 包含 '英雄', '最大生命', '生命成长', '初始生命', '最大法力', '法力成长', '初始法力', '最高物攻', '物攻成长', '初始物攻', '最大物防', '物防成长', '初始物防', '最大每5秒回血', '每5秒回血成长', '初始每5秒回血', '最大每5秒回蓝', '每5秒回蓝成长', '初始每5秒回蓝', '最大攻速', '攻击范围', '主要定位', '次要定位 ' 这些属性, 其中 '英雄', '最大攻速', '攻击范围', '主要定位', '次要定位 ' 列为非数值型数据, 其他为数值型数据; 只有'次要定位' 列包含40 个缺失值; '最大法力' 等法力值相关属性有为0 的值, 经过分析,是王者荣耀中张飞、吕布等没有法力值英雄的属性, 为正常现象; '主要定位'包含法师、战士等6种官方定位, '攻击范围'包含远程和近战两种值, '最大攻速' 有两例 0.00% 值, 为异常数据.
代码:
# 数据探索
pd.set_option('display.max_columns', None)
data = pd.read_csv('./heros.csv', encoding='gb18030')
print(data.columns)
print(data.head())
print(data.info())
print(data.describe())
print(data.describe(include=['O']))
print(data['最大攻速'].value_counts())
print(data['攻击范围'].value_counts())
print(data['主要定位'].value_counts())
原始数据中'主要定位'属性为官方的定位, 如作为聚类的特征, 相对于其他特征应赋予较高的权重, 在此案例中把'主要定位'属性作为参考属性, 与聚类结果进行比较;
'次要定位' 包含缺失值, '最大攻速' 1包含异常数据, 对两种属性采用删除操作;
'攻击范围' 属性列, 使用数值0, 1 分别替代 '近战', '远程', 以便于后续分析;
最后把'英雄'列作为索引, 使用 StandardScaler() 对数据进行标准化, 因为处理后的数据还包含19个特征, 在此使用PCA主成分分析进降维, 在设置PCA模型属性 n_components='mle' 时, 数据只从19维降为了18维, 效果不显著, 最后手动设置 n_components=10, 转换后的特征维度的方差占比和为0.9981, 基本符合要求.
相关代码:
# 数据变换
data_dw = data['主要定位']
data.drop(['最大攻速', '主要定位', '次要定位 '], axis=1, inplace=True)
data['攻击范围'].replace(['近战', '远程'], [0, 1], inplace=True)
data.set_index(['英雄'], inplace=True)
# print(data.head())
# 标准化
data = data.astype('float64')
ss = StandardScaler()
n_data = ss.fit_transform(data)
print(n_data.shape)
# PCA 降维
# pca = PCA(n_components='mle')
pca = PCA(n_components=10)
n_data = pca.fit_transform(n_data)
print(n_data.shape)
print(pca.explained_variance_ratio_)
使用GMM 模型进行聚类, 把聚类结果与原始数据的'主要定位'拼接成DataFrame按聚类结果排序并保存为.csv 文件.
相关代码:
# EM聚类 使用GMM 高斯混合模型
gmm = GaussianMixture(n_components=6, covariance_type='full')
res = gmm.fit_predict(n_data)
res_data = pd.DataFrame({'分类结果':res, '定位':data_dw.values}, index=data.index)
res_data.reset_index(inplace=True)
res_data.sort_values(['分类结果'], inplace=True)
res_data.to_csv('./result/res_6.csv', index=False)
在设置聚类参数 n_components=6 时, 数据被聚为6个簇, 与官方的'主要定位'分类数相同. 通过下图进行对比, 可以看出分类结果1 大部分为射手, 分类结果3和5 基本为辅助与法师, 分类结果4 大部分为坦克, 可见聚类结果有很高的可信度.
当设置n_components=30时, 部分结果如下:
此表格可以为玩家提供一些建议, 比如在排位赛中玩家的常用英雄鬼谷子被BAN, 可以考虑使用太乙真人代替.
详细代码及数据请点击:https://github.com/Vincentchu9527/wzry_01