6. 结果分析与解读

在这一部分,我们将对模型的结果进行详细分析,解释不同聚类方法(K-Means 和 GMM)在客户数据上的表现,并给出具有业务指导意义的解读。

6.1 K-Means 聚类结果分析

6.1.1 K-Means 聚类的特点

通过 K-Means 聚类算法,数据被分成了 5 个簇。该方法基于欧几里得距离来计算数据点之间的相似度,目标是最小化每个簇内的数据点与簇中心的距离。

K-Means 聚类中心

在我们的案例中,K-Means 找到的每个簇的聚类中心 可以解释为每个群体的“代表性”特征。例如:

  • 簇 1 可能是年轻且低收入的客户,他们的消费较低。
  • 簇 2 可能是年轻且高收入的客户,他们的消费较高。
  • 簇 3 可能是中年且低收入的客户,消费评分中等。
  • 簇 4 可能是中年且高收入的客户,他们的消费偏高。
  • 簇 5 可能是年长且高收入的客户,他们的消费比较稳定。

这些聚类结果帮助我们理解不同类型客户的消费行为模式。

K-Means 聚类优缺点

优点:

  • 计算速度快,适合大规模数据集。
  • 容易理解,通过聚类中心直观展示不同群体的特征。

缺点:

  • K-Means 假设簇是球形且大小相似,这对于现实中可能不成立(例如,客户群体的特征差异较大时)。

6.1.2 K-Means 可视化

K-Means 聚类结果的可视化展示了不同簇在 “年收入”和“消费评分” 两个维度上的分布。通过颜色不同的散点图,我们可以清晰看到每个簇的分布情况。

例如,簇 1 可能主要集中在“低年收入”和“低消费评分”区域,而簇 4 可能集中在“高年收入”和“高消费评分”区域。

通过这些可视化图表,业务团队能够明确地看出哪些客户群体是高消费、高收入的目标群体,哪些群体是低收入或低消费的潜力客户。

6.2 GMM 聚类结果分析

6.2.1 GMM 聚类的特点

与 K-Means 相比,GMM 聚类 允许簇具有不同的形状,而不仅仅是球形。这使得 GMM 更加灵活,能够处理复杂的簇形分布。

GMM 聚类的软分配

GMM 的独特之处在于它提供了软分配,即每个客户数据点属于每个簇的概率。因此,某些客户可能属于多个簇,只是它们在某个簇的概率较高。

GMM 聚类优缺点

优点:

  • GMM 可以处理更复杂的簇形状,适用于实际数据中的多样性。
  • 软分配 可以提供更多关于客户的不确定性信息,有助于为每个客户制定个性化的策略。

缺点:

  • GMM 的计算复杂度较高,比 K-Means 更慢。
  • 对初始参数设置敏感,可能需要较多的调优工作。

6.2.2 GMM 可视化

GMM 聚类结果的可视化与 K-Means 类似,但我们可以看到,每个客户属于不同簇的概率分布。这使得我们能够对每个客户进行更精准的分类,并根据客户的隶属度来制定不同的营销策略。

6.3 聚类评估结果

6.3.1 轮廓系数

通过计算轮廓系数,我们评估了两种模型的聚类效果:

  • K-Means 的轮廓系数: 表明 K-Means 模型的聚类效果是合理的,因为该值较接近 1,说明簇之间有良好的分离度。
  • GMM 的轮廓系数: GMM 的轮廓系数也表现不错,证明该模型能较好地处理具有不同形状的簇。

轮廓系数越接近 1,表示聚类结果越好。因此,两种模型都能有效地将客户分群,并且有较好的簇间区分。

6.3.2 WCSS(聚类内平方误差)

K-Means 的 WCSS 值为一个较小的值,这表示簇内的数据点相对紧密,聚类效果较好。较低的 WCSS 值说明该模型已成功将数据集划分为几乎没有重叠的群体。

6.4 模型优化与超参数调优

通过 网格搜索(GridSearchCV),我们优化了模型的超参数,并选择了最佳的聚类数 K 和 GMM 的组件数。这些优化帮助提高了模型的精度,避免了过拟合或欠拟合。

6.5 业务指导意义

6.5.1 客户细分

根据 K-Means 和 GMM 的聚类结果,业务团队可以根据不同的客户群体制定更加精准的营销策略:

  • 高收入高消费群体: 这些客户是最具价值的目标客户,可以通过定制化的产品推荐、会员奖励等策略来提高他们的忠诚度和消费频次。
  • 低收入低消费群体: 对这些客户可以采取优惠券、折扣等激励措施,激发他们的消费潜力。
  • 中等收入群体: 这些客户属于潜力客户,可以通过个性化推荐和高质量的客户服务来吸引他们进行更多消费。

6.5.2 资源优化

通过客户分群分析,企业能够优化资源分配。例如,企业可以将更多的广告预算和资源投入到高收入高消费的群体,而不是浪费在对价格敏感的低消费群体上。

6.5.3 精准营销与个性化推荐

基于客户群体的差异化需求,业务可以通过个性化的推荐系统为每个客户提供量身定制的产品推荐,提高客户的满意度和忠诚度。

6.5.4 风险识别

对于一些不活跃或高风险客户群体(例如,消费频次低的群体),公司可以提前识别并采取措施,如提供特别优惠来鼓励客户回流,或者实施更严格的信用风险管理。

6.6 小结

  • K-Means 和 GMM 聚类都有效地对客户进行了分群,并且从聚类评估指标来看,模型表现良好。
  • K-Means 聚类 适用于对簇形状要求不高的简单场景,且计算较为高效。
  • GMM 聚类 则能够处理更复杂的簇形状,并提供软分配,适用于客户行为的精细化分析。
  • 通过 模型优化 和超参数调优,我们提高了聚类模型的准确性,最终可以为企业提供精准的客户细分,从而推动业务增长。

7. 完整代码

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.mixture import GaussianMixture
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

# 读取数据
file_path = "./dataset/008/Mall_Customers.csv"
df = pd.read_csv(file_path)

# 查看数据基本信息
print(df.info())
print(df.describe())

# 查看前 5 行数据
df.head()

# 检查缺失值
print("缺失值情况:\n", df.isnull().sum())

# 检查重复数据
print("重复值情况:", df.duplicated().sum())

# 统计每一列的唯一值数量
print("唯一值数量:\n", df.nunique())

# 检查极端值(利用 IQR 方法)
Q1 = df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']].quantile(0.25)
Q3 = df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']].quantile(0.75)
IQR = Q3 - Q1

# 计算异常值范围
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 查找异常值
outliers = ((df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']] < lower_bound) |
            (df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']] > upper_bound)).sum()
print("异常值统计:\n", outliers)

# 设置 Seaborn 风格
sns.set(style="whitegrid")

# 年龄、年收入、消费评分的分布
fig, axes = plt.subplots(1, 3, figsize=(18, 5))

sns.histplot(df['Age'], bins=20, kde=True, color='royalblue', ax=axes[0])
axes[0].set_title('Age Distribution')
axes[0].set_xlabel('Age')

sns.histplot(df['Annual Income (k$)'], bins=20, kde=True, color='tomato', ax=axes[1])
axes[1].set_title('Annual Income Distribution')
axes[1].set_xlabel('Annual Income (k$)')

sns.histplot(df['Spending Score (1-100)'], bins=20, kde=True, color='seagreen', ax=axes[2])
axes[2].set_title('Spending Score Distribution')
axes[2].set_xlabel('Spending Score')

plt.show()

# 计算相关性矩阵
corr_matrix = df[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']].corr()

# 可视化相关性
plt.figure(figsize=(6, 5))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt=".2f")
plt.title("Feature Correlation Heatmap")
plt.show()

# 三个变量的关系
plt.figure(figsize=(10, 6))
sns.scatterplot(x='Annual Income (k$)', y='Spending Score (1-100)', hue='Age', size='Age',
                palette='viridis', sizes=(20, 200), data=df)
plt.title("Annual Income vs Spending Score (Age as Hue)")
plt.xlabel("Annual Income (k$)")
plt.ylabel("Spending Score")
plt.legend(title="Age")
plt.show()

# 删除无关列
df_cluster = df.drop(columns=['CustomerID', 'Gender'])

# 归一化数据
scaler = MinMaxScaler()
df_cluster_scaled = pd.DataFrame(scaler.fit_transform(df_cluster), columns=df_cluster.columns)

# 查看归一化后的数据
df_cluster_scaled.head()

# 将数据集划分为训练集(80%)和测试集(20%)
train_data, test_data = train_test_split(df_cluster_scaled, test_size=0.2, random_state=42)

# 输出数据形状
print("训练集大小:", train_data.shape)
print("测试集大小:", test_data.shape)

# 选择 K 值(使用肘部法则)
wcss = []
for k in range(1, 11):
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(df_cluster_scaled)
    wcss.append(kmeans.inertia_)

# 绘制肘部法则图
plt.figure(figsize=(8, 5))
plt.plot(range(1, 11), wcss, marker='o', linestyle='-', color='royalblue')
plt.xlabel("Number of Clusters")
plt.ylabel("WCSS")
plt.title("Elbow Method for Optimal K")
plt.show()

# 训练 K-Means
optimal_k = 5  # 例如通过肘部法则确定为5
kmeans = KMeans(n_clusters=optimal_k, random_state=42)
df_cluster_scaled['KMeans_Cluster'] = kmeans.fit_predict(df_cluster_scaled)

# 训练 GMM
gmm = GaussianMixture(n_components=optimal_k, random_state=42)
df_cluster_scaled['GMM_Cluster'] = gmm.fit_predict(df_cluster_scaled)

# 训练 K-Means 模型
optimal_k = 5  # 通过肘部法则确定的最佳 K 值
kmeans = KMeans(n_clusters=optimal_k, random_state=42)
df_cluster_scaled['KMeans_Cluster'] = kmeans.fit_predict(df_cluster_scaled)

# 查看聚类结果
print(df_cluster_scaled[['Age', 'Annual Income (k$)', 'Spending Score (1-100)', 'KMeans_Cluster']].head())

# 训练 GMM 模型
gmm = GaussianMixture(n_components=optimal_k, random_state=42)
df_cluster_scaled['GMM_Cluster'] = gmm.fit_predict(df_cluster_scaled)

# 查看聚类结果
print(df_cluster_scaled[['Age', 'Annual Income (k$)', 'Spending Score (1-100)', 'GMM_Cluster']].head())

# 计算 K-Means 和 GMM 的轮廓系数
kmeans_score = silhouette_score(df_cluster_scaled[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']],
                                df_cluster_scaled['KMeans_Cluster'])
gmm_score = silhouette_score(df_cluster_scaled[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']],
                             df_cluster_scaled['GMM_Cluster'])

print(f"K-Means Silhouette Score: {kmeans_score:.4f}")
print(f"GMM Silhouette Score: {gmm_score:.4f}")

# 计算 K-Means 的 WCSS(聚类内平方误差)
wcss = kmeans.inertia_
print(f"K-Means WCSS: {wcss:.4f}")

# 定义参数范围
param_grid = {
    'n_clusters': [3, 4, 5, 6, 7, 8, 9, 10]  # K 值范围
}

# 使用 GridSearchCV 进行超参数调优
grid_search = GridSearchCV(estimator=KMeans(random_state=42), param_grid=param_grid, cv=3,
                           scoring='neg_mean_squared_error')
grid_search.fit(df_cluster_scaled[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])

# 输出最佳参数
print(f"Best K for K-Means: {grid_search.best_params_['n_clusters']}")

# 定义参数范围
param_grid_gmm = {
    'n_components': [3, 4, 5, 6],  # 簇数
    'covariance_type': ['full', 'tied', 'diag', 'spherical'],  # 协方差类型
    'max_iter': [100, 200]  # 最大迭代次数
}

# 使用 GridSearchCV 进行超参数调优
grid_search_gmm = GridSearchCV(estimator=GaussianMixture(), param_grid=param_grid_gmm, cv=3)
grid_search_gmm.fit(df_cluster_scaled[['Age', 'Annual Income (k$)', 'Spending Score (1-100)']])

# 输出最佳参数
print(f"Best GMM Parameters: {grid_search_gmm.best_params_}")

# K-Means 聚类结果的可视化
plt.figure(figsize=(10, 6))
sns.scatterplot(x='Annual Income (k$)', y='Spending Score (1-100)', hue='KMeans_Cluster', data=df_cluster_scaled,
                palette='Set1', s=100, marker='o')
plt.title('K-Means Clustering (5 clusters)')
plt.xlabel('Annual Income (k$)')
plt.ylabel('Spending Score (1-100)')
plt.legend(title='Cluster')
plt.show()

# GMM 聚类结果的可视化
plt.figure(figsize=(10, 6))
sns.scatterplot(x='Annual Income (k$)', y='Spending Score (1-100)', hue='GMM_Cluster', data=df_cluster_scaled,
                palette='Set2', s=100, marker='o')
plt.title('GMM Clustering (5 components)')
plt.xlabel('Annual Income (k$)')
plt.ylabel('Spending Score (1-100)')
plt.legend(title='Cluster')
plt.show()

# 对比 K-Means 和 GMM 的聚类效果
fig, axes = plt.subplots(1, 2, figsize=(18, 6))

# K-Means 可视化
sns.scatterplot(x='Annual Income (k$)', y='Spending Score (1-100)', hue='KMeans_Cluster', data=df_cluster_scaled,
                palette='Set1', s=100, marker='o', ax=axes[0])
axes[0].set_title('K-Means Clustering')
axes[0].set_xlabel('Annual Income (k$)')
axes[0].set_ylabel('Spending Score (1-100)')

# GMM 可视化
sns.scatterplot(x='Annual Income (k$)', y='Spending Score (1-100)', hue='GMM_Cluster', data=df_cluster_scaled,
                palette='Set2', s=100, marker='o', ax=axes[1])
axes[1].set_title('GMM Clustering')
axes[1].set_xlabel('Annual Income (k$)')
axes[1].set_ylabel('Spending Score (1-100)')

plt.show()
© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发
头像-大赛人网
欢迎您留下宝贵的见解!
提交
头像-大赛人网

昵称

取消
昵称

    请登录后查看评论内容