聚类分析
常用聚类方法如下表: 常用聚类算法如下表:
K-Means聚类算法
- K-Means算法是典型的基于距离的非层次聚类算法,在最小化误差函数的基础上将数据划分为预定的类数K,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。
- K-Means聚类算法中,一般需要度量样本之间的距离、样本与簇之间的距离以及簇与簇之间的距离。
算法过程
- 从N个样本数据中随机选取K个对象作为初始的聚类中心;
- 分别计算每个样本到各个聚类中心的距离,将对象分配到距离最近的聚类中;
- 所有对象分配完成后,重新计算K个聚类的中心;
- 与前一次计算得到的K个聚类中心比较,如果聚类中心发生变化,转2),否则转5;
- 当质心不发生变化时停止并输出聚类结果。
聚类的结果可能依赖于初始聚类中心的随机选择,可能使得结果严重偏离全局最优分类。实践中,为了得到较好的结果,通常选择不同的初始聚类中心,多次运行K-Means算法。在所有对象分配完成后,重新计算K个聚类的中心时,对于连续数据,聚类中心取该簇的均值,但是当样本的某些属性时分类变量是,均值可能无定义,可以使用K-众数方法。
数据类型与相似性的度量
连续属性
文档数据
目标函数
Python实现
简单实践(仅数值型数据)
部分餐饮客户的消费行为特征数据,consumption_data,根据这些数据将客户分类成不同客户群,并评价这些客户群的价值。
采用K-Means聚类算法,设定聚类个数K为3,最大迭代次数为500次,距离函数取欧氏距离。输出结果如下表 以下是用Pandas和Matplotlib绘制的不同客户分群的概率密度函数图,通过这些图能直观地比较不同客户群的价值。 分群 1 的概率密度函数图: 分群1特点:R间隔相对较小,主要集中在030天之间;消费次数集中在1025次;消费金额在500~2000。
分群 2的概率密度函数图: 分群2特点:R间隔分布在0-30天之间;消费次数集中在0-12次;消费金额在0-1800。
分群 3的概率密度函数图: 分群3特点:R间隔相对较大,间隔分布在30-80天之间;消费次数集中在0-15次;消费金额在0-2000。
对比分析:分群1时间间隔较短,消费次数多,而且消费金额较大,是高消费高价值人群。分群2的时间间隔、消费次数和消费金额处于中等水平,代表着一般客户。分群3的时间间隔较长,消费次数较少,消费金额也不是特别高,是价值较低的客户群体。
data_type
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
inputfile = 'data/consumption_data.xls'
outputfile = 'tmp/data_type.xls'
k = 3
iteration = 500
data = pd.read_excel(inputfile, index_col='Id')
data_zs = 1.0*(data - data.mean())/data.std()
model = KMeans(n_clusters=k, max_iter=iteration)
model.fit(data_zs)
r1 = pd.Series(model.labels_).value_counts()
r2 = pd.DataFrame(model.cluster_centers_)
r = pd.concat([r2, r1], axis=1)
r.columns = list(data.columns) + [u'类别数目']
print(r)
r = pd.concat([data, pd.Series(model.labels_, index=data.index)], axis=1)
r.columns = list(data.columns) + [u'聚类类别']
r.to_excel(outputfile)
def density_plot(data,k):
p = data.plot(kind='kde', linewidth=2, subplots=True, sharex=False)
[p[i].set_ylabel(u'密度') for i in range(k)]
plt.legend()
return plt
pic_output = 'tmp/pd_'
for i in range(k):
density_plot(data[r[u'聚类类别'] == i],k).savefig(
u'%s%s.png' % (pic_output, i))
较复杂实践(数值型数据及分类数据)
导入数据,引用包
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
def density_plot(data,k):
p = data.plot(kind='kde', linewidth=2, subplots=True, sharex=False)
[p[i].set_ylabel(u'密度') for i in range(k)]
plt.legend()
return plt
inputfile = 'tmp/sport.csv'
outputfile = 'tmp/sport_kmeans.xls'
raw_data = pd.read_csv(inputfile)
raw_data=raw_data[["学号","年级代码","学院","体重指数", "肺活量", "一分钟仰卧起坐", "坐位体前屈", "立定跳远", "800米秒"]]
raw_data[['年级代码']] = raw_data[['年级代码']].astype(str)
raw_data[['学号']] = raw_data[['学号']].astype(str)
raw_data.head()
numbercols=["体重指数", "肺活量", "一分钟仰卧起坐", "坐位体前屈", "立定跳远", "800米秒"]
classcols=[ "学院"]
查看基本状态
print('{:*^60}'.format('数据前两行:'))
print(raw_data.head(2))
print('{:*^60}'.format('数据类型:'))
print(pd.DataFrame(raw_data.dtypes).T)
print('{:*^60}'.format('数据统计描述:'))
print(raw_data.describe().round(2).T)
缺失值审查
na_cols = raw_data.isnull().any(axis=0)
print('{:*^60}'.format('含有缺失值的列:'))
print(na_cols[na_cols==True])
print('总共有多少数据缺失: {0}'.format(raw_data.isnull().any(axis=1).sum()))
相关性分析
print('{:*^60}'.format('Correlation analysis:'))
print(raw_data.corr().round(2).T)
ylabels = raw_data[numbercols].columns.values.tolist()
plt.subplots(figsize=(15, 10))
sns.heatmap(raw_data[numbercols].corr(), annot=True, vmax=1, square=True,
yticklabels=ylabels, xticklabels=ylabels, cmap="RdBu")
for x in classcols:
data=raw_data[x].unique()
print("变量【{0}】的取值有:\n{1}".format(x,data))
print("-·"*20)
model_ohe = OneHotEncoder(sparse=False)
ohe_matrix = model_ohe.fit_transform(raw_data[classcols])
print(ohe_matrix[:2])
ohe_matrix1=pd.get_dummies(raw_data[classcols])
ohe_matrix1.head(5)
sacle_matrix = raw_data[numbercols]
model_scaler = MinMaxScaler()
data_scaled = model_scaler.fit_transform(sacle_matrix)
print(data_scaled.round(2))
X = np.hstack((data_scaled, ohe_matrix))
score_list = list()
silhouette_int = -1
for n_clusters in range(2, 5):
model_kmeans = KMeans(n_clusters=n_clusters)
labels_tmp = model_kmeans.fit_predict(X)
silhouette_tmp = silhouette_score(X, labels_tmp)
if silhouette_tmp > silhouette_int:
best_k = n_clusters
silhouette_int = silhouette_tmp
best_kmeans = model_kmeans
cluster_labels_k = labels_tmp
score_list.append([n_clusters, silhouette_tmp])
print('{:*^60}'.format('K值对应的轮廓系数:'))
print(np.array(score_list))
print('最优的K值是:{0} \n对应的轮廓系数是:{1}'.format(best_k, silhouette_int))
r = pd.concat([raw_data, pd.Series(best_kmeans.labels_, index=raw_data.index)], axis=1)
r.columns = list(raw_data.columns) + [u'聚类类别']
r.to_excel(outputfile)
pic_output = 'tmp/pd_'
for i in range(best_k):
density_plot(raw_data[r[u'聚类类别'] == i],len(numbercols)).savefig(
u'%s%s.png' % (pic_output, i))
cluster_labels = pd.DataFrame(cluster_labels_k, columns=['clusters'])
merge_data = pd.concat((raw_data, cluster_labels), axis=1)
merge_data.head()
clustering_count = pd.DataFrame(merge_data['学号'].groupby(merge_data['clusters']).count()).T.rename({'学号': 'counts'})
clustering_ratio = (clustering_count / len(merge_data)).round(2).rename({'counts': 'percentage'})
print(clustering_count)
print("#"*30)
print(clustering_ratio)
cluster_features = []
for line in range(best_k):
label_data = merge_data[merge_data['clusters'] == line]
part1_data = label_data[numbercols]
part1_desc = part1_data.describe().round(3)
merge_data1 = part1_desc.iloc[2, :]
part2_data = label_data[classcols]
part2_desc = part2_data.describe(include='all')
merge_data2 = part2_desc.iloc[2, :]
merge_line = pd.concat((merge_data1, merge_data2), axis=0)
cluster_features.append(merge_line)
cluster_pd = pd.DataFrame(cluster_features).T
print('{:*^60}'.format('每个类别主要的特征:'))
all_cluster_set = pd.concat((clustering_count, clustering_ratio, cluster_pd),axis=0)
print(all_cluster_set)
num_sets = cluster_pd.iloc[:6, :].T.astype(np.float64)
num_sets_max_min = model_scaler.fit_transform(num_sets)
print('-'*60)
print(num_sets_max_min)
fig = plt.figure(figsize=(6,6))
ax = fig.add_subplot(111, polar=True)
labels = np.array(merge_data1.index)
cor_list = ['g', 'r', 'y', 'b','o','PuRd','YlGnBu']
angles = np.linspace(0, 2 * np.pi, len(labels), endpoint=False)
angles = np.concatenate((angles, [angles[0]]))
for i in range(len(num_sets)):
data_tmp = num_sets_max_min[i, :]
data = np.concatenate((data_tmp, [data_tmp[0]]))
ax.plot(angles, data, 'o-', c=cor_list[i], label="第%d类学生"%(i))
ax.fill(angles, data,alpha=0.5)
ax.set_thetagrids(angles * 180 / np.pi, labels, fontproperties="SimHei")
ax.set_title("各聚类类别显著特征对比", fontproperties="SimHei")
ax.set_rlim(-0.2, 1.2)
plt.legend(loc="upper right" ,bbox_to_anchor=(1.2,1.0))
plt.show()
|