@spiritnotes
2016-04-08T10:33:51.000000Z
字数 19153
阅读 5662
机器学习
读书笔记
机器学习就是将无序的数据转换成有用的信息
特征或者属性通常是训练样本集的列,他们是独立测量得到的结果,多个特征联系在一起共同组成一个训练样本
知识表示,计算机算法通过学习获得的知识,某些算法可以产生很容易理解的知识表示,而某些算法的知识表示也许只能为计算机所理解
抽象取样样本集中特征最相似(最近邻)的数据的分类标签
归一化数据:将数据取值范围处理为0~1、-1~1之间。
信息的定义:待分类的事务可能处于多个类中,则符号的信息定义如下:
优点:在数据较少的情况下仍然有效,可以处理多类别问题;
缺点:对于输入数据的准备方式较为敏感;
适用数据类型:标称型数据
使用档词袋模型
利用逻辑回归进行分类的主要思想:根据现有数据对分类边界线建立回归公式,以此进行分类。
Sigmoid函数
Sigmoid输入值记为z
要找到函数的最大值,最好的办法是沿着该函数的梯度方向探寻
梯度上升用以求最大值,梯度下降用以求最小值
推导过程:
1.
2.
3. if y=1
if y=0
4.
5.
def sigmoid(inX):
return 1.0/(1+exp(-inX))
def gradAscent(dataMatIn, classLabels):
m,n = shape(dataMatrix)
alpha = 0.001
maxCycles = 500
weights = ones((n,1))
for k in range(maxCycles): #heavy on matrix operations
h = sigmoid(dataMatrix*weights) #matrix mult
error = (labelMat - h) #vector subtraction
weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
return weights
随机梯度上升是一个在线学习算法,只使用一个样本来更改回归系数
- alpha每次迭代的时候都会调整,会缓解数据波动或者高频波动;j<
- 随机选择样本来更新回归系数
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = shape(dataMatrix)
weights = ones(n) #initialize to all ones
for j in range(numIter):
dataIndex = range(m)
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001 #apha decreases with iteration, does not
randIndex = int(random.uniform(0,len(dataIndex)))#go to 0 because of the constant
h = sigmoid(sum(dataMatrix[randIndex]*weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex])
return weights
可选做法:
本处选择用0作为缺失值:
如果标签数据缺失,则可以简单丢弃该数据
随机梯度上升法与梯度上升法相当,但占用更少的计算资源。
关注支持向量机的SMO(序列最小优化:Sequential Minimal Optimization)实现
线性可分,分割超平面
希望找到离分割超平面最近的点,确保它们离分割面的距离尽可能远
间隔(margin):点到分隔面的距离
支持向量(support vector):离超平面最近的那些点
需要最大化支持向量到分割面的距离
A点到超平面的法线的长度:
使用单位阶跃函数对 作用使其标签值为-1()或者+1(),这样计算间隔就可以采用
现在目标是为了找出分类器的 w 和 b:
收集数据:任意
准备数据:需要数值型数据
分析数据:有利于可视化分割超平面
训练算法:SVM的大部分时间都源自训练,该过程主要实现两个参数的调优
测试算法:十分简单的计算过程可以实现
使用算法:几乎所有分类问题都可以使用SVM,值得一提的是,SVM本身是一个二类分类器,对多类问题应用SVM需要对代码做一些修改
工作原理:每次循环中选择两个alpha进行优化处理,一旦找到一系列alpha和b
SMO伪代码
核函数:将低维特征空间映射到高维空间。SVM所有的运算都写成内积的形式,而直接将内积运算替换成核函数,称为核技巧。
高斯函数,径向基函数的一种。
支持向量过少就会得到一个很差的决策边界。支持向量太多,也就相当于每次利用整个数据集进行分类,相当于k近邻。
元算法是对其他算法进行组合的一种方式
优点:泛化错误率低,易编码,可以应用在大部分分类器上,无参数调整
缺点:对离群点敏感
适用数据类型:数值型和标称型数据
AdaBoost(adaptive boosting)的一般流程:
收集数据:任意
准备数据:依赖于所使用的弱分类器类型。作为弱分类器,简单分类器的效果更好
分析数据:任意
训练算法:大部分时间用于训练,分类器将多次在同一数据集上训练弱分类器
测试算法:计算分类的错误率
使用算法:预测两个分类中的一个。如果需要应用到多个分类,则需要修改
自举汇聚法,是从原始数据集选择S词后得到S个新数据集的一种技术。新数据集与原始数据集大小相等。每个数据集都是通过在原始数据集中随机选择一个样本来进行替换而得到的。这里的替换意味着可以多次地选择同一样本。当需要对新数据进行分类时,则使用上面S个数据集训练的分类器进行分类,选择投票结果中最多的类别作为结果。
与bagging类似,多个分类器的类型都是一样的。boosting中,不同的分类器是通过串行训练而获得的,每个新分类器都根据已训练出的分类器的性能来进行训练。boosting是通过集中关注被已有分类器错分的那些数据来获得新的分类器。boosting分类中各个分类器的权重是不一样的。
弱分类器:分类器性能比随机猜测要好,但是也不会好太多
对每个分类器定义一个权重alpha,错误率epsion
单层决策树(decision stump,也称决策树桩),是一种简单的决策树。
针对每个特征,每个步长来选择合适的分割点,使其以该特征该分割点分割的数据具有最小的错误率。
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):#just classify the data
retArray = ones((shape(dataMatrix)[0],1))
if threshIneq == 'lt':
retArray[dataMatrix[:,dimen] <= threshVal] = -1.0
else:
retArray[dataMatrix[:,dimen] > threshVal] = -1.0
return retArray
def buildStump(dataArr,classLabels,D):
dataMatrix = mat(dataArr); labelMat = mat(classLabels).T
m,n = shape(dataMatrix)
numSteps = 10.0; bestStump = {}; bestClasEst = mat(zeros((m,1)))
minError = inf #init error sum, to +infinity
for i in range(n):#loop over all dimensions
rangeMin = dataMatrix[:,i].min(); rangeMax = dataMatrix[:,i].max();
stepSize = (rangeMax-rangeMin)/numSteps
for j in range(-1,int(numSteps)+1):#loop over all range in current dimension
for inequal in ['lt', 'gt']: #go over less than and greater than
threshVal = (rangeMin + float(j) * stepSize)
predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)#call stump classify with i, j, lessThan
errArr = mat(ones((m,1)))
errArr[predictedVals == labelMat] = 0
weightedError = D.T*errArr #calc total error multiplied by D
#print "split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, threshVal, inequal, weightedError)
if weightedError < minError:
minError = weightedError
bestClasEst = predictedVals.copy()
bestStump['dim'] = i
bestStump['thresh'] = threshVal
bestStump['ineq'] = inequal
return bestStump,minError,bestClasEst
对每次迭代:
利用buildStump函数找到最佳的单层决策树
将最佳单层决策树加入到单层决策树数组
计算alpha
计算新的权重向量D
更新累计类别估计值
如果错误率等于0.0,则退出循环
classEst = clster.predict(X)
expon = multiply(-1*alpha*mat(Y).T, classEst)
D = multiply(D, exp(expon))
D = D / D.sum()
aggclassest += alpha * classEst
aggerror = multiply(sign(aggclassest) != mat(Y).T, ones((m,1)))
errorrate = aggerrors.sum() / m
if errorate == 0: break
通过所有的分类器进行预测,其结果与权重内积再取符号
马得疝病是否会死亡预测
AdaBoost测试错误率在达到一个最小值后随着分类器的个数增加变差了,发生了过拟合。对于好的数据集来说,AdaBoost算法会稳定在一个错误率,而不会再变大。AdaBoost与SVM是监督学习中最强大的两种算法。
可以使用混淆矩阵(confusion matrix)来了解分类中的错误。
正确率: TP/(TP+FP)
召回率: TP/(TP+FN)
ROC曲线(接受者操作特征 receiver operating characteristic):横轴为假阳率(FP/(FP+TN),阴判断为阳性的比例),纵轴为真阳率(TP/(TP+FN),实际阳中判断为阳的比例)
AUC(Area Unser the Curve),ROC曲线下的面积,完美分类器为1,随机猜测为0.5。
为了画ROC,分类器必须提供每个样例被判为阳性或者阴性的可信程度值。朴素贝叶斯,逻辑回归中输入sigmod函数中的值,Adaboost和SVM传递给sign函数的值。
创建算法:
将所有预测按照预测强度排序
从最低点开始(也即是之前的点判为负例,之后判为正例,也即是全判正),此时点为 1, 1
以正例的个数作为Y轴的最大的长度,1/num_pos作为步长,1/num_neg为X轴步长
依次移动分界线,也即是真阳率每次下降一个步长,计算伪阳率,从右上往下画图
AUC: ysum*xstep
调节分类器输出阀值
代价敏感的学习(cost sensitive learning)
正常代价为 TP*0 + FN*1 + FP*1 + TN*0
可调整为 TP*-5 + FN*1 + FP*50 + TN*0
分类算法中引入代价信息:
AdaBoost中,基于代价函数来调整错误权重向量D
朴素贝叶斯中,可以选择具有最小期望而不是最大概率的类作为输出结果
SVM中,可以在代价函数中对于不同的类别选择不同的参数C
以上做法都会给较小类更多的权重,即训练时,小类中只允许更少的错误
欠抽样(undersampling):删除部分样例
过抽样(oversampling):复制部分样例
XTX = xMat.T*xMat
if linalg.det(XTX) == 0.0: #奇异矩阵,不可逆
rasie ....
#可以使用 ws = linalg.solve(xTx, xMat.T*yMatT)
可以通过相关系数来查看预测y,与实际y的相关系数
corrcoef(yEstimate, yActual)
LWLR需要针对每一个点都要进行整个数据集的耦合。
采用rsserror来计算在新数据上的误差
如果数据的特征比样本点还多,则其输入矩阵不是满秩矩阵,求逆会出问题
岭回归是在矩阵XTX上加一个矩阵使其非奇异。其中I为m×m的单位矩阵,对角线上元素全是1,其他全为0.
lambda的计算,是通过交叉验证,看lambda的取值最佳值。首先需要对数据进行标准化,原值-均值/方差,保证所有特征维度一致
增加约束就会得到岭公式
lasso方法为增加约束,其结果在lambda足够小的时候就会有一些系数缩减到0.可以帮忙理解数据。lasso需要采用二次规划算法解决。
属于贪心算法,即每一步尽量减少误差。刚开始,所有的权重设置为1,每一步所做的决策就是将某个权重增加或者减少一个很小的值,最大迭代次数设定。
迭代次数越多与线性回归越接近。步长过长则会容易导致震荡。
逐步线性回归算法可以帮忙人们理解现有模型并做出改进,可以找出重要的特征,并停止那些不重要特征的收集。
用于测试,该算法可以每100次迭代后构建一个模型,交叉验证,最终选择使误差最小化的模型。
训练误差和测试误差之间由三部分组成:偏差、随机误差和随机噪声。
方差可以度量,例如从数据中取一个随机样本集,用线性模型拟合,得出一组回归系数。同样再取另一组,进行拟合,两者系数的差异大小就是模型方差大小的反映。
使用Google购物的API
决策树不断将数据切分成小数据集,直到所有目标变量完全相同,或者数据不能再切分为止。决策树是一种贪心算法,在给定时间内作出最佳选择,并不关心能否达到全局最优。
CART使用二元切分来处理连续型变量。对CART稍作修改就可以处理回归问题。
构建算法:
回归树假设叶节点是常数值,这种策略认为数据中的复杂关系可以用树结构来概括。
通过降低决策树的复杂度来避免过拟合的过程称为剪枝。
预剪枝通过算法中的参数min_sample_num, min_delta_error来进行控制
后剪枝方法将数据集分成测试集和训练集。首先指定参数,使得构建出来的树足够大、足够复杂,便于剪枝。接下来从上而下找到叶节点,用测试集判断将这些叶节点合并能否降低测试误差,如果是就合并。
除了可以把叶节点设置为常数值外,还可以将叶节点设置为分段线性函数(piecewise linear),所谓的分段线性是指模型由多个线性片段组成。
叶节点产生为函数
def model_leaf(dataset):
ws, x, y = linesolve(dataset)
return ws
def model_error(dataset):
ws, x, y = linesolve(dataset)
yhat = x*ws
return sum(power(y - yhat, 2)
回归判断哪个模型好:
用y与预测y计算相关性进行判断, corrcoef
树回归方法一般比标准回归更有效
聚类是一种无监督的学习,它将相似的对象归到同一个簇中。有点像全自动分类,聚类方法几乎可以应用于所有对象,簇内的对象越相似,聚类的效果越好。簇识别(cluster identification)给出聚类结果的含义。
聚类分析试图将相似对象归入同一簇,将不相似对象归到不同簇。相似这一概念取决于所选择的相似度计算方法。
优点:容易实现
缺点:可能收敛到局部最小值,在大规模数据集上收敛较慢
适用数据类型:数值型数据
伪代码:
K均值收敛但是聚类效果差的原因是,K-均值算法收敛到了局部最小值,而非全局最小值。
用于度量聚类效果的指标是SSE(Sum of Squared Error,误差平方和),SSE值越小表示数据点越接近于它们的质心,聚类效果也越好。对误差取了平方,因此更加重视那些远离中心的点。可以通过降低SSE值的方法是增加簇的个数,但违背聚类的目标。聚类的目标是在保持簇数目不变的情况下提高簇的质量。
将具有最大SSE值的簇划分成两个簇。具体实现时可以将最大簇包含的点过滤出来并在这些点上运行K-均值算法,k为2.
首先将所有点作为一个簇继续进行划分,选择哪一个簇进行划分取决于对其划分是否可以最大程度降低SSE的值,上述划分过程不断重复,直到用户指定的簇数目为止
伪代码:
采用经纬度进行计算
从大规模数据集中寻找物品间的隐含关系被称为关联分析(association analysis)或者关联规则学习(association rule learning)。
某个项集是频繁的,那么它的所有子集也是频繁的。反过来说,如果一个项集是非频繁集,那么它所有的超集也是非频繁的。
Apriori算法是发现频繁项集的一种方法。Apriori算法的输入参数分别是最小支持度和数据集。首先生成所有单个物品的频繁项集列表,接着扫描交易记录来查看哪些项集满足最小支持度要求,那么不满足的的集合被去掉,对剩下的集合进行组合以生成包含两个元素的项集。重新扫描,去除。。。
数据集扫描伪代码:
Apriori算法伪代码:
生成新集合的伪代码:
只比较k-1个项的目的,假设能够生成某k+1项集,则当前项集集合中会存在k+1个项集,而这k+1个项集是只对应于该k+1项集,如果L1,L2为排序的话,则只有一种会存在L1和L2中前k-1相同,即[1,...,k-1,k]和[1,...,k-1,k+1],而其他情况下两者的不同不会是最后一位。
前件 后件
规则的可信度定义为
如果某条规则不满足最小可信度要求,则该规则的前件的所有子集以及后件的超集都不会满足可信度要求
生成规则的方法:分级法
通过发现蘑菇有毒的频繁集来发现相关特征
FP-growth算法发现频繁项集的基本过程如下:
1. 构建FP树
2. 从FP树中挖掘频繁项集
一个元素可以在FP树中出现多次。FP树会存储项集的出现频率,而每个项集以路径的方式存储在树中。存在相似元素的集合会共享树的一部分。只有当集合完全不同时才会分叉。树节点上给出集合中单个元素以及其在序列中出现的次数,路径给出该序列的出现次数。
创建一个树node类
在构建前,需要按照绝对出现频率排序。从空集开始,向其不断添加频繁项集。过滤、排序后的事务依次添加到树中,如果树中已存在现有元素,则增加现有元素的值,如果现有元素不存在,则向树中添加一个分支。
条件模式基是以所查找元素项为结尾的路径集合。每一条路径其实是一条前缀路径(prefix path),是介于所查找元素项与树根节点之间的所有内容。可以通过FP树的头表达到计算该元素的所有前缀路径。
对于每一个频繁项,都要创建一个条件FP树。
def mineTree(inTree, headerTable, minSup, preFix, freqItemList):
bigL = [v[0] for v in sorted(headerTable.items(), key=lambda p: p[1])]#(sort header table)
for basePat in bigL: #start from bottom of header table
newFreqSet = preFix.copy()
newFreqSet.add(basePat)
#print 'finalFrequent Item: ',newFreqSet #append to set
freqItemList.append(newFreqSet)
condPattBases = findPrefixPath(basePat, headerTable[basePat][1])
#print 'condPattBases :',basePat, condPattBases
#2. construct cond FP-tree from cond. pattern base
myCondTree, myHead = createTree(condPattBases, minSup)
#print 'head from conditional tree: ', myHead
if myHead != None: #3. mine cond. FP-tree
#print 'conditional tree for: ',newFreqSet
#myCondTree.disp(1)
mineTree(myCondTree, myHead, minSup, newFreqSet, freqItemList)
采用kosarak数据,Hungarian online news portal clickstream
http://fimi.ua.ac.be/data/
人们看电视将电视屏幕的百万像素点维度转换成了实际的空间三维。在低维下,数据更易于处理。其相关特征可能在数据中明确地显示出来。
PCA(Principal Component Analysis,主成分分析)。在PCA中,数据从原来的坐标系转换到了新的坐标系,新坐标的选择由数据本身确定。第一个新坐标轴选择的是原始数据中方差最大的方向,第二个选择的是和第一个坐标轴正交且具有最大方差的方向。该过程一直重复,次数为原始数据中特征的数目。
因子分析(Factor Analysis)。假设在观察数据的生成中有一些观察不到的隐变量(latent variable)。假设观测数据是这些隐变量和某些噪声的线性组合。那么隐变量的数据可能比观测数据的数目少。
独立成因分析(Independent Component Analysis,ICA)。假设数据是从n个数据源生成的。假设数据为多个源的混合观测结果。这些数据源在统计上是相互独立的。如果数据源的数目少于观察数据的数目,则可以实现降维。
优点: 降低数据的复杂度,识别最重要的多个特征
缺点: 不一定需要,且可能损失有用信息
适用数据类型: 数值型数据
第一条坐标轴旋转到覆盖数据的最大方差位置,数据的最大方差给出了数据的最重要的信息。然后正交选择第二坐标轴。
坐标轴的旋转并没有减少数据的维度。通过PCA进行降维处理,我们可以同时获得SVM和决策树的优点:一方面,得到和决策树一样简单的分类器,同时分类和SVM一样好。
def pca(dataMat, topNfeat=9999999):
meanVals = mean(dataMat, axis=0)
meanRemoved = dataMat - meanVals #remove mean
covMat = cov(meanRemoved, rowvar=0)
eigVals,eigVects = linalg.eig(mat(covMat))
eigValInd = argsort(eigVals) #sort, sort goes smallest to largest
eigValInd = eigValInd[:-(topNfeat+1):-1] #cut off unwanted dimensions
redEigVects = eigVects[:,eigValInd] #reorganize eig vects largest to smallest
lowDDataMat = meanRemoved * redEigVects#transform data into new dimensions
reconMat = (lowDDataMat * redEigVects.T) + meanVals
return lowDDataMat, reconMat
可视化
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(data_mat[:,0],...)
ax.scatter(recon_mat[:,0],...)
uci上面secom数据集
for i in range(numfeat):
meanval = mean(dataMat[nonzero(~isnan(datamat[:,i].A))[0],i])
dataMat[nonzero(isnan(datamat[:,i].A))[0],i] = meanval
SVD(Singular Value Decomposition),奇异值分解。
优点:简化数据,去除噪声,提高算法的结果
缺点:数据的转化可能难以理解
适用数据类型:数值型数据
利用SVD实现,我们可以适用小得多的数据集来表示原始数据集。实际上是去除了噪声和冗余信息。
一个矩阵由文档和词语组成,应用SVD时,会构建出多个奇异值。这些奇异值代表了文档中的概念或主题,可以用于更高效的文档搜索。
推荐系统中的评分矩阵可以通过SVD划分为各种主题,例如计算机方面的书籍、经管方面的数据等是可以通过SVD发现的。
Netflix的获奖者就使用了SVD。
SVD将原始的聚则Data分解成三个矩阵
科学和工程中,一直存在这样一个普遍事实,在某个奇异值的数目(r个)后,其他的特征值都置为0。意味着数据集中仅有r个重要特征,而其余特征则是噪声或者冗余特征。
U,Sigma,VT = linalg.svd(data)
#Sigma理应为矩阵,在输出中为数组,只记录对角值
一般情况下是保留矩阵中90%的能量信息。将所有奇异值求平方,然后累计和到90%即可。另一种如果奇异值太多,可以保留前面的20%到30%。
协同过滤不关心物品的描述属性,而是严格地按照许多用户的观点来计算相似度。
根据具体的用户数和物品数来选择。
def svdEst(dataMat, user, simMeas, item):
n = shape(dataMat)[1]
simTotal = 0.0; ratSimTotal = 0.0
U,Sigma,VT = la.svd(dataMat)
Sig4 = mat(eye(4)*Sigma[:4]) #arrange Sig4 into a diagonal matrix
xformedItems = dataMat.T * U[:,:4] * Sig4.I #create transformed items
for j in range(n):
userRating = dataMat[user,j]
if userRating == 0 or j==item: continue
similarity = simMeas(xformedItems[item,:].T,\
xformedItems[j,:].T)
print 'the %d and %d similarity is: %f' % (item, j, similarity)
simTotal += similarity
ratSimTotal += similarity * userRating
if simTotal == 0: return 0
else: return ratSimTotal/simTotal
对手写体图片进行压缩
def imgCompress(numSV=3, thresh=0.8):
myl = []
for line in open('0_5.txt').readlines():
newRow = []
for i in range(32):
newRow.append(int(line[i]))
myl.append(newRow)
myMat = mat(myl)
print "****original matrix******"
printMat(myMat, thresh)
U,Sigma,VT = la.svd(myMat)
SigRecon = mat(zeros((numSV, numSV)))
for k in range(numSV):#construct diagonal matrix from vector
SigRecon[k,k] = Sigma[k]
reconMat = U[:,:numSV]*SigRecon*VT[:numSV,:]
print "****reconstructed matrix using %d singular values******" % numSV
printMat(reconMat, thresh)
只需要使用2个奇异值就可以重构图像,而实际的空间需要为U(32*2),VT(32*2),为2。
优点:可在短时间内完成大量工作
缺点:算法必须经过重写,需要对系统工程有一定的了解
适用数据类型:数值型和标称型数据
学习要点:
Hadoop可以使用其余语言在Hadoop流上运行
mapper产生:
reducer:
cumVal=0.0
cumSumSq=0.0
cumN=0.0
for instance in mapperOut:
nj = float(instance[0])
cumN += nj
cumVal += nj*float(instance[1])
cumSumSq += nj*float(instance[2])
#calculate means
mean = cumVal/cumN
meanSq = cumSumSq/cumN
varsum = (cumSumSq - 2*mean*cumval + cumN*mean*mean)/cumM
一般情况下是不需要MapReduce的
包括两种数据结构
array数组
matrix矩阵
矩阵的元素之间相乘使用np.multipy
向量范数会给予向量赋予一个正标量值