机器学习 Machine Learning
- 1 基础
- 2 基本概念
- 3 监督学习-分类
1 基础
基础知识(Basic Concepts)
训练集,测试集,特征值,监督学习,非监督学习,分类,回归
1.1 机器学习概念
- 多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度等多门学科。
- 专门研究计算机怎样模拟和实现人类的学习行为,以获取新的知识和技能,重新组织新的知识结构使之不断改善自身的性能
1.2 学科定位
- 人工智能(Artificial Intelligence,AI)的核心,是使计算机具有智能的根本途径,其应用遍及人工智能的各个领域,主要方法是归纳、综合而不是演绎。
1.3 机器学习定义
- 探究和开发一系列算法来如何使计算机不需要通过外部明显的指示,而可以自己通过数据来学习和建模,并且利用建好的模型和新的输入来进行预测的学科。
- 一门不需要外部程序指示,而让计算机有能力自我学习的学科。
- 机器学习是一门人工智能的科学,该领域的主要研究对象是人工智能,特别是如何在经验学习中改善算法的性能。
- 机器学习是对能通过经验自动改进的计算机算法的研究。
1.4 什么是学习
- 针对经验E(Experience)和一些列的任务T(Task)和一定表现的衡量P(performe),如果随着经验的积累,针对定义好的任务T可以提高表现P,说明计算机具有学习能力。
- 下棋、语音识别、自动驾驶、语言翻译、计算机视觉、推荐系统、无人机、识别垃圾邮件、人脸识别、推荐系统
1.5 深度学习
- 深度学习是机器学习延伸出来的一个新领域,由以人脑结构为启发的神经网络算法为起源,加之模型结构的增加发展,并伴随大数据和计算能力的提高而产生的一系列新的算法。
- 深度学习作为机器学习中延伸出来的一个领域,被应用在图像处理和计算机视觉,自然语言处理以及语音识别等领域。自2006年至今,学术界和工业界合作在深度学习方面的研究与应用取得了突破性的进展。以ImageNet为数据库的经典图像中的物体识别竞赛为例,击败了所有传统算法,取得了前所未有的精确度。
1.5 监督学习-分类
监督学习(Supervised Learning):分类(Classification)
- 决策树(Decision Tree) ,银行信用自动评估系统
- 邻近取样(Nearest Neighbor) ,人脸识别
- 支持向量机(Support Vector Machine) ,图片中的红眼检测,结肠癌晚期分类
- 神经网络算法(Neural Network),手写数字识别,图片分类
1.6 监督学习-回归
监督学习(Supervised Learning):回归(Regression)
- 线性回归(Linear Regression),销量预测,价格预测
- 非线性回归(Non-linear Regression),销售预测,价格预测
1.7 非监督学习
非监督学习(Unsupervised Learning)
- K-mean算法聚类(Clustering),人脸分类
- hierarchical dustering算法聚类,人脸噪音移除
1.8 机器学习步骤框架
- 把数据拆分为训练集和测试集
- 用训练集和训练集的特征向量来训练算法
- 用学习来的算法运用在测试集上来评估算法,可能要调整参数(parameter tuning),
2 基本概念
- 基本概念:训练集、测试集、特征值、监督学习、非监督学习、半监督学习、分类、回归
- 概念学习是指从有关某个布尔函数的输入输出样例中推断出该布尔函数。
- 概念定义在实例(Instance)集合之上,这个集合表示为X。
- 待学习的概念或目标函数成为目标概念(Target Concept),记作做C。
- 训练集(training set / data)/ 训练样例(training examples):用来进行训练,也就是生产模型,或者算法的数据集
- 测试集(testing set / data)/ 测试样例(testing example):用来专门进行测试已学习好的模型或者算法的数据集
- 特征向量(features/feature vector):属性的集合,通常用一个向量来表示,附属于一个实例
- 标记(label):C(x),实例类别的标记
- 正例:positive example
- 反例:negative example
- 分类(Classification):目标标记为类别型数据(category)
- 回归(regression):目标标记为连续性数值(Continuous Numeric Value)
- 有监督学习(supervised learning):训练集有类别标记(Calss Label)
- 无监督学习(unsupervised learning):无类别标记(Class Label)
- 半监督学习(semi-supervised learning):有类别标记训练集+无类别标记训练集
3 监督学习-分类
监督学习(Superviesd Learning):分类(Classification)
3.1 决策树
决策树(Decision Tree)
3.1.1 机器学习中分类和预测算法的评估
- 准确率
- 速度
- 强壮性
- 可规模性
- 可解释性
3.1.2 什么是决策树/判定树?
- 判定树是一个类似于流程图的数结构,其中每个内部节点表示在一个属性上的测试,每个分支代表一个属性输出,而每个树叶节点代表类和类分布。树的最顶层是根节点。
3.1.2 熵(entropy)概念
- 信息和抽象如何度量?
- 1948年香农提出信息熵的概念
- 一条信息的信息量大小和他的不确定性有直接的关系
- 要搞清楚一件非常不确定的事情,或者是我们一无所知的事情,需要了解大量的信息
- 信息量的度量等于不确定性的多少
- 变量的不确定性越大,熵也越大
3.1.3 决策树归纳算法(ID3)
信息获取量(Information Gain):Gain(A)=Info(D)-Info_A(D).
通过A来作为节点分类获取了多少信息
- 树以代表训练样本的单个节点开始(步骤1)
- 如果样本都在同一个类,则该节点成为树叶,并用该类标号(步骤2和3)
- 否则,算法使用称为信息增益的基于熵的度量作为启发信息,选择能够最好的将样本分类的属性(步骤6).该属性成为该节点的“测试”或“判定”属性(步骤7)
- 在算法的该版本中,所有的属性都是分类的,即离散值。连续属性必须离散化。
- 对测试属性的每个已知的值,创建一个分支,并据从划分样本(步骤8-10)
- 算法使用同样的过程,递归的形成每个划分上的样本的判定树。一旦一个属性出现在一个结点时,就不必该节点的任何后代上考虑它(步骤13)
- 递归划分步骤划分条件仅当下列条件之一停止。
- (a)给定结点的所有样本属于同一类(步骤2和3)
- (b)没有剩余属性可以用来进一步划分样本(步骤4),在此情况下,使用多数表决(步骤5)
- 这涉及将给定结点转换成树叶,并用样本中的多数所在的类标记它
3.1.4 树叶剪枝(避免overfitting)
- 先剪枝
- 后剪枝
3.1.5 决策树的优点
- 直观
- 便于理解
- 小规模数据集有效
3.1.6 决策树的缺点
- 处理连续变量不好
- 类别较多时,错误增加的较快
- 可规模性一般
3.1.7 代码实现
Python 机器学习库:scikit-learn
简单高效的数据挖掘和机器学习库
对所有用户开放,根据不同需求,高度可重用性
基于Numpy、SciPy、matplotlib,开源
- 数据
RID,age,income,student,credit_rating,Class_buys_computer
1,youth,high,no,fair,no
2,youth,high,no,excellent,no
3,middle_aged,high,no,fair,yes
4,senior,medium,no,fair,yes
5,senior,low,yes,fair,yes
6,senior,low,yes,excellent,no
7,middle_aged,low,yes,excellent,yes
8,youth,medium,no,fair,no
9,youth,low,yes,fair,yes
10,senior,medium,yes,fair,yes
11,youth,medium,yes,excellent,yes
12,middle_aged,medium,no,excellent,yes
13,middle_aged,high,yes,fair,yes
14,senior,medium,no,excellent,no
- 代码
from sklearn.feature_extraction import DictVectorizer
import csv
from sklearn import preprocessing
from sklearn import tree
from sklearn.externals.six import StringIO
allElectronicsData = open(r'D:\IDEA\ML\MachineLearningBasics\DataSets\AllElectronics.csv', 'rb')
reader = csv.reader(allElectronicsData)
headers = reader.next()
print 'headers'
print(headers)
featureList = []
labelList = []
for row in reader:
labelList.append(row[len(row) - 1])
rowDict = {}
for i in range(1, len(row) - 1):
rowDict[headers[i]] = row[i]
featureList.append(rowDict)
print 'featureList'
print(featureList)
vec = DictVectorizer()
dummyX = vec.fit_transform(featureList).toarray()
print("dummyX:" + str(dummyX))
print(vec.get_feature_names())
print("labelList:" + str(labelList))
lb = preprocessing.LabelBinarizer()
dummyY = lb.fit_transform(labelList)
print("dummyY:" + str(dummyY))
clf = tree.DecisionTreeClassifier(criterion='entropy')
clf = clf.fit(dummyX, dummyY)
print('clf:' + str(clf))
with open("allElectronicInformationGainOri.dot", 'w') as f:
f = tree.export_graphviz(clf, feature_names=vec.get_feature_names(), out_file=f)
oneRowX = dummyX[0, :]
print('oneRowX:' + str(oneRowX))
newRowX = oneRowX
newRowX[0] = 1
newRowX[2] = 0
print('newRowX:' + str(newRowX))
# predictedY = clf.predict(newRowX)
# print('predictedY:' + str(predictedY))
- 结果
3.2 邻近取样
邻近取样(Nearest Neighbor)
3.2.1 最邻近规则分类(K-Nearest Neighbor) KNN算法
Cover和Hart在1968年提出最初的邻近算法
分类(Classification)算法
输入基于实例的学习(instance-based learning),懒惰学习(Lazy Learning)
3.2.2 算法详述
- 为了判断未知实例的类别,以所有已知类别的实例作为参照
- 选择参数K
- 计算未知实例与所有已知实例的距离
- 选择最近K个已知实例
- 根据少数服从多数的投票法则(majority-voting),让未知实例归类为K个最邻近样本中最多数的类别
3.2.3 关于距离衡量方法
- Euclidean Distance 定义
- 其他距离衡量:余弦值(COS),相关度(correlation),曼哈顿距离(Manhattan Distance)
3.2.4 算法评价
- 优点:简单,易于理解,容易实现,通过对K的选择可具备丢噪音数据的健壮性
- 缺点:需要大量空间存储所有已知实例,算法复杂度高(需要比较所有已知实例与要分类的实例)
- 当其样本分布不平衡时,比如其中一类样本过大(实例数量过多)占主导时,新的未知实例容易被归类为这个主导样本,因为这类样本实例的数量过大,但这个新的未知实例并不接近目标样本
3.2.5 KNN算法应用
最邻近规则分类KNN(K-Nearest Neighbor)算法应用
- SKLearnExample.py
# Example of KNN implemented
from sklearn import neighbors
from sklearn import datasets
knn = neighbors.KNeighborsClassifier()
iris = datasets.load_iris()
print iris
knn.fit(iris.data, iris.target)
predictedLabel = knn.predict([[0.1, 0.2, 0.3, 0.4]])
print predictedLabel
3.2.6 Iris(虹膜)数据集介绍
- 150个实例
- sepal length:萼片长度,sepal width:萼片宽度,petal length:花瓣长度,petal width:花瓣宽度
- 类别:setosa,versicolor,virginica
3.2.7 代码实现
# coding=utf-8
import csv
import random
import math
import operator
# filename 文件名称
# split 分割
# trainingSet 训练集
# testSet 测试集
def loadDataset(filename, split, trainingSet=[], testSet=[]):
with open(filename, 'rb') as csvFile:
lines = csv.reader(csvFile)
dataset = list(lines)
for x in range(len(dataset) - 1):
for y in range(4):
dataset[x][y] = float(dataset[x][y])
if random.random() < split:
trainingSet.append(dataset[x])
else:
testSet.append(dataset[x])
# instance1 第一个座标
# instance2 第二个座标
# length 维数
def euclideanDistance(instance1, instance2, length):
distance = 0
for x in range(length):
distance += pow((instance1[x] - instance2[x]), 2)
return math.sqrt(distance)
# 获取K个最近的实例
def getNeighbors(trainingSet, testInstance, k):
distances = []
length = len(testInstance) - 1
for x in range(len(trainingSet)):
dist = euclideanDistance(testInstance, trainingSet[x], length)
distances.append((trainingSet[x], dist))
distances.sort(key=operator.itemgetter(1))
neighbors = []
for x in range(k):
neighbors.append(distances[x][0])
return neighbors
def getResponse(neighbors):
class_votes = {}
for x in range(len(neighbors)):
response = neighbors[x][-1]
if response in class_votes:
class_votes[response] += 1
else:
class_votes[response] = 1
sorted_votes = sorted(class_votes.iteritems(), key=operator.itemgetter(1), reverse=True)
return sorted_votes[0][0]
# 获取准确率
def getAccuracy(testSet, predictions):
correct = 0
for x in range(len(testSet)):
if testSet[x][-1] == predictions[x]:
correct += 1
return (correct / float(len(testSet))) * 100.0
def main():
training_set = []
test_set = []
split = 0.67
loadDataset(r'D:\IDEA\ML\MachineLearningBasics\DataSets\iris.data.txt', split, training_set, test_set)
print 'Train Set:' + repr(len(training_set))
print 'Test Set:' + repr(len(test_set))
predictions = []
k = 3
for x in range(len(test_set)):
neighbors = getNeighbors(training_set, test_set[x], k)
result = getResponse(neighbors)
predictions.append(result)
print '>> predicted=' + repr(result) + ',actual=' + repr(test_set[x][-1])
accuracy = getAccuracy(test_set, predictions)
print 'Accuracy:' + repr(accuracy) + '%'
main()
3.3 支持向量机
支持向量机(Support Vector Machine,SVM)
3.3.1 原理简介
- 最早于1963年被提出,深度学习出现之前(2012),SVM被认为机器学习中近十年来,最成功、表现最好的算法。
- 机器学习的一般框架:训练集,提取特征向量, 结合一定的算法(分类器:比如决策树,KNN),得到结果
- SVM寻找区分两类的超平面(hyper plane),使边际(margin)最大
- 总共可以有多少个超平面?无数个
- 如何选取边际最大的超平面(Max Margin Hyper plane)?
- 超平面到一侧最近点的距离等于到另一侧最近点的距离,两侧的两个超平面平行
- 线性可区分(linear separable)和线性不可区分(linear inseparable)
3.3.2 定义与公式建立
- 一般情况
超平面可定义为:W * X + b = 0
W:Weight Vector,权重
W={w1,w2,w3,w4...wn}
n:特征值的个数
X:训练实例
b:bias,偏好
- 二维平面
假设二维特征向量:x=(x1,x2)
把b想象成额外的weight
超平面的方程变为:w0 + w1*x1 + w2*x2 = 0
超平面右上方的点满足:w0 + w1*x1 + w2*x2 > 0
超平面左下方的点满足:w0 + w1*x1 + w2*x2 < 0
- 所有坐落在边际的两边的超平面上的向量被成为支持向量(support vectors)
from sklearn import svm
x = [[2, 0], [1, 1], [2, 3]]
y = [0, 0, 1]
clf = svm.SVC(kernel='linear')
clf.fit(x, y)
print clf
# get support vectors
print clf.support_vectors_
# get indices of support vectors
print clf.support_
# get number of support vectors for each class
print clf.n_support_
3.3.3 SVM算法特性
- 训练好的模型的算法复杂度是由支持向量的个数决定的,而不是由数据的维度决定的。所以SVM不容易产生Overfitting。
- SVM训练出来的模型完全依赖于支持向量(Support Vector),即使训练集里面所有非支持向量被去除,重复训练过程,结果依然会得到完全一样的模型。
- 一个SVM如果训练得出的支持向量个数比较少,SVM训练出来的模型容易被泛化
3.3.4 线性不可分情况
- 数据集在空间中对应的向量不可被一个超平面区分
两个步骤来解决
- 利用一个非线性的映射,把源数据集中的向量转化到一个更高维度的空间
- 在这个高维度的空间中,找一个线性的超平面来根据线性可分的情况处理
- 如何选择合理的非线性转化把数据转化到高维度?
- 如何解决计算内积时算法复杂度非常高的问题?
3.3.5 具体实现
print __doc__
import numpy as np
import pylab as pl
from sklearn import svm
# create 40 separable points
np.random.seed(0)
x = np.r_[np.random.randn(20, 2) - [2, 2], np.random.randn(20, 2) + [2, 2]]
y = [0] * 20 + [1] * 20
# fit the model
clf = svm.SVC(kernel='linear')
clf.fit(x, y)
# get the separating hyper plane
w = clf.coef_[0]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - (clf.intecept_[0]) / w[1]
# plot the parallels to the separating hyper plane the pass through the support vectors
b = clf.support_vectors_[0]
yy_down = a * xx + (b[1] - a * b[0])
b = clf.support_vectors[-1]
yy_up = a * xx + (b[1] - a * b[0])
print "w:", w
print "a:", a
print "support_vectors:", clf.support_vectors_
print "clf.coef_", clf.coef_
# plot the line,the points,and the nearest vectors the plane
pl.plot(xx, yy, 'k-')
pl.plot(xx, yy_down, 'k--')
pl.plot(xx, yy_up, 'k--')
pl.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=80, facecolor='none')
pl.scatter(x[:, 0], x[:, 1], c=y, cmap=pl.cm.Paired)
pl.axis('tight')
pl.show()
3.4 神经网络算法
神经网络算法(Neural Network)
3.4.1 算法详述
-
背景:以人脑中的神经网络为启发,历史上出现多个不同的版本,最著名的算法是1980年的Back Propagation,被使用在多层向前神经网络上
-
多层向前神经网络Multilayer Feed-Forward Neural Network
-
多层向前神经网络由以下部分组成:输入层(Input Layer),隐藏层(hidden layer),输入层()
-
每层由单元(units)组成
-
输入层(Input Layer)是由训练集的实例特征向量传入
-
经过连接点的权重(weight)传入下一层,一层的输出是另一层的输入
-
隐藏层的个数可以是任意的,输入层有一层,输出层有一层
-
每个单元也可以被称作神经结点,根据生物学来定义
-
以上称为两层的神经网络(输入层不算)
-
一层中加权的求和,根据非线性方程转化输出
-
作为多层向前神经网络,理论上,如果有足够多的隐藏层和足够大的训练集,理论上可模拟出任何方程。
3.4.2 设计神经网络结构
- 使用神经网络设计数据之前,必须确定神经网络的层数,以及每层单元的个数
- 特征向量在传入输入层时,通常先被标准化(normalize)0到1之间,为了加速学习的过程
- 离散型变量可以被编码成每一个输入单元对应一个特征值可能赋的值,比如:特征值A可能取三个值(a0,a1,a2),可以使用三个输入单元来代表A;如果A=a0,那么代表a0的单元值就取1,其他取0;如果A=a1,那么代表a1的单元值就取1,其他取0,以此类推
- 神经网络可以用来做分类问题(Classification)问题,也可以解决回归问题(regression)问题
- 对于分类问题,如果是两类,可以用一个输入单元表示,0和1分别代表两类
- 如果多于两类,每一个类别用一个输入单元表示,输入层的单元数量通常等于类别数量
- 没有明确的规则来设计最好有多少个隐藏层,根据实验测试及误差以及准确度来改进
- 交叉验证方法(Cross Validation)
3.4.3 Backpropagation算法
- 通过迭代性来处理训练集中的实例
- 对比经过神经网络后,输入值预测值(predicted value)与真实值(target Value)之间
- 反方向(输出层-隐藏层-输入层)来以最小化误差来更新每个连接的权重
- 算法详细介绍
输入:D:数据集,学习率(Learning rate),一个层向前神经网路
输出:一个训练好的神经网路(a trained neural network)
初始化权重(weights)和偏向(bias) :随机初始化到-1到1之间,或者-0.5到0.5之间,每个单元由一个偏向