小白一个,才疏学浅。写的不好大家见谅。
Jaccard相似系数。(Jarrcard Similarity Coefficient)用于比较有限样本集之间的相似性和差异性。Jarrcard系数值越大,样本相似度越高。
余弦距离,余弦相似度
余弦值的范围在[-1, 1]之间,值越接近于1,代表两个向量的方向越接近
越趋近于-1, 他们的方向越相反; 接近于0, 表示两个向量几乎于正交
最常见的应用就是计算文本相似度。将两个文本根据他们的词,建立两个向量,
计算这两个向量的余弦值,就可以知道两个文本在统计学方法中他们的相似度情况。
本质上,N个样本,映射到K个簇中
每个簇至少有一个样本,一般情况下,一个样本只属于一个簇(也有一个样样本属于多个簇的
最基本:
先给定一个初始划分,迭代改变样本和簇的隶属关系,每次都比前一次好。
聚类是一种无监督的机器学习任务,它可以自动将数据划分成类cluster。因此聚类分组不需要提前被告知所划分的组应该是什么样子的。因为我们甚至可能都不知道我们再寻找什么,所以聚类是用于知识发现而不是预测。
聚类原则是一个组内的记录,彼此必须非常相似,而与该组之外的记录截然不同。所有聚类做的就是遍历所有,数据然后找到这些相似性。
选择K个初始的簇中心,随机的(拍脑袋给的),或者先验知识给的某一个样本和某一个聚类中心的距离,计算所属聚类的样本均值
代码实现:
"""
Date: 2019--11 16:24
User: yz
Email: [email protected]
Desc:
"""
import numpy as np
import matplotlib.pyplot as plt
import sklearn.datasets as ds
import matplotlib.colors
from sklearn.cluster import KMeans
def expand(a, b):
"""
为了扩展x,y轴的长度
"""
d = (b - a) * 0.1
return a-d, b+d
if __name__ == '__main__':
# 创建400个样本
N = 400
# 准备分出4个类别
centers = 4
# 创建聚类的数据(按照4个正太分布创建点)【想看看方差一样的,数据量一样的,分类效果好不好】
data, y = ds.make_blobs(N, n_features=2, centers=centers, random_state=2)
print(data)
# 方差和上面不一样,方差越大,数据集越分散;方差越小,数据集越密集【想看看方差不一样,数据量一样,分类效果好不好】
data2, y2 = ds.make_blobs(N, n_features=2, centers=centers, cluster_std=(1, 2.5, 0.5, 2), random_state=2)
# 从原来数据中选一部分的数据出来【想看看从每条数据里选不同的样本数量的分类效果好不好】
data3 = np.vstack((data[y==0][:], data[y==1][:50], data[y==2][:20], data[y==3][:5]))
# 按道理来说,聚类是不需要y值的,这里的y主要是为了看我们的聚类效果准不准
y3 = np.array([0] * 100 + [1] * 50 + [2] * 20 + [3] * 5)
print(y3)
# k-means++是为了改变初始化的值,所以参数名称是init
cls = KMeans(n_clusters=5, init='k-means++')
y_hat = cls.fit_predict(data)
y2_hat = cls.fit_predict(data2)
y3_hat = cls.fit_predict(data3)
# matplotlib.rcParams['font.sans-serif'] = [u'SimHei']
cm = matplotlib.colors.ListedColormap(list('rgbm'))
plt.figure(figsize=(9, 10), facecolor='w')
# subplot用来画子表的 4行 2列 1第一个图
plt.subplot(421)
plt.title("Original Data")
# scatter散点图
plt.scatter(data[:, 0], data[:, 1], c=y, s=10, cmap=cm, edgecolors='none')
x1_min, x2_min = np.min(data, axis=0)
x1_max, x2_max = np.max(data, axis=0)
x1_min, x1_max = expand(x1_min, x1_max)
x2_min, x2_max = expand(x2_min, x2_max)
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.grid(True)
plt.subplot(422)
plt.title("KMeans ++ Clusting")
plt.scatter(data[:, 0], data[:, 1], c=y_hat, s=30, cmap=cm, edgecolors='none')
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.grid(True)
"""
对数据进行旋转
"""
m = np.array(((1, 1), (1, 3)))
data_r = data.dot(m)
y_r_hat = cls.fit_predict(data_r)
plt.subplot(423)
plt.title('Rotation Data')
plt.scatter(data_r[:, 0], data_r[:, 1], c=y, s=30, cmap=cm, edgecolors='none')
x1_min, x2_min = np.min(data_r, axis=0)
x1_max, x2_max = np.max(data_r, axis=0)
x1_min, x1_max = expand(x1_min, x1_max)
x2_min, x2_max = expand(x2_min, x2_max)
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.grid(True)
plt.subplot(424)
plt.title('Rotated KMeans++ Clusting')
plt.scatter(data_r[:, 0], data_r[:, 1], c=y_r_hat, s=30, cmap=cm, edgecolors='none')
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.grid(True)
plt.subplot(425)
plt.title('Different Variance Data')
plt.scatter(data2[:, 0], data2[:, 1], c=y2_hat, s=30, cmap=cm, edgecolors='none')
x1_min, x2_min = np.min(data2, axis=0)
x1_max, x2_max = np.max(data2, axis=0)
x1_min, x1_max = expand(x1_min, x1_max)
x2_min, x2_max = expand(x2_min, x2_max)
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.grid(True)
plt.subplot(426)
plt.title('Different Variance Data KMeans++ Clusting')
plt.scatter(data2[:, 0], data2[:, 1], c=y2_hat, s=30, cmap=cm, edgecolors='none')
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.grid(True)
plt.tight_layout(2, rect=(0, 0, 1, 0.97))
plt.show()
选择的初始值会对聚类结果有影响吗?如何调整,那么首先回答损失函数是什么?
MSE1, MSE2, MSE3, MSE4
两个簇里面的样本数量都很小
两个簇中心很近,两个MSE很小,合并,簇中心离的很远,
MSE很大,分开
选择初始化簇中心稍微远一点,随机选择第一个,算每个样本到第一个样本距离,样本距离可以算成概率,概率化选择。
公式化解释K均值
所以K均值假设了高斯混合模型,GMM,并且假设了方差sigma是一样的,K均值是在给定损失函数的情况下,梯度下降的一个应用,高斯混合分布不是线性回归凸函数,有多个极小值,K-means++或者多算几次。
K = N, MSE 为 0
K = 1, MSE就是原始数据的方差
选择一开始下降速度快,后来下降速度慢的,elbow method, 不止于K均值。
理解起来有点像无监督的决策树
分裂的层次聚类: DIANA
把原始数据集去不断的分裂,然后去计算每个子数据集里面的相似性,然后不断的分裂,把数据集分为很多的类别
凝聚的层次聚类: AGNES
把一个个样本,不断的自底向上的聚类,然后一层一层的来聚,最后聚成一个完整的数据集,这种用的更多一些。
如果两个样本,可以很好的度量距离,如果已经聚了一层,如何度量簇之间的相似性。
最小距离: 两个簇中,最接近样本的距离,城市和城市边界最短距离,成链状一条直线了
最大距离: 两个簇中,最远的样本的距离,某一个簇存在异常值就很麻烦,簇本身比较狭长
平均距离:
两两样本距离的平均
两两样本距离的平方和。
统计样本周边的密度,把密度给定一个阈值,不断的把样本添加到最近的簇。
人口密度,根据密度,聚类出城市,解决类似圆形的K-Means聚类的缺点,密度聚类缺点计算复杂度大,空间索引来降低计算时间,降低查找速度。
DBSCAN
Density Based Spatial Clustering of Application with Noise
对象邻域:给定对象的半径内的区域
如果给定5为阈值,那么q是7, p是3, 那么q是核心对象
而p是在q这个范围(制定一个半径)内的,那么说q到p是核心密度可达
q密度可达p1, p1密度可达p, 那么q到p是密度可达。
密度可达
从o点能密度可达q,也能密度可达p
P和q叫密度相连
簇就是密度相连的最大的点的集合
即最大的密度相连构成的集合就是簇
如何一个点不是核心对象,也不能被别的点密度可达,就是噪声。
具体代码实现:
"""
Date: 2019--11 17:01
User: yz
Email: [email protected]
Desc:
"""
import numpy as np
import matplotlib.pyplot as plt
import sklearn.datasets as ds
import matplotlib.colors
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler
def expand(a, b):
d = (b - a) * 0.1
return a-d, b+d
if __name__ == '__main__':
N = 1000
centers = [[1, 2], [-1, -1], [1, -1], [-1, 1]]
# make_blobs模拟生成聚类的数据 centers:给定的中心点,根据中心点模拟生成数据 cluster_std生成数据的方差
data, y = ds.make_blobs(N, n_features=2, centers=centers, cluster_std=[0.5, 0.25, 0.7, 0.5], random_state=0)
# StandardScaler 做归一化的:先做均值归一化,再说方差归一化
data = StandardScaler().fit_transform(data)
# 数据的参数 (epsilon, min_sample)第一个是r,第二个是阈值
params = ((0.1, 5), (0.1, 10), (0.1, 15), (0.3, 5), (0.3 ,10), (0.3, 15))
plt.figure(figsize=(12, 8), facecolor='w')
# plt.suptitle('DBSCAN Clusting', fontsize=20)
for i in range(6):
eps, min_samples = params[i]
model = DBSCAN(eps=eps, min_samples=min_samples)
model.fit(data)
y_hat = model.labels_
# print(y_hat)
core_indices = np.zeros_like(y_hat, dtype=bool)
core_indices[model.core_sample_indices_] = True
# print(core_indices)
y_unique = np.unique(y_hat)
# print(y_hat)
# 假设有离群点 n_cluster - 1
n_clusters = y_unique.size - (1 if -1 in y_hat else 0)
print(y_unique, "聚类簇的个数为:", n_clusters)
plt.subplot(2, 3, i+1)
# 谱: 提取更好的特征(特征提取的作用)
clrs = plt.cm.Spectral(np.linspace(0, 0.8, y_unique.size))
# print(clrs)
for k, clr in zip(y_unique, clrs):
cur = (y_hat == k)
if k == -1:
plt.scatter(data[cur, 0], data[cur, 1], s=20)
continue
# 把我们分类好的类别,一个点一个点画出来(画离群点)
plt.scatter(data[cur, 0], data[cur, 1], s=30, c=clr, edgecolors='k')
# 把我们分类好的类别,一个点一个点画出来(画非离群点)
plt.scatter(data[cur & core_indices][:, 0], data[cur & core_indices][:, 1], s=60, c=clr, marker='o', edgecolors='k')
x1_min, x2_min = np.min(data, axis=0)
x1_max, x2_max = np.max(data, axis=0)
x1_min, x1_max = expand(x1_min, x1_max)
x2_min, x2_max = expand(x2_min, x2_max)
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))
plt.grid(True)
plt.title(u'epsilon = %.1f m = %d CA:%d' % (eps, min_samples, n_clusters), fontsize=16)
plt.tight_layout()
plt.subplots_adjust(top=0.9)
plt.show()
Y = AX, 矩阵X乘以A等于对矩阵X做了空间线性变换,那么Y=map[X], A就是map这个线性算子,它的所有特征值的全体,称之为方阵的谱
方阵的谱半径为最大的特征值
谱聚类是一种基于图论的聚类方式,通过对样本数据的拉普拉斯矩阵的特征向量进行聚类,从而达到对样本数据进行聚类的目的。
L矩阵是NN的,N是样本个数,实数形成的对数矩阵,求特征值和特征向量,Lui = lambda iui, lambda是特征值,ui是特征向量,一组lambda有从大到小可以排序
每个对应的lambda都对应一个ui,每个ui是一个个的列向量,比如u11, u21, u31, un1
根据排序默认从小到大,逆序之后我们就取前面的几个ui列向量就可以了,其实这是一种降维。
然后我们的前面的这几个列向量ui就成了新的对应每个样本的几个重要的特征
最后我们用K-Means聚类算法对样本进行聚类就好了。
谱聚类和PCA的关系
就是Laplace矩阵做了一个主成分分析PCA,然后做K均值聚类。
PCA降维:
盲目减少指标会损失很多信息
容易产生错误的结论
各变量间存在一定的相关关系
先均值归一化,映射到原点
协方差矩阵
协方差(Covariance)
用于衡量两个变量的总体误差。
独立事件:
在一次实验中,一个事件的发生不会影响到另一个事件发生的概率P(AB) = P(A)P(B)。
病人分类的例子:
P(A|B) = P(B|A) P(A) / P(B)
A : 感冒
B :打喷嚏 x 建筑工人
P(感冒|打喷嚏X建筑工人)
=P(打喷嚏x建筑工人|感冒)xP(感冒)/P(打喷嚏X建筑工人)
=P(打喷嚏|感冒) x P(建筑工人|感冒) x P(感冒) / P(打喷嚏) x P(建筑工人)
= 0.66 x 0.33 x 0.5 / 0.5 x0.33
=0.66
使用贝叶斯对在线社区留言本进行分类:
为了不影响社区的发展,我们要屏蔽侮辱性言论。
所以要构建一个快速的过滤器,如果某条留言使用了负面或者侮辱性的语言,
那么就将该留言标识为内容不当
A: 侮辱性言论的概率
B: 我说这句话的概率 = 我说的这句话中的文字出现的概率
思想:
说白了,套一下公式P(A|B) = P(B|A) P(A) / P(B),就是
P(侮辱性言论的概率|我说的这句话中的文字出现的概率)
= P(我说的这句话中的文字出现的概率|当言论是侮辱性的时候)*P(侮辱性言论的概率)
/P(我说的这句话中的文字出现的概率)