22

把英雄分类,看 Python 带你上王者

 4 years ago
source link: https://www.tuicool.com/articles/Q7nqUbJ
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

王者荣耀这幺久了,还没上王者?哈哈哈,看过来,是不是对英雄理解的不够透彻呢,是不是还没有很好的为英雄分类呢,今天就来看看英雄分类

技术栈

一、EM 聚类简介

二、爬取网上的英雄初始属性值

三、做成饼图

EM 聚类简介

EM 英文名是 Expectation Maximization,也叫最大期望算法。

在统计计算中,最大期望(EM)算法是在概率(probabilistic)模型中寻找参数最大似然估计或者最大后验估计的算法,其中概率模型依赖于无法观测的隐藏变量(Latent Variable)。

最大期望算法经过两个步骤交替进行计算,第一步是计算期望(E),利用对隐藏变量的现有估计值,计算其最大似然估计值;第二步是最大化(M),最大化在 E 步上求得的最大似然值来计算参数的值。M 步上找到的参数估计值被用于下一个 E 步计算中,这个过程不断交替进行。

进行英雄聚类

使用 sklearn 库中的的 EM 聚类算法框架,采用高斯混合模型

from sklearn.mixture import GaussianMixture

一些主要参数意义如下,其他参数可以查看相关文档

n_components:混合高斯模型个数,也就是想要的聚类个数,默认为1

covariance_type:协方差类型,包括{‘full’,‘tied’, ‘diag’, ‘spherical’}四种,分别对应完全协方差矩阵(元素都不为零),相同的完全协方差矩阵(HMM会用到),对角协方差矩阵(非对角为零,对角不为零),球面协方差矩阵(非对角为零,对角完全相同,球面特性),默认‘full’ 完全协方差矩阵

max_iter:最大迭代次数,默认100

所以可以构造 GMM 聚类如下:

# 构造 GMM 聚类
gmm = GaussianMixture(n_components=20, covariance_type='full')

有一份如下结构的数据:

mauAVnz.png!web

可以看到,涉及到的属性非常多,初始的属性设置如下:

feature = ['1级物理攻击', '15级物理攻击', '每级成长',
           '1级生命', '15级生命', '生命成长值', '1级物理防御',
           '15级物理防御', '每级物理防御成长', '攻速成长',
           '1级每5秒回血', '15级每5秒回血', '1级最大法力',
           '15级最大法力', '最大法力成长', '1级每五秒回蓝',
           '15级每5秒回蓝', '近/远程?', '移速', '定位', '个人建议分路']

属性降维

可以先通过热力图来判断下哪些属性是强相关的,只保留唯一属性

import seaborn as sns
import matplotlib.pyplot as plt
corr = data[feature].corr()
plt.figure(figsize=(14, 14))
sns.heatmap(corr, annot=True)
plt.show()

JriU3yV.png!web

可以看到,其中”1级最大法力“,”15级最大法力“,”最大法力成长“,是强相关的,由此可以做出属性筛选,最终保留的属性如下:

features_remain = ['15级生命', '15级物理攻击',
                   '15级物理防御', '15级最大法力',
                   '15级每5秒回血', '15级每5秒回蓝', '移速',
                   '攻速成长', '近/远程?']

数据规范化

将攻击范围字段(”近/远程?“)转换为 0 和 1

data_new['近/远程?'] = data_new['近/远程?'].map({'远程': 1, '近程': 0})

EM 聚类计算

采用高斯混合模式,并把生成的类别写入 csv 文件中

# 构造 GMM 聚类
 gmm = GaussianMixture(n_components=20, covariance_type='full')
 gmm.fit(data_new)
 
 # 训练数据
 prediction = gmm.predict(data_new)
 # print(prediction)
 
 hero_data.insert(0, '分组', prediction)
 hero_data.to_csv('hero_out.csv', index=False, sep=',', encoding='gb18030')

饼图输出

为了更加直观的查看各个英雄的分组情况,这里使用饼图来做可视化 首先取出数据的”分组“和”名称“两个字段,并对”分组“字段进行分组处理

df = hero_data[['分组', '名称']]
grouped = df.groupby(['分组'])

然后取出分组中的数值,并用 pyecharts 来画饼图

from pyecharts import Pie
 
 k = []
 for name, group in grouped:
     k.append({name: list(group['名称'].values)})
 
 kk = []
 for i in k:
     for k, v in i.items():
        kk.append(v)
length = []
key = []
for i in kk:
    key.append(str(i))
    length.append(len(i))
pie = Pie('英雄完全属性分类图', title_pos='center')
pie.add("", key, length,
        is_label_show=True, legend_pos="bottom", legend_orient="vertical",)
pie.render()

ye2Ujin.png!web

抓取英雄初始属性

要想获得更加全的英雄数据,还是需要到网上抓取,这样才能够保证英雄的数量是最新的。这里我使用的是db.18183.com/ 网站的数据,页面如下:

BjU32qf.png!webENZnQzA.png!web

获取英雄页面 URL

使用 BeautifulSoup 来定位到 class 为 mod-iconlist 的 ul 元素,里面保存的就是各个英雄的页面

url = 'http://db.18183.com/'
    url_list = []
    res = requests.get(url + 'wzry').text
    content = BeautifulSoup(res, "html.parser")
    ul = content.find('ul', attrs={'class': "mod-iconlist"})
    hero_url = ul.find_all('a')
    for i in hero_url:
        url_list.append(i['href'])

抓取详细信息

循环抓取到的 URL 列表,抓取每个英雄的详细信息

base_url = 'http://db.18183.com/'
     detail_list = []
     for i in url:
         # print(i)
         res = requests.get(base_url + i).text
         content = BeautifulSoup(res, "html.parser")
         name_box = content.find('div', attrs={'class': 'name-box'})
         name = name_box.h1.text
         hero_attr = content.find('div', attrs={'class': 'attr-list'})
        attr_star = hero_attr.find_all('span')
        survivability = attr_star[0]['class'][1].split('-')[1]
        attack_damage = attr_star[1]['class'][1].split('-')[1]
        skill_effect = attr_star[2]['class'][1].split('-')[1]
        getting_started = attr_star[3]['class'][1].split('-')[1]
        details = content.find('div', attrs={'class': 'otherinfo-datapanel'})
        # print(details)
        attrs = details.find_all('p')
        attr_list = []
        for attr in attrs:
            attr_list.append(attr.text.split(':')[1].strip())
        detail_list.append([name, survivability, attack_damage,
                            skill_effect, getting_started, attr_list])

保存到 csv 文件

open 一个文件,把对应的列表字段存入

with open('all_hero_init_attr.csv', 'w', encoding='gb18030') as f:
         f.write('英雄名字,生存能力,攻击伤害,技能效果,上手难度,最大生命,最大法力,物理攻击,'
                 '法术攻击,物理防御,物理减伤率,法术防御,法术减伤率,移速,物理护甲穿透,法术护甲穿透,攻速加成,暴击几率,'
                 '暴击效果,物理吸血,法术吸血,冷却缩减,攻击范围,韧性,生命回复,法力回复\n')
         for i in details:
             try:
                 rowcsv = '{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}'.format(
                     i[0], i[1], i[2], i[3], i[4], i[5][0], i[5][1], i[5][2], i[5][3], i[5][4], i[5][5],
                     i[5][6], i[5][7], i[5][8], i[5][9], i[5][10], i[5][11], i[5][12], i[5][13], i[5][14], i[5][15],
                    i[5][16], i[5][17], i[5][18], i[5][19], i[5][20]
                )
                f.write(rowcsv)
                f.write('\n')
            except:
                continue

数据清理

因为这个网站可能做的不是很用心,有些属性会存在两个百分号和为空的情况,如图:

BZrymeA.png!web

所以需要处理下。

对于两个百分号,直接使用 notepad++ 把所有的 %% 的替换为单 % 即可

对于为空的字段,使用如下代码处理,填为 0

# 把空值设置为0
data_init = data_init.fillna(0)

完成

对于数据规范化,GMM 聚类和饼图呈现,都和前面类似,不再赘述,下面来看看饼图效果

6bmUrav.png!web

虽然通过这两张饼图,没有办法一下子提高你手残的毛病,但是明确了英雄的分类,不是离王者更近了一步吗

完整代码在这里: github.com/zhouwei713/…


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK