目前拥有一个数据集,里面包含客户对不同类产品的年度采购额。通过分析数据集的内在结构,一个批发商不同种类顾客之间的差异,建立模型,帮助批发商能够更好的组织他们的物流服务以满足每个客户的需求。
# 引入这个项目需要的库
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 |
考虑这六个类别中的一个(或者多个)产品类别,是否对于理解客户的购买行为具有实际的相关性。也就是说,当用户购买了一定数量的某一类产品,我们是否能够确定他们必然会成比例地购买另一种类的产品。有一个简单的方法可以检测相关性:我们用移除了某一个特征之后的数据集来构建一个监督学习(回归)模型,然后用这个模型去预测那个被移除的特征,再对这个预测结果进行评分,看看预测结果如何。
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');
通过在数据上做一个合适的缩放,并检测异常点将数据预处理成一个更好的代表客户的形式。预
如果数据不是正态分布的,尤其是数据的平均数和中位数相差很大的时候(表示数据非常歪斜)。一种实现这个缩放的方法是使用 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');
在使用了一个自然对数的缩放之后,数据的各个特征会显得更加的正态分布。
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 之外的特征,那么该数据点被认定为异常点。
在下面的代码单元中,完成下面的功能:
Q1
。使用 np.percentile
来完成这个功能。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在一个数据集上会计算出最大化方差的维度,我们将找出哪一个特征组合能够最好的描绘客户。
既然数据被缩放到一个更加正态分布的范围中并且我们也移除了需要移除的异常点,我们现在就能够在 good_data
上使用PCA算法以发现数据的哪一个维度能够最大化特征的方差。除了找到这些维度,PCA 也将报告每一个维度的解释方差比(explained variance ratio)–这个数据有多少方差能够用这个单独的维度来解释。注意 PCA 的一个组成部分(维度)能够被看做这个空间中的一个新的“特征”,但是它是原来数据中的特征构成的。
sklearn.decomposition.PCA
并且将 good_data
用 PCA 并且使用6个维度进行拟合后的结果保存到 pca
中。pca.transform
将 log_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)
运行下面的代码,查看经过对数转换的样本数据在进行一个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)
运行以下代码观察当仅仅使用两个维度进行 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 |
双标图是一个散点图,每个数据点的位置由它所在主成分的分数确定。坐标系是主成分(这里是 Dimension 1
和 Dimension 2
)。此外,双标图还展示出初始特征在主成分上的投影。一个双标图可以帮助我们理解降维后的数据,发现主成分和初始特征之间的关系。
运行下面的代码来创建一个降维后数据的双标图。
# 可视化双标图
vs.biplot(good_data, reduced_data, pca);
一旦我们有了原始特征的投影(红色箭头),就能更加容易的理解散点图每个数据点的相对位置。
在这个部分,选择使用 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)
上面的可视化图像中提供的每一个聚类都有一个中心点。这些中心(或者叫平均点)并不是数据中真实存在的点,但是是所有预测在这个簇中的数据点的平均。对于创建客户分类的问题,一个簇的中心对应于那个分类的平均用户。因为这个数据现在进行了降维并缩放到一定的范围,我们可以通过施加一个反向的转换恢复这个点所代表的用户的花费。
在下面的代码单元中,将实现下列的功能:
pca.inverse_transform
将 centers
反向转换,并将结果存储在 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)