机器学习简介1--概念和KNN

2019-04-24  本文已影响0人  Magnetor

从16年开始接触学习机器学习方向的各种知识,一直在学习,但却一直缺少总结。从本篇起,尝试总结下这几年自己学习过的一些经典算法。我会把文章分为两部分,尽可能让没有算法基础(非技术同学)和已有数学编程基础的同学都能有一些收获。

机器学习这个概念从14年再次火了起来。我们在总结机器学习,神经网络等知识前,有必要了解下机器学习的概念,以及机器学习目前到底可以做什么。机器学习(Machine Learning, ML)是一门多领域交叉学科,涉及概率论、统计学、逼近论凸分析算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。
上面是百度百科的官方解释。我们再low一点具体一点:机器学习的核心是“使用算法解析数据,从中学习,然后对世界上的某件事情做出决定或预测”。简单说就是,让算法总结数据,总结规律,然后用这个总结的数据规律来预测与数据相关的问题。我们知道,在计算机的世界中,有了二进制和逻辑运算(与或非),就可以表达所有的自然事务和规律。同样的在机器学习的世界里,是不是只要我们有了预测数据分类和逻辑的算法,就足以表述所有的逻辑?答案是肯定的或者说是类似的。

image.png

机器学习三种主要类型:监督学习、非监督学习和强化学习。

监督学习的两种主要类型是分类和回归。分类的作用就是,机器模型可以将数据划分成特定的两类。这里举个不太合适的简单例子,我们根据女性体重和身高,训练一个简单的分类模型。通过我们人为告诉机器美女数据样本的美丑,让模型总结,最终我们训练了一个鉴别美女和丑女的模型。当我们有一个新的女性的身高和体重的数据时,就可以让机器自动分类,判断这个女性是丑女或者美女了。这就是一个典型的分类问题。

回归是使用先前标记的数据,通过模型拟合数据,来预测将来的结果。这里也举个简单的例子。比如通过大量的历史房价涨跌数据,股票市场的涨跌数据,来拟合规律曲线,进而预测接下来的结果。这就是典型的回归问题。

在无监督学习中,数据都是没有标签的。无监督学习分为聚类和降维。聚类是算法根据数据的属性和特征,自发的把同类数据聚集在一起。我们还以上面鉴别妹子美丑为例。假如我们此时,只有大量的妹子们的身高和体重的数据,并没有见过她们,也没法判断那个身高和体重样本的妹子是美女。这种情况就是聚类算法擅长的。我们通过合适的聚类算法,可以把自发的把有相同特征的妹子,自动聚集在一起。仍然可以区分开,哪些是美女,哪些是丑女。

降维通过找到共同点来减少数据集的变量。大数据可视化使用降维来识别趋势和规则。降维的理解就更容易了。降维也常常用在计算机视觉的图片压缩上。核心就是保留图片的主要信息。

最后,强化学习使用机器的个人历史和经验来做出决定。与进化算法的思想基本一直。强化学习的经典应用是玩游戏。与监督和非监督学习不同,强化学习不涉及提供“正确的”答案或输出。他更像是进化算法的一种思路。

这里贴上这种非常经典的机器学习算法分类图。

image

传统机器学习的主要内容就包括这些。接下来我们一起从最常用的,分类算法看起。

常用的分类算法主要包括,KNN,Decision Tree,Naive Bayes,Logictic Regression,svm,Adaboost,GBDT等。本篇就介绍最经典的KNN算法。以KNN为例介绍机器学习从数据收集到模型训练,模型预测的过程。

首先我们一句话说明下KNN的思路:如果一个样本在特征空间中,k个最相似的样本中的大多数属于某一个类别,则该样本也属于这个类别。这个算法可以分为两个步骤:1. 找到与待预测样本最相近的k个样本 2. 查看这k个样本里,数量最多的那个类别。则待预测样本,属于数量最多的那个类别。这里举个简单直观的例子。

我们基于上面判断妹子美丑的例子来扩展。假设我们目前有一些这样的妹子数据{身高,体重,胸围,颜值等级}。(胸围A-D,我们用1-4表示。颜值的等级低,中,高,我们用1,2,3来表示),我们的目标是根据已有的数据,通过新来妹子的身高,体重和胸围,来预测此妹子的颜值等级。

我们假设已有的4个妹子数据如下。

妹子0 :{150,60,4,1},妹子1 :{160,60,3,2},妹子2 :{161,60,2,2},妹子2 :{170,60,4,3}。

现在有一个新妹子的数据,妹子5:{160,60,2}。我们需要根据此妹子160的身高,60kg的体重和B的胸围来预测妹子5的颜值。我们只需要计算出,妹子5距离最近的K个妹子,在看看样本数据中最多颜值等级是哪个,即得到妹子5的颜值等级。我们设定k==2,通过计算妹子5与每个妹子的距离,来选出距离最近的前两个妹子。

这里距离的计算我们采用最常见的L2距离,即欧氏距离。当然衡量距离的计算方法有多种,这里以L2欧氏距离为准。

image

第一步,可以计算出,距离最近的两个妹子是妹子1和妹子2。第二步,统计距离最近的两个妹子分别属于哪一类。类别个数最多的,即为妹子5的所属类型。很明显,这个妹子5也属于颜值中等的类型。

上面就是KNN的一个非常简洁的例子。在实际的工程应用中,我们的样本数据往往会非常多。理论上样本数据越多,K值较大,我们预测的结果也越准确。但是,数据样本过多,K值选取过大,往往会造成,计算量乘数倍的增加,使算法的运算速度大大下降。例如在电商中广泛应用的协同过滤算法,其一部分即为Knn的思想。也存在数据量大时,算法性能下降,怎么优化算法,这里暂不讨论。

非开发的同学如果已经理解了上面的入门例子,不想再深究下面的代码,可以不用再继续看下去。这里我会给出一个入门级的knn算法python实现。如需要其他语言版本可在下方留言。

首先我们采用sklearn包自带的例子数据和knn实现方法:


from sklearnimport neighbors

from sklearnimport datasets

knn = neighbors.KNeighborsClassifier()

iris = datasets.load_iris()

knn.fit(iris.data,iris.target)

predictedLabel = knn.predict([[0.1,0.2,0.3,0.4]])

print(iris.target_names[predictedLabel])

通过调用datasets.load_iris(),我们可以获取一个150个样本的数据集,记录萼片长度,萼片宽度,花瓣长度,花瓣宽度(sepal length, sepal width, petal length and petal width),对应Iris setosa, Iris versicolor, Iris virginica类别。调用knn.predict([[0.1,0.2,0.3,0.4]]),内部会将该测试数据与所有数据求欧氏距离,然后取K个最近点,投票,算得最后的类别。

这里是采用了sklearn自带的样本数据和KNN实现。如果有兴趣可以点进KNeighborsClassifier去阅读下框架的实现代码。下面给出机器学习实战中的一个简单实现代码。(我做了一点调整,把代码改成了python3版本)

这里不太方便上传附件测试数据,我把数据格式做个说明。其中数据一共有4个熟悉,样本为男士。前三个属性代表样本的每年飞行里程数,玩游戏所占时间比,每周吃的冰激凌数。第四列代表男性的魅力值,没有魅力,一般,极有魅力。

数据样例如下:

40920 8.326976 0.953952 3

14488 7.153469 1.673904 2

26052 1.441871 0.805124 1

代码如下:


from numpyimport *

import operator

from osimport listdir

def classify0(inX, dataSet, labels, k):

dataSetSize = dataSet.shape[0]

diffMat = tile(inX, (dataSetSize,1)) - dataSet

sqDiffMat = diffMat **2

    sqDistances = sqDiffMat.sum(axis=1)

distances = sqDistances **0.5

    sortedDistIndicies = distances.argsort()

classCount = {}

for iin range(k):

voteIlabel = labels[sortedDistIndicies[i]]

classCount[voteIlabel] = classCount.get(voteIlabel,0) +1

    sortedClassCount =sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)

return sortedClassCount[0][0]

def createDataSet():

group = array([[1.0,1.1], [1.0,1.0], [0,0], [0,0.1]])

labels = ['A','A','B','B']

return group, labels

def file2matrix(filename):

fr =open(filename)

numberOfLines = len(fr.readlines())# get the number of lines in the file

    returnMat = zeros((numberOfLines,3))# prepare matrix to return

    classLabelVector = []# prepare labels return

    fr =open(filename)

index =0

    for linein fr.readlines():

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):

minVals = dataSet.min(0)

maxVals = dataSet.max(0)

ranges = maxVals - minVals

normDataSet = zeros(shape(dataSet))

m = dataSet.shape[0]

normDataSet = dataSet - tile(minVals, (m,1))

normDataSet = normDataSet / tile(ranges, (m,1))# element wise divide

    return normDataSet, ranges, minVals

def datingClassTest():

hoRatio =0.50  # hold out 10%

    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')# load data setfrom file

    normMat, ranges, minVals = autoNorm(datingDataMat)

m = normMat.shape[0]

numTestVecs =int(m * hoRatio)

errorCount =0.0

    for iin range(numTestVecs):

classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m],3)

print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))

if (classifierResult != datingLabels[i]): errorCount +=1.0

    print("the total error rate is: %f" % (errorCount /float(numTestVecs)))

print(errorCount)

def img2vector(filename):

returnVect = zeros((1,1024))

fr =open(filename)

for iin range(32):

lineStr = fr.readline()

for jin range(32):

returnVect[0,32 * i + j] =int(lineStr[j])

return returnVect

def handwritingClassTest():

hwLabels = []

trainingFileList = listdir('trainingDigits')# load the training set

    m = len(trainingFileList)

trainingMat = zeros((m,1024))

for iin range(m):

fileNameStr = trainingFileList[i]

fileStr = fileNameStr.split('.')[0]# take off .txt

        classNumStr =int(fileStr.split('_')[0])

hwLabels.append(classNumStr)

trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr)

testFileList = listdir('testDigits')# iterate through the test set

    errorCount =0.0

    mTest = len(testFileList)

for iin range(mTest):

fileNameStr = testFileList[i]

fileStr = fileNameStr.split('.')[0]# take off .txt

        classNumStr =int(fileStr.split('_')[0])

vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)

classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels,3)

print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))

if (classifierResult != classNumStr): errorCount +=1.0

    print("\nthe total number of errors is: %d" % errorCount)

print("\nthe total error rate is: %f" % (errorCount /float(mTest)))

datingClassTest()

如果对代码部分有不理解的同学,欢迎在下面评论。我会一一解答。

相信通过这个例子,大家已经对基本的Knn算法有所认识。Knn实际也有许多其他的变种和回归应用。更多更深入的应用,大家可以去参考sk框架的实现源码。

下一章,我会总结下经典的墒增原理和决策树的算法原理以及剪枝操作。照例把文章分为两部分,前半段非程序同学以及后半段的代码实例讲解部分。

上一篇下一篇

猜你喜欢

热点阅读