探索如何通过聚类分析揭露糖尿病预测数据集的特征!我们将运用Python的强力工具,深入挖掘数据,以直观的可视化揭示不同特征间的关系。一同探索聚类分析在糖尿病预测中的实践!
所有这些可视化都可以通过数据操作的基本工具(pandas和numpy)以及可视化的基础知识(matplotlib和seaborn)来创建。
from matplotlib import colormaps, pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import load_diabetes
from sklearn.preprocessing import MinMaxScaler
import numpy as np
import pandas as pd
import seaborn as sns
对于这个教程,我将使用嵌入在matplotlib中的糖尿病预测数据集,拟合了一个简单的k-means模型。
diabetesData = load_diabetes(as_frame = True).data
# 中心化和规模化可聚类特征
diabetesScaler = MinMaxScaler().fit(diabetesData)
diabetesDataScaled = pd.DataFrame(diabetesScaler.transform(diabetesData)
, columns = diabetesData.columns
, index = diabetesData.index) # 构建三个小的聚类模型
km3 = KMeans(n_clusters = 3).fit(diabetesDataScaled)
km4 = KMeans(n_clusters = 4).fit(diabetesDataScaled)
km10 = KMeans(n_clusters = 10).fit(diabetesDataScaled)
matplotlib包通过其colormaps注册表提供了许多内置的颜色方案。选择一个颜色图对于整个可视化来说是方便的,而且选择得当是很重要的。这可能意味着评估从数据是否可以沿着从低到高的规模解释,还是在两个极端中最相关的数据,以及是否对主题(例如地形项目的绿色和棕色)具有主题性。当数据与将以什么顺序呈现之间没有特定关系时,nipy_spectral颜色图是一个不错的选择。
nps = colormaps['nipy_spectral']
# 查看整个颜色图
nps
每个matplotlib颜色图都由一系列元组组成,每个元组以RGBA格式描述颜色(尽管组件缩放到[0,1]而不是[0,255])。可以通过整数(介于0和255之间)或浮点数(介于0和1之间)访问地图中的单个颜色。靠近0的数字对应于颜色图的较低端的颜色,而靠近255的整数和靠近1.0的浮点数对应于颜色图的较高端的颜色。直观地说,可以通过整数或表示该整数作为255的商的浮点数来描述相同的颜色。
print(nps(51))
print(nps(0.2))
#(0.0, 0.0, 0.8667, 1.0)
聚类模型的经典可视化是一系列散点图,比较了输入到聚类模型中的每对特征,用颜色表示聚类分配。有实现此目标的内置方法,但DIY方法可以更好地控制颜色方案等细节。
def plotScatters(df, model):
""" 根据数据帧中的每对列创建散点图。
使用颜色表示模型标签。
"""
# 创建图形和轴
plotRows = df.shape[1]
plotCols = df.shape[1]
fig, axes = plt.subplots(
# 为数据帧中的每个特征创建一行和一列
plotRows, plotCols
# 放大图形大小以便于查看
, figsize = ((plotCols * 3), (plotRows * 3))
)
# 遍历子图以创建散点图
pltindex = 0
for i in np.arange(0, plotRows):
for j in np.arange(0, plotCols):
pltindex += 1
# 确定当前子图
plt.subplot(plotRows, plotCols, pltindex)
plt.scatter(
# 比较数据帧的第i个和第j个特征
df.iloc[:, j], df.iloc[:, i]
# 使用整数聚类标签和颜色图来统一颜色选择
, c = model.labels_, cmap = nps
# 选择较小的标记大小以减少重叠
, s = 1)
# 在子图的底部行上标记x轴
if i == df.shape[1] - 1:
plt.xlabel(df.columns[j])
# 在子图的第一列上标记y轴
if j == 0:
plt.ylabel(df.columns[i])
plt.show()
这些图表同时完成了两项任务,显示了一对特征之间的关系,以及这些特征与聚类分配之间的关系。
plotScatters(diabetesDataScaled, km3)
随着分析的进行,很容易专注于较小的特征子集。
plotScatters(diabetesDataScaled.iloc[:, 2:7], km4)
为了更好地了解每个特征在每个聚类中的分布,我们还可以查看小提琴图。如果您不熟悉小提琴图,请将它们视为经典箱线图的成年表亲。箱线图只
识别分布的一些关键描述符,而小提琴图则根据整个概率密度函数进行轮廓绘制。
def plotViolins(df, model, plotCols = 5):
""" 创建数据帧中每个特征的小提琴图
使用模型标签进行分组。
"""
# 计算绘图网格所需的行数
plotRows = df.shape[1] // plotCols
while plotRows * plotCols < df.shape[1]:
plotRows += 1
# 创建图形和轴
fig, axes = plt.subplots(plotRows, plotCols
# 放大图形大小以便于查看
, figsize = ((plotCols * 3), (plotRows * 3))
)
# 从模型中识别唯一的聚类标签
uniqueLabels = sorted(np.unique(model.labels_))
# 从唯一标签中创建自定义子调色板
# 这将返回
npsTemp = nps([x / max(uniqueLabels) for x in uniqueLabels])
# 向输入数据帧添加整数聚类标签
df2 = df.assign(cluster = model.labels_)
# 遍历子图以创建小提琴图
pltindex = 0
for col in df.columns:
pltindex += 1
plt.subplot(plotRows, plotCols, pltindex)
sns.violinplot(
data = df2
# 使用聚类标签作为x分组器
, x = 'cluster'
# 使用当前特征作为y值
, y = col
# 使用聚类标签和自定义调色板来统一颜色选择
, hue = model.labels_
, palette = npsTemp
).legend_.remove()
# 用特征名标记y轴
plt.ylabel(col)
plt.show()
plotViolins(diabetesDataScaled, km3, plotCols = 5)
小提琴图显示了每个聚类中每个特征的分布,但是查看每个聚类在每个特征的更广泛分布中的表示也是有帮助的。修改后的直方图可以很好地说明这一点。
def histogramByCluster(df, labels, plotCols = 5, nbins = 30, legend = False, vlines = False):
""" 创建每个特征的直方图。
使用模型标签进行颜色编码。
"""
plotRows = df.shape[1] // plotCols
while plotRows * plotCols < df.shape[1]:
plotRows += 1
# 识别唯一的聚类标签
uniqueLabels = sorted(np.unique(labels))
# 创建图形和轴
fig, axes = plt.subplots(plotRows, plotCols
# 放大图形大小以便于查看
, figsize = ((plotCols * 3), (plotRows * 3))
)
pltindex = 0
# 遍历输入数据中的特征
for col in df.columns:
# 将特征离散化到指定数量的箱中
tempBins = np.trunc(nbins * df[col]) / nbins
# 将离散化的特征与聚类标签交叉
tempComb = pd.crosstab(tempBins, labels)
# 创建与交叉表相同大小的索引
# 这将有助于对齐
ind = np.arange(tempComb.shape[0])
# 确定相关的子图
pltindex += 1
plt.subplot(plotRows, plotCols, pltindex)
# 创建分组直方图数据
histPrep = {}
# 一次处理一个聚类
for lbl in uniqueLabels:
histPrep.update(
{
# 关联聚类标签...
lbl:
# ...与柱状图
plt.bar(
# 使用特征特定的索引设置x
位置
x = ind
# 使用与此聚类关联的计数作为柱高
, height = tempComb[lbl]
# 将此柱堆叠在先前聚类柱的顶部
, bottom = tempComb[[x for x in uniqueLabels if x < lbl]].sum(axis = 1)
# 消除柱之间的间隙
, width = 1
, color = nps(lbl / max(uniqueLabels))
)
}
)
# 使用特征名标记每个图的x轴
plt.xlabel(col)
# 在第一列的图中标记y轴
if pltindex % plotCols == 1:
plt.ylabel('Frequency')
plt.xticks(ind[0::5], np.round(tempComb.index[0::5], 2))
# 如果需要,覆盖垂直线
if vlines:
for vline in vlines:
plt.axvline(x = vline * ind[-1], lw = 0.5, color = 'red')
if legend:
leg1 = []; leg2 = []
for key in histPrep:
leg1 += [histPrep[key]]
leg2 += [str(key)]
plt.legend(leg1, leg2)
plt.show()
histogramByCluster(diabetesDataScaled, km4.labels_)
当需要更多聚类类别时,这个过程很容易扩展。
histogramByCluster(diabetesDataScaled, km10.labels_)
这些可视化将为评估聚类模型提供强有力的基础。
我是superpenglife,一个拥有十年经验的Python、机器学习、深度学习、数据分析和大模型工程师。我的目标是为你提供关于各种清晰且实用的指南。
你的关注、点赞是对我最大的支持。