机器学习实战--机器学习概述

目标与方法

  • Scikit-Learn非常易于使用,它有效的实现了许多机器学习算法,因此称为学习机器学习的重要切入点。
  • TensorFlow是用于分布式数值计算的更复杂的库。通过将计算分布在数百个GPU(图形处理单元)服务器上,它可以有效地训练和运行大型神经网络。TensorFlow是由Google创建的,并支持许多大型机器学习应用程序。
  • Keras是高层深度学习API,使训练和运行神经网络变得非常简单。它可以在TensorFlow、Theano或微软Cognitive Toolkit(CNTK)之上运行。TensorFlow附带了该API自己的实现,称为tf.keras,支持某些高级TensorFlow功能(例如有效加载数据的能力)。

机器学习适用于

  • 有解决方案(但解决方案需要进行大量人工微调或需要遵循大量规则)的问题:机器学习算法通常可以简化代码,相比传统方法有更好的性能。
  • 传统方法难以解决的复杂问题:最好的机器学习技术也许可以找到解决方案。
  • 环境有波动:机器学习算法可以适应新数据。
  • 洞察复杂问题和大量数据。

机器学习的应用示例

  • 分析生产线上的产品图像来对产品进行自动分类
    这是图像分类问题,使用卷积神经网络(CNN)的典型示例。
  • 通过脑部扫描发现肿瘤
    这是语义分割,图像中的每个像素都需要被分类(当我们想确定肿瘤的确切位置和形状时),也使用CNN。
  • 自动分类新闻
    这是自然语言处理(NLP),更具体地是文本分类,可以使用循环神经网络(RNN),CNN或者Transformer。
  • 论坛中自动标记恶评
    这也是文本分类,使用相同地自然语言处理工具。
  • 自动对长文章做总结
    这是自然语言处理地一个分支,叫做文本总结,使用相同的工具。
  • 创建一个聊天机器人或者个人助理
    这涉及自然语言处理的很多分支,包括自然语言理解(NLU)和问答模块。
  • 基于很多性能指标来预测公司下一年的收入
    这是一个回归问题(如预测值),需要使用回归模型进行处理,例如线性回归或多项式回归、SVM回归、随机森林回归或者人工神经网络,如果考虑过去的性能指标,可以使用RNN、CNN或者Transformer。
  • 让应用对语音命令做出反应
    这是语音识别,要求能处理音频采样。因为音频是很长、很复杂的序列,所以一般使用RNN、CNN或者Transformer进行处理。
  • 检测信用卡欺诈
    这是异常检测。
  • 基于客户的购买记录来对客户进行分类,对每一类客户设计不同的市场策略。
    这是聚类问题。
  • 用清晰而有洞察力的图表来表示复杂的高维数据集
    这是数据可视化,经常涉及降维技术。
  • 基于以前的购买记录给客户推荐可能感兴趣的产品
    这是推荐系统,一个办法是将以前的购买记录(和客户的其他信息)输入人工神经网络,从而输出客户最可能购买的产品。这个神经网络是在所有客户的购买记录上训练的。
  • 为游戏建造智能机器人
    这通常通过强化学习(RL)来解决。强化学习是机器学习的一个分支,在一个给定的环境(例如游戏)中,训练代理(例如机器人)选择在一段时间内将它们的奖励最大化的行动(例如,机器人可能会在玩家每次失去一些生命值时获得奖励)。在为期比赛中打败世界冠军的著名AlphaGo程序就是使用RL构建的。

机器学习系统的类型

  • 是否在人类监督下训练(有监督学习、无监督学习、半监督学习和强化学习)
  • 是否可以动态地进行增量学习(在线学习和批量学习)
  • 是简单地将新的数据点和已知的数据点进行匹配,还是像科学家那样,对训练数据进行模式检测然后建立一个预测模型(基于实例的学习和基于模型的学习)

有监督学习和无监督学习

根据训练期间接受的监督数量和监督类型,可以将机器学习系统分为以下四个主要类别:有监督学习、无监督学习、半监督学习和强化学习

  • 有监督学习
    在有监督学习中,提供给算法的包含所需解决方案的训练集称为标签。
    分类任务是一个典型的有监督学习任务。
    垃圾邮件过滤器就是一个很好的示例:通过大量的电子邮件示例及其所属的类别(垃圾邮件还是常规邮件)进行训练,然后学习如何对新邮件进行分类。
    另一个典型的任务是通过给定一组称为预测器的特征(里程、使用年限、品牌等)来预测一个目标数值(例如汽车的价格)。这种类型称为回归。要训练这样一个系统,需要提供大量的汽车示例,包括它们的预测器和标签(即价格)。
    回归问题:在给定输入特征的情况下预测值(通常有多个输入特征,有时有多个输出值)
    在机器学习中,属性是一种数据类型(例如’里程‘),而特征取决于上下文,可能有多个含义。但是通常状况下,特征意味着一个属性加上其值(例如:”里程 = 15000“)。
    一些回归算法也可以用于分类任务。逻辑回归就被广泛地用于分类,因为它可以输出”属于某个给定类别地概率“的值(例如,20%的概率是垃圾邮件)
重要的有监督学习算法
  • k-近邻算法
  • 线性回归
  • 逻辑回归
  • 支持向量机(SVM)
  • 决策树和随机森林
  • 神经网络

无监督学习
无监督学习的训练数据都是未经标记的。系统会在没有”老师“的情况下进行学习。

重要的无监督学习算法
  • 聚类算法
    k-均值算法
    DBSCAN算法
    分层聚类分析(HCA)

  • 异常检测和新颖性检测
    单类SVM
    孤立森林

  • 可视化和降维
    主成分分析(PCA)
    核主成分分析
    局部线性嵌入(LLE)
    t-分布随机近邻嵌入(t-SNE)

  • 关联规则学习
    Apriori
    Eclat

可视化算法也是无监督学习算法的一个不错的示例:提供大量复杂的、未标记的数据,算法轻松绘制输出2D或3D的数据表示。这些算法会尽其所能地保留尽量多的结构(例如,尝试保持输入的单独集群在可视化中不会被重叠),以便于你理解这些数据是怎么组织的,甚至识别出一些未知的模式。

与之相关的一个任务是降维。降维的目的是在不丢失太多信息的前提下简化数据。方法之一是将多个相关特征合并为一个。(例如,汽车里程与其使用年限存在很大的相关性,所以降维算法会将它们合并成一个代表汽车磨损的特征,这个过程叫做特征提取)

通常比较好的做法是,先使用降维算法减少训练数据的维度,再将其提供给另一个机器学习算法(例如有监督学习算法)。这会使它运行得更快,数据占用得磁盘空间核内存都会更小,在某些情况下,执行性能也会更高。

另一个很重要得无监督任务是异常检测(例如异常检测信用卡交易以防止欺诈,捕捉制造缺陷,或者在给另一种机器学习算法提供数据之前自动从数据集中移除异常值)系统用正常实例进行训练,然后当看到新的实例时,它就可以判断出这个实例看上去是正常还是异常。

一个非常类似的任务是新颖性检测。它的目的是检测看起来与训练集中的所有实例不同的新实例(例如,如果有很多照片,其中1%是吉娃娃犬,那么一个新颖性检测算法不应将吉娃娃犬的新图片视为新颖)。另一方面,异常检测算法可能会认为这些狗非常罕见,应该与其他狗不同,可能会把它们归为异类。

还有一个常见的无监督任务是关联规则学习,其目的是挖掘大量数据,发现属性之间的有趣联系(例如,假设你开了一家超市,在销售日志上运行关联规则之后发现买烧烤酱和薯片的人也倾向于购买牛排,那么,你可能会将这几样商品摆放的更近一些)。

半监督学习

由于通常给数据做标记是非常耗时和昂贵的,你往往会有很多未标记的数据而很少有已知标记的数据。有些算法处理部分已标记的数据。这被称为半监督学习(有些照片托管服务Goole相册,就是很好的示例。一旦将所有的照片上传到服务器后,会自动识别出人物A出现在1,5,11中,人物B出现在照片2、5和7中)。这是算法的无监督部分(聚类)。现在系统需要你做的只是告诉它这些人都是谁。给每个人一个标签之后,它就可以给每张照片中的每个人命名,这对于搜索这些图片非常重要。
大多数半监督学习算法是无监督算法和有监督算法的结合。例如,深度理念网络(DBN)基于一种互相堆叠的无监督组件,这个组件叫做受限波尔兹曼机(RBM)。受限玻尔兹曼机以无监督方式进行训练,然后使用有监督学习技术对整个系统进行微调。

强化学习

强化学习是一个非常与众不同的”巨兽“,它的学习系统(在其语境中称为智能体)能够观察环境,做出选择,执行动作,并获得回报(或者是以负面回报的形式获得惩罚)。所以它必须自行学习什么是最好的策略,从而随着时间的推移获得最大的回报。策略代表智能体在特定情况下应该选择的动作(例如,许多机器人通过强化学习算法学习如何行走。DeepMind的AlphaGo项目也是一个强化学习的好示例)。

批量学习和在线学习

另一个给机器学习系统分类的标准是看系统是否可以从传入的数据流中进行增量学习。

批量学习

在批量学习中,系统无法进行增量学习----即必须使用所有可用数据进行训练。这需要大量时间和计算资源,所以通常都是离线完成的。离线学习就是先训练系统,然后将其投入生产环境,这时学习过程停止,它只是将其所学到的应用出来。

如果希望批量学习系统学习新数据(例如新型垃圾邮件),需要在完整数据集(包括新数据和旧数据)的基础上重新训练系统的新版本,然后停用旧系统,用新系统取而代之。

幸运的是,整个训练,评估和启动机器学习系统的过程可以很轻易地实现自动化,所以即使是批量学习系统也能适应变化。只是需要不断地更新数据,并根据需要频繁地训练系统的新版本。

这个解决方案比较简单,通常也能正常工作,只是每次都使用完整数据集进行训练可能需要花费好几个小时,所以,你很有可能会选择每天甚至每周训练一次新系统。如果系统需要应对快速变化的数据(例如,预测股票价格),那么你需要一个更具影响力的解决方案。此外,使用完整数据集训练需要耗费大量的计算资源(CPU、内存空间、磁盘空间、磁盘I/O、网络I/O等),如果你的数据量非常大,并且每天从零开始自动执行训练系统,那最终你将为此耗费大量金钱。而假如你面对的是海量数据,甚至可能无法再应用批量学习算法。

在线学习

在在线学习中,你可以循序渐进地给系统提供训练数据,逐步累积学习成果。这种提供数据的方式可以是单独的,也可以采用小批量的小组数据来进行训练。每一步学习都很快速并且便宜,这样系统就可以根据飞速写入的最新数据进行学习。
在线学习中,模型经过训练并投入生产环境,然后随着新数据的进入而不断学习。
使用在线学习系统,需要接收持续的数据流(例如股票价格),同时对数据流的变化做出快速或自主的反应,使用在线学习是一个非常好的方式。新的数据实例一旦经过在线学习系统的学习,就不再需要,可以将其丢弃。这可以节省大量空间。
对于超大数据集----超出一台计算机的主存储器的数据,在线学习算法也同样适用(这称为核外学习)。算法每次只加载部分数据,并针对这部分数据进行训练,然后不断重复这个过程,直到完成所有数据的训练。
核外学习通常是离线完成的(也就是不在实时系统上),因此在线学习这个名字很容易让人产生误解。我们可以将其视为增量学习。
在线学习系统的一个重要参数是其适用不断变化的数据的速度,这就是所谓的学习率。如果设置的学习率很高,那么系统将会迅速适应新数据,但同时也会很快忘记旧数据。反过来,如果学习率很低,系统会有更高的惰性,也就是说,学习会更缓慢,同时也会对新数据中的噪音或者非典型数据点(离群值)的序列更不敏感。
在线学习面临的一个重大挑战是,如果给系统输入不良数据,系统的性能会逐渐下降。

基于实例的学习与基于模型的学习

另一种对机器学习系统进行分类的方法是看它们如何泛化。大多数机器学习任务是要做出预测。这意味着系统需要通过给定的训练示例,在它此前并未见过的示例上进行预测(泛化)。在训练数据上实现良好的性能指标固然重要,但是还不够充分。真正的目的是要在新的对象实例上表现出色。
泛化的主要方法有两种:基于实例的学习基于模型的学习

基于实例的学习

被称为基于实例的学习:系统用心学习这些示例,然后通过使用相似度度量来比较新实例和已经学习的实例(或它们的子集),从而泛化新实例。

基于模型的学习

从一组示例集中实现泛化的另一种方法是构建这些示例的模型,然后使用该模型进行预测。这称为基于模型的学习。

确定值对衡量模型的性能表现

要么定义一个效用函数(或适用度函数)来衡量模型有多好,要么定义一个成本函数来衡量模型有多差。对于线性回归问题,通常的选择是使用成本函数来衡量线性模型的预测与训练实例之间的差距,目的在于尽量使这个差距最小化。
这正是线性回归算法的意义所在:通过你提供的训练样本,找出最符合提供数据的线性模型的参数,这称为训练模型。
模型选择包括选择模型的类型和完全指定它的架构。训练一个模型意味着运行一种寻找模型参数的算法,使其最适合训练数据(希望能对新的数据做出好的预测)。

使用sklearn训练并要运行一个线性模型

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import sklearn.linear_model
def prepare_country_stats(oecd_bli, gdp_per_capita):
    oecd_bli = oecd_bli[oecd_bli["INEQUALITY"]=="TOT"]
    oecd_bli = oecd_bli.pivot(index="Country", columns="Indicator", values="Value")  
    #pandas.DataFrame.pivot 返回由给定索引/列值组织的重新整形的DataFrame
    #print(oecd_bli)
    gdp_per_capita.rename(columns={
    
    "2015": "GDP per capita"}, inplace=True)
    gdp_per_capita.set_index("Country", inplace=True)
    full_country_stats = pd.merge(left=oecd_bli, right=gdp_per_capita,
                                  left_index=True, right_index=True) 
    #pandas.merge 使用数据库样式连接合并 DataFrame或命名的Series对象。 
    full_country_stats.sort_values(by="GDP per capita", inplace=True) 
    #以GDP per capita为索引进行排序
    remove_indices = [0, 1, 6, 8, 33, 34, 35]
    #remove_indices = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] #去除一些样本
    keep_indices = list(set(range(36)) - set(remove_indices))
    return full_country_stats[["GDP per capita", 'Life satisfaction']].iloc[keep_indices] #pandas.DataFrame.iloc 基于整数位置的索引,用于按位置选择。
# Load the data
oecd_bli = pd.read_csv("./datasets/lifesat/oecd_bli_2015.csv",thousands = ',')
gdp_per_capita = pd.read_csv("./datasets/lifesat/gdp_per_capita.csv",thousands = ',',delimiter = '\t',encoding = 'latin_1', na_values = "n/a")
# Prepare the data
country_stats = prepare_country_stats(oecd_bli, gdp_per_capita)
X = np.c_[country_stats["GDP per capita"]]
y = np.c_[country_stats["Life satisfaction"]]
# Visualize the data
country_stats.plot(kind = 'scatter', x = "GDP per capita", y = 'Life satisfaction')
plt.show()

在这里插入图片描述

# Select a linear model
model = sklearn.linear_model.LinearRegression()
# Train the model
model.fit( X,y )
t0,t1 = model.intercept_[0],model.coef_[0][0]
t0,t1

(4.853052800266436, 4.911544589158483e-05)

# Make a prediction for Cyprus
X_new = [[22587]]  #输入塞浦路斯的人均GDP
print(model.predict(X_new)) # outputs [[ 5.96242338]] 预测该国幸福指数

[[5.96242338]]

#将线性回归模型换为k-近邻回归模型
import sklearn.neighbors
model = sklearn.neighbors.KNeighborsRegressor(n_neighbors = 3)
model.fit(X,y)
# Make a prediction for Cyprus
X_new = [[22587]]  #输入塞浦路斯的人均GDP
print(model.predict(X_new)) # outputs [[ 5.96242338]] 预测该国幸福指数

[[5.76666667]]

简而言之:

  • 研究数据
  • 选择模型
  • 使用训练数据进行训练(即前面学习算法搜索模型参数值,从而使成本函数最小化的过程)
  • 最后,应用模型对新示例进行预测(称为推断),希望模型的泛化结果不错。

机器学习的主要挑战

简单来说,由于你的主要任务是选择一种学习算法,并对某些数据进行训练,所以最可能出现的两个问题是”坏算法“和”坏数据“。

训练数据的不同

大部分机器学习算法需要大量的数据才能正常工作。即使是最简单的问题,很可能也需要成千上万个示例,而对于诸如图像或语音识别等复杂问题,则可能需要数百万个示例。

训练数据不具有代表性

为了很好地实现泛化,至关重要地一点是对于将要泛化的新示例来说,训练数据一定要非常有代表性。无论你使用的是基于实例的学习还是基于模型的学习,都是如此。

针对你想要泛化的案例使用具有代表性的训练集,这一点至关重要。但是不是很容易实现,如果样本集太小,将会出现采样噪声(即非代表性数据被选中);而即便是非常大的样本数据,如果采样方式欠妥,也同样可能导致非代表性数据集,这就是所谓的采样偏差。

低质量数据

如果训练集满是错误、异常值和噪声(低质量的测量产生的数据),系统将更难检测到底层模式,更不太可能表现良好。所以花时间来清理训练数据是非常值得的投入。

  • 如果某些实例明显是异常情况,那么直接将其丢弃,或者尝试手动修复错误,都会大有帮助。
  • 如果某些实例缺少部分特征(例如,5%的顾客没有指定年龄),你必须决定是整体忽略这些特征、忽略这部分有缺失的实例、将缺失的值补充完整(例如,填写年龄值得中位数),还是训练一个带这个特征的模型,再训练一个不带这个特征的模型。
无关特征

只有训练数据里包含足够多的相关特征以及较少的无关特征,系统才能完成学习。一个成功的机器学习项目,其关键部分是提取出一组好的用来训练的特征集。
这个过程叫作特征工程,包括以下几点:

  • 特征选择(从现有特征中选择最有用的特征进行训练)
  • 特征提取(将现有特征进行整合,产生更有用的特征----降维算法可以提供帮助)
  • 通过收集新数据创建新特征。
过拟合训练数据

模型在训练数据上表现良好,但是在泛化时却不尽人意,称为过拟合。
诸如深度网络这类的复杂模型可以检测到数据中的微小模式,但是如果训练集本身是有噪声的,或者数据集太小(引入了采样噪声),那么很可能会导致模型检测噪声本身的模式。很显然,这些模式不能泛化至新的实例。
当模型相对于训练数据的数量和噪度都过于复杂时,会发生过拟合。可能的解决方案如下:

  • 简化模型:可以选择较少参数的模型(例如,选择线性模型而不是高阶多项式模型)也可以减少训练数据中的属性数量,或者是约束模型。
  • 收集更多的训练数据。
  • 减少训练数据中的噪声(例如,修复数据错误和消除异常值)

通过约束模型使其简单,并降低过拟合的风险,这个过程称为正则化。需要在完美匹配数据和保持模型简单之间找到合适的平衡点,从而确保模型能够更好地泛化。

在学习时,应用正则化地程度可以通过一个超参数来控制。超参数是学习算法(不是模型)的参数。因此,它不受算法本身的影响。超参数必须在训练之前设置好,并且在训练期间保持不变。如果将正则化超参数设置为非常大的值,会得到一个几乎平坦的模型(斜率接近零)。学习算法虽然肯定不会过拟合训练数据,但是也更加不可能找到一个好的解决方案。调整超参数事构建机器学习系统非常重要的组成部分。

欠拟合训练数据

欠拟合和过拟合正好相反。它的产生通常是因为对于底层的数据结构来说,比如模型太过简单。(用线性模型来描述生活满意度就属于欠拟合)。
解决欠拟合的主要方式:

  • 选择一个带有更多参数、更强大的模型。
  • 给学习算法提供更好的特征集(特征工程)。
  • 减少模型中的约束(减少正则化超参数)。

关于机器学习

  • 机器学习是关于如何让机器可以更好地处理某些特定任务的理论,它从数据中学习,而无须清晰地编码规则。
  • 机器学习系统有很多类型:有监督和无监督,批量的和在线的,基于实例的和基于模型的,等等。
  • 在一个机器学习项目中,你从训练集中采集数据,然后将数据交给学习算法来计算。如果算法是基于模型的,它会调整一些参数来将模型适配于训练集(即对训练集本身做出很好的预测),然后算法就可以对新的场景做出合理的预测。如果算法你是基于实例的,它会记住这些示例,并根据相似度度量将它们与所学的实例进行比较,从而泛化这些新实例。
  • 如果训练集的数据太少或数据代表性不够,包含太多噪声或者被一些无关特征污染,那么系统将无法很好地工作。最后模型既不能太简单(会导致欠拟合),也不能太复杂(会导致过拟合)。

测试与验证

了解一个模型对于新场景地泛化能力地唯一办法就是让模型真实地去处理新场景。做法之一是将其部署在生产环境中,然后监控它地输出。
更好的选择是将数据分割成两部分:训练集和测试集。用训练集的数据来训练数据,用测试集的数据来测试模型。应对新场景的误差率称为泛化误差(或者样例外误差),通过测试集来评估你的模型,就可以得到对这个误差的评估。这个估值可以告诉你模型在处理新场景时的能力如何。
如果训练误差很低(模型对于训练集来说很少出错),但是泛化误差很高,那么说明你的模型对于训练数据存在过拟合。
通常将80%的数据用于训练,而保持20%的数据供测试用。但是,这取决于数据集的大小。

超参数调整和模型选择

评估一个模型很简单:用测试集就可以。
在选择两个模型时,需要训练两个模型,然后对比它们对测试数据的泛化能力。
现在假设线性模型的泛化能力更强,但是需要应用一些正则化来避免过拟合,通过使用100个不同的超参数值来训练100个不同的模型,然后假设由此找到了最佳的超参数值,它生成的模型泛化误差最小,比如仅仅5%,然后在生产环境中运行这个模型。
但可能会出现产生较大误差的问题,是因为对测试集的泛化误差进行了多次度量,并且调整模型和超参数来得到拟合那个测试集的最佳模型。这意味着该模型对于新的数据不太可能有良好的表现。
解决此问题的常见方法称为保持验证:你只需要保持训练集的一部分,以评估几种候选模型并选择最佳模型。新的保留集称为验证集,有时也称为开发集。更具体的说:可以在简化的训练集上(即完整训练集减去验证集)训练具有各种超参数的多个模型,并且选择在验证集上表现最佳的模型。在此保持验证之后,你在完整的训练集(包括验证集)上训练最佳模型,这就是最终模型。最后在测试集上评估这个模型以获得泛化误差的估计值。
执行使用许多小验证集重复进行交叉验证。每个模型都在对其余数据进行训练后名,在每个验证集上评估一次。通过对模型的所有评估求平均值,可以更准确的衡量模型的性能。但是,耗费时间时验证集个数的倍数。

数据不匹配

在某些情况下,很容易获得大量训练数据,但是这些数据可能不能完全代表将用于生产环境的数据。
验证集和测试集必须在生产环境中使用的数据具有相同的代表性。

猜你喜欢

转载自blog.csdn.net/weixin_45867259/article/details/132417610