查看原文
其他

从零开始学Python数据分析【29】-- K均值聚类(实战部分)

2017-12-25 刘顺祥 Python爱好者社区

作者:刘顺祥

个人微信公众号:每天进步一点点2015


前文传送门:

从零开始学Python数据分析【1】--数据类型及结构

从零开始学Python数据分析【2】-- 数值计算及正则表达式

从零开始学Python数据分析【3】-- 控制流与自定义函数

从零开始学Python数据分析【4】-- numpy

从零开始学Python数据分析【5】-- pandas(序列部分)

从零开始学Python数据分析【6】-- pandas(数据框部分01)

从零开始学Python数据分析【7】-- pandas(数据框部分02)

从零开始学Python数据分析【8】-- pandas(数据框部分03)

从零开始学Python数据分析【9】-- pandas(数据框部分04)

从零开始学Python数据分析【10】-- matplotlib(条形图)

从零开始学Python数据分析【11】-- matplotlib(饼图)

从零开始学Python数据分析【12】-- matplotlib(箱线图)

从零开始学Python数据分析【13】-- matplotlib(直方图)

从零开始学Python数据分析【14】-- matplotlib(折线图)

从零开始学Python数据分析【15】-- matplotlib(散点图)

从零开始学Python数据分析【16】-- matplotlib(雷达图)

从零开始学Python数据分析【17】-- matplotlib(面积图)

从零开始学Python数据分析【18】-- matplotlib(热力图)

从零开始学Python数据分析【19】-- matplotlib(树地图)

从零开始学Python数据分析【20】--线性回归(理论部分)

从零开始学Python数据分析【21】--线性回归(实战部分)

从零开始学Python数据分析【22】--线性回归诊断(第一部分)

从零开始学Python数据分析【23】--线性回归诊断(第二部分)

从零开始学Python数据分析【24】--岭回归及LASSO回归(理论部分)

从零开始学Python数据分析【25】--岭回归及LASSO回归(实战部分)

从零开始学Python数据分析【26】--Logistic回归(理论部分)

从零开始学Python数据分析【27】--Logistic回归(实战部分)

从零开始学Python数据分析【28】-- K均值聚类(理论部分)

前言


      我们接着《从零开始学Python【28】--K均值聚类(理论部分)》一文,继续跟大家分享一下如何借助于Python和R语言工具完成K均值聚类的实战。本次实战的数据来源于虎扑体育(https://nba.hupu.com/stats/players),我们借助于NBA球员的命中率和罚球命中率两个来给各位球员做一次“人以群分”的效果。

      首先,我们使用pandas中的read_html函数读取虎扑体育网页中的球员数据表,然后再对数据作清洗(主要是数据类型的转换、变量的重命名和观测的删除):

# 加载第三包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

# 读取网页中的数据表
table = []for i in range(1,7):    table.append(pd.read_html('https://nba.hupu.com/stats/players/pts/%d' %i)[0])

# 所有数据纵向合并为数据框    
players = pd.concat(table)
# 变量重命名
columns=['排名','球员','球队','得分','命中-出手','命中率','命中-三分','三分命中率','命中-罚球','罚球命中率','场次','上场时间'] players.columns=columns

# 数据类型转换
players.得分 = players.得分.astype('float') players.命中率 = players.命中率.str[:-1].astype('float')/100
players.三分命中率 = players.三分命中率.str[:-1].astype('float')/100
players.罚球命中率 = players.罚球命中率.str[:-1].astype('float')/100
players.场次 = players.场次.astype('int') players.上场时间 = players.上场时间.astype('float')

# 删除行标签为0的记录
players.drop(0,inplace=True) players.head()

本次一共获得286名球员的历史投篮记录,这些记录包括球员姓名、所属球队、得分、各命中率等信息,下面我们仅使用球员的命中率和罚球命中率来做聚类,主要是为了方便展现聚类效果的图形。首先,我们来看看这两个指标下的散点图:

# 中文和负号的正常显示
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] plt.rcParams['axes.unicode_minus'] = False
# 设置绘图风格
plt.style.use('ggplot')

# 绘制得分与命中率的散点图
players.plot(x='罚球命中率',y='命中率',kind='scatter') plt.show()

通过肉眼,似乎还无法对这286名球员进行聚类(画圈),如果画圈的话,该划为几类合适呢?一般我们可以通过迭代的方式选出合适的聚类个数,即让k值从1到K依次执行一遍,再查看每一次k值对应的簇内离差平方和之和的变化,如果变化幅度突然由大转小时,那个k值就是我们选择的合理个数。具体我们通过图形展现来说明上面的文字:

# 选择最佳的K值
X = players[['罚球命中率','命中率']] K = range(1,int(np.sqrt(players.shape[0])))
GSSE = []
for k in K:    SSE = []    kmeans = KMeans(n_clusters=k, random_state=10)    kmeans.fit(X)    labels = kmeans.labels_    centers = kmeans.cluster_centers_
   for label in set(labels):        SSE.append(np.sum(np.sum((players[['罚球命中率','命中率']].loc[labels == label,]-centers[label,:])**2)))    GSSE.append(np.sum(SSE))
   
# 绘制K的个数与GSSE的关系
plt.plot(K, GSSE, 'b*-') plt.xlabel('聚类个数') plt.ylabel('簇内离差平方和') plt.title('选择最优的聚类个数') plt.show()

从图中结果显示,当k为7时,看上去簇内离差平方和之和的变化已慢慢变小,那么,我们不妨就将球员聚为7类。如下为聚类效果的代码:

#调用sklearn的库函数
num_clusters = 6
kmeans = KMeans(n_clusters=num_clusters, random_state=1) kmeans.fit(X)

# 聚类结果标签
players['cluster'] = kmeans.labels_
# 聚类中心
centers = kmeans.cluster_centers_

# 绘制散点图
plt.scatter(x = X.iloc[:,0], y = X.iloc[:,1], c = players['cluster'], s=50, cmap='rainbow') plt.scatter(centers[:,0], centers[:,1], c='k', marker = '*', s = 180) plt.xlabel('罚球命中率') plt.ylabel('命中率')
# 图形显示
plt.show()

上图中,散点的不同颜色表示的是聚为不同的簇,黑色五角星为各簇的中心点,看上去其聚类效果有那么点意思。到此,关于使用Python实现K均值聚类的实战我们就分享到这里,接下来将使用R语言重新复现一遍,希望对R语言熟悉的朋友有一点的帮助。如下是R语言的复现脚本:

# 加载第三方包
library(ggplot2)

# 读取Python中现成下好的数据
players = read.csv(file = file.choose()) head(players)

# 绘制罚球命中率和命中率散点图
ggplot(data = players, mapping = aes(x = 罚球命中率, y = 命中率)) +  geom_point()

# 自定义函数选择最佳的K值
tot.wssplot <- function(data, nc, seed=1234){
 #假设分为一组时的总的离差平方和                tot.wss <- (nrow(data)-1)*sum(apply(data,2,var))  for (i in 2:nc){
     #必须指定随机种子数     set.seed(seed)     tot.wss[i] <- sum(kmeans(data, centers=i)$withinss)  }  ggplot(data = NULL, mapping = aes(x = 1:nc, y = tot.wss)) +    geom_point() +    geom_line(color = 'steelblue', size = 1) +    labs(x = '聚类个数', y = '簇内离差平方和', title = '选择最优的聚类个数') +    theme(plot.title = element_text(hjust = 0.5, face = 'bold'))  }
     
#绘制各种组数下的总的组内平方和图
tot.wssplot(data = players[,c('罚球命中率','命中率')],            nc = as.integer(sqrt(nrow(players))))

# 聚类
clust <- kmeans(x = players[,c('罚球命中率','命中率')], centers = 7) centers = clust$centers players$cluster = clust$cluster

# 聚类效果图
ggplot() +  geom_point(data = players,             mapping = aes(x = 罚球命中率, y = 命中率, color = factor(cluster)),size = 1.5) +  geom_point(aes(x = centers[,1], y = centers[,2]),             fill = 'black', shape = 18, size = 3) +  labs(title = '聚类效果图') +  theme(plot.title = element_text(hjust=0.5, face = 'bold'),legend.position="none")

结语


      OK,关于使用Python和R语言完成K均值聚类的实战我们就分享到这里,如果你有任何问题,欢迎在公众号的留言区域表达你的疑问。同时,也欢迎各位朋友继续转发与分享文中的内容,让更多的人学习和进步。

Python爱好者社区历史文章大合集

Python爱好者社区历史文章列表(每周append更新一次)

福利:文末扫码立刻关注公众号,“Python爱好者社区”,开始学习Python课程:

关注后在公众号内回复“课程”即可获取:

小编的Python入门视频课程!!!

崔老师爬虫实战案例免费学习视频。

丘老师数据科学入门指导免费学习视频。

陈老师数据分析报告制作免费学习视频。

玩转大数据分析!Spark2.X+Python 精华实战课程免费学习视频。

丘老师Python网络爬虫实战免费学习视频。

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

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