数据挖掘面试笔试 (8)
【校招面经】机器学习与数据挖掘常见面试题整理 part3
四十一、请简要说说EM算法
有时候因为样本的产生和隐含变量有关(隐含变量是不能观察的),而求模型的参数时一般采用最大似然估计,由于含有了隐含变量,所以对似然函数参数求导是求不出来的,这时可以采用EM算法来求模型的参数的(对应模型参数个数可能有多个),EM算法一般分为2步: E步:选取一组参数,求出在该参数下隐含变量的条件概率值; M步:结合E步求出的隐含变量条件概率,求出似然函数下界函数(本质上是某个期望函数)的最大值。 重复上面2步直至收敛。作者:史兴
链接:https://www.zhihu.com/question/27976634/answer/39132183
理论:
简版:猜(E-step),反思(M-step),重复;
啰嗦版:
你知道一些东西(观察的到的数据), 你不知道一些东西(观察不到的),你很好奇,想知道点那些不了解的东西。怎么办呢,你就根据一些假设(parameter)先猜(E-step),把那些不知道的东西都猜出来,假装你全都知道了; 然后有了这些猜出来的数据,你反思一下,更新一下你的假设(parameter), 让你观察到的数据更加可能(Maximize likelihood; M-stemp); 然后再猜,在反思,最后,你就得到了一个可以解释整个数据的假设了。
1. 注意,你猜的时候,要尽可能的猜遍所有情况,然后求期望(Expected);就是你不能仅仅猜一个个例,而是要猜出来整个宇宙;
2. 为什么要猜,因为反思的时候,知道全部的东西比较好。(就是P(X,Z)要比P(X)好优化一些。Z是hidden states)
3. 最后你得到什么了?你得到了一个可以解释数据的假设,可能有好多假设都能解释数据,可能别的假设更好。不过没关系,有总比没有强,知足吧。(你陷入到local minimum了)
====
实践:
背景:公司有很多领导=[A总,刘总,C总],同时有很多漂亮的女职员=[小甲,小章,小乙]。(请勿对号入座)你迫切的怀疑这些老总跟这些女职员有问题。为了科学的验证你的猜想,你进行了细致的观察。于是,
观察数据:
1)A总,小甲,小乙一起出门了;
2)刘总,小甲,小章一起出门了;
3)刘总,小章,小乙一起出门了;
4)C总,小乙一起出门了;
收集到了数据,你开始了神秘的EM计算:
初始化,你觉得三个老总一样帅,一样有钱,三个美女一样漂亮,每个人都可能跟每个人有关系。所以,每个老总跟每个女职员“有问题”的概率都是1/3;
这样,(E step)借用我之前看到的一个例子来讲一下EM算法吧。
现在一个班里有50个男生,50个女生,且男生站左,女生站右。我们假定男生的身高服从正态分布
,女生的身高则服从另一个正态分布:
。这时候我们可以用极大似然法(MLE),分别通过这50个男生和50个女生的样本来估计这两个正态分布的参数。
但现在我们让情况复杂一点,就是这50个男生和50个女生混在一起了。我们拥有100个人的身高数据,却不知道这100个人每一个是男生还是女生。
这时候情况就有点尴尬,因为通常来说,我们只有知道了精确的男女身高的正态分布参数我们才能知道每一个人更有可能是男生还是女生。但从另一方面去考量,我们只有知道了每个人是男生还是女生才能尽可能准确地估计男女各自身高的正态分布的参数。
这个时候有人就想到我们必须从某一点开始,并用迭代的办法去解决这个问题:我们先设定男生身高和女生身高分布的几个参数(初始值),然后根据这些参数去判断每一个样本(人)是男生还是女生,之后根据标注后的样本再反过来重新估计参数。之后再多次重复这个过程,直至稳定。这个算法也就是EM算法。
作者:文兄
来源:https://www.zhihu.com/question/27976634/answer/154998358
1) A总跟小甲出去过了 1/2 * 1/3 = 1/6 次,跟小乙也出去了1/6次;(所谓的fractional count)
2)刘总跟小甲,小章也都出去了1/6次
3)刘总跟小乙,小章又出去了1/6次
4)C总跟小乙出去了1/3次
总计,A总跟小甲出去了1/6次,跟小乙也出去了1/6次 ; 刘总跟小甲,小乙出去了1/6次,跟小章出去了1/3次;C总跟小章出去了1/3次;
你开始跟新你的八卦了(M step),
A总跟小甲,小乙有问题的概率都是1/6 / (1/6 + 1/6) = 1/2;
刘总跟小甲,小乙有问题的概率是1/6 / (1/6+1/6+1/6+1/6) = 1/4; 跟小章有问题的概率是(1/6+1/6)/(1/6 * 4) = 1/2;
C总跟小乙有问题的概率是 1。
然后,你有开始根据最新的概率计算了;(E-step)
1)A总跟小甲出去了 1/2 * 1/2 = 1/4 次,跟小乙也出去 1/4 次;
2)刘总跟小甲出去了1/2 * 1/4 = 1/12 次, 跟小章出去了 1/2 * 1/2 = 1/4 次;
3)刘总跟小乙出去了1/2 * 1/4 = 1/12 次, 跟小章又出去了 1/2 * 1/2 = 1/4 次;
4)C总跟小乙出去了1次;
重新反思你的八卦(M-step):
A总跟小甲,小乙有问题的概率都是1/4/ (1/4 + 1/4) = 1/2;
B总跟小甲,小乙是 1/12 / (1/12 + 1/4 + 1/4 + 1/12) = 1/8 ; 跟小章是 3/4 ;
C总跟小乙的概率是1。
你继续计算,反思,总之,最后,你得到了真相!(马总表示我早就知道真相了)
你知道了这些老总的真相,可以开始学习机器翻译了。
四十二、密度聚类
来源:https://www.cnblogs.com/pinard/p/6208966.html
DBSCAN的聚类定义很简单:由密度可达关系导出的最大密度相连的样本集合,即为我们最终聚类的一个类别,或者说一个簇。
这个DBSCAN的簇里面可以有一个或者多个核心对象。如果只有一个核心对象,则簇里其他的非核心对象样本都在这个核心对象的ϵ-邻域里;如果有多个核心对象,则簇里的任意一个核心对象的ϵ-邻域中一定有一个其他的核心对象,否则这两个核心对象无法密度可达。这些核心对象的ϵ-邻域里所有的样本的集合组成的一个DBSCAN聚类簇。
那么怎么才能找到这样的簇样本集合呢?DBSCAN使用的方法很简单,它任意选择一个没有类别的核心对象作为种子,然后找到所有这个核心对象能够密度可达的样本集合,即为一个聚类簇。接着继续选择另一个没有类别的核心对象去寻找密度可达的样本集合,这样就得到另一个聚类簇。一直运行到所有核心对象都有类别为止。
四十三、决策树计算样例
注意信息增益率的计算:https://www.cnblogs.com/hermione1985/p/6750209.html
四十四、聚类数量的确定
https://blog.csdn.net/qq_15738501/article/details/79036255
确定聚类数k的方法有以下两类。
1.手肘法
1.1 理论
手肘法的核心指标是SSE(sum of the squared errors,误差平方和),
其中,Ci是第i个簇,p是Ci中的样本点,mi是Ci的质心(Ci中所有样本的均值),SSE是所有样本的聚类误差,代表了聚类效果的好坏。
手肘法的核心思想是:随着聚类数k的增大,样本划分会更加精细,每个簇的聚合程度会逐渐提高,那么误差平方和SSE自然会逐渐变小。并且,当k小于真实聚类数时,由于k的增大会大幅增加每个簇的聚合程度,故SSE的下降幅度会很大,而当k到达真实聚类数时,再增加k所得到的聚合程度回报会迅速变小,所以SSE的下降幅度会骤减,然后随着k值的继续增大而趋于平缓,也就是说SSE和k的关系图是一个手肘的形状,而这个肘部对应的k值就是数据的真实聚类数。当然,这也是该方法被称为手肘法的原因。
1.2 实践
我们对预处理后数据.csv 中的数据利用手肘法选取最佳聚类数k。具体做法是让k从1开始取值直到取到你认为合适的上限(一般来说这个上限不会太大,这里我们选取上限为8),对每一个k值进行聚类并且记下对于的SSE,然后画出k和SSE的关系图(毫无疑问是手肘形),最后选取肘部对应的k作为我们的最佳聚类数。python实现如下:
[python] view plain copy
- import pandas as pd
- from sklearn.cluster import KMeans
- import matplotlib.pyplot as plt
- df_features = pd.read_csv(r'C:\预处理后数据.csv',encoding='gbk') # 读入数据
- '利用SSE选择k'
- SSE = [] # 存放每次结果的误差平方和
- for k in range(1,9):
- estimator = KMeans(n_clusters=k) # 构造聚类器
- estimator.fit(df_features[['R','F','M']])
- SSE.append(estimator.inertia_)
- X = range(1,9)
- plt.xlabel('k')
- plt.ylabel('SSE')
- plt.plot(X,SSE,'o-')
- plt.show()
画出的k与SSE的关系图如下:
显然,肘部对于的k值为4,故对于这个数据集的聚类而言,最佳聚类数应该选4
2. 轮廓系数法
2.1 理论
该方法的核心指标是轮廓系数(Silhouette Coefficient),某个样本点Xi的轮廓系数定义如下:
其中,a是Xi与同簇的其他样本的平均距离,称为凝聚度,b是Xi与最近簇中所有样本的平均距离,称为分离度。而最近簇的定义是
其中p是某个簇Ck中的样本。事实上,简单点讲,就是用Xi到某个簇所有样本平均距离作为衡量该点到该簇的距离后,选择离Xi最近的一个簇作为最近簇。
求出所有样本的轮廓系数后再求平均值就得到了平均轮廓系数。平均轮廓系数的取值范围为[-1,1],且簇内样本的距离越近,簇间样本距离越远,平均轮廓系数越大,聚类效果越好。那么,很自然地,平均轮廓系数最大的k便是最佳聚类数。
2.2 实践
我们同样使用2.1中的数据集,同样考虑k等于1到8的情况,对于每个k值进行聚类并且求出相应的轮廓系数,然后做出k和轮廓系数的关系图,选取轮廓系数取值最大的k作为我们最佳聚类系数,python实现如下:
[python] view plain copy
- import pandas as pd
- from sklearn.cluster import KMeans
- from sklearn.metrics import silhouette_score
- import matplotlib.pyplot as plt
- df_features = pd.read_csv(r'C:\Users\61087\Desktop\项目\爬虫数据\预处理后数据.csv',encoding='gbk')
- Scores = [] # 存放轮廓系数
- for k in range(2,9):
- estimator = KMeans(n_clusters=k) # 构造聚类器
- estimator.fit(df_features[['R','F','M']])
- Scores.append(silhouette_score(df_features[['R','F','M']],estimator.labels_,metric='euclidean'))
- X = range(2,9)
- plt.xlabel('k')
- plt.ylabel('轮廓系数')
- plt.plot(X,Scores,'o-')
- plt.show()
得到聚类数k与轮廓系数的关系图:
可以看到,轮廓系数最大的k值是2,这表示我们的最佳聚类数为2。但是,值得注意的是,从k和SSE的手肘图可以看出,当k取2时,SSE还非常大,所以这是一个不太合理的聚类数,我们退而求其次,考虑轮廓系数第二大的k值4,这时候SSE已经处于一个较低的水平,因此最佳聚类系数应该取4而不是2。
但是,讲道理,k=2时轮廓系数最大,聚类效果应该非常好,那为什么SSE会这么大呢?在我看来,原因在于轮廓系数考虑了分离度b,也就是样本与最近簇中所有样本的平均距离。为什么这么说,因为从定义上看,轮廓系数大,不一定是凝聚度a(样本与同簇的其他样本的平均距离)小,而可能是b和a都很大的情况下b相对a大得多,这么一来,a是有可能取得比较大的。a一大,样本与同簇的其他样本的平均距离就大,簇的紧凑程度就弱,那么簇内样本离质心的距离也大,从而导致SSE较大。所以,虽然轮廓系数引入了分离度b而限制了聚类划分的程度,但是同样会引来最优结果的SSE比较大的问题,这一点也是值得注意的。
总结
从以上两个例子可以看出,轮廓系数法确定出的最优k值不一定是最优的,有时候还需要根据SSE去辅助选取,这样一来相对手肘法就显得有点累赘。因此,如果没有特殊情况的话,我还是建议首先考虑用手肘法。
四十五、解决lr非线性问题
1. 分箱+one-hot+交叉相乘
2. 特征项加平方
3. gbdt+lr
四十六、集成决策树与神经网络
四十七、更多聚类算法
http://blog.chinaunix.net/uid-10289334-id-3758310.html
基于划分聚类算法(partition clustering)
k-means: |
是一种典型的划分聚类算法,它用一个聚类的中心来代表一个簇,即在迭代过程中选择的聚点不一定是聚类中的一个点,该算法只能处理数值型数据 |
k-modes: |
K-Means算法的扩展,采用简单匹配方法来度量分类型数据的相似度 |
k-prototypes: |
结合了K-Means和K-Modes两种算法,能够处理混合型数据 |
k-medoids: |
在迭代过程中选择簇中的某点作为聚点,PAM是典型的k-medoids算法 |
CLARA: |
CLARA算法在PAM的基础上采用了抽样技术,能够处理大规模数据 |
CLARANS: |
CLARANS算法融合了PAM和CLARA两者的优点,是第一个用于空间数据库的聚类算法 |
Focused CLARAN: |
采用了空间索引技术提高了CLARANS算法的效率 |
PCM: |
模糊集合理论引入聚类分析中并提出了PCM模糊聚类算法 |
基于层次聚类算法:
CURE: |
采用抽样技术先对数据集D随机抽取样本,再采用分区技术对样本进行分区,然后对每个分区局部聚类,最后对局部聚类进行全局聚类 |
ROCK: |
也采用了随机抽样技术,该算法在计算两个对象的相似度时,同时考虑了周围对象的影响 |
CHEMALOEN(变色龙算法): |
首先由数据集构造成一个K-最近邻图Gk ,再通过一个图的划分算法将图Gk 划分成大量的子图,每个子图代表一个初始子簇,最后用一个凝聚的层次聚类算法反复合并子簇,找到真正的结果簇 |
SBAC: |
SBAC算法则在计算对象间相似度时,考虑了属性特征对于体现对象本质的重要程度,对于更能体现对象本质的属性赋予较高的权值 |
BIRCH: |
BIRCH算法利用树结构对数据集进行处理,叶结点存储一个聚类,用中心和半径表示,顺序处理每一个对象,并把它划分到距离最近的结点,该算法也可以作为其他聚类算法的预处理过程 |
BUBBLE: |
BUBBLE算法则把BIRCH算法的中心和半径概念推广到普通的距离空间 |
BUBBLE-FM: |
BUBBLE-FM算法通过减少距离的计算次数,提高了BUBBLE算法的效率 |
基于密度聚类算法:
DBSCAN: |
DBSCAN算法是一种典型的基于密度的聚类算法,该算法采用空间索引技术来搜索对象的邻域,引入了“核心对象”和“密度可达”等概念,从核心对象出发,把所有密度可达的对象组成一个簇 |
GDBSCAN: |
算法通过泛化DBSCAN算法中邻域的概念,以适应空间对象的特点 |
DBLASD: |
|
OPTICS: |
OPTICS算法结合了聚类的自动性和交互性,先生成聚类的次序,可以对不同的聚类设置不同的参数,来得到用户满意的结果 |
FDC: |
FDC算法通过构造k-d tree把整个数据空间划分成若干个矩形空间,当空间维数较少时可以大大提高DBSCAN的效率 |
基于网格的聚类算法:
STING: |
利用网格单元保存数据统计信息,从而实现多分辨率的聚类 |
WaveCluster: |
在聚类分析中引入了小波变换的原理,主要应用于信号处理领域。(备注:小波算法在信号处理,图形图像,加密解密等领域有重要应用,是一种比较高深和牛逼的东西) |
CLIQUE: |
是一种结合了网格和密度的聚类算法 |
OPTIGRID: |
基于神经网络的聚类算法:
自组织神经网络SOM: |
该方法的基本思想是--由外界输入不同的样本到人工的自组织映射网络中,一开始时,输入样本引起输出兴奋细胞的位置各不相同,但自组织后会形成一些细胞群,它们分别代表了输入样本,反映了输入样本的特征 |
基于统计学的聚类算法:
COBWeb: |
COBWeb是一个通用的概念聚类方法,它用分类树的形式表现层次聚类 |
CLASSIT: |
|
AutoClass: |
是以概率混合模型为基础,利用属性的概率分布来描述聚类,该方法能够处理混合型的数据,但要求各属性相互独立 |
---------------------------------------------------------
几种常用的聚类算法从可伸缩性、适合的数据类型、高维性(处理高维数据的能力)、异常数据的抗干扰度、聚类形状和算法效率6个方面进行了综合性能评价,评价结果如表1所示:
算法名称 |
可伸缩性 |
适合的数据类型 |
高维性 |
异常数据的抗干扰性 |
聚类形状 |
算法效率 |
WaveCluster |
很高 |
数值型 |
很高 |
较高 |
任意形状 |
很高 |
ROCK |
很高 |
混合型 |
很高 |
很高 |
任意形状 |
一般 |
BIRCH |
较高 |
数值型 |
较低 |
较低 |
球形 |
很高 |
CURE |
较高 |
数值型 |
一般 |
很高 |
任意形状 |
较高 |
K-Prototypes |
一般 |
混合型 |
较低 |
较低 |
任意形状 |
一般 |
DENCLUE |
较低 |
数值型 |
较高 |
一般 |
任意形状 |
较高 |
OptiGrid |
一般 |
数值型 |
较高 |
一般 |
任意形状 |
一般 |
CLIQUE |
较高 |
数值型 |
较高 |
较高 |
任意形状 |
较低 |
DBSCAN |
一般 |
数值型 |
较低 |
较高 |
任意形状 |
一般 |
CLARANS |
较低 |
数值型 |
较低 |
较高 |
球形 |
较低 |
四十八、负采样
负采样
训练一个神经网络意味着使用一个训练样本就要稍微调整一下所有的神经网络权重,这样才能够确保预测训练样本更加精确。换句话说,每个训练样本都会改变神经网络中的权重。
正如我们上面讨论的,单词表的大小意味着我们的skip-gram神经网络拥有非常庞大的权重数,所有权重都会被十亿个样本中的一个稍微地进行更新!
负采样通过使每一个训练样本仅仅改变一小部分的权重而不是所有权重,从而解决这个问题。下面介绍它是如何进行工作的。
当通过(”fox”, “quick”)词对来训练神经网络时,我们回想起这个神经网络的“标签”或者是“正确的输出”是一个one-hot向量。也就是说,对于神经网络中对应于”quick”这个单词的神经元对应为1,而其他上千个的输出神经元则对应为0。
使用负采样,我们通过随机选择一个较少数目(比如说5个)的“负”样本来更新对应的权重。(在这个条件下,“负”单词就是我们希望神经网络输出为0的神经元对应的单词)。并且我们仍然为我们的“正”单词更新对应的权重(也就是当前样本下”quick”对应的神经元)。
论文说选择5~20个单词对于较小的样本比较合适,而对于大样本,我们可以悬着2~5个单词。
回想一下,我们模型的输出层有大约300 x 10,000维度的权重矩阵。所以我们只需要更新正确的输出单词”quick”的权重,加上额外的5个其他应该输出为0的单词的权重。也就是总共6个输出神经元,和总共1800个的权重值。这些总共仅仅是输出层中3百万个权重中的0.06%。
在隐藏层中,只更新了输入单词对应的权重(不论你是否使用了复采样)。
选择负采样样本
“复采样样本”(也就是我们需要训练的五个输出为0单词)使用“一元分部”(“unigram distribution”)来进行选取。
从本质上来说,选择一个单词来作为负样本的概率取决于它出现频率,对于更经常出现的单词,我们将更倾向于选择它为负样本。
在使用C语言实现的词转向量(word2vec)中,你可以看到这个概率公式。每个单词都被给予一个等于它频率的权重(单词出现的数目)的3/4次方。选择某个单词的概率就是它的权重除以所有单词权重之和。
使用频率的3/4次方显然是根据经验来的;在他们的文章中,他们说到这个公式比其他函数的表现更为优秀。你可以通过在谷歌中输入: plot y = x^(3/4) and y = x并且调整焦距为x = [0, 1]范围。当我们增加数值一点点的时候它的图像有一点小弯曲。
使用C语言来实现这个样本选择的实现很有意思。他们有一个1亿元素大小的数组(每一个都相当于一个一元模型的表格)。表格中通过索引来多次记录每一个在单词表中出现的单词,在这里单词指标大小通过 P(wi) * table_size 来表达。其次,为了切实选择一个负样本,你仅仅只需要创造一个0到1亿的随机整数样本,并且使用这个数字在表格中索引的单词。由于更高概率的单词在表格中出现的次数会更多,所以你将更倾向于选择到它们。
四十九、防止过拟合的方法
1. 正则l1l2
2. dropout(或者subsample)
3. 特征选择、特征降维
4. 增加数据
5. 早停
6. 调参(剪枝、增加分类平面等)
7. ensemble
五十、sigmoid的导数