创建细分客户的无监督学习项目

http://blog.itpub.net/29829936/viewspace-2643138/

 

在整个项目中,我们将分析一些产品类别中几个客户的消费行为。该项目的主要目标是:

将客户分组为具有相近支出特征的集群。

描述不同集群内的变化,以便为每个集团找到最佳的交付结构。

创建细分客户的无监督学习项目

 

要执行此项目,我们将使用可在以下UCI机器学习库中找到的数据集。

我们将重点分析为客户记录的六个产品类别,不包括"渠道"和"区域"字段。

# Import libraries necessary for this project
 import numpy as np
 import pandas as pd
 from IPython.display import display # Allows the use of display() for DataFrames
 
 # Import supplementary visualizations code visuals.py
 import visuals as vs
 
 # Pretty display for notebooks
 %matplotlib inline
 
 # Load the wholesale customers dataset
 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?")

创建细分客户的无监督学习项目

 

创建细分客户的无监督学习项目

 

数据探索

现在,我们将通过可视化和代码探索数据集,以便了解特征之间的关系。此外,我们将计算数据集的统计描述并考虑每个特征的整体相关性。

# Display a description of the dataset
 display(data.describe())

创建细分客户的无监督学习项目

 

# Display the head of the dataset
 data.head()

创建细分客户的无监督学习项目

 

选择样本

为了更好地理解我们的数据集以及如何通过分析转换数据,我们将选择一些样本点并详细探索它们。

# Select three indices to sample from the dataset
 indices = [85,181,338]
 
 # Create a DataFrame of the chosen samples
 samples = pd.DataFrame(data.loc[indices], columns = data.keys()).reset_index(drop = True)
 print("Chosen samples of wholesale customers dataset:")
 display(samples)

创建细分客户的无监督学习项目

 

注意事项

现在让我们考虑每个产品类别的总购买成本以及我们样本客户的上述数据集的统计描述。如果我们必须预测所选择的三个样本中的每一个代表什么类型的企业:

考虑平均值:

  • 新鲜:12000.2977
  • 牛奶:5796.2
  • 杂货店:3071.9
  • 清洁纸r:2881.4
  • 熟食店:1524.8

我们可以做出以下预测:

指数85:零售商:

  • 最大的清洁剂,纸张和杂货的整个数据集,通常是房屋产品。
  • 高于牛奶的平均支出。
  • 冷冻产品的支出低于平均水平。

指数181:大市场

  • 几乎所有产品类别的高消费。
  • 对整个数据集的新鲜产品的最高支出。可能是一个大市场。
  • 洗涤剂支出低。

指数338:餐厅

  • 每种产品的数量都明显低于前两位客户。
  • 新鲜产品的支出是整个数据集中最低的。
  • 牛奶,洗涤剂和纸张的支出处于最低四分位数。
  • 它可能是一个小而便宜的餐厅,需要杂货和冷冻食品来供应餐点。

特征相关性

我们现在将分析这些特征的相关性,以了解客户的购买行为。换句话说,确定购买一定数量的一类产品的客户是否必须购买一定比例的另一类产品。

我们将通过在一个数据子集上训练有监督的回归学习器并移除一个特征来研究这一点,然后评估该模型可以预测移除的特征的程度。

# Display the head of the dataset
 data.head(1)

创建细分客户的无监督学习项目

 

# Make a copy of the DataFrame, using the 'drop' function to drop the given feature
 new_data = data.drop('Grocery', axis=1)
 
 # Split the data into training and testing sets(0.25) using the given feature as the target
 # Set a random state.
 from sklearn.model_selection import train_test_split
 
 X_train, X_test, y_train, y_test = train_test_split(new_data, data.Grocery, test_size=0.25, random_state=42)
 
 # Create a decision tree regressor and fit it to the training set
 from sklearn.tree import DecisionTreeRegressor
 regressor = DecisionTreeRegressor()
 regressor = regressor.fit(X_train, y_train)
 prediction = regressor.predict(X_test)
 
 # Report the score of the prediction using the testing set
 from sklearn.metrics import r2_score
 score = r2_score(y_test, prediction)
 print("Prediction score is: {}".format(score))

创建细分客户的无监督学习项目

 

  • 我们试图预测Grocery特征。
  • 报告的预测得分为67.25%。
  • 当我们获得高分时,它作为非常合适的指标。因此,考虑到其余的花费习惯,这个特征很容易预测,因此,对于识别顾客的消费习惯不是很有必要。

可视化特征分布

为了更好地理解我们的数据集,我们将显示每个产品特征的散布矩阵。

显示散点图矩阵相关性的产品特征与预测其他特征相关。

# Produce a scatter matrix for each pair of features in the data
 pd.scatter_matrix(data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');

创建细分客户的无监督学习项目

 

# Display a correlation matrix
 import seaborn as sns
 sns.heatmap(data.corr())

创建细分客户的无监督学习项目

 

使用散点矩阵和相关矩阵作为参考,我们可以推断出以下内容:

  • 数据不是正态分布的,它是正偏态的,并且它可以重新定义对数正态分布。
  • 在大多数情节中,大多数数据点位于原点附近,它们之间几乎没有相关性。
  • 从散点图和相关热图,我们可以看到“杂货店”和“清洁纸”特征之间存在很强的相关性。“杂货店”和“牛奶”等特征也表现出良好的相关性。
  • 这种相关性证实了我对'Grocery'特征的相关性的猜测,可以使用'Detergent_paper'特征准确预测。因此,它不是数据集中绝对必要的特征。

数据预处理

此步骤对于确保获得的结果具有重要意义。我们将通过缩放数据并检测潜在异常值来预处理数据。

特征缩放

通常,当数据不是正态分布,特别是如果平均数和中位数显著变化,这是最适合施加非线性缩放的,尤其是对财务数据。

实现此缩放的一种方法是使用Box-Cox测试,该测试计算数据的最佳功率变换,从而减少偏斜。在大多数情况下可以使用的更简单的方法是应用自然对数。

# Scale the data using the natural logarithm 
 log_data = np.log(data) 
# Scale the sample data using the natural logarithm 
 log_samples = np.log(samples) 
# Produce a scatter matrix for each pair of newly-transformed features 
 pd.scatter_matrix(log_data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');

创建细分客户的无监督学习项目

 

总结

在对数据应用自然对数缩放后,每个要素的分布显得更加正常。对于我们之前已经确定为相关的任何特征对,我们在此观察到相关性仍然存在(以及它现在是否比之前更强或更弱)。

显示实际数据:

# Display the log-transformed sample data
 display(log_samples)

创建细分客户的无监督学习项目

 

异常值检测

在任何分析的数据预处理步骤中检测数据中的异常值都非常重要。异常值的存在通常会使这些数据点的结果产生偏差。

在这里,我们将使用Tukey的方法来识别异常值:异常步骤计算为四分位数范围(IQR)的1.5倍。具有超出该特征的IQR之外的异常步骤的特征的数据点被认为是异常的。

outliers = []
 
 # For each feature find the data points with extreme high or low values
 for feature in log_data.keys():
 
 # Calculate Q1 (25th percentile of the data) for the given feature
 Q1 = np.percentile(log_data[feature],25)
 
 # Calculate Q3 (75th percentile of the data) for the given feature
 Q3 = np.percentile(log_data[feature],75)
 
 # Use the interquartile range to calculate an outlier step (1.5 times the interquartile range)
 step = 1.5 * (Q3-Q1)
 
 # Display the outliers
 print("Data points considered outliers for the feature '{}':".format(feature))
 display(log_data[~((log_data[feature] >= Q1 - step) & (log_data[feature] <= Q3 + step))])
 lista = log_data[~((log_data[feature] >= Q1 - step) & (log_data[feature] <= Q3 + step))].index.tolist()
 outliers.append(lista)

创建细分客户的无监督学习项目

 

创建细分客户的无监督学习项目

 

创建细分客户的无监督学习项目

 

outliers

创建细分客户的无监督学习项目

 

# Detecting outliers that appear in more than one product
 seen = {}
 dupes = []
 
 for lista in outliers:
 for index in lista:
 if index not in seen:
 seen[index] = 1
 else:
 if seen[index] == 1:
 dupes.append(index)
 seen[index] += 1
 dupes = sorted(dupes)
 dupes

创建细分客户的无监督学习项目

 

# Removing outliers 
 good_data = log_data.drop(dupes, axis=0).reset_index(drop=True)

总结

  • 数据点被认为存在于多个特征中的异常值是:65,66,75,128,154。
  • K-Means受到异常值的影响很大,因为它们显着增加了算法试图最小化的损失函数。该损失函数是每个数据点与质心的距离的平方和,因此,如果异常值足够远,则质心将被错误地定位。因此,应删除异常值。

特征转换

现在我们将使用主成分分析来提取有关数据集隐藏结构的结论。PCA用于计算最大化方差的那些维度,因此我们将找到最能描述每个客户的特征组合。

主成分分析(PCA)

一旦数据被缩放到正态分布并且已经去除了必要的异常值,我们就可以应用PCA good_data来发现关于数据的哪些维度最大化所涉及的特征的方差。

除了找到这些维度之外,PCA还将报告每个维度的解释方差比 - 数据中的差异仅由该维度解释。

# Get the shape of the log_samples
 log_samples.shape

创建细分客户的无监督学习项目

 

# Apply PCA by fitting the good data with the same number of dimensions as features
 from sklearn.decomposition import PCA
 pca = PCA(n_components=good_data.shape[1])
 pca = pca.fit(good_data)
 
 # Transform log_samples using the PCA fit above
 pca_samples = pca.transform(log_samples)
 
 # Generate PCA results plot
 pca_results = vs.pca_results(good_data, pca)

创建细分客户的无监督学习项目

 

总结

  • 前两个主成分解释的差异占总数的70.68%。
  • 前三个主要组成部分解释的差异是总数的93.11%。

尺寸讨论

  • 维度1:就负面差异而言,此维度代表以下特征:Detergent_Paper,Milk和杂货。主要用于日常消费。
  • 维度2:就负面差异而言,此维度代表以下特征:Fresh,Frozen和Delicatessen。主要是食物消耗。
  • 维度3:根据正方差,熟食特征和负差异de Fresh特征,此维度表示良好。当天要消耗的食物。
  • 维度4:根据正方差,冻结特征以及负方差,熟食特征,该维度表示良好。可以存放的食物。
# Display sample log-data after having a PCA transformation applied
 display(pd.DataFrame(np.round(pca_samples, 4), columns = pca_results.index.values))

创建细分客户的无监督学习项目

 

降维

使用主成分分析时,主要目标之一是减少数据的维度。

尺寸降低是有代价的:使用的尺寸越少意味着数据中的总方差变化越小。因此,累积解释的方差比对于了解问题需要多少维度非常重要。另外,如果仅通过两维或三维解释显着的方差量,则可以在之后可视化减少的数据。

# Apply PCA by fitting the good data with only two dimensions
 pca = PCA(n_components=2).fit(good_data)
 
 # Transform the good data using the PCA fit above
 reduced_data = pca.transform(good_data)
 
 # Transform log_samples using the PCA fit above
 pca_samples = pca.transform(log_samples)
 
 # Create a DataFrame for the reduced data
 reduced_data = pd.DataFrame(reduced_data, columns = ['Dimension 1', 'Dimension 2'])

下面的单元格显示了仅使用两个维度对PCA转换应用后,对数转换后的样本数据的变化情况。观察与六维中的PCA变换相比,前两个维度的值如何保持不变。

# Display sample log-data after applying PCA transformation in two dimensions
 display(pd.DataFrame(np.round(pca_samples, 4), columns = ['Dimension 1', 'Dimension 2']))

创建细分客户的无监督学习项目

 

可视化Biplot

双标图是散点图,其中每个数据点由其沿主要分量的分数表示。轴是主要组件。

双标图显示了原始特征沿组件的投影。双标图可以帮助我们解释数据的缩小尺寸,并发现主要组件和原始特征之间的关系。

# Create a biplot
 vs.biplot(good_data, reduced_data, pca)

创建细分客户的无监督学习项目

 

一旦我们得到原始特征投影(红色),就可以更容易地解释散点图中每个数据点的相对位置。

例如,点图的右下角将有可能对应于花费了大量的客户“牛奶”,“杂货店”和“清洁纸”,但没有这么多的其他产品类别。

聚类

在本节中,我们将选择使用K-Means聚类算法或高斯混合模型(GMM)聚类算法来识别隐藏在数据中的各种客户群。

然后,我们将从群集中恢复特定数据点,以通过将它们转换回原始维度和比例来了解它们的重要性。

K-Means与GMM

使用K-Means作为聚类算法的主要优点是:

  • 易于实施。
  • 对于大量变量,如果(K很小),它可能在计算上比分层次聚类更快。
  • 一致且规模不变。
  • 保证收敛。

使用高斯混合模型作为聚类算法的主要优点是:

  • 就集群协方差而言,它更加灵活。这意味着每个集群可以具有无约束的协方差结构。换句话说,虽然K-means假设每个簇都具有球形结构,但GMM允许椭圆形。
  • 点可以属于不同的集群,具有不同的成员级别。这种成员级别是每个点属于每个集群的概率。

选择算法:

  • 所选择的算法是高斯混合模型。因为数据不是在明确的和不同的集群中分割的,所以我们不知道有多少集群。

创建集群

当先前不知道簇的数量时,不能保证给定数量的簇最好地对数据进行分段,因为不清楚数据中存在什么结构。

但是,我们可以通过计算每个数据点的轮廓系数来量化聚类的"优点" 。数据点的轮廓系数测量它与指定簇的相似程度,从-1(不相似)到1(相似)。计算平均轮廓系数提供了给定聚类的简单评分方法。

# Import the necessary libraries
 from sklearn.mixture import GaussianMixture
 from sklearn.metrics import silhouette_score
 
 scores = {}
 for i in range(2,7):
 
 print('Number of clusters: ' + str(i))
 
 # Apply your clustering algorithm of choice to the reduced data 
 clusterer = GaussianMixture(random_state=42, n_components=i)
 clusterer.fit(reduced_data)
 
 # Predict the cluster for each data point
 preds = clusterer.predict(reduced_data)
 
 # Find the cluster centers
 centers = clusterer.means_
 print('Cluster Center: ' + str(centers))
 
 # Predict the cluster for each transformed sample data point
 sample_preds = clusterer.predict(pca_samples)
 print('Sample predictions: ' + str(sample_preds))
 
 # Calculate the mean silhouette coefficient for the number of clusters chosen
 score = silhouette_score(reduced_data, preds)
 scores[i] = score
 print('Silhouette score is: ' + str(score), '
')
 
 print('Scores: ' + str(scores))

创建细分客户的无监督学习项目

 

创建细分客户的无监督学习项目

 

具有最佳Silhouette Score的群集数为2,得分为0.42。

集群可视化

一旦我们使用上面的评分指标为聚类算法选择了最佳聚类数,我们现在可以在下面的代码块中可视化结果。

# Apply your clustering algorithm of choice to the reduced data 
 clusterer = GaussianMixture(random_state=42, n_components=2)
 clusterer.fit(reduced_data)
 
 # Predict the cluster for each data point
 preds = clusterer.predict(reduced_data)
 
 # Find the cluster centers
 centers = clusterer.means_
 print('Cluster Center: ' + str(centers))
 
 # Predict the cluster for each transformed sample data point
 sample_preds = clusterer.predict(pca_samples)
 print('Sample predictions: ' + str(sample_preds))
 
 # Calculate the mean silhouette coefficient for the number of clusters chosen
 score = silhouette_score(reduced_data, preds)
 scores[i] = score
 print('Silhouette score is: ' + str(score), '
')

创建细分客户的无监督学习项目

 

# Display the results of the clustering from implementation
 vs.cluster_results(reduced_data, preds, centers, pca_samples)

创建细分客户的无监督学习项目

 

数据恢复

上面的可视化中存在的每个群集都有一个中心点。这些中心不是来自数据的特定数据点,而是各个集群中预测的所有数据点的平均值。

对于创建客户群的问题,群集的中心点对应于该段的平均客户。由于数据目前在尺寸上减小并按对数缩放,我们可以通过应用逆变换从这些数据点恢复代表性客户支出。

# Inverse transform the centers
 log_centers = pca.inverse_transform(centers)
 
 # Exponentiate the centers
 true_centers = np.exp(log_centers)
 
 # Display the true 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)

创建细分客户的无监督学习项目

 

  • 第0段可能代表一个新鲜食品市场,因为除冷冻和新鲜之外的每个特征均低于中位数。
  • 细分1可以代表超市,因为除了新鲜和冷冻之外的每个特征都高于中位数。

创建细分客户的无监督学习项目

 

下面的代码显示了每个样本点的预测属于哪个ckustr。

# Display the predictions
 for i, pred in enumerate(sample_preds):
 print("Sample point", i, "predicted to be in Cluster", pred)

创建细分客户的无监督学习项目

 

结论

  • 样品点0→超市和原始猜测是一个零售商。可以解释这种差异,因为群集的大小(相当大)
  • 样品点1→超市和原产地猜测是一样的。
  • 样品点2→新鲜食品市场和原始猜测是一个餐厅,考虑到特征的消费金额是合理的。

总结

批发经销商如何仅使用其估计的产品支出和客户细分数据来标记新客户?

可以使用监督学习算法,将估计的产品花费作为属性,将客户群作为目标变量,使其成为分类问题。由于客户群与产品支出之间没有明确的数学关系,KNN可能是一个很好的算法。

可视化底层分布

在该项目开始时,讨论了将从数据集中排除'Channel'和'Region'特征,以​​便在分析中强调客户产品类别。通过将'Channel'特征重新引入数据集,当考虑先前应用于原始数据集的相同PCA维数减少时,会出现一个有趣的结构。

下面的代码块显示了每个数据点的标签'HoReCa'(酒店/餐厅/咖啡厅)或'Retail'缩小的空间。

# Display the clustering results based on 'Channel' data vs.channel_results(reduced_data, preds, pca_samples)

创建细分客户的无监督学习项目

 

我们可以观察到,群集算法可以很好地将数据聚类到底层分布,因为群集0可以与零售商和群集1完美地关联到Ho / Re / Ca(酒店/餐厅/咖啡厅)

上一篇:使用树状图做层次聚类分析


下一篇:使用树状图做层次聚类分析