前言
在上篇《 Python 机器学习实战 —— 无监督学习(上)》介绍了数据集变换中最常见的 PCA 主成分分析、NMF 非负矩阵分解等无监督模型,举例说明使用使用非监督模型对多维度特征数据集进行降维的意义及实用方法。对 MDS 多维标度法、LLE 局部线性嵌入法、Isomap 保距映射法、t-SNE 分布邻域嵌入算法等 ML 流形学习模型的基础使用方法进行讲解。
本文将对聚类算法进行讲解,聚类算法就是将数据集划分成组的任务,这些组叫成簇,同一个簇内的数据点特征非常相似,不同簇内的数据点特征区别很大,这点与监督学习中的分类算法很类似,运行完成后系统会为同一簇内的数据分配同一个数字,不同簇的数字都不一样。常见的聚类模型有 KMeans、DBSCAN、GMM 、Agglomerative 等,下面将一一介绍。
目录
四、KMeans 均值聚类
4.1 KMeans 的基本原理
KMeans 均值聚类是最简单最常用的聚类算法之一,它会尝试找到代表数据区域的簇中心,并保存在 cluster_centers 属性中。再把每个数据点分配给最接近的簇中心,并把每个簇中心设置为所分配数据点的平均值。当簇中心的值根据模型运算设置不再发生变化时,算法结束。
构造函数
1 class KMeans(TransformerMixin, ClusterMixin, BaseEstimator):
2 @_deprecate_positional_args
3 def __init__(self, n_clusters=8, *, init='k-means++', n_init=10,
4 max_iter=300, tol=1e-4, precompute_distances='deprecated',
5 verbose=0, random_state=None, copy_x=True,
6 n_jobs='deprecated', algorithm='auto'):
- n_clusters:int 类型,默认为8,代表生成簇中心数目
- init:选择 {’k-means++’, ‘random ’} 之一, 或者传递一个ndarray向量,代表初始化方式,默认值为 ‘k-means++’。‘k-means++’ 用一种特殊的方法选定初始聚类中发,可加速迭代过程的收敛;‘random’ 随机从训练数据中选取初始质心。如果传递的是一个ndarray,则应该形如 (n_clusters, n_features) 并给出初始质心。
- n_init:int 类型,默认值为10,用不同的聚类中心初始化值运行算法的次数,最终解是在 inertia 意义下选出的最优结果。
- max_iter: int 类型,默认值为 300 ,代表模型优化的最大迭代数。
- tol:float类型,默认值为 1e-4 ,代表求解方法精度
- precompute_distances: 可选值 {‘auto’,True,False }, 代表预计算距离,计算速度更快但占用更多内存。‘auto’:如果 样本数乘以聚类数大于 12million 的话则不预计算距离;True:总是预先计算距离;False:永远不预先计算距离。’ deprecated ‘ 旧版本使用,新版已丢弃。
- verbose: int 类型,默认为 0,详细程度。
- random_state:默认值为None 随机数种子,推荐设置一个任意整数,同一个随机值,模型可以复现
- copy_x: bool 类型,默认值True。当 precomputing distances 生效时,将数据中心化会得到更准确的结果。如果把此参数值设为True,则原始数据不会被改变。如果是False,则会直接在原始数据上做修改并在函数返回值时将其还原。但是在计算过程中由于有对数据均值的加减运算,数据返回后,原始数据和计算前可能会有细小差别。
- n_jobs:int 类型,默认为 None, CPU 并行数。内部原理是同时进行n_init指定次数的计算时,若值为 -1,则用所有的CPU进行运算。若值为1,则不进行并行运算。若值小于-1,则用到的CPU数为(n_cpus + 1 + n_jobs)。因此如果 n_jobs值为-2,则用到的CPU数为总CPU数减1。’ deprecated ‘ 旧版本使用,新版已丢弃。
- algorithm: str 类型,{ auto,full,elkan } 三选一。full就是一般意义上的K-Means算法; elkan是使用的elkan K-Means算法; auto则会根据数据值是否是稀疏的(稀疏一般指是有大量缺失值),来决定如何选择full 和 elkan。如果数据是稠密的,就选择elkan K-means,否则就使用普通的Kmeans算法。
常用参数
- cluster_centers_: 代表簇中心 ,训练后簇中心都会被保存在此属性中
- labels_:返回数据点所属的簇标志,与 predict 方法返回值相同
4.2 KMeans 的应用场景
下面先用简单的 make_blobs 数据集了解 KMeans 的基础使用方式,KMeans 模型在分别把簇中心设置为 3 和 5,观察一下数据的变化。注意测试数据集中默认为 3 类,然而 KMeans 是无监督学习模型,不会使用数据集给出的结果进行分类,而是按照 n_clusters 的设置进行分类。这是 KMeans 模型的优点也可以说是缺点,虽然没有受数据集类型的限制,然而在运行前必须先设置簇的数量。实事上在现实场景中,很多数据事先是无法确定簇数量的。
1 def kmean_test(n):
2 #生成数据集
3 X, y = datasets.make_blobs(n_samples=100, n_features=2, random_state=1)
4 #使用KMeans模型,3个簇中心
5 kmean=KMeans(n_clusters=n)
6 model=kmean.fit_predict(X)
7 #显示运算结果
8 plt.scatter(X[:,0],X[:,1],s=50,c=model,marker='^')
9 plt.xlabel('feature0')
10 plt.ylabel('feature1')
11 #显示簇中心
12 center=kmean.cluster_centers_
13 plt.scatter(center[:,0],center[:,1],s=200,color='red',marker='.')
14 #显示簇边界
15 radii=[cdist(X[model==i],[center]).max() for i,center in enumerate(center)]
16 for c,r in zip(center,radii):
17 axes.add_patch(plt.Circle(c,r,alpha=0.3,zorder=1))
18 plt.show()
19
20 if __name__=='__main__':
21 kmean_test(3)
22 kmean_test(5)
3 簇中心运行结果
5 簇中心运行结果
下面例子尝试利用 digits 数据集,通过 KMeans 训练,再查看一下分辨手写数字的准确率,可见单凭 KMeans 模型已经可以分辨手写数字的准确率到达将近80% 。
1 def kmean_test():
2 # 输入测试数据
3 digits=datasets.load_digits()
4 #使用KMeans模型,10个簇中心
5 kmean=KMeans(10)
6 #训练数据
7 model=kmean.fit_predict(digits.data)
8 #计算匹配度
9 labels=np.zeros_like(model)
10 for i in range(10):
11 mask=(model==i)
12 labels[mask]=mode(digits.target[mask])[0]
13 #计算准确率
14 acc=accuracy_score(digits.target,labels)
15 print(acc)
运行结果
还记得在上一篇文章《 Python 机器学习实战 —— 无监督学习(上)》介绍 ML 流形学习中曾经提过, t-SNE 模型是一个非线性嵌入算法,特别擅长保留簇中的数据点。在此尝试把 KMeans 与 t-SNE 相结合一起使用,有意想不到的效果。
运行后可以发现末经过调试的算法,准确率已经可以达到 94% 以上。可见,只要适当地运用无监督学习,也能够精准地实现数据的分类。
1 def kmean_test():
2 # 输入测试数据
3 digits=datasets.load_digits()
4 #使用t-SNE 模型进行训练
5 tsne=TSNE()
6 model0=tsne.fit_transform(digits.data)
7 #使用KMeans模型进行训练
8 kmean=KMeans(10)
9 model1=kmean.fit_predict(model0)
10 #计算匹配度
11 labels=np.zeros_like(model1)
12 for i in range(10):
13 mask=(model1==i)
14 labels[mask]=mode(digits.target[mask])[0]
15 #计算准确率
16 acc=accuracy_score(digits.target,labels)
17 print(acc)
运行结果
4.3 通过核转换解决 KMeans 的非线性数据问题
虽然 KMeans 模型适用的场景很多,然而 KMeans 也有一个问题就是它只能确定线性聚类边界,当簇中心点呈现非线性的复杂形状时,此算法是不起作用的。例如以 make_moons 数据集为例,把 noise 参数设置为 0.04,用 KMeans 模型进行测试。分别把 n_clusters 设置为 2 和 10,运行一下程序,可见单凭 KMeans 模型是无法分开复杂形状的非线性数据的。
1 def kmean_test(n):
2 #生成数据集
3 X, y = datasets.make_moons(n_samples=300, noise=0.04,random_state=1)
4 #使用KMeans模型,n个簇中心
5 kmean=KMeans(n_clusters=n)
6 model=kmean.fit_predict(X)
7 #显示运算结果
8 plt.scatter(X[:,0],X[:,1],s=50,c=model,marker='^')
9 plt.xlabel('feature0')
10 plt.ylabel('feature1')
11 #显示簇中心
12 center=kmean.cluster_centers_
13 plt.scatter(center[:,0],center[:,1],s=200,color='red',marker='.')
14 plt.show()
15
16 if __name__=='__main__':
17 kmean_test(2)
18 kmean_test(10)
n_clusters 为 2 时
n_clusters 为 10 时
此时,大家可能会想起在上一章《 Python 机器学习实战 —— 监督学习(下)》中提到的核函数技巧,类似地 skLearn 也提供了 SpectralClustering 评估器来完成 KMeans 非线性边界的问题。
构造函数
1 class SpectralClustering(ClusterMixin, BaseEstimator):
2 @_deprecate_positional_args
3 def __init__(self, n_clusters=8, *, eigen_solver=None, n_components=None,
4 random_state=None, n_init=10, gamma=1., affinity='rbf',
5 n_neighbors=10, eigen_tol=0.0, assign_labels='kmeans',
6 degree=3, coef0=1, kernel_params=None, n_jobs=None,
7 verbose=False):
- n_clusters:int 类型,默认为 8,代表生成簇中心数目
- eigen_solver: {'arpack', 'lobpcg', 'amg','None'} 之一,默认为 None ,代表特征值求解的策略 。
- n_components:int, 默认值为 None。int 时则是直接指定特征维度数目,此时 n_components是一个大于等于 1 的整数。当使用默认值,即不输入n_components,此时n_components=min(样本数,特征数)。
- random_state:int 类型,默认值为None, 随机数种子,推荐设置一个任意整数,同一个随机值,模型可以复现。
- n_init: int 类型,默认为值 10,当 assign_labels 为 ’kmeans' 时,指定聚类中心初始化值运行算法的次数。
- gamma:float 类型,默认值为1.0,指高斯核函数的中心值。如果用k近邻法,则此参数无用。
- affinity:str 类型 {’rbf','nearest_neighbors','precomputed' , 'precomputed_nearest_neighbors'} 之一 或 callable,默认值为 ‘rbf' ,用于设定构造矩阵的方法。 ‘ rbf ' 指使用径向基函数构造矩阵(RBF)高斯内核 ; 'nearest_neighbors' 指使用 k近邻算法来构造内核; 'precomputed' 是将``X``解释为一个预先计算的亲和力矩阵,较大值表示实例之间的相似性更大; 'precomputed_nearest_neighbors': 将``X``解释为稀疏图,从每个实例的``n_neighbors``的最近邻居构造一个二进制亲和矩阵。
- n_neighbors:int 类型,默认值为10。当 affinity 设定为 ‘nearest_neighbors’ 使用 k 近邻内核时的邻居数量,当使用 ‘rbf’ 高斯内核时无效。
- eigen_tol:float 类型,默认值为 0.0。 当`eigen_solver='arpack' 时候,设定拉普拉斯矩阵特征分解的停止判断依据。
- assign_labels:str 类型 {‘kmeans’, ‘discretize’} 之一,默认值为 ‘kmeans',用于指定分配标签的策略 。’kmeans‘ 是较常用的策略,初始化时灵敏性强。 ‘discretize’ 是随机初始化的另一种策略,灵敏性较弱。
- degree: int 类型,默认值为 3,当 eigen_solver 为 'arpack' 时,设定拉普拉斯矩阵特征分解的停止判据依据。
- coef0: float参数 默认为1.0,核函数中的独立项,控制模型受高阶多项式的影响程度, 只有对内核为 ‘poly’和‘sigmod’ 的核函数有用
- kernel_params: dict 类型 或者 str 类型,默认值为 None ,内核的参数。
- n_job:int 类型,默认值为 None 。当 affinity 为 ‘nearest_neighbors’ 和 ‘precomputed_nearest_neighbors’ 指定 CPU 并行数, 为 -1 指运行所有 CPU, 为 None 时只运行1个CPU。
- verbose: int 类型,默认为 0,详细程度。
尝试 SpectralClustering 评估器来完成非线性数据的分类问题,把 affinity 设置 'nearest_neighbors‘ 使用 k 近邻算法内核,assign_labels 设置为 'kmeans' 策略。从运行结果可以看到,SpectralClustering 使用 k 近邻内核完美地实现了数据边界的分离。
1 def kmean_test():
2 #生成数据集
3 X, y = datasets.make_moons(n_samples=300, noise=0.04,random_state=1)
4 #使用SpectralClustering评估器
5 spectral=SpectralClustering(n_clusters=2,affinity='nearest_neighbors',assign_labels='kmeans')
6 model=spectral.fit_predict(X)
7 #显示运算结果
8 plt.scatter(X[:,0],X[:,1],s=50,c=model,marker='^')
9 plt.xlabel('feature0')
10 plt.ylabel('feature1')
11 plt.show()
运行结果
五、GMM 高斯混合模型
5.1 GMM 的基本原理
由于 KMeans 模型是围绕着簇中心而计算的,造成当中存在短板,数据点分配是依赖簇中心到数据点的平均值的,因此簇的模型必须是圆形的(在上节的例子中可以看出)。当簇中心比较接近时,数据点分配就会发生重叠而引起混乱。
为解决 KMeans 模型的问题,GMM 高斯混合模型应运而生,它会改 KMeans 模型簇边界的计算方式,把圆形改成椭圆形,让数据边界更明显。
构造函数
1 class GaussianMixture(BaseMixture):
2 @_deprecate_positional_args
3 def __init__(self, n_components=1, *, covariance_type='full', tol=1e-3,
4 reg_covar=1e-6, max_iter=100, n_init=1, init_params='kmeans',
5 weights_init=None, means_init=None, precisions_init=None,
6 random_state=None, warm_start=False,
7 verbose=0, verbose_interval=10):
- n_components: int 类型,默认为1,设定混合高斯模型个数
- covariance_type: str 类型 {‘full’,‘tied’, ‘diag’, ‘spherical ’} 之一,选择四种协方差类型,默认值为 ‘full’ 完全协方差矩阵。full: 对应完全协方差矩阵(元素都不为零), 每个分量都有各自的一般协方差矩阵 ; tied: 相同的完全协方差矩阵(HMM会用到)所有的分量都共享相同的一般协方差矩阵; ’ diag': 对角协方差矩阵(非对角为零,对角不为零)每个分量都有各自的对角协方差矩阵 ; ‘spherical': 球面协方差矩阵(非对角为零,对角完全相同,球面特性),每个组件都有它自己的单一方差。
- tol:float 类型,默认为1e-3,EM迭代停止阈值。
- reg_covar: float 类型,默认为 1e-6,协方差对角非负正则化,保证协方差矩阵均为正。
- max_iter: int 类型,默认值 100,最大迭代次数。
- n_init: int 类型,默认为1,初始化次数,指定聚类中心初始化值运行算法的次数。
- init_params: str 类型,{‘kmeans’, ‘random’} 之一,默认值 kmeans ,初始化参数实现方式
- weights_init: array 类型 (n_components, ) ,默认为 None ,用户提供的初始权重,若为空时,则使用 init _params 方法进行初始化。
- means_init: array 类型 (n_components, n_features), 默认为 None ,用户提供的初始权重,若为空时,则使用 init _params 方法进行初始化。
- precisions_init: array 类型 ,默认为 None ,用户提供的初始权重,若为空时,则使用 init _params 方法进行初始化。当 covariance_type 为 full 则为 (n_components, n_features, n_features) 格式; 'diag' 时格式为 (n_components, n_features) ; 'tied' 时格式为 (n_features, n_features); 'spherical' 时格式为 (n_components, )
- random_state :int 类型,默认值为None, 随机数种子,推荐设置一个任意整数,同一个随机值,模型可以复现。
- warm_start : bool 类型,默认为 False,若为True,则fit()调用会以上一次fit()的结果作为初始化参数,适合相同问题多次fit的情况,能加速收敛。
- verbose :int 类型,默认为0,使能迭代信息显示,可以为1或者大于1(显示的信息不同)
- verbose_interval :int 类型,默认10次,与 verbose 挂钩,若使能迭代信息显示,设置多少次迭代后显示信息。
参数说明
- weights_:array, 混合条件的权重
- means_:array, 均值
- covariances_: array 协方差阵
- converged_: bool 是否收敛
方法说明
- predict_proba(X):返回 [n_samples,n_clusters],预测给定的数据点属于某个簇的概率
- predict_proba() :预测所有数据点属于某个簇的概率
- score_samples(X):计算某个数据点样本的属于某个簇的加权对数概率
继续使用 make_blobs 数据集进行测试,适当修改数据点之间的间距,使用 GMM 模型进行计算,将为每个数据点找到对应每个簇的概率作为权重,然后更新每个簇的位置,将其标准化,最后把所有数据点的权重来确定形状。如此一来,数据点跟预期一样更为集中,数据边界会根据数据点的分布形成椭圆形。
1 def draw_ellipse(position, covariance, ax=None, **kwargs):
2 # 计算图形边界
3 if covariance.shape == (2, 2):
4 U, s, Vt = np.linalg.svd(covariance)
5 angle = np.degrees(np.arctan2(U[1, 0], U[0, 0]))
6 width, height = 2 * np.sqrt(s)
7 else:
8 angle = 0
9 width, height = 2 * np.sqrt(covariance)
10 # 画图
11 for nsig in range(1, 4):
12 ax.add_patch(Ellipse(position, nsig * width, nsig * height,
13 angle, **kwargs))
14
15 def gmm_test():
16 #测试数据集
17 X, y = datasets.make_blobs(n_samples=100,centers=4,n_features=2,random_state=1)
18 #修改数据点间距
19 rng=np.random.RandomState(12)
20 X1=np.dot(X,rng.randn(2,2))
21 fig,axes=plt.subplots(1,1)
22 #使用GMM模型
23 gmm=GaussianMixture(n_components=4,random_state=28)
24 model=gmm.fit_predict(X1)
25 #显示运算结果
26 plt.scatter(X1[:,0],X1[:,1],s=50,c=model,marker='^')
27 plt.xlabel('feature0')
28 plt.ylabel('feature1')
29 #显示簇边界
30 n=0.2/gmm.weights_.max()
31 for mean,covar,weight in zip(gmm.means_,gmm.covariances_,gmm.weights_):
32 draw_ellipse(mean,covar,ax=axes,alpha=weight*n)
33 plt.show()
34
35 if __name__=='__main__':
36 gmm_test()
运行结果
六、Agglomerative 凝聚聚类
Agglomerative 凝聚聚类算法首先会声明每个点都是一个簇,然后合并两个最相似的簇,直到满足设定条件准则为止。这个准则可以通过 linkage 参数确定,linkage 为 { 'ward', 'complete', 'average', 'single' } 之一,下面将会详细说明。
观察下面系统自带的合并过程,当运行到第4步后,两点最相近的簇完成合并,到第5步一个两点簇增加到三个点,当三个点的簇完成合并后,到第8步,五点的簇开始合并,如此类推,到最后完成合并任务。
构造函数
1 class AgglomerativeClustering(ClusterMixin, BaseEstimator):
2 @_deprecate_positional_args
3 def __init__(self, n_clusters=2, *, affinity="euclidean",
4 memory=None,
5 connectivity=None, compute_full_tree='auto',
6 linkage='ward', distance_threshold=None,
7 compute_distances=False):
- n_clusters:int 类型,默认值为2,指定最终分类簇的数量
- affinity:str 类型,{ ’euclidean’,’l1’,’l2’,’mantattan’,’cosine’,’precomputed’ }之一,默认值为 ’euclidean’ ,作用是选择一个计算距离的可调用对象。当 linkage=’ward’,affinity 只能为’euclidean’
- memory:str 类型,默认值为 None, 用于缓存计算结果的输出,默认不作任何缓存。如果设定字符串路径,则它会缓存到对应的路径。
- connectivity:array-like 或 callable 类型,默认为 None,用于指定连接矩阵,临近的数据将使用相同的结构。
- compute_full_tree:bool 类型,默认值为 auto,当训练了 n_clusters后,训练过程就会停止,但是如果 compute_full_tree=True,则会继续训练从而生成一颗完整的树。当 distance_threshold 不为 None 时,则 compute_full_tree 必须为是 True。
- linkage:str 类型, { 'ward', 'complete', 'average', 'single' } 之一,默认值为 'ward' 一个字符串,用于指定链接算法。‘ward’:单链接 single-linkage,使所有簇中的方差 dmindmin 增加最小的簇合并; ‘complete’:全链接 complete-linkage 算法,使簇中点之间的最大距离 dmaxdmax 最小的两个簇合并 ; 'average’:均连接 average-linkage 算法,使簇中所有点之间平均距离 davgdavg 最小的两个簇合并。’single' :新增于 0.20 版,使簇中所有点距离最小的两个簇合并。
- distance_threshold:float 类型,默认值为 None,链接距离阈值超过此设置,集群将不会合并。当使用此设置时,‘n_clusters’ 必须是 None 和 'compute_full_tree' 必须是 True 。
- compute_distances:bool 类型,默认值为 False,当不使用 distance_threshold 时,计算簇之间的距离。此功能可以用于使树状图可视化,但此计算将消耗计算机的内存。
使用 make_blobs 数据集作测试,把 n_cluster3 设置为 3,由于 AgglomerativeClustering 没有 predict 方法,可以直接使用 fit_predict 方法进行计算。完成计算后,可以利用 SciPy 的 dendrogram 函数绘制树状图,以观察簇的构建过程。
1 def agglomerative_test():
2 # 测试数据集
3 X,y=make_blobs(random_state=1)
4 # 使用 AgglomerativeClustering模型
5 agglomerative=AgglomerativeClustering(n_clusters=3)
6 # 开始运算
7 model=agglomerative.fit_predict(X)
8 # 显示簇合并结果
9 fig, axes = plt.subplots(1, 2, figsize=(10,5))
10 ax0=axes[0]
11 ax0.scatter(X[:,0],X[:,1],s=50,c=model,marker='^')
12 # 显示树状图
13 ax1=axes[1]
14 shc.dendrogram(shc.ward(X[::5]))
15 plt.show()
运行结果
七、DBSCAN 密度聚类
DBSCAN 密度聚类是最常用的模型之一,一般用于分析形状比较复杂的簇,还可找到不属于任何簇的数据点。上面介绍到的 KMeans 模型、SpectralClustering 评估器、Agglomerative 模型都需要在建立模型前通过 n_clusters 参数预先设置簇的个数,然而在复杂的数据中,单凭简单的数据分析去正确评估簇数据是很困难的。 DBSCAN 的优点在于它不需要预先设置簇的个数,而是通过特征空间的数据点密度来区分簇。DBSCAN 最常用到的参数是 eps 和 min_samples,eps 是用于设定距离,DBSCAN 将彼此距离小于 eps 设置值的核心样本放在同一个簇。min_samples 则用于设置同一簇内数据点的最少数量,如果数据点数量少于此设置则把这此点默认为噪点 noise,数据点数量大于等于此数值时则默认一个簇。
1 class DBSCAN(ClusterMixin, BaseEstimator):
2 @_deprecate_positional_args
3 def __init__(self, eps=0.5, *, min_samples=5, metric='euclidean',
4 metric_params=None, algorithm='auto', leaf_size=30, p=None,
5 n_jobs=None):
- esp:float 类型,默认值为 0.5,用于设定距离,DBSCAN 将彼此距离小于 eps 设置值的核心样本放在同一个簇。
- min_samples: int 类型,默认值为5,用于设置同一簇内数据点的最少数量,如果数据点数量少于此设置则把这此点默认为噪点 noise,数据点数量大于等于此数值时则默认一个簇。
- metric:string 或 callable 类型,['cityblock', 'cosine', 'euclidean', 'l1', 'l2', 'manhattan'] 之一,默认值为 ‘euclidean’, 用于定义计算数据点之间的距离时使用的度量。使用欧式距离 “euclidean”; 使用曼哈顿距离 “manhattan”;
- metric_params: dict 类型,默认值为 None,根据 metric 选择填入相关参数。
- algorithm:str 类型,{'auto', 'ball_tree', 'kd_tree', 'brute'} 之一,默认值为 auto,定义计算近邻数据点的方法。 ‘auto’:会在上面三种算法中做权衡,选择一个拟合最好的最优算法。‘ball_tree’ 球面树搜索,数据点比较分散时可试用 ball_tree; kd_tree: kd树搜索,数据点分布比较均匀时效率较高; ‘brute’:暴力搜索;
- leaf_size:int 类型,默认为30,定义停止建立子树的叶子节点数量的阈值。 最近邻搜索算法参数,为使用KD树或者球树时, 这个值越小,则生成的KD树或者球树就越大,层数越深,建树时间越长,反之,则生成的KD树或者球树会小,层数较浅,建树时间较短。
- p: 最近邻距离度量参数。只用于闵可夫斯基距离和带权重闵可夫斯基距离中p值的选择,p=1为曼哈顿距离, p=2为欧式距离。如果使用默认的欧式距离不需要管这个参数。
- n_jobs:CPU 并行数,默认为None,代表1。若设置为 -1 的时候,则用所有 CPU 的内核运行程序。
使用 make_blobs 数据集,分别把 eps 设置为 0.5,1.0,1.5,观察一下测试结果,紫蓝色的是噪点。随着 eps 的增大,噪点越来越少,测试结果也越来越接近真实数据。然而 eps 对结果的影响也很大,如果 eps 设置得过大,可能会导致所有数据点形成同一个簇,如果 eps 太小,可能会导致所有数据点都是噪点。
1 def dbscan_test(eps,title):
2 # 测试数据集
3 X,y=datasets.make_blobs(random_state=1)
4 # 使用DBSCAN,输入eps参数
5 dbscan=DBSCAN(eps=eps)
6 model=dbscan.fit_predict(X)
7 # 显示测试后结果
8 plt.scatter(X[:,0],X[:,1],c=model,s=50,marker='^')
9 plt.xlabel('feature0')
10 plt.ylabel('feature1')
11 plt.title(title)
12 plt.show()
13
14 if __name__=='__main__':
15 dbscan_test(0.5,'EPS:0.5 ')
16 dbscan_test(1,'EPS 1')
17 dbscan_test(1.5,'EPS 1.5')
运行结果
eps = 0.5
eps = 1.0
eps = 1.5
使用相同数据集,把 eps 设置为1.0,尝试修改 min_samples 参数,看看参数对模型的影响,紫蓝色为噪点。随着 min_samples 的减少,测试结果也越来越接近真实数据。
1 def dbscan_test(min,title):
2 # 测试数据集
3 X,y=datasets.make_blobs(random_state=1)
4 # 使用DBSCAN,输入eps,min_samples参数
5 dbscan=DBSCAN(eps=1.0,min_samples=min)
6 model=dbscan.fit_predict(X)
7 # 显示测试后结果
8 plt.scatter(X[:,0],X[:,1],c=model,s=50,marker='^')
9 plt.xlabel('feature0')
10 plt.ylabel('feature1')
11 plt.title(title)
12 plt.show()
13
14 if __name__=='__main__':
15 dbscan_test(20,'MIN SAMPLES 20')
16 dbscan_test(10,'MIN SAMPLES 10')
17 dbscan_test(5,'MIN SAMPLES 5')
运行结果
min_samples = 20
min_samples = 10
min_samples = 5
第四节介绍 KMeans 模型时曾经介绍到 KMeans 模型是无法分开复杂形状的非线性数据的,只能用到 SpectralClustering 评估器来解决此类问题。然而 DBSCAN 模型的密度分布算法侧可以轻松地解决此类问题,同样使用 make_moons 数据集,使用 DBSCAN 模型时把 eps 设置为0.4,min_samples 设置为30。通过测试结果可以看出,只需要利用 DBSCAN 模型最常用的参数配置就可以解决复杂的非线性数据问题。
1 def dbscan_test(title):
2 # 测试数据集
3 X, y = datasets.make_moons(n_samples=300, noise=0.04,random_state=1)
4 # 使用DBSCAN,输入eps,min_samples参数
5 dbscan=DBSCAN(eps=0.4,min_samples=30)
6 model=dbscan.fit_predict(X)
7 # 显示测试后结果
8 plt.scatter(X[:,0],X[:,1],c=model,s=50,marker='^')
9 plt.xlabel('feature0')
10 plt.ylabel('feature1')
11 plt.title(title)
12 plt.show()
13
14 if __name__=='__main__':
15 dbscan_test('DBSCAN')
运行结果
在前一章《 Python 机器学习实战 —— 无监督学习(上)》中介绍到的 PCA 模型, 下面这个例子就是先利用PCA模型对数据特征进行降维处理,然后再使用 DBSCAN 找出噪点,观察一下噪点与簇数据的区别出自哪里。使用 fetch_lfw_person 数据集,利用 PCA 模型把主要成分保持在 95%,完成训练后再使用 DBSCAN 模型,把 eps 设置为 23,min_samples 设置 3 ,再进行训练。
最后把噪点通过主要成分还原数据进行显示,从运行结果可以看到,噪点主要是因为人物有带帽子,眯着眼睛,张开嘴巴,用手捂嘴等动作造成的。 通过噪点分析,能找出很多有趣的与别不同的特征。
1 def dbscan_test():
2 # 测试数据集
3 person = datasets.fetch_lfw_people()
4 # 使用PCA模型把特征降至60
5 pca=PCA(0.95,whiten=True,random_state=1)
6 pca_model=pca.fit_transform(person.data)
7 # 使用DBSCAN,输入eps,min_samples参数
8 dbscan=DBSCAN(eps=23,min_samples=3)
9 model=dbscan.fit_predict(pca_model)
10 # 显示测试后结果
11 fig,axes=plt.subplots(5, 5, figsize=(25,25))
12 # 获取噪点的特征成分图
13 noise=pca_model[model==-1]
14 # 输出噪点数量
15 print(str.format('noise len is {0}'.format(len(noise))))
16 for componemt,ax in zip(noise,axes.ravel()):
17 # 获取噪点提取成分后还原图
18 image=pca.inverse_transform(componemt)
19 ax.imshow(image.reshape(62, 47), cmap = 'viridis')
20 plt.show()
运行结果
本章总结
本单主要介绍了 KMeans、GMM 、Agglomerative 、DBSCAN 等模型的使用,KMeans 是最常用最简单的模型,它尝试根据 n_clusters 设置找到代表数据区域的簇中心。而 GMM 可以看成是升级版的 KMeans ,它会改 KMeans 模型簇边界的计算方式,把圆形改成椭圆形,让数据边界更明显。Agglomerative 则更类似于树模型,使用近邻合并的模型,把相近的数据点合并为簇。DBSCAN 是更智能化的模型,通过数据点的聚集程度判断簇中心,在没有设置固定 n_clusters 的情况下分配出符合实际情况的簇。
对机器学习的原理及应用场景介绍到这里结束,后面将开始讲述深度学习的相关内容,敬请留意。
希望本篇文章对相关的开发人员有所帮助,由于时间仓促,错漏之处敬请点评。