机器学习入门

现在入门可能都晚了

机器学习历史

1956 年提出 AI 概念,短短3年后(1959)Arthur Samuel就提出了机器学习的概念.

机器学习研究和构建的是一种特殊算法(而非某一个特定的算法),能够让计算机自己在数据中学习从而进行预测。

所以,机器学习不是某种具体的算法,而是很多算法的统称。

此外还有一个经典概念.

假设用 P 来评估计算机程序在某任务类 T 上的性能,若一个程序利用经验 E 在任务 T 上获得了性能改善,则我们就说关于 T 和 P, 该程序对 E 进行了学习。

机器学习中一些流行的任务 T 包括:

  • 分类:基于特征将实例分为某一类。
  • 回归:基于实例的其他特征预测该实例的数值型目标特征。
  • 聚类:基于实例的特征实现实例的分组,从而让组内成员比组间成员更为相似。
  • 异常检测:寻找与其他样本或组内实例有很大区别的实例。
  • 其他更多任务

经验 E 指的是数据(没有数据我们什么也干不了)。根据训练方式,机器学习算法可以分为监督(supervised)和无监督(unsupervised)两类。无监督学习需要训练含有很多特征的数据集,然后学习出这个数据集上有用的结构性质。而监督学习的数据集除了含有很多特征外,它的每个样本都要有一个标签(label)或目标(target)

机器学习包含了很多种不同的算法,深度学习就是其中之一,其他方法包括决策树,聚类,贝叶斯等。

需要的知识:学会Numpy,matplotlib,seaborn,pandas和scipy.基本的一些方法要知道同时要知道如何查阅文档,这个可能更重要.

同时需要一些基础的数学知识.

监督学习:regression和classification.

无监督学习:clustering和密度估计.

一般步骤

  1. 收集数据

    利用爬虫或是已有数据得到一般的未处理的文本文件等 格式可以为json,csv,xml或者一般的txt.

  2. 准备数据

    使用python解析文本文件,一般利用简单的open读取,pandas等能够对所有数据进行解析.

    目的得到数据的特征值和目标向量.

  3. 分析数据
    使用matplotlib等可视化数据进行初步分析(通常需要得到二维扩散图)

  4. 训练算法
    后面会提到

  5. 测试算法
    使用测试数据作为测试样本,通过这一步得到算法的正确率

  6. 使用算法
    输入数据判断

Classification

进行分类 标称值

KNN

第一个分类器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import operator
import numpy as np

def createDataSet():
group = np.array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]]) #创建 numpy数组 特征值
labels = ['A', 'A', 'B', 'B'] #目标变量
return group, labels


def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0] #获得数据集的数目
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet #inX是分类向量(1X2) 列数为特征数 广播后与数据集相减
sqDiffMat = diffMat ** 2 #每个值平方
sqDistances = sqDiffMat.sum(axis=1) #返回一个List,值是每一行值相加 相当于得到每一个点与需要测试点的距离(还未开根)
distances = sqDistances ** 0.5 #开根
sortedDistIndices = distances.argsort() #返回一个list 值是输入数组的值从小到大的索引 相当于按照距离给值排序
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndices[i]] #取得最近的第i个值
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 #个数+1
sortdClassCount = sorted(classCount.items(),
key=operator.itemgetter(1), reverse=True) #排序 返回一个List
return sortdClassCount[0][0]

解析数据

假设我们已经有了文本或是其他格式的数据,需要用python解析数据将特征和标签提取出来转为numpy格式.

下面是从文本中提取.格式为

1
value	value 	value	label
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def file2matrix(filename):
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines)
returnMat = np.zeros((numberOfLines,3)) #3个特征
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat,classLabelVector

分析数据

利用matplotlib可视化

1
2
3
4
5
6
scatter = plt.scatter(datingDataMat[:,1],datingDataMat[:,2],15*np.array(labelvector),12*np.array(labelvector))
i, j = scatter.legend_elements()
# print(i, j)
j = ['$\\mathdefault{不受欢迎}$', '$\\mathdefault{受欢迎}$', '$\\mathdefault{一般}$']
ax.legend(i,j,loc='best')
plt.show()

准备数据

归一化

一个样本有多个特征,这些特征的值是不一样的,有些可能一般的值是几十左右,但是其他特征一般的值要高上很大的数量级,但这些特征是等价的.我们需要特征归一化,将取值范围缩小.比如均缩为(0,1)

1
newvalue = (oldValue-min)/(max-min)
1
2
3
4
5
6
7
8
9
def autonorm(dataSet):
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = np.zeros(dataSet.shape)
m = dataSet.shape[0]
normDataSet = dataSet - np.tile(minVals,(m,1))
normDataSet = normDataSet/np.tile(ranges,(m,1))
return normDataSet,ranges,minVals

测试算法

评估算法的正确率

将已有数据的一部分用来训练(在KNN这里不需要训练),另一部分用来测试错误率,即这个算法是否优秀

1
2
3
4
5
6
7
8
9
10
11
12
13
def datingClassTest():
hoRatio = 0.1 #测试数据 10%
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
normMat,ranges,minVals = autonorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m*hoRatio)
errorCount = 0.0
for i in 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
print("the total error rate is:%f" %(errorCount/float(numTestVecs)))

使用算法

当测试算法后即可直接使用了,输入自己的数据预测

1
2
3
4
5
6
7
8
9
10
def classifyPerson():
resultList = ['not at all','in small doses','in large doses']
percentTats = float(input("percentage of time spent playing games?"))
ffMiles = float(input("frequent flier miles earned per year?"))
iceCream = float(input("liters of ice cream consumed per year?"))
datingDataMat,datingLabels = file2matrix("./datingTestSet2.txt")
normMat,ranges,minVals = autonorm(datingDataMat)
inArr = np.array([ffMiles,percentTats,iceCream])
classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
print("you will probably look like this person:",resultList[classifierResult-1])

这样一个分类器就实现了.不过比较简单而且是KNN,没有经过算法训练.

手写识别系统

步骤:

  1. 收集数据 提供文本文件
  2. 准备数据 编写函数img2vector() 将图像格式转为分类器使用的向量
  3. 分析数据
  4. 训练算法,knn不需要
  5. 测试算法
  6. 使用算法

手写识别也就是识别图像,而图像的特征可以有很多.

这里识别3232的图像,将每个像素当作特征,也就是一个样本数据是1\1024的向量

首先编写函数3232的二度图转为1\1024的一个样本,特征有1024个

1
2
3
4
5
6
7
8
def img2vector(filename):
returnVect = np.zeros((1, 1024))
with open(filename, "r+") as f:
for i in range(32):
lineStr = f.readline()
for j in range(32):
returnVect[0, i * 32 + j] = int(lineStr[j])
return returnVect

这样一转化就跟上面一个例子类似了.

然后只要根据已给数据得到特征集和对应label

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def handwritingClassTest():
hwLabel = []
trainingDataFileList = os.listdir("trainingDigits")
# print(trainingDataFileList)
m = len(trainingDataFileList)
trainingMat = np.zeros((m, 1024)) # 数据集 m个样本 1024个特征
for i in range(m):
fileNameStr = trainingDataFileList[i]
fileStr = fileNameStr.split('.')[0]
classNumStr = fileStr.split('_')[0]
hwLabel.append(int(classNumStr)) #label 目标向量
trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr) #得到每一个样本的特征
testFileList = os.listdir('testDigits')
errorCount = 0
mTest = len(testFileList)
for i in range(mTest): #类似的处理流程 通过得到结果进行比较
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileNameStr.split('_')[0])
vectorUnderTest = img2vector("testDigits/%s" % fileNameStr)
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabel, 3)
print("the classifier came back with:%d,and the real answer is %s" % (classifierResult, classNumStr))
if classifierResult != classNumStr:
errorCount += 1
print("the total number of errors is %d\n" % errorCount)
print("the total error rate is %f\n" % (errorCount / float(mTest)))

因为特征值都是0或1,在一个量级不需要归一化.

通过上面的KNN学习,可以了解到KNN的时间和空间效率并不高,需要改进.

特点:简单有效,使用算法时必须有接近实际数据的训练样本数据.必须保存全部数据集,必须对每个数据计算距离值,实际使用时可能非常耗时.

决策树

不好意思鸽了这么久

决策树常常是专家经验的概括,是一种分享特定过程知识的方式。例如,在引入可扩展机器学习算法之前,银行业的信用评分任务是由专家解决的,能否放贷是基于一些直观(或经验)的规则,这些规则就可以表示为决策树的形式.它合并一连串逻辑规则,使之成为一个树形的数据结构,这些规则的形式为「特征 a 的值小于 x,特征 b 的值小于 y … => 类别 1」

决策树

可以简单地发现,决策树可以认为是一种状态图.

根据不同的决策剔除选项.那么如何判断哪些决策能剔除更多的选项呢?

重要概念

熵是一个在物理、信息论和其他领域中广泛应用的重要概念,可以衡量获得的信息量。

对于具有 N 种可能状态的系统而言,熵定义为

其中,$p_i$ 是系统位于第 i 个状态的概率。熵可以描述为系统的混沌程度,熵越高,系统的有序性越差,反之亦然。

信息增益

熵的下降被称为信息增益

对数据进行分组后,对每一组进行熵的计算,再将每组的熵乘以该组所占的比例.得到的就是分组后的熵

所以决策树的构建就很重要.需要避免过拟合的问题.为了避免过拟合,直到熵为某个较小的值。不同的算法使用不同的推断,通过「提前停止」或「截断」以避免构建出过拟合的树.

不同的决策树构建算法依据的指标不一样.

C4.5是信息增益率,ID3是信息增益.同时还有基尼不确定性,$G = 1 - \sum\limits_k (p_k)^2$

错分率 $E = 1 - \max\limits_k p_k$

基尼不确定性和信息增益的效果差不多

二元分类熵的计算

基尼不确定性

1
2
3
4
5
6
7
8
9
10
11
12
plt.figure(figsize=(6, 4))
xx = np.linspace(0, 1, 50)
plt.plot(xx, [2 * x * (1-x) for x in xx], label='gini')
plt.plot(xx, [4 * x * (1-x) for x in xx], label='2*gini')
plt.plot(xx, [-x * np.log2(x) - (1-x) * np.log2(1 - x)
for x in xx], label='entropy')
plt.plot(xx, [1 - max(x, 1-x) for x in xx], label='missclass')
plt.plot(xx, [2 - 2 * max(x, 1-x) for x in xx], label='2*missclass')
plt.xlabel('p+')
plt.ylabel('criterion')
plt.title('Criteria of quality as a function of p+ (binary classification)')
plt.legend()

区分不同的标准

附件

1936图灵 自动机理论

自动机有如下基本概念:

符号 :有某种意义或在这个机器上有效的任意数据(datum)。符号有时就叫做“字母”。

字:通过一些符号串接而形成的有限字符串。

字母表 :符号的有限集合。字母表经常指示为Sigma,它是在字母表中所有字母的集合。

语言 :字的集合,由给顶字母表中的符号形成。可以是也可以不是无限的。

学习资料

Cousera吴恩达的机器学习课程

很好的ai学习网站

《机器学习实战》python2.x

蓝桥云课程.

-------------本文结束感谢您的阅读-------------
感谢阅读.

欢迎关注我的其它发布渠道