K-means是一种常见的聚类分析算法,它可以将一个数据集划分为K个不同的簇(cluster)。它的基本思想是:通过计算样本之间的相似度(欧氏距离、曼哈顿距离等),将所有数据样本划分为候选簇。然后,通过计算每个簇中所有样本的中心点,并将距离最近的未分配到簇(簇心)的样本重新分配簇,直到所有的样本都被分到一个簇中。

以下是一个使用k-means聚类算法进行航空公司客户分析的实例:

数据集

 具体代码实现

### 导入所需包 ###
import sklearn
from sklearn.cluster import KMeans
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#导入csv数据
datafile = open('data/air_data.csv',encoding='gbk',errors='ignore')
dataset = pd.read_csv(datafile)
print(dataset.shape)
print(dataset.head())

#清洗数据,删除异常数据(票价为空)
dataset = dataset[dataset["SUM_YR_1"].notnull() & dataset["SUM_YR_2"].notnull()]
index1 = dataset["SUM_YR_1"] != 0
index2 = dataset["SUM_YR_2"] != 0
index3 = (dataset["SEG_KM_SUM"] == 0) & (dataset["avg_discount"] == 0)
dataset = dataset[index1|index2|index3]
print(dataset.shape)

#保存清洗后的数据
cleanedfile = 'temp/dataset_cleaned.csv'
dataset.to_csv(cleanedfile)

#选择与LRMFC指标相关的6个属性:FFP_DATE、LOAD_TIME、FLIGHT_COUNT、AVG_DISCOUNT、SEG_KM_SUM、LAST_TO_END。即入会时间、观测窗口结束时间、观测窗口的飞行次数、平均折扣率、观测窗口的总飞行公里数、最后一次乘机时间至观测窗口末端时长。

outfile = 'temp/data_selected.csv'
df = dataset[['FFP_DATE','LOAD_TIME','avg_discount','FLIGHT_COUNT','SEG_KM_SUM','LAST_TO_END']]
df.to_csv(outfile)

#LRFMC指标取值
#   (1) L = LOAD_TIME - FFP_DATE
#       会员入会时间距观测窗口结束的月数 = 观测窗口的结束时间 - 入会时间 [单位:月]
#   (2) R = LAST_TO_END
#       客户最近一次乘坐公司飞机距观测窗口结束的月数 = 最后一次乘机时间至观测窗口末端时长 [单位:月]
#   (3) F = FLIGHT_COUNT
#       客户在观测窗口内乘坐公司飞机的次数 = 观测窗口的飞行次数 [单位:次]
#   (4) M = SEG_KM_SUM
#       客户在观测时间内在公司累计的飞行里程 = 观测窗口的总飞行公里数 [单位:公里]
#   (5) C = AVG_DISCOUNT
#       客户在观测时间内乘坐舱位所对应的折扣系数的平均值 = 平均折扣率 [单位:无]

datafile = open('temp/data_selected.csv',encoding='gbk',errors='ignore')
standardfile = 'temp/data_standard.csv'

data = pd.read_csv(datafile)

#获取LRFMC各个指标数据
df = data[['LAST_TO_END','FLIGHT_COUNT','SEG_KM_SUM','avg_discount']].copy()
df['L'] = (pd.to_datetime(data['LOAD_TIME']) - pd.to_datetime(data['FFP_DATE'])).dt.days/30#计算日期差,单位为月
df.rename(columns={'LAST_TO_END':'R','FLIGHT_COUNT':'F','SEG_KM_SUM':'M','avg_discount':'C'},inplace = True)

#使用标准差进行数据标准化
df = (df - df.mean(axis=0))/(df.std(axis=0))
df.columns = ['z'+i for i in df.columns]

df.to_csv(standardfile)

#K-means聚类模型
np.set_printoptions(threshold=np.inf)
datafile = open('temp/data_standard.csv',encoding='gbk',errors='ignore')

#读取训练数据并删除索引列
dataset = pd.read_csv(datafile).drop(['Unnamed: 0'],axis=1)

print(dataset.head())

# 创建一个空列表来存储 SSE
SSE = []
# 按照 K 的个数循环,依次计算 SSE
for k in range(1, 11):
    kmeans = KMeans(n_clusters=k, init='k-means++', random_state=0)
    kmeans.fit(dataset)
    SSE.append(kmeans.inertia_)

# 绘制 SSE 折线图
plt.plot(range(1, 11), SSE,'-o')
plt.axhline(SSE[4], color='k', linestyle='--', linewidth=1)
plt.xlabel('K')
plt.ylabel('SSE')
plt.title('K-means Clustering')
plt.show()

#调用sklearn的KMeans算法
k=5
kmodel = KMeans(n_clusters = k)
kmodel.fit(dataset) #训练模型
print("聚类中心:",kmodel.cluster_centers_)#查看聚类中心


#客户价值分析,聚类结果可视化,使用雷达图
labels = dataset.columns #标签
k = 5 #数据个数
plot_data = kmodel.cluster_centers_
color = ['b', 'g', 'r', 'c', 'y'] #指定颜色

angles = np.linspace(0, 2*np.pi, k, endpoint=False)
plot_data = np.concatenate((plot_data, plot_data[:,[0]]), axis=1)
angles = np.concatenate((angles, [angles[0]]))
labels=np.concatenate((labels,[labels[0]]))#使雷达图连线封闭

fig = plt.figure()
ax = fig.add_subplot(111, polar=True)
for i in range(len(plot_data)):
  ax.plot(angles, plot_data[i], 'o-', color = color[i], label = u'customer'+str(i+1), linewidth=2)

ax.set_rgrids(np.arange(0.01, 3.5, 0.5), np.arange(-1, 2.5, 0.5), fontproperties="SimHei")
ax.set_thetagrids(angles * 180/np.pi, labels, fontproperties="SimHei")
plt.legend(loc = 4)
plt.show()

model.inertia_ 是K-means聚类算法中的一个属性,它代表了各数据样本到其所属簇中心点的距离之和,也被称为误差平方和(Sum of Squared Errors, SSE)。一般而言,在执行K-means算法时,我们希望误差平方和越小越好。

当K-means算法迭代完成时,每个数据样本都会被分配到一个簇中,并且每个簇都有一个对应的中心点。model.inertia_属性计算的是每个数据样本到其所属簇中心点的距离的平方和。这个值越小,说明样本到中心点之间的距离越小,样本在簇中的相似度越高,聚类效果也就越好,反之则聚类效果较差。

在K-means算法中,通过不断迭代计算中心点和样本所属簇,可以使误差平方和逐渐减小。因此,通过监控model.inertia_属性的变化可以判断算法是否已收敛,或者选择更好的K值。

可以看出k=5时,SSE已经趋于收敛,故将k值设置为5。

最终结果:

 

更多推荐