机器学习-用代码打开AI的大门

511 阅读7分钟

1.KNN最邻近算法

K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一,有监督算法。该方法的思路是:如果一个样本在特征空间中的k个最相似的样本中的大多数属于某一个类别,则该样本也属于这个类别。KNN算法由你的邻居来推断出你的类别,KNN算法就是用距离来衡量样本之间的相似度

如果K = 3,绿色圆点的最近的3个邻居是2个红色小三角形和1个蓝色小正方形,少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于红色的三角形一类。

如果K = 5,绿色圆点的最近的5个邻居是2个红色三角形和3个蓝色的正方形,还是少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于蓝色的正方形一类。

K 值的选择,距离度量和分类决策规则是该算法的三个基本要素。K值的选择一般低于样本数据的平方根,一般是不大于20的整数。距离度量常用的有欧式距离,曼哈顿距离,余弦距离等,一般使用欧氏距离,对于文本分类,常用余弦距离。分类决策就是“少数服从多数”的策略。

2.KNN算法步骤:

  • 对于未知类别的数据(对象,点),计算已知类别数据集中的点到该点的距离。
  • 按照距离由小到大排序
  • 选取与当前点距离最小的K个点
  • 确定前K个点所在类别出现的概率
  • 返回当前K个点出现频率最高的类别作为当前点预测分类

3.KNN算法复杂度:

KNN 分类的计算复杂度和训练集中的文档数目成正比,也就是说,如果训练集中文档总数为 n,那么 KNN 的分类时间复杂度为O(n)

4.KNN问题:

该算法在分类时有个主要的不足是,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的 K 个邻居中大容量类的样本占多数。解决:可以采用权值的方法,根据和该样本距离的远近,对近邻进行加权,距离越小的邻居权值大,权重一般为距离平方的倒数

5.KNN数据归一化:

为了防止某一维度的数据的数值大小对距离计算产生影响,保证多个维度的特征是等权重的,最终结果不能被数值的大小影响,应该将各个维度进行数据的归一化,把数据归一化到[0,1]区间上

归一化公式:

6.距离度量

欧式距离

也称欧几里得距离,在一个N维度的空间里,求两个点的距离,这个距离肯定是一个大于等于零的数字,那么这个距离需要用两个点在各自维度上的坐标相减,平方后加和再开方。一维,二维,三维的欧式距离计算方法

一维

二维

三维

平方欧式距离

就是欧式距离的平方。

7.KNN案例

import numpy as np
import operator

def classify(normData,dataSet,labels,k):
    dataSetSize = dataSet.shape[0]
#     print 'dataSetSize 长度 =',dataSetSize
    #当前点到所有点的坐标差值
    diffMat = np.tile(normData, (dataSetSize,1)) - dataSet
    #对每个坐标差值平方
    sqDiffMat = diffMat ** 2
    #对于二维数组 sqDiffMat.sum(axis=0)指定对数组b对每列求和,sqDiffMat.sum(axis=1)是对每行求和
    sqDistances = sqDiffMat.sum(axis = 1)
    #欧式距离 最后开方
    distance = sqDistances ** 0.5
    #argsort() 将x中的元素从小到大排序,提取其对应的index 索引,返回数组
    sortedDistIndicies = distance.argsort()
#     classCount保存的K是魅力类型   V:在K个近邻中某一个类型的次数
    classCount = {}
    for i in range(k):
        #获取对应的下标的类别
        voteLabel = labels[sortedDistIndicies[i]]
        #给相同的类别次数计数
        classCount[voteLabel] = classCount.get(voteLabel,0) + 1
    sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]


def file2matrix(filename):
    fr = open(filename)
#     readlines:是一次性将这个文本的内容全部加载到内存中(列表)
    arrayOflines = fr.readlines()
    numOfLines = len(arrayOflines)
#     print "numOfLines = " , numOfLines
    #numpy.zeros 创建给定类型的矩阵  numOfLines 行 ,3列
    returnMat = np.zeros((numOfLines,3))
    classLabelVector = []
    index = 0
    for line in arrayOflines:
        #去掉一行的头尾空格
        line = line.strip()
        listFromline = line.split('\t')
        returnMat[index,:] = listFromline[0:3]
        classLabelVector.append(int(listFromline[-1]))
        index += 1
    return returnMat,classLabelVector
'''
    将训练集中的数据进行归一化
    归一化的目的:
        训练集中飞行公里数这一维度中的值是非常大,那么这个纬度值对于最终的计算结果(两点的距离)影响是非常大,
        远远超过其他的两个维度对于最终结果的影响
    实际约会姑娘认为这三个特征是同等重要的
    下面使用最大最小值归一化的方式将训练集中的数据进行归一化
'''

def autoNorm(dataSet):
#     dataSet.min(0)   代表的是统计这个矩阵中每一列的最小值     返回值是一个矩阵1*3矩阵
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    #dataSet.shape[0] 计算行数, shape[1] 计算列数
    m = dataSet.shape[0]
#     normDataSet存储归一化后的数据
#     normDataSet = np.zeros(np.shape(dataSet))
    #np.tile(minVals,(m,1)) 在行的方向上重复 minVals m次 即复制m行,在列的方向上重复munVals 1次,即复制1列
    normDataSet = dataSet - np.tile(minVals,(m,1))
    normDataSet = normDataSet / np.tile(ranges,(m,1))
    return normDataSet,ranges,minVals
    
def datingClassTest():
    hoRatio = 0.1
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
    #将数据归一化
    normMat,ranges,minVals = autoNorm(datingDataMat)
    # m 为行数 = 1000
    m = normMat.shape[0]
#     print 'm =%d 行'%m
    #取出100行数据测试
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        #normMat[i,:] 取出数据的第i行,normMat[numTestVecs:m,:]取出数据中的100行到1000行 作为训练集,datingLabels[numTestVecs:m] 取出数据中100行到1000行的类别,4是K
        classifierResult = classify(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],4)
        print '模型预测值: %d ,真实值 : %d' %(classifierResult,datingLabels[i])
        if (classifierResult != datingLabels[i]):
            errorCount += 1.0
    errorRate = errorCount / float(numTestVecs)
    print '正确率 : %f' %(1-errorRate)
    return 1-errorRate
    
def classifyperson():
    resultList = ['没感觉', '看起来还行','极具魅力']
    input_man= [30000,3,0.1]
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
    normMat,ranges,minVals = autoNorm(datingDataMat) 
    result = classify((input_man - minVals)/ranges,normMat,datingLabels,3)   
    print '你即将约会的人是:' ,  resultList[result-1]  
    
if __name__ == '__main__':
    acc = datingClassTest()
    if(acc > 0.9):
        classifyperson()

调用python 中 Scikit-learn 实现KNN算法:

from sklearn.neighbors import NearestNeighbors
import numpy as np
from KNNDateOnHand import *

datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
normMat,ranges,minVals = autoNorm(datingDataMat)
t作为训练集拟合模型 
nbrs = NearestNeighbors(n_neighbors=3).fit(normMat)  
input_man= [30000,3,2]
#数据归一化
S = (input_man - minVals)/ranges
#找到当前点的K个临近点,也就是找到临近的3个点
distances, indices = nbrs.kneighbors(S)
print indices  
print distances 
# classCount   K:类别名    V:这个类别中的样本出现的次数
classCount = {}
for i in range(3):应的索引的类别号
    voteLabel = datingLabels[indices[0][i]]
    classCount[voteLabel] = classCount.get(voteLabel,0) + 1
sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)
resultList = ['没感觉', '看起来还行','极具魅力']
print resultList[sortedClassCount[0][0]-1]

8.监督学习

1、监督式学习(Supervised learning),是一个机器学习中的方法,可以由训练资料中学到或建立一个模式( learning model),并依此模式推测新的实例。训练资料是由输入物件(通常是向量)和预期输出所组成。函数的输出可以是一个连续的值(称为回归分析),或是预测一个分类标签(称作分类)。
2.无监督式学习(Unsupervised Learning )是人工智能网络的一种算法(algorithm),其目的是去对原始资料进行分类,以便了解资料内部结构。有别于监督式学习网络,无监督式学习网络在学习时并不知道其分类结果是否正确,亦即没有受到监督式增强(告诉它何种学习是正确的)。其特点是仅对此种网络提供输入范例,而它会自动从这些范例中找出其潜在类别规则。当学习完毕并经测试后,也可以将之应用到新的案例上。