客户细分数据分析

创建用户分类

目前拥有一个数据集,里面包含客户对不同类产品的年度采购额。通过分析数据集的内在结构,一个批发商不同种类顾客之间的差异,建立模型,帮助批发商能够更好的组织他们的物流服务以满足每个客户的需求。

导入相关的库和数据

# 引入这个项目需要的库
import numpy as np
import pandas as pd
import visuals as vs
from IPython.display import display # 使得我们可以对DataFrame使用display()函数

# 设置以内联的形式显示matplotlib绘制的图片(在notebook中显示更美观)
%matplotlib inline
# 高分辨率显示
%config InlineBackend.figure_format='retina'

# 载入整个客户数据集
try:
    data = pd.read_csv("customers.csv")
    data.drop(['Region', 'Channel'], axis = 1, inplace = True)
    print("Wholesale customers dataset has {} samples with {} features each.".format(*data.shape))
except:
    print("Dataset could not be loaded. Is the dataset missing?")
Wholesale customers dataset has 440 samples with 6 features each.

分析数据

数据集包含了6个重要的产品类型:‘Fresh’, ‘Milk’, ‘Grocery’, ‘Frozen’, **‘Detergents_Paper’**和 ‘Delicatessen’。想一下这里每一个类型代表购买什么样的产品。

data.head()
Fresh Milk Grocery Frozen Detergents_Paper Delicatessen
0 12669 9656 7561 214 2674 1338
1 7057 9810 9568 1762 3293 1776
2 6353 8808 7684 2405 3516 7844
3 13265 1196 4221 6404 507 1788
4 22615 5410 7198 3915 1777 5185
# 显示数据集的一个描述
display(data.describe())
Fresh Milk Grocery Frozen Detergents_Paper Delicatessen
count 440.000000 440.000000 440.000000 440.000000 440.000000 440.000000
mean 12000.297727 5796.265909 7951.277273 3071.931818 2881.493182 1524.870455
std 12647.328865 7380.377175 9503.162829 4854.673333 4767.854448 2820.105937
min 3.000000 55.000000 3.000000 25.000000 3.000000 3.000000
25% 3127.750000 1533.000000 2153.000000 742.250000 256.750000 408.250000
50% 8504.000000 3627.000000 4755.500000 1526.000000 816.500000 965.500000
75% 16933.750000 7190.250000 10655.750000 3554.250000 3922.000000 1820.250000
max 112151.000000 73498.000000 92780.000000 60869.000000 40827.000000 47943.000000
data.columns
Index(['Fresh', 'Milk', 'Grocery', 'Frozen', 'Detergents_Paper',
       'Delicatessen'],
      dtype='object')

选择样本

为了对客户有一个更好的了解,并且了解代表他们的数据将会在这个分析过程中如何变换。最好是选择几个样本数据点,并且更为详细地分析它们。在下面的代码单元中,选择三个索引加入到索引列表indices中,不断尝试,直到找到三个明显不同的客户。

indices = [1, 50, 200]

# 为选择的样本建立一个DataFrame
samples = pd.DataFrame(data.loc[indices], columns = data.keys()).reset_index(drop = True)
print("Chosen samples of wholesale customers dataset:")
display(samples)
Chosen samples of wholesale customers dataset:
Fresh Milk Grocery Frozen Detergents_Paper Delicatessen
0 7057 9810 9568 1762 3293 1776
1 6269 1095 1980 3860 609 2162
2 3067 13240 23127 3941 9959 731

特征相关性

考虑这六个类别中的一个(或者多个)产品类别,是否对于理解客户的购买行为具有实际的相关性。也就是说,当用户购买了一定数量的某一类产品,我们是否能够确定他们必然会成比例地购买另一种类的产品。有一个简单的方法可以检测相关性:我们用移除了某一个特征之后的数据集来构建一个监督学习(回归)模型,然后用这个模型去预测那个被移除的特征,再对这个预测结果进行评分,看看预测结果如何。

首先试试分类模型是否能够很好的表达

  • 导入一个 DecisionTreeRegressor (决策树回归器),设置一个 random_state,然后用训练集训练它。
  • 使用回归器的 score 函数输出模型在测试集上的预测得分。
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_squared_error, r2_score
# 为DataFrame创建一个副本,用'drop'函数丢弃一个特征# TODO: 
new_data = data.drop(columns='Delicatessen')

# 使用给定的特征作为目标,将数据分割成训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(new_data, data['Delicatessen'], test_size=0.25, random_state=40)

# 创建一个DecisionTreeRegressor(决策树回归器)并在训练集上训练它
regressor = DecisionTreeRegressor().fit(X_train, y_train)

# 输出在测试集上的预测得分
score = r2_score(y_test, regressor.predict(X_test))
print(score)
-3.623322659278208

-模型并不理想。

可视化特征分布

为了能够对这个数据集有一个更好的理解,对数据集中的每一个产品特征构建一个散布矩阵(scatter matrix)。

# 对于数据中的每一对特征构造一个散布矩阵
pd.plotting.scatter_matrix(data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');

客户细分数据分析_第1张图片

数据预处理

通过在数据上做一个合适的缩放,并检测异常点将数据预处理成一个更好的代表客户的形式。预

特征缩放

如果数据不是正态分布的,尤其是数据的平均数和中位数相差很大的时候(表示数据非常歪斜)。一种实现这个缩放的方法是使用 Box-Cox 变换,这个方法能够计算出能够最佳减小数据倾斜的指数变换方法。一个比较简单的并且在大多数情况下都适用的方法是使用自然对数。

from sklearn.preprocessing import FunctionTransformer
# 使用自然对数缩放数据
log_data = pd.DataFrame(FunctionTransformer(np.log).fit_transform(data))

# 使用自然对数缩放样本数据
log_samples = pd.DataFrame(FunctionTransformer(np.log).fit_transform(samples))

# 为每一对新产生的特征制作一个散射矩阵
pd.plotting.scatter_matrix(log_data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');

客户细分数据分析_第2张图片

观察

在使用了一个自然对数的缩放之后,数据的各个特征会显得更加的正态分布。

log_data.columns = data.columns
log_samples.columns = samples.columns
# 展示经过对数变换后的样本数据
display(log_samples.head())
Fresh Milk Grocery Frozen Detergents_Paper Delicatessen
0 8.861775 9.191158 9.166179 7.474205 8.099554 7.482119
1 8.743372 6.998510 7.590852 8.258422 6.411818 7.678789
2 8.028455 9.490998 10.048756 8.279190 9.206232 6.594413

异常值检测

对于任何的分析,在数据预处理的过程中检测数据中的异常值都是非常重要的一步。异常值的出现会使得把这些值考虑进去后结果出现倾斜。这里有很多关于怎样定义什么是数据集中的异常值的经验法则。这里使用[Tukey 的定义异常值的方法:一个异常阶(outlier step)被定义成1.5倍的四分位距(interquartile range,IQR)。一个数据点如果某个特征包含在该特征的 IQR 之外的特征,那么该数据点被认定为异常点。

在下面的代码单元中,完成下面的功能:

  • 将指定特征的 25th 分位点的值分配给 Q1 。使用 np.percentile 来完成这个功能。
  • 将指定特征的 75th 分位点的值分配给 Q3 。同样的,使用 np.percentile 来完成这个功能。
  • 将指定特征的异常阶的计算结果赋值给 step
  • 选择性地通过将索引添加到 outliers 列表中,以移除异常值。
log_data.keys()
Index(['Fresh', 'Milk', 'Grocery', 'Frozen', 'Detergents_Paper',
       'Delicatessen'],
      dtype='object')
# 对于每一个特征,找到值异常高或者是异常低的数据点
outliers  = np.array([])

for feature in log_data.keys():
    
    Q1 = np.percentile(log_data[feature], 25)
    
    Q3 = np.percentile(log_data[feature], 75)
    
    step = 1.5 * (Q3 - Q1)
    
    # 显示异常点
    print("Data points considered outliers for the feature '{}':".format(feature))
    print("data {} value: [{}, {}]".format(feature, Q1 - step, Q3 + step))
    outlier = log_data[~((log_data[feature] >= Q1 - step) & (log_data[feature] <= Q3 + step))]
    outliers = np.concatenate((outlier.index, outliers))
    display(outlier)

outliers = outliers.astype(int)
good_data = log_data.drop(log_data.index[outliers]).reset_index(drop = True)
Data points considered outliers for the feature 'Fresh':
data Fresh value: [5.514550833608026, 12.270571816559475]
Fresh Milk Grocery Frozen Detergents_Paper Delicatessen
65 4.442651 9.950323 10.732651 3.583519 10.095388 7.260523
66 2.197225 7.335634 8.911530 5.164786 8.151333 3.295837
81 5.389072 9.163249 9.575192 5.645447 8.964184 5.049856
95 1.098612 7.979339 8.740657 6.086775 5.407172 6.563856
96 3.135494 7.869402 9.001839 4.976734 8.262043 5.379897
128 4.941642 9.087834 8.248791 4.955827 6.967909 1.098612
171 5.298317 10.160530 9.894245 6.478510 9.079434 8.740337
193 5.192957 8.156223 9.917982 6.865891 8.633731 6.501290
218 2.890372 8.923191 9.629380 7.158514 8.475746 8.759669
304 5.081404 8.917311 10.117510 6.424869 9.374413 7.787382
305 5.493061 9.468001 9.088399 6.683361 8.271037 5.351858
338 1.098612 5.808142 8.856661 9.655090 2.708050 6.309918
353 4.762174 8.742574 9.961898 5.429346 9.069007 7.013016
355 5.247024 6.588926 7.606885 5.501258 5.214936 4.844187
357 3.610918 7.150701 10.011086 4.919981 8.816853 4.700480
412 4.574711 8.190077 9.425452 4.584967 7.996317 4.127134
Data points considered outliers for the feature 'Milk':
data Milk value: [5.016732967223546, 11.198728361406147]
Fresh Milk Grocery Frozen Detergents_Paper Delicatessen
86 10.039983 11.205013 10.377047 6.894670 9.906981 6.805723
98 6.220590 4.718499 6.656727 6.796824 4.025352 4.882802
154 6.432940 4.007333 4.919981 4.317488 1.945910 2.079442
356 10.029503 4.897840 5.384495 8.057377 2.197225 6.306275
Data points considered outliers for the feature 'Grocery':
data Grocery value: [5.275759987575941, 11.67270989103498]
Fresh Milk Grocery Frozen Detergents_Paper Delicatessen
75 9.923192 7.036148 1.098612 8.390949 1.098612 6.882437
154 6.432940 4.007333 4.919981 4.317488 1.945910 2.079442
Data points considered outliers for the feature 'Frozen':
data Frozen value: [4.260350248162942, 10.525223584187506]
Fresh Milk Grocery Frozen Detergents_Paper Delicatessen
38 8.431853 9.663261 9.723703 3.496508 8.847360 6.070738
57 8.597297 9.203618 9.257892 3.637586 8.932213 7.156177
65 4.442651 9.950323 10.732651 3.583519 10.095388 7.260523
145 10.000569 9.034080 10.457143 3.737670 9.440738 8.396155
175 7.759187 8.967632 9.382106 3.951244 8.341887 7.436617
264 6.978214 9.177714 9.645041 4.110874 8.696176 7.142827
325 10.395650 9.728181 9.519735 11.016479 7.148346 8.632128
420 8.402007 8.569026 9.490015 3.218876 8.827321 7.239215
429 9.060331 7.467371 8.183118 3.850148 4.430817 7.824446
439 7.932721 7.437206 7.828038 4.174387 6.167516 3.951244
Data points considered outliers for the feature 'Detergents_Paper':
data Detergents_Paper value: [1.4587426638529726, 12.363699359688528]
Fresh Milk Grocery Frozen Detergents_Paper Delicatessen
75 9.923192 7.036148 1.098612 8.390949 1.098612 6.882437
161 9.428190 6.291569 5.645447 6.995766 1.098612 7.711101
Data points considered outliers for the feature 'Delicatessen':
data Delicatessen value: [3.7695940025105954, 9.7490090809691]
Fresh Milk Grocery Frozen Detergents_Paper Delicatessen
66 2.197225 7.335634 8.911530 5.164786 8.151333 3.295837
109 7.248504 9.724899 10.274568 6.511745 6.728629 1.098612
128 4.941642 9.087834 8.248791 4.955827 6.967909 1.098612
137 8.034955 8.997147 9.021840 6.493754 6.580639 3.583519
142 10.519646 8.875147 9.018332 8.004700 2.995732 1.098612
154 6.432940 4.007333 4.919981 4.317488 1.945910 2.079442
183 10.514529 10.690808 9.911952 10.505999 5.476464 10.777768
184 5.789960 6.822197 8.457443 4.304065 5.811141 2.397895
187 7.798933 8.987447 9.192075 8.743372 8.148735 1.098612
203 6.368187 6.529419 7.703459 6.150603 6.860664 2.890372
233 6.871091 8.513988 8.106515 6.842683 6.013715 1.945910
285 10.602965 6.461468 8.188689 6.948897 6.077642 2.890372
289 10.663966 5.655992 6.154858 7.235619 3.465736 3.091042
343 7.431892 8.848509 10.177932 7.283448 9.646593 3.610918

特征转换

在这个部分中将使用主成分分析(PCA)来分析批发商客户数据的内在结构。由于使用PCA在一个数据集上会计算出最大化方差的维度,我们将找出哪一个特征组合能够最好的描绘客户。

主成分分析(PCA)

既然数据被缩放到一个更加正态分布的范围中并且我们也移除了需要移除的异常点,我们现在就能够在 good_data 上使用PCA算法以发现数据的哪一个维度能够最大化特征的方差。除了找到这些维度,PCA 也将报告每一个维度的解释方差比(explained variance ratio)–这个数据有多少方差能够用这个单独的维度来解释。注意 PCA 的一个组成部分(维度)能够被看做这个空间中的一个新的“特征”,但是它是原来数据中的特征构成的。

  • 导入 sklearn.decomposition.PCA 并且将 good_data 用 PCA 并且使用6个维度进行拟合后的结果保存到 pca 中。
  • 使用 pca.transformlog_samples 进行转换,并将结果存储到 pca_samples 中。
from sklearn.decomposition import PCA
# 通过在good data上进行PCA,将其转换成6个维度
pca = PCA(n_components=6).fit(good_data)

# 使用上面的PCA拟合将变换施加在log_samples上
pca_samples = pca.transform(log_samples)

# 生成PCA的结果图
pca_results = vs.pca_results(good_data, pca)

客户细分数据分析_第3张图片

  • 对每个主成分中的特征分析权重的正负和大小。
  • 结合每个主成分权重的正负讨论消费行为。
  • 某一特定维度上的正向增长对应正权特征的增长和负权特征的减少。增长和减少的速率和每个特征的权重相关。

观察

运行下面的代码,查看经过对数转换的样本数据在进行一个6个维度的主成分分析(PCA)之后会如何改变。观察样本数据的前四个维度的数值。考虑这和初始对样本点的解释是否一致。

# 展示经过PCA转换的sample log-data
display(pd.DataFrame(np.round(pca_samples, 4), columns = pca_results.index.values))
Dimension 1 Dimension 2 Dimension 3 Dimension 4 Dimension 5 Dimension 6
0 1.8820 0.4617 0.2764 0.1055 0.0958 -0.2093
1 -1.0691 0.6047 0.7706 -0.2588 -1.1878 0.0163
2 3.0820 0.1314 0.3994 -1.4197 0.4747 0.2263

降维

当使用主成分分析的时候,一个主要的目的是减少数据的维度,这实际上降低了问题的复杂度。当然降维也是需要一定代价的:更少的维度能够表示的数据中的总方差更少。因为这个,**累计解释方差比(cumulative explained variance ratio)**对于我们确定这个问题需要多少维度非常重要。另外,如果大部分的方差都能够通过两个或者是三个维度进行表示的话,降维之后的数据能够被可视化。

# 通过在good data上进行PCA,将其转换成两个维度
pca = PCA(n_components=2).fit(good_data)

# 使用上面训练的PCA将good data进行转换
reduced_data = pca.transform(good_data)

# 使用上面训练的PCA将log_samples进行转换
pca_samples = pca.transform(log_samples)

# 为降维后的数据创建一个DataFrame
reduced_data = pd.DataFrame(reduced_data, columns = ['Dimension 1', 'Dimension 2'])
pca_results = vs.pca_results(good_data, pca)

客户细分数据分析_第4张图片

观察

运行以下代码观察当仅仅使用两个维度进行 PCA 转换后,观察这里的结果与一个使用六个维度的 PCA 转换相比较时,前两维的数值是保持不变的。

# 展示经过两个维度的PCA转换之后的样本log-data
display(pd.DataFrame(np.round(pca_samples, 4), columns = ['Dimension 1', 'Dimension 2']))
Dimension 1 Dimension 2
0 1.8820 0.4617
1 -1.0691 0.6047
2 3.0820 0.1314

可视化一个双标图(Biplot)

双标图是一个散点图,每个数据点的位置由它所在主成分的分数确定。坐标系是主成分(这里是 Dimension 1Dimension 2)。此外,双标图还展示出初始特征在主成分上的投影。一个双标图可以帮助我们理解降维后的数据,发现主成分和初始特征之间的关系。

运行下面的代码来创建一个降维后数据的双标图。

# 可视化双标图
vs.biplot(good_data, reduced_data, pca);

客户细分数据分析_第5张图片

观察

一旦我们有了原始特征的投影(红色箭头),就能更加容易的理解散点图每个数据点的相对位置。

聚类

在这个部分,选择使用 K-Means 聚类算法或者是高斯混合模型聚类算法以发现数据中隐藏的客户分类。然后,从簇中恢复一些特定的关键数据点,通过将它们转换回原始的维度和规模,从而理解他们的含义。

创建聚类

针对不同情况,有些问题需要的聚类数目可能是已知的。但是在聚类数目不作为一个先验知道的情况下,我们并不能够保证某个聚类的数目对这个数据是最优的,因为我们对于数据的结构(如果存在的话)是不清楚的。但是,我们可以通过计算每一个簇中点的轮廓系数来衡量聚类的质量。数据点的轮廓系数衡量了它与分配给他的簇的相似度,这个值范围在-1(不相似)到1(相似)。平均轮廓系数为我们提供了一种简单地度量聚类质量的方法。

from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
def kmean(clu_num):
    for i in range(clu_num-1):
        # 在降维后的数据上使用聚类算法
        clusterer = KMeans(random_state=40, n_clusters=i+2).fit(reduced_data)
        
        # 预测每一个点的簇
        preds = clusterer.predict(reduced_data)
        
        # 找到聚类中心
        centers = clusterer.cluster_centers_
        
        # 预测在每一个转换后的样本点的类
        sample_preds = clusterer.transform(reduced_data)
        
        # 计算选择的类别的平均轮廓系数(mean silhouette coefficient)
        score = silhouette_score(reduced_data, preds)
        print("When n_clusters={}, silhouette_score={}".format(i+2, score))
        print('-'*100)
kmean(10)
When n_clusters=2, silhouette_score=0.44715774229346705
----------------------------------------------------------------------------------------------------
When n_clusters=3, silhouette_score=0.36398647984017407
----------------------------------------------------------------------------------------------------
When n_clusters=4, silhouette_score=0.33115095428456554
----------------------------------------------------------------------------------------------------
When n_clusters=5, silhouette_score=0.3512662278159221
----------------------------------------------------------------------------------------------------
When n_clusters=6, silhouette_score=0.3636499317128344
----------------------------------------------------------------------------------------------------
When n_clusters=7, silhouette_score=0.36655853692752555
----------------------------------------------------------------------------------------------------
When n_clusters=8, silhouette_score=0.3612744549267258
----------------------------------------------------------------------------------------------------
When n_clusters=9, silhouette_score=0.3667615587335842
----------------------------------------------------------------------------------------------------
When n_clusters=10, silhouette_score=0.35244010571408
----------------------------------------------------------------------------------------------------

聚类可视化

选好了通过上面的评价函数得到的算法的最佳聚类数目,通过使用下面的代码块可视化来得到的结果。

# 从已有的实现中展示聚类的结果
# 在降维后的数据上使用选择的聚类算法
clusterer = KMeans(random_state=40, n_clusters=3).fit(reduced_data)

# 预测每一个点的簇
preds = clusterer.predict(reduced_data)

# 找到聚类中心
centers = clusterer.cluster_centers_

# 预测在每一个转换后的样本点的类
sample_preds = clusterer.transform(reduced_data)

# 计算选择的类别的平均轮廓系数(mean silhouette coefficient)
score = silhouette_score(reduced_data, preds)

vs.cluster_results(reduced_data, preds, centers, pca_samples)

客户细分数据分析_第6张图片

数据恢复

上面的可视化图像中提供的每一个聚类都有一个中心点。这些中心(或者叫平均点)并不是数据中真实存在的点,但是是所有预测在这个簇中的数据点的平均。对于创建客户分类的问题,一个簇的中心对应于那个分类的平均用户。因为这个数据现在进行了降维并缩放到一定的范围,我们可以通过施加一个反向的转换恢复这个点所代表的用户的花费。

在下面的代码单元中,将实现下列的功能:

  • 使用 pca.inverse_transformcenters 反向转换,并将结果存储在 log_centers 中。
  • 使用 np.log 的反函数 np.exp 反向转换 log_centers 并将结果存储到 true_centers 中。
# 反向转换中心点
log_centers = pca.inverse_transform(centers)

# 对中心点做指数转换
true_centers = np.exp(log_centers)

# 显示真实的中心点
segments = ['Segment {}'.format(i) for i in range(0,len(centers))]
true_centers = pd.DataFrame(np.round(true_centers), columns = data.keys())
true_centers.index = segments
display(true_centers)
Fresh Milk Grocery Frozen Detergents_Paper Delicatessen
Segment 0 19165.0 3281.0 4008.0 4518.0 554.0 1618.0
Segment 1 4891.0 7796.0 11680.0 1006.0 4676.0 1063.0
Segment 2 6296.0 1494.0 1931.0 1451.0 235.0 515.0
# 显示预测结果
for i, pred in enumerate(sample_preds):
    print("Sample point", i, "predicted to be in Cluster", pred)
Sample point 0 predicted to be in Cluster [3.14393155 0.48298342 3.55697135]
Sample point 1 predicted to be in Cluster [2.62378875 0.88692671 3.80949478]
Sample point 2 predicted to be in Cluster [2.54851536 1.63368661 4.19781879]

结论

首先,考虑不同组的客户客户分类,针对不同的派送策略受到的影响会有什么不同。其次,每一个客户都被打上了标签(客户属于哪一个分类)可以给客户数据提供一个多一个特征。最后,把客户分类与一个数据中的隐藏变量做比较,看一下这个分类是否辨识了特定的关系。

通过聚类技术,我们能够将原有的没有标记的数据集中的附加结构分析出来。因为每一个客户都有一个最佳的划分(取决于选择使用的聚类算法),我们可以把用户分类作为数据的一个[工程特征]

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split

# 读取包含聚类结果的数据
cluster_data = pd.read_csv("cluster.csv")
y = cluster_data['Region']
X = cluster_data.drop(['Region'], axis = 1)

# 划分训练集测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=24)

clf = RandomForestClassifier(random_state=24)
clf.fit(X_train, y_train)
score_with_cluster = clf.score(X_test, y_test)

# 移除cluster特征
X_train = X_train.copy()
X_train.drop(['cluster'], axis=1, inplace=True)
X_test = X_test.copy()
X_test.drop(['cluster'], axis=1, inplace=True)
clf.fit(X_train, y_train)
score_no_cluster = clf.score(X_test, y_test)

print("不使用cluster特征的得分: %.4f"%score_no_cluster)
print("使用cluster特征的得分: %.4f"%score_with_cluster)
不使用cluster特征的得分: 0.6437
使用cluster特征的得分: 0.6667


E:\Anaconda\file\envs\PYTHON\lib\site-packages\sklearn\ensemble\forest.py:246: FutureWarning: The default value of n_estimators will change from 10 in version 0.20 to 100 in 0.22.
  "10 in version 0.20 to 100 in 0.22.", FutureWarning)

可视化内在的分布

在这个项目的开始,我们讨论了从数据集中移除 'Channel''Region' 特征,这样在分析过程中我们就会着重分析用户产品类别。通过重新引入 Channel 这个特征到数据集中,并施加和原来数据集同样的 PCA 变换的时候我们将能够发现数据集产生一个有趣的结构。

运行下面的代码单元以查看哪一个数据点在降维的空间中被标记为 'HoReCa' (旅馆/餐馆/咖啡厅)或者 'Retail'。另外,发现样本点在图中被圈了出来,用以显示他们的标签。

# 根据‘Channel‘数据显示聚类的结果
vs.channel_results(reduced_data, outliers, pca_samples)

客户细分数据分析_第7张图片

你可能感兴趣的:(机器学习)