本文最后更新于:2020年7月12日 下午

层次聚类(Hierarchical Clustering)

1、聚合(agglomerative)或自下而上(bottom-up)聚类
2、分裂(divisive)或自上而下(top-down)聚类


AGNES(Agglomerative Nesting):凝聚层次聚类——自下而上
1、构造m个类,每个类包含一个样本
2、计算类与类之间的距离$d_{ij}$,记做矩阵$D=[d_{ij}]_{m \times m}$
3、合并间距最小的两个类
4、若达到聚类数k则退出
5、重新计算类之间的距离$d_{ij}$,重复3

计算类间距离
1、最小距离(单连接,single linkage)
2、最大距离(完全连接,complete linkage)
3、中心/均值距离(计算中心,两个类中心之间的距离)
4、平均距离

代码

import matplotlib.pyplot as plt
import matplotlib as mpl
import scripy.io
import numpy as np
from sklearn.cluster import AgglomerativeClustering
def loaddata():
    data = np.loadtxt('data/cluster_data.csv', delimiter=',')
    return data
X = loaddata()
# linkage可取值:
# -ward:方差
# -complete:最大距离
# -average:平均距离
# -single:最小距离
model = AgglomerativeClustering(n_clusters=3, affinity='euclidean',linkage='complete')
# AgglomerativeClustering(affinity='euclidean', compute_full_tree='auto',
#                        connectivity=None, distance_threshold=None,
#                        linkage='complete', memory=None, n_clusters=3)
model.fit(X)
pirnt('每个样本所属的簇:',model.labels_)
cm_dark = mpl.colors.ListedColormap(['g','r','b'])
plt.scatter(X[:,0],X[:,1], c=model.labels_, cmap=cm_dark, s=20)
plt.show()

输出:

每个样本所属的簇: [1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 1]

image-20200710211716375

密度聚类(Density-based clustering)

DBSCAN是一种著名的密度聚类方法,给定参数$(\varepsilon,Minpts)$
1、$\varepsilon$领域
2、核心对象(Core object)
3、密度直达(directly density-reachable)
4、密度可达(density-reachable)

若$minPts=3$,则$x_1,x_2$等都是核心对象
$x_2$由$x_1$密度直达,$x_3$由$x_1$密度可达

密度聚类算法过程:
1、首先设置$(\varepsilon,Minpts)$参数
2、确定核心对象,假设为$\Omega ={x^{(3)},x^{(5)},x^{(6)},x^{(8)},x^{(9)},x^{(13)},x^{(14)},x^{(18)} ,x^{(19)} ,x^{(24)} ,x^{(25)},x^{(28)},x^{(29)}}$
3、从$\Omega$中随机选取一个核心对象作为种子(假设为$x^{(8)}$),找出由它密度可达的所有样本,构成一个聚类簇,假设第一个聚类簇为$C_1 = \{ x^{(6)},x^{(7)},x^{(8)},x^{(10)},x^{(12)},x^{(18)},x^{(19)},x^{(20)},x^{(23)} \}$
4、从$\Omega$中去除$C_1$中包含的核心对象后,$\Omega ={x^{(3)},x^{(5)},x^{(9)},x^{(13)},x^{(14)},x^{(24)} ,x^{(25)},x^{(28)},x^{(29)}}$,重复3直至$\Omega$为空。

代码

import matplotlib.pyplot as plt
import matplotlib as mpl
import scripy.io
import numpy as np
from sklearn.cluster import DBSCAN
def loaddata():
    data = np.loadtxt('data/cluster_data.csv', delimiter=',')
    return data
X = loaddata()
model = DBSCAN(eps=0.5, min_samples=5, metric='euclidean')
model.fit(X)
print('每个样本所属的簇:', model.labels_)
cm_dark = mpl.colors.ListedColormap(['g','r','b','c'])
plt.scatter(X[:,0], X[:,1], c=model.labels_, cmap=cm_dark, s=20)

输出(-1类为离群点):

每个样本所属的簇: [ 0 -1  1  0  0  0  0  0  0  0  0  0  0  0  0  0 -1  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 -1
  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0 -1  0  0  0  0
  0  0  0  0  0  0  0  0  0  0  0  0 -1  0  0  0  0  0  0  0  0  0  0 -1
  0  0  0  0  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2
  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2
  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2
  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2
  2  2  2  2 -1  2 -1  2  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
  1 -1 -1  1  1  1  1  1  1  1  1  1  1  1  1 -1  1  1  1  1  1  1  1  1
  1  1  1  1  1  1  1  1  1  1  1  0]

image-20200710214909170

高斯混合模型(Gaussian Mixed Model)

高斯模型($x$为单变量):

均值为0,方差为1的概率密度函数:

高斯模型($X$为多变量,维度为$n$,$d=n$,$\sum$为$X$的协方差矩阵,大小为$n \times n$,$\overrightarrow{u}=(u_1,u_2,\ldots,u_n)$):

为什么要用高斯混合模型:

用单变量高斯模型无法拟合上图所示分布(两类数据的分布),用高斯混合模型可以较好拟合。

其中 $k$ 为类别数,$\pi_k$为第 $k$ 个高斯模型的权重,$N(x|u_k,\sum_k)$为第 $k$ 个高斯模型,$u_k,\sum_k$是第 $k$ 个高斯模型的参数(均值向量,协方差矩阵)。

高斯混合模型参数计算
第 $i$ 个样本属于第k个类别的概率:

交替更新,直至收敛稳定。

手工代码

一、生成数据进行实验

import numpy as np
import matplotlib.pyplot as plt
# 生成一些数据进行实验
# 1.生成均值为1.71,标准差为0.056的男生身高数据
np.random.seed(0)
mu_m = 1.71 # 期望
sigma_m = 0.056 # 标准差
num_m = 10000 # 数据个数为10000
random_data_m = np.random.normal(mu_m, sigma_m, num_m) #生成数据
y_m = np.ones(num_m) # 生成标签
# 2.生成均值为1.58,标准差为0.051的女生身高数据
np.random.seed(0)
mu_w = 1.58  #期望
sigma_w = 0.051  #标准差数据
num_w = 10000  #个数为10000
rand_data_w = np.random.normal(mu_w, sigma_w, num_w)#生成数据
y_w = np.zeros(num_m)#生成标签
# 3.把男生数据和女生数据合在一起
data = np.append(rand_data_m,rand_data_w)
data = data.reshape(-1,1)
y = np.append(y_m,y_w)
print(data)
print(y)

输出:

[[1.80878693]
 [1.7324088 ]
 [1.76480933]
 ...
 [1.60636048]
 [1.57832104]
 [1.64620368]]
[1. 1. 1. ... 0. 0. 0.]

二、高斯混合模型拟合数据

from scipy.stats import multivariate_normal

num_iter = 1000
n, d = data.shape
#初始化参数
mu1 = data.min(axis=0)
mu2 = data.max(axis=0)
sigma1 = np.identity(d)
sigma2 = np.identity(d)
pi = 0.5

for i in range(num_iter):
    #计算gamma
    norm1 = multivariate_normal(mu1, sigma1)
    norm2 = multivariate_normal(mu2, sigma2)
    tau1 = pi * norm1.pdf(data)
    # print('tau1', tau1)
    tau2 = (1 - pi) * norm2.pdf(data)
    gamma = tau1 / (tau1 + tau2)
    # print('gamma',gamma)

    #计算mu1
    mu1 = np.dot(gamma, data) / np.sum(gamma)
    # print("第%d iter: mul=%f" % (i, mu1))
    #计算mu2
    mu2 = np.dot(1-gamma, data) / np.sum(1 - gamma)
    #计算sigma1
    sigma1 = np.dot(gamma * (data-mu1).T, (data - mu1) ) / np.sum(gamma)
    # print("第%d iter: sigma1=%f" %(i,sigma1))
    #计算sigmal2
    sigma2 = np.dot((1-gamma) * (data-mu2).T, (data - mu2)) / np.sum(1 - gamma)
    #计算pi
    # print("第%d iter: sigma1=%f" %(i,sigma2))
    pi = np.sum(gamma)/n

print(u'类别概率:\t', pi)
print(u'均值:\t', mu1, mu2)
print(u'方差:\n', sigma1, '\n\n', sigma2, '\n')

输出:

类别概率:	 0.4873884639284559
均值:	 [1.57749047] [1.70726384]
方差:
 [[0.00244834]] 
 [[0.00315184]]

sklean实现高斯混合模型

一、生成实验数据

import numpy as np
import matplotlib.pyplot as plt
# 生成一些数据进行实验
# 1.生成均值为1.71,标准差为0.056的男生身高数据
np.random.seed(0)
mu_m = 1.71 # 期望
sigma_m = 0.056 # 标准差
num_m = 10000 # 数据个数为10000
random_data_m = np.random.normal(mu_m, sigma_m, num_m) #生成数据
y_m = np.ones(num_m) # 生成标签
# 2.生成均值为1.58,标准差为0.051的女生身高数据
np.random.seed(0)
mu_w = 1.58  #期望
sigma_w = 0.051  #标准差数据
num_w = 10000  #个数为10000
rand_data_w = np.random.normal(mu_w, sigma_w, num_w)#生成数据
y_w = np.zeros(num_m)#生成标签
# 3.把男生数据和女生数据合在一起
data = np.append(rand_data_m,rand_data_w)
data = data.reshape(-1,1)
y = np.append(y_m,y_w)
print(data)
print(y)

二、sklean实现高斯混合模型拟合数据

from sklearn.mixture import GaussianMixture
# n_components:类别数 max_iter:迭代次数
g = GaussianMixture(n_components=2, covariance_type='full', tol=1e-6, max_iter=1000)
g.fit(data)
print(u'类别概率:\t', g.weights_[0])
print(u'类别概率:\t', g.weights_[1])
print(u'均值:\n', g.means_, '\n')
print(u'方差:\n', g.covariances_, '\n')

输出:

类别概率:	 0.4996454306546242
类别概率:	 0.5003545693453813
均值:
 [[1.57895001]
 [1.70898537]] 

方差:
 [[[0.00251652]]
 [[0.00306363]]]

测试准确率:

from sklearn.metrics import accuracy_score
y_hat = g.predict(data)
print(accuracy_score(y,y_hat))

输出(重叠区域不好判断):

0.8891

对亚洲足球队进行聚类分析

代码
导入数据

import numpy as np
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler # 标准归一化
df = pd.read_csv('data/football_team_data.csv', index_col='国家')
print(df)

输出:

     2019国际排名  2018世界杯  2015亚洲杯
国家                                
中国            73       40        7
日本            60       15        5
韩国            61       19        2
伊朗            34       18        6
沙特            67       26       10
伊拉克           91       40        4
卡塔尔          101       40       13
阿联酋           81       40        6
乌兹别克斯坦        88       40        8
泰国           122       40       17
越南           102       50       17
阿曼            87       50       12
巴林           116       50       11
朝鲜           110       50       14
印尼           164       50       17
澳洲            40       30        1
叙利亚           76       40       17
约旦           118       50        9
科威特          160       50       15
巴勒斯坦          96       50       16

取出数字列

X = df.values
print(X)

输出:

array([[ 73,  40,   7],
       [ 60,  15,   5],
       [ 61,  19,   2],
       [ 34,  18,   6],
       [ 67,  26,  10],
       [ 91,  40,   4],
       [101,  40,  13],
       [ 81,  40,   6],
       [ 88,  40,   8],
       [122,  40,  17],
       [102,  50,  17],
       [ 87,  50,  12],
       [116,  50,  11],
       [110,  50,  14],
       [164,  50,  17],
       [ 40,  30,   1],
       [ 76,  40,  17],
       [118,  50,   9],
       [160,  50,  15],
       [ 96,  50,  16]], dtype=int64)
X = StandardScaler().fit_transform(X)
X

输出:

array([[-0.5842676 ,  0.05223517, -0.64677721],
       [-0.97679881, -2.12423024, -1.03291285],
       [-0.9466041 , -1.77599577, -1.61211632],
       [-1.76186121, -1.86305439, -0.83984503],
       [-0.76543585, -1.16658546, -0.06757374],
       [-0.04076286,  0.05223517, -1.22598067],
       [ 0.26118422,  0.05223517,  0.51162973],
       [-0.34270994,  0.05223517, -0.83984503],
       [-0.13134698,  0.05223517, -0.45370938],
       [ 0.89527309,  0.05223517,  1.28390102],
       [ 0.29137893,  0.92282133,  1.28390102],
       [-0.16154169,  0.92282133,  0.31856191],
       [ 0.71410485,  0.92282133,  0.12549408],
       [ 0.5329366 ,  0.92282133,  0.70469755],
       [ 2.16345083,  0.92282133,  1.28390102],
       [-1.58069297, -0.81835099, -1.80518414],
       [-0.49368348,  0.05223517,  1.28390102],
       [ 0.77449426,  0.92282133, -0.26064156],
       [ 2.042672  ,  0.92282133,  0.89776537],
       [ 0.11021068,  0.92282133,  1.0908332 ]])

使用KMeans聚合数据

model = KMeans(n_clusters=3, max_iter=10)
model.fit(X)
#KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=10,
#       n_clusters=3, n_init=10, n_jobs=None, precompute_distances='auto',
#       random_state=None, tol=0.0001, verbose=0)
df["聚类结果"] = model.labels_
print(df)

输出:

 2019国际排名  2018世界杯  2015亚洲杯  聚类结果
国家                                      
中国            73       40        7     2
日本            60       15        5     0
韩国            61       19        2     0
伊朗            34       18        6     0
沙特            67       26       10     0
伊拉克           91       40        4     2
卡塔尔          101       40       13     1
阿联酋           81       40        6     2
乌兹别克斯坦        88       40        8     2
泰国           122       40       17     1
越南           102       50       17     1
阿曼            87       50       12     1
巴林           116       50       11     1
朝鲜           110       50       14     1
印尼           164       50       17     1
澳洲            40       30        1     0
叙利亚           76       40       17     1
约旦           118       50        9     1
科威特          160       50       15     1
巴勒斯坦          96       50       16     1

根据结果看出,这些国家分为了三类,结合数据进行分析,亚洲足球队强弱顺序依次是0,2,1.


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

机器学习-主成分分析 上一篇
leetcode309 下一篇