在讨论SVM的时候,我们聊到了向量到超平面的距离,还说“距离”是个很重要的概念。这一次,我们将直接以向量之间的欧式距离为基础,探索一下传说中的K-means聚类,是个怎样的东东,据说它还有个很高大上的名字:“非监督学习”

首先,来个餐前菜,聊两个在平时聊天中经常被问到的话题,我把我的理解写在下面,不一定严谨,但用来应付我们对模型内部的理解,到目前来看,我觉得没有任何问题,下面就分别说一下。先贴张图:

右边手写体是某大咖学习花书做的笔记,左边宋体字是我做的标注

问题1:机器学习中,经常提到的向量是什么,张量又是什么?

这个问题,在前几篇中略有提及,这里做一个大概的总结吧:

在数学意义上,在二维中,向量是平面上的一个点。

在物理意义上,你可以把它想成一条线,但需要定义一个原点,从原点到该点的连线,就是向量。

三维类推,数学上,向量是三维空间中的一个点,物理上,也要定义原点,再连线。

计算机数据里,一个向量,可以把它看成数据库中的一条记录,或一列数据,因为有时候你需要转置。

张量,数学上和物理上的定义,和向量是一回事。

但在机器学习和深度学习这个领域内,他们把张量,说成是一组向量的集合。名字上有区别,张量是tensor,向量是vector,一个tensor可以是一个或一个以上vector的集合。

————————————————————————

问题2:张量,亦即是向量的集合,存在的意义是什么?

意义是形成矩阵,往线性代数上面靠,便于批量计算。所以在这种计算中,很少会用for循环,而是直接一个矩阵丢进去,用矩阵乘法或加法进行计算,满足一些计算规律,比如分配律啊,交换律啊,啥的,好变换一些,这也是numpy存在的意义。

来看看python代码里,观察到的向量和张量是什么样子的:

我们在爬坡,从线性回归开始,数据分析中一大波数学方法即将袭来里,曾经这样使用过线性回归,

X = np.array(sport_data[factor_name][:, np.newaxis])model.fit(X, sport_data[target_name])  # sport_data[target_name]就是Y

X和Y的区别看出来没有,X用的数据,多了一个[:, np.newaxis],这是用来扩展维度的,这里的维度指的是向量维度dim,而不是数据维度,也就是说,X比Y多了一层方括号,为啥要多这层方括号?因为X是一组向量vector的集合,他们称这是“张量”,即tensor。

我们在用from sklearn.model_selection import train_test_split这个工具直接进行数据集切分的时候,返回的X数据,也比Y数据,多一层方括号,即多一个维度的dim,就是因为X是一个张量tensor。例如:

看出区别没有,需要这么做,而且必须这么做,无论是一条记录还是多条记录,X都是要比Y多一个维度的(保个底,大部分时候是这样)。

——————————————————————————

Now,进入今天的正题

我们先看看,什么是“欧式距离”,顾名思义,欧式距离就是欧几里得距离,就是几何距离,我们仍以平面上的两个点,作为向量,来做示意图:

图1

向量a和向量b之间的距离dist,完全可以求出来吧,上勾股定理,下面直接列一下公式,二维情况下,令(a1,a2)=(x1,y1),(b1,b2)=(x2,y2):

推广到N维情况下:

不要被公式吓到,说白了,就是将两个向量,对应的元素相减,再平方,再把所有的这些值,累加起来,然后开方,即可。

python表达式是:

    import numpy as np    def dist_E(vector1, vector2):        return np.sqrt(np.sum(np.square(vector1-vector2)))

当然,scipy库中有现成的欧式函数方法,可以直接调用

from scipy.spatial.distance import cdist# metric='euclidean'即为欧式距离cdist(vector1, vector2, metric='euclidean')

计算这个欧式距离能做什么呢?还是看图1,如果这两个向量之间的欧式距离越小,他俩就挨得越近,我们通常可以认为他俩越相似,越有可能属于同一类,诸如此类的表述,总之就是说他俩关系密切。

比如,还是以我们之前用过的数据,学生的体育成绩表,如果学生A和学生B的数据['100m', '身高',  '体重', 'bmi'],这个4维数据,做成两个向量后,计算两个向量之间的距离,发现距离很小的话,那么如果我们知道学生A的1000m跑的很快,我们是否可以基本确定学生B的1000米也能跑的很快呢?

接下来我们就来验证这个事。首先,我们挑两个差不多数据的学生出来,怎么挑呢,先确定一个学生,然后把这个学生和所有其他学生之间的数据,计算欧式距离,距离最小的,我们挑选出来,然后用线性相关的皮尔逊相关系数来验证一下(这个系数,往往也用来衡量相似度啊,越接近1,越相似,但不能跟线性方程中自变量的系数弄混)。——因为维度较少(参与计算的是4维),这样做稍微有点牵强,但作为示例来说,是够了的,只要记住这个方法可以推广到更多维的情况。

依然用爬坡,从线性回归开始,数据分析中一大波数学方法即将袭来中造的数据

# coding:utf-8import pandas as pdimport numpy as np###标准化def standard(df, filter_column):    for col in df.columns:        if col in filter_column:            continue        a = df[col].astype('Float64')        df[col] = (a - np.mean(a)) / np.std(a)    return dfdef _sigmoid(x):    u = 1 / (2.71 ** (-x) + 1)    return u###映射def sigmoid(df, filter_column):    for col in df.columns:        if col in filter_column:            continue        a = df[col].astype('Float64')        df[col] = _sigmoid(a)    return dfsport_data = pd.read_csv('体育成绩表.csv', encoding='utf-8-sig', engine='python').set_index('姓名')filter_column = ['1000m']sport_data = standard(sport_data, filter_column=filter_column)sport_data = sigmoid(sport_data, filter_column=filter_column)# 分为三类sport_data['grade'] = 1m1000_grade_0 = sport_data['1000m'].quantile(q=0.33)m1000_grade_1 = sport_data['1000m'].quantile(q=0.66)sport_data.loc[sport_data['1000m'] > m1000_grade_1, 'grade'] = 2sport_data.loc[sport_data['1000m'] < m1000_grade_0, 'grade'] = 0my_data = np.array(sport_data)X_data = my_data[:, :-2]  # 用于计算的数据,不要标签和1000m成绩

批量计算欧式距离的方法:

source_vector = X_data[-1, :]  # 姑且用最后一个学生的数据做对比标的吧# 批量计算欧式距离distances = np.sqrt(np.sum(np.asarray(source_vector - X_data)**2, axis=1))# 除了自己以外,距离最小的人的序号similar_vector_index = list(distances).index(np.sort(distances)[1])# 打印两个向量print(X_data[similar_vector_index, :])print(source_vector)# 打印两个学生数据print(sport_data.iloc[similar_vector_index])print(sport_data.iloc[-1])

没错,这两个学生的grade,都是0,的确是一类人。

计算一下我们挑选出来的两个向量,之间的皮尔逊相关系数

from scipy.stats import pearsonrp_1 = pearsonr(source_vector, X_data[similar_vector_index, :])print(p_1)

这个值是一个元组,p_1[0]是皮尔逊相关系数,0.95是一个相当不错的值,强相关。而p_1[1]是这对关系的p_value值,当这个值小于0.05的时候,才具有统计意义,这里似乎太靠近阈值,没关系,这主要是因为我们的维度少,向量不够长。

我们用最小二乘法再验证一下

import statsmodels.api as smX2 = sm.add_constant(source_vector)est = sm.OLS(X_data[similar_vector_index, :], X2)  # OLS就是最小二乘法est2 = est.fit()print(est2.summary())

最上面那个红框,就是我们之前聊过的R^2判断系数,右下的红框就是刚刚计算皮尔逊相关系数给出的p_value,这个值最好小于0.05,才有统计意义,这涉及到统计分析方法中的F检验和T检验,各位有空可以去恶补一下。左下的红框,就是线性回归方程的系数和常数。

总的来说,这两个向量的相关性,距离,都是符合预期的。

说了这么多,还没进入正题,K-means还没弄,下面就弄。

K-means的算法原理,可以上网去搜一下,简单说,和世界上其他的聚类,几乎是同一个原则,即:让类内距离尽量的小,同时,让类间距离尽量的大。对K-means来说,指定一个K值(簇数),本着让簇内距离最小的原则,一顿迭代,找到各个簇的成员,然后,随机初始化每个簇的中心点,经过一顿迭代操作,找出每个簇中心点的距离,把多次迭代后,最大的那个间距记下来,作为簇间间距。经过这两个类型的迭代(两种迭代是嵌套进行的)之后,确定综合性能(簇内间距小,簇间间距大)最好的一种方案

首先,我们假定事先,我们并不知道究竟该聚为多少簇(一个簇,看成一类)合适,因此,我们做一个循环迭代,让簇数量从1~20,迭代着看看效果

from sklearn.cluster import KMeans  # k-means包from scipy.spatial.distance import cdist  # 欧式距离import matplotlib.pyplot as pltimport matplotlib as mplmpl.rcParams['font.sans-serif'] = ['SimHei']  # 指定默认字体mpl.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题K = range(1, 20)mean_distortions = []for k in K:    kmeans = KMeans(n_clusters=k)    kmeans.fit(X_data)    # 这里出现cdist这个函数,就是我们上面说过的欧式距离    mean_distortions.append(sum(np.min(cdist(X_data, kmeans.cluster_centers_, metric='euclidean'), axis=1)) / X_data.shape[0])plt.plot(K, mean_distortions, 'bx-')plt.xlabel('k')plt.ylabel(u'平均畸变程度')plt.title(u'用肘部法确定最佳的K值')plt.show()

这里用来确定分类效果的,是K-means的肘部法则,即处于曲线转弯位置的簇的数量,是比较合适的分类数量。

红框中,都可以认为是肘部K=(2,3,4),最后,我们验证出来的结果是,K=2及K=3时,分类效果和我们事先打的标签,效果比较接近。

K-means算法的评估方法有2个。

一个是“肘部法则”,依据是一个被称为“畸变程度”的东东,每个簇的质点(中心点)与簇内样本点的平方距离误差和称为畸变程度(distortions),那么,对于一个簇,它的畸变程度越低,代表簇内成员越紧密,畸变程度越高,代表簇内结构越松散。很显然,如果每个点单独作为一个簇,那么这个畸变程度是最低的,但那也是没有意义的。而所有点都在一个簇内,畸变程度最高,但也没有意义。我们要找的“肘部”,就是畸变程度受簇数增加,变化不大的时候,前面那几个数,当作肘部,有时候肘部只有一个数,有时候不止一个,但起码可以大概把范围确定下来,我们可以再逐个尝试。

另一个是“轮廓系数”,也是围绕距离去计算的,原理和实现方法,各位看官可以去网上搜一下,依然可以用本例中的数据测试。

我们把最终效果打印出来看看,还是以分三类为例

from sklearn.cluster import KMeansestimator = KMeans(n_clusters=3)  # 构造聚类器estimator.fit(X_data)  # 聚类label_pred = estimator.labels_  # 获取聚类标签print('聚类结果:', label_pred)print('标签:', sport_data['grade'].tolist())#绘制k-means结果x0 = X_data[label_pred == 0]x1 = X_data[label_pred == 1]x2 = X_data[label_pred == 2]# K-means聚类出来的结果idx_0 = [i for i, x in enumerate(label_pred) if x == 0]idx_1 = [i for i, x in enumerate(label_pred) if x == 1]idx_2 = [i for i, x in enumerate(label_pred) if x == 2]# 我们之前打的标签idx_0_m = [i for i, x in enumerate(sport_data['grade'].tolist()) if x == 0]idx_1_m = [i for i, x in enumerate(sport_data['grade'].tolist()) if x == 1]idx_2_m = [i for i, x in enumerate(sport_data['grade'].tolist()) if x == 2]# 各类各有多少个样本print(len(x0))print(len(x1))print(len(x2))# 各类聚类结果在原始数据中的位置print(idx_0)print(idx_1)print(idx_2)# 各类原始标签位置print(idx_0_m)print(idx_1_m)print(idx_2_m)

差不多就是这么个结果,有点相似,各位看官自己找不同,O(∩_∩)O

分成3类后,挑选100m和tall两个特征来画聚类二维图,效果如下:

如果想要真正探究一下准确率,应该怎么做呢?

有个办法,我想到了另一个相似性(或距离,1-相似性),这个相似性叫做:杰卡德相似性  Jaccard similarity,定义如下:

即,杰卡德相似度,等于,集合A和集合B的交集长度,除以他俩的并集长度。这个值处于[0, 1]区间,值越大,说明两个集合就越相似,如果这两个集合完全重合,交集和并集一样大,那么这个值就是1。

于是,我们在某次聚类之后,挑选出两个list去计算,如下:

# 被挑选出来的两列数,每个数字是学生处于数据表中的index位置a_list = [0, 1, 5, 8, 9, 11, 16, 17, 18, 19, 20, 21, 22, 23, 29, 32, 37, 40, 41, 43, 45, 48, 49, 50, 59, 64, 68, 69, 71, 86, 90, 95]b_list = [0, 1, 8, 11, 14, 16, 17, 18, 21, 22, 23, 32, 37, 41, 42, 43, 45, 46, 48, 49, 50, 59, 60, 61, 62, 63, 64, 69, 71, 86, 87, 90, 93, 95]# 交集intersection = list(set(a_list).intersection(set(b_list)))# 并集union = list(set(a_list).union(set(b_list)))print(intersection)jaccard_similarity = len(intersection) / len(union)print(jaccard_similarity)

交集: [0, 1, 8, 11, 16, 17, 18, 21, 22, 23, 32, 37, 41, 43, 45, 48, 49, 50, 59, 64, 69, 71, 86, 90, 95]

jaccard_similarity: 0.6097560975609756

效果一般,勉强可信。

如果分成2类,效果如下:

因为聚类非监督学习打标签和我们自己打的标签,0、1、2是无法指定的,因此,聚类结果的标签和自己打的标签,基本是对不上的,但是,看下面我们找出来各个类别中,包含元素的具体位置,目测,相似度还是可以的。

2分类时的散点情况,100m和tall特征

从聚类结果中,挑选两列出来,比较杰卡德相似度情况:

a_list = [2, 3, 4, 6, 7, 10, 12, 13, 15, 24, 25, 26, 27, 30, 31, 34, 35, 36, 38, 44, 47, 51, 52, 53, 54, 55, 56, 58, 65, 66, 67, 70, 72, 73, 75, 77, 78, 80, 81, 82, 83, 84, 88, 89, 91, 92, 94, 97, 98, 99]b_list = [0, 2, 4, 9, 10, 12, 13, 15, 24, 25, 26, 29, 30, 31, 34, 36, 38, 40, 44, 47, 51, 52, 53, 54, 55, 65, 66, 67, 70, 72, 73, 75, 77, 81, 83, 84, 85, 88, 89, 91, 92, 97, 99]intersection = list(set(a_list).intersection(set(b_list)))union = list(set(a_list).union(set(b_list)))print('交集:', intersection)jaccard_similarity = len(intersection) / len(union)print('jaccard_similarity:', jaccard_similarity)

交集: [2, 4, 10, 12, 13, 15, 24, 25, 26, 30, 31, 34, 36, 38, 44, 47, 51, 52, 53, 54, 55, 65, 66, 67, 70, 72, 73, 75, 77, 81, 83, 84, 88, 89, 91, 92, 97, 99]

jaccard_similarity: 0.6909090909090909

2分类时,聚类效果和人工标签的效果稍微好一些,不过也只有7成左右相似。这个可能与数据有关,也有可能是算法需要打磨,不过,作为例子来说,本例基本能够说明问题。

至此,我们在一个例子中,使用了欧式距离,使用了皮尔逊相关系数,并进行了最小二乘法验证,最后用K-means聚类,自动确定需要分的类别数量,并使用杰卡德相似度,将自动打标签,和我们手工打的标签进行对比。

——————分割线——————

至此,可能有些看官心存狐疑,似乎觉得有很多计算包,或者机器学习包,python都提供了,没必要讲那么多原理,推导那么些公式,直接调包不就行了?究竟行不行呢?答案是,行!但天花板就低了。

这里我解释一下:

在将来的很多时候,我们可能并不是用这些模型去直接输出结果,判断分类啥的,说到底,就算调包,也是工具,最多就是做个demo玩玩。真正有用的是理解这些工具包的计算逻辑,理解他们的一些中间变量的含义,代表了什么,我们可能需要把这些中间变量,拿去做另一个模型的输入,或者用来表示一个相对量,类似对原始数据进行了编码。如果我们不能深入理解这些算法的含义,我们的思想就会受到局限,很多玩法甚至都不会进入我们的脑海,思路嘎然而止。——这就是天花板。

理解得越深,天花板越高,直至拿掉天花板,面对整个天空。

很明显的,我们将来会用本文中的很多知识,去做更有意思的事。

一套打完,各位看官是否满意。

乘法分配律逆运算是什么意思_聚类,我们先操弄一下Kmeans,看看什么是非监督学习...相关推荐

  1. 乘法分配律逆运算是什么意思_什么是乘法分配律的逆运算

    什么是乘法分配律的逆运算 时间:2020-11-26  编辑:admin  访问:43 瞎扯现代数学的基础,分派律: a(b + c) = ab + ac; 界说:正整数是:1,2=1+1,3 =1+ ...

  2. sap中泰国有预扣税设置吗_泰国餐厅密度细分:带有K-means聚类的python

    sap中泰国有预扣税设置吗 Hi! I am Tung, and this is my first stories for my weekend project. What inspired this ...

  3. python函一维聚类_聚类实战:一维数组数据聚类

    大部分聚类方法针对的是多维数据,现实场景中还有可能存在以为数据的情况,针对以为数组的聚类和多维的数据有很大的不同,今天就来实战演练下: 需求内容:分析订单的价格分布 常见方案:按照100为梯度,分析不 ...

  4. k-均值聚类算法_聚类算法-K-均值算法

    k-均值聚类算法 聚类算法-K-均值算法 (Clustering Algorithms - K-means Algorithm) K-Means算法简介 (Introduction to K-Mean ...

  5. 机器学习集群_机器学习中的多合一集群技术在无监督学习中应该了解

    机器学习集群 Clustering algorithms are a powerful technique for machine learning on unsupervised data. The ...

  6. K-means聚类算法的三种改进(K-means++,ISODATA,Kernel K-means)介绍与对比

    原文:http://www.cnblogs.com/yixuan-xu/p/6272208.html K-means聚类算法的三种改进(K-means++,ISODATA,Kernel K-means ...

  7. 聚类图像像素 Clustering Pixels Using K-Means

    在K-Means Using Python中,给出了一个用K-Means聚类的tutorial,这次将K-Means用在具体图像像素聚类中,需要说明的是除了在很简单的图像上,单纯在像素值上应用K-Me ...

  8. 5 分钟带你弄懂 k-means 聚类

    聚类与分类的区别 分类:类别是已知的,通过对已知分类的数据进行训练和学习,找到这些不同类的特征,再对未分类的数据进行分类.属于监督学习. 聚类:事先不知道数据会分为几类,通过聚类分析将数据聚合成几个群 ...

  9. r语言 聚类求和_R语言聚类分析:k-means和层次聚类

    尽管我个人非常不喜欢人们被划分圈子,因为这样就有了歧视.偏见.排挤和矛盾,但"物以类聚,人以群分"确实是一种客观的现实--这其中就蕴含着聚类分析的思想. 前面所提到的机器学习算法主 ...

  10. 矩阵乘法分配律+bitset优化——hdu4920

    因为是模3,所以把原矩阵拆成两个01矩阵,然后按分配律拆开分别进行矩阵乘法,行列用bitset来存进行优化即可 注意 int bitset<int>::count() 函数可以统计bits ...

最新文章

  1. 观察者模式的Java实现及应用
  2. pythonapriori算法特点_Python --深入浅出Apriori关联分析算法(一)
  3. PHP创建图像的应用!!!!
  4. SpringMVC实现简单登录
  5. Ant Design入门之开始使用
  6. php多个构造方法,php多构造器的实例代码
  7. 让我的 .NET Core 博客系统支持 Docker
  8. 解决Sublime Text3莫名的中文乱码问题
  9. 世纪互联、微软Azure与无穷小微积分
  10. STM32打印log--使用J-Link RTT Viewer
  11. 策略模式探究(二)多个门禁对接使用策略模式
  12. echarts 自定义鼠标划过的显示 与 自定义legend
  13. Netbeans使用问题整理
  14. Andriod Studio安装教程
  15. 竞品分析----夸克:我离百度还有多少步?
  16. JavaBean技术的应用——购物车
  17. java rpm卸载_rpm安装和卸载软件
  18. js:bind(this)这是什么写法
  19. python爬取智联招聘职位信息(单进程)
  20. 茶云导航网站源码v1.2 PHP带后台管理

热门文章

  1. .php on line 0,windows启动apache提示PHP Startup: in Unknown on line 0
  2. 请详细描述listview与gridview的异同点_专利和著作权有什么异同点,听听专业人士怎么说...
  3. gdi作图与系统不兼容_技术作图:技能准备amp;物理装备
  4. suse 内核编译安装_Linux内核编译与安装
  5. 更改应用程序图标_苹果手机升级iOS14试试自定义应用图标
  6. android studio 工程rebuild没反应,Andriod Studio Clear Project或Rebuild Project出错
  7. 线性求逆元模板_专栏:ACM算法面面观[9]逆元
  8. 怎么python安装mysql库_python在windows上怎么安装mysql数据库
  9. java jdbc 参数 转义_jdbc URL中的各个参数详解
  10. jquery中ajax的post方法,jQuery中Ajax的get、post等方法详解