Bootstrap

机器学习基础

机器学习组成:模型、策略、优化

《统计机器学习》中指出:机器学习=模型+策略+算法。其实机器学习可以表示为:Learning= Representation+Evalution+Optimization。我们就可以将这样的表示和李航老师的说法对应起来。机器学习主要是由三部分组成,即:表示(模型)、评价(策略)和优化(算法)。

表示(或者称为:模型):Representation

表示主要做的就是建模,故可以称为模型。模型要完成的主要工作是转换:将实际问题转化成为计算机可以理解的问题,就是我们平时说的建模。类似于传统的计算机学科中的算法,数据结构,如何将实际的问题转换成计算机可以表示的方式。这部分可以见“简单易学的机器学习算法”。给定数据,我们怎么去选择对应的问题去解决,选择正确的已有的模型是重要的一步。

评价(或者称为:策略):Evalution

评价的目标是判断已建好的模型的优劣。对于第一步中建好的模型,评价是一个指标,用于表示模型的优劣。这里就会是一些评价的指标以及一些评价函数的设计。在机器学习中会有针对性的评价指标。

分类问题
优化:Optimization

优化的目标是评价的函数,我们是希望能够找到最好的模型,也就是说评价最高的模型。

开发机器学习应用程序的步骤

(1)收集数据

我们可以使用很多方法收集样本护具,如:制作网络爬虫从网站上抽取数据、从RSS反馈或者API中得到信息、设备发送过来的实测数据。

(2)准备输入数据

得到数据之后,还必须确保数据格式符合要求。

(3)分析输入数据

这一步的主要作用是确保数据集中没有垃圾数据。如果是使用信任的数据来源,那么可以直接跳过这个步骤

(4)训练算法

机器学习算法从这一步才真正开始学习。如果使用无监督学习算法,由于不存在目标变量值,故而也不需要训练算法,所有与算法相关的内容在第(5)步

(5)测试算法

这一步将实际使用第(4)步机器学习得到的知识信息。当然在这也需要评估结果的准确率,然后根据需要重新训练你的算法

(6)使用算法

转化为应用程序,执行实际任务。以检验上述步骤是否可以在实际环境中正常工作。如果碰到新的数据问题,同样需要重复执行上述的步骤

模型的选择

算法是核心,数据和计算是基础。这句话很好的说明了机器学习中算法的重要性。那么我们开看下机器学习的几种分类:

  • 监督学习
    分类 k-近邻算法、决策树、贝叶斯、逻辑回归(LR)、支持向量机(SVM)
    回归 线性回归、岭回归
    标注 隐马尔可夫模型(HMM)

  • 无监督学习
    聚类 k-means
    如何选择合适的算法模型:

  • 在解决问题的时候,必须考虑下面两个问题:
    一、使用机器学习算法的目的,想要算法完成何种任务,比如是预测明天下雨的概率是对投票者按照兴趣分组;
    二、需要分析或者收集的数据时什么

  • 首先考虑使用机器学习算法的目的。
    如果想要预测目标变量的值,则可以选择监督学习算法,否则可以选择无监督学习算法,确定选择监督学习算法之后,需要进一步确定目标变量类型,如果目标变量是离散型,如是/否、1/2/3,A/B/C/或者红/黑/黄等,则可以选择分类算法;如果目标变量是连续的数值,如0.0~100.0、-999~999等,则需要选择回归算法

如果不想预测目标变量的值,则可以选择无监督算法。进一步分析是否需要将数据划分为离散的组。如果这是唯一的需求,则使用聚类算法。

当然在大多数情况下,上面给出的选择办法都能帮助读者选择恰当的机器学习算法,但这也并非已成不变。也有分类算法可以用于回归。

其次考虑的是数据问题,我们应该充分了解数据,对实际数据了解的越充分,越容易创建符合实际需求的应用程序,主要应该了解数据的一下特性:特征值是 离散型变量 还是 连续型变量 ,特征值中是否存在缺失的值,何种原因造成缺失值,数据中是够存在异常值,某个特征发生的频率如何,等等。充分了解上面提到的这些数据特性可以缩短选择机器学习算法的时间。

机器学习算法分类

监督学习

  • 分类 : k-近邻算法、贝叶斯分类、决策树与随机森林、逻辑回归、神经网络
  • 回归 线性回归、岭回归, 隐马尔可夫模型
    无监督学习
  • 聚类 k-means
    在这里插入图片描述
    监督学习:(英语:Supervised learning),可以由输入数据中学到或建立一个模型,并依此模式推测新的结果。输入数据是由输入特征值和目标值所组成。函数的输出可以是一个连续的值(称为回归),或是输出是有限个离散值(称作分类)。
    无监督学习(英语:Supervised learning),可以由输入数据中
    学到或建立一个模型,并依此模式推测新的结果。输入数据是由输入特征值所组成。

分类问题

概念:分类是监督学习的一个核心问题,在监督学习中,当输出变量取有限个离散值时,预测问题变成为分类问题。最基础的便是二分类问题,即判断是非,从两个类别中选择一个作为预测结果

分类问题的应用:
在这里插入图片描述
分类问题 分类是监督学习的一个核心问题,在监督学习中,当输出变量取有限个离散值时,预测问题变成为分类问题。这时,输入变量可以是离散的,也可以是连续的。监督学习从数据中学习一个分类模型活分类决策函数,称为分类器。分类器对新的输入进行输出的预测,称为分类。最基础的便是二分类问题,即判断是非,从两个类别中选择一个作为预测结果;除此之外还有多酚类的问题,即在多于两个类别中选择一个。

分类问题包括学习和分类两个过程,在学习过程中,根据已知的训练数据集利用有效的学习方法学习一个分类器,在分类过程中,利用学习的分类器对新的输入实例进行分类。图中(X1,Y1),(X2,Y2)…都是训练数据集,学习系统有训练数据学习一个分类器P(Y|X)或Y=f(X);分类系统通过学习到的分类器对于新输入的实例子Xn+1进行分类,即预测术其输出的雷标记Yn+1
分类在于根据其特性将数据“分门别类”,所以在许多领域都有广泛的应用。例如,在银行业务中,可以构建一个客户分类模型,按客户按照贷款风险的大小进行分类;在网络安全领域,可以利用日志数据的分类对非法入侵进行检测;在图像处理中,分类可以用来检测图像中是否有人脸出现;在手写识别中,分类可以用于识别手写的数字;在互联网搜索中,网页的分类可以帮助网页的抓取、索引和排序。

即一个分类应用的例子,文本分类。这里的文本可以是新闻报道、网页、电子邮件、学术论文。类别往往是关于文本内容的。例如政治、体育、经济等;也有关于文本特点的,如正面意见、反面意见;还可以根据应用确定,如垃圾邮件、非垃圾邮件等。文本分类是根据文本的特征将其划分到已有的类中。输入的是文本的特征向量,输出的是文本的类别。通常把文本的单词定义出现取值是1,否则是0;也可以是多值的,,表示单词在文本中出现的频率。直观地,如果“股票”“银行““货币”这些词出现很多,这个文本可能属于经济学,如果“网球””比赛“”运动员“这些词频繁出现,这个文本可能属于体育类

回归问题

概念:回归是监督学习的另一个重要问题。回归用于预测输入变量和输出变量之间的关系,输出是连续型的值。
回归是监督学习的另一个重要问题。回归用于预测输入变量和输出变量之间的关系,特别是当初如变量的值发生变化时,输出变量的值随之发生的变化。回归模型正式表示从输入到输出变量之间映射的函数。回归稳日的学习等价与函数拟合:选择一条函数曲线使其更好的拟合已知数据且很好的预测位置数据
在这里插入图片描述
回归问题按照输入变量的个数,分为一元回归和多元回归;按照输入变量和输出变量之间关系的类型即模型的类型,分为线性回归和非线性回归。

许多领域的任务都可以形式化为回归问题,比如,回归可以用于商务领域,作为市场趋势预测、产品质量管理、客户满意度调查、偷袭风险分析的工具。

scikit-learn数据集

我们将介绍sklearn中的数据集类,模块包括用于加载数据集的实用程序,包括加载和获取流行参考数据集的方法。它还具有一些人工数据生成器。

sklearn.datasets
(1)datasets.load_*()

获取小规模数据集,数据包含在datasets里

(2)datasets.fetch_*()

获取大规模数据集,需要从网络上下载,函数的第一个参数是data_home,表示数据集下载的目录,默认是 ~/scikit_learn_data/,要修改默认目录,可以修改环境变量SCIKIT_LEARN_DATA

(3)datasets.make_*()

本地生成数据集

load和 fetch 函数返回的数据类型是 datasets.base.Bunch,本质上是一个 dict,它的键值对可用通过对象的属性方式访问。主要包含以下属性:

data:特征数据数组,是 n_samples * n_features 的二维numpy.ndarray数组

target:标签数组,是 n_samples 的一维 numpy.ndarray 数组

DESCR:数据描述

feature_names:特征名

target_names:标签名

数据集目录可以通过datasets.get_data_home()获取,clear_data_home(data_home=None)删除所有下载数据

datasets.get_data_home(data_home=None)
返回scikit学习数据目录的路径。这个文件夹被一些大的数据集装载器使用,以避免下载数据。默认情况下,数据目录设置为用户主文件夹中名为“scikit_learn_data”的文件夹。或者,可以通过“SCIKIT_LEARN_DATA”环境变量或通过给出显式的文件夹路径以编程方式设置它。'〜'符号扩展到用户主文件夹。如果文件夹不存在,则会自动创建。

sklearn.datasets.clear_data_home(data_home=None)
删除存储目录中的数据

机器学习一般的数据集会划分为两个部分:

训练数据:用于训练,构建模型

测试数据:在模型检验时使用,用于评估模型是否有效

获取小数据集

  • 用于分类sklearn.datasets.load_iris
    参数介绍:
class sklearn.datasets.load_iris(return_X_y=False)
  """
  加载并返回虹膜数据集

  :param return_X_y: 如果为True,则返回而不是Bunch对象,默认为False

  :return: Bunch对象,如果return_X_y为True,那么返回tuple,(data,target)
  """

实现:

from sklearn.datasets import load_iris
# 鸢尾 目标离散值
# 分类  决策树
li=load_iris()
print('获取特征值:',li.data) # 获取特征值
print("目标值:",li.target) # 获取目标值
print('特征名:',li.feature_names) # 特征名
print('标签名:',li.target_names) # 标签名
print('--------------数据描述--------------')
print(li.DESCR) # 数据描述
  • 分类sklearn.datasets.load_digits`
    参数:
class sklearn.datasets.load_digits(n_class=10, return_X_y=False)
    """
    加载并返回数字数据集

    :param n_class: 整数,介于0和10之间,可选(默认= 10,要返回的类的数量

    :param return_X_y: 如果为True,则返回而不是Bunch对象,默认为False

    :return: Bunch对象,如果return_X_y为True,那么返回tuple,(data,target)
    """

实现:

In [20]: from sklearn.datasets import load_digits

In [21]: digits = load_digits()

In [22]: print(digits.data.shape)
(1797, 64)

In [23]: digits.target
Out[23]: array([0, 1, 2, ..., 8, 9, 8])

In [24]: digits.target_names
Out[24]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [25]: digits.images
Out[25]:
array([[[  0.,   0.,   5., ...,   1.,   0.,   0.],
        [  0.,   0.,  13., ...,  15.,   5.,   0.],
        [  0.,   3.,  15., ...,  11.,   8.,   0.],
        ...,
        [  0.,   4.,  11., ...,  12.,   7.,   0.],
        [  0.,   2.,  14., ...,  12.,   0.,   0.],
        [  0.,   0.,   6., ...,   0.,   0.,   0.]],

        [[  0.,   0.,  10., ...,   1.,   0.,   0.],
        [  0.,   2.,  16., ...,   1.,   0.,   0.],
        [  0.,   0.,  15., ...,  15.,   0.,   0.],
        ...,
        [  0.,   4.,  16., ...,  16.,   6.,   0.],
        [  0.,   8.,  16., ...,  16.,   8.,   0.],
        [  0.,   1.,   8., ...,  12.,   1.,   0.]]])
  • 用于回归sklearn.datasets.load_boston
    参数介绍:
class  sklearn.datasets.load_boston(return_X_y=False)
  """
  加载并返回波士顿房价数据集

  :param return_X_y: 如果为True,则返回而不是Bunch对象,默认为False

  :return: Bunch对象,如果return_X_y为True,那么返回tuple,(data,target)
  """

实现:

from sklearn.datasets import load_boston
# boston 的房价 目标值连续值连续值
# 回归数据集
lp=load_boston()
print('获取特征值:',lp.data) # 获取特征值
print("目标值:",lp.target) # 获取目标值
print('特征名:',lp.feature_names) # 特征名
# print('标签名:',lp.target_names) # 标签名
print('--------------数据描述--------------')
print(lp.DESCR) # 数据描述
  • 回归sklearn.datasets.load_diabetes
  • 参数介绍
class sklearn.datasets.load_diabetes(return_X_y=False)
  """
  加载和返回糖尿病数据集

  :param return_X_y: 如果为True,则返回而不是Bunch对象,默认为False

  :return: Bunch对象,如果return_X_y为True,那么返回tuple,(data,target)
  """
  • 实现:
In [13]:  from sklearn.datasets import load_diabetes

In [14]: diabetes = load_diabetes()

In [15]: diabetes.data
Out[15]:
array([[ 0.03807591,  0.05068012,  0.06169621, ..., -0.00259226,
         0.01990842, -0.01764613],
       [-0.00188202, -0.04464164, -0.05147406, ..., -0.03949338,
        -0.06832974, -0.09220405],
       [ 0.08529891,  0.05068012,  0.04445121, ..., -0.00259226,
         0.00286377, -0.02593034],
       ...,
       [ 0.04170844,  0.05068012, -0.01590626, ..., -0.01107952,
        -0.04687948,  0.01549073],
       [-0.04547248, -0.04464164,  0.03906215, ...,  0.02655962,
         0.04452837, -0.02593034],
       [-0.04547248, -0.04464164, -0.0730303 , ..., -0.03949338,
        -0.00421986,  0.00306441]])

获取大数据集

  • subset: ‘train’或者’test’,‘all’,可选,选择要加载的数据集.
    训练集的“训练”,测试集的“测试”,两者的“全部”
  • datasets.clear_data_home(data_home=None)
    清除目录下的数据
  • sklearn.datasets.fetch_20newsgroups
    参数:
class sklearn.datasets.fetch_20newsgroups(data_home=None, subset='train', categories=None, shuffle=True, random_state=42, remove=(), download_if_missing=True)
  """
  加载20个新闻组数据集中的文件名和数据

  :param subset: 'train'或者'test','all',可选,选择要加载的数据集:训练集的“训练”,测试集的“测试”,两者的“全部”,具有洗牌顺序


  :param data_home: 可选,默认值:无,指定数据集的下载和缓存文件夹。如果没有,所有scikit学习数据都存储在'〜/ scikit_learn_data'子文件夹中

  :param categories: 无或字符串或Unicode的集合,如果没有(默认),加载所有类别。如果不是无,要加载的类别名称列表(忽略其他类别)

  :param shuffle: 是否对数据进行洗牌

  :param random_state: numpy随机数生成器或种子整数

  :param download_if_missing: 可选,默认为True,如果False,如果数据不在本地可用而不是尝试从源站点下载数据,则引发IOError

  :param remove: 元组
  """

实现:

In [29]: from sklearn.datasets import fetch_20newsgroups

In [30]: data_test = fetch_20newsgroups(subset='test',shuffle=True, random_sta
    ...: te=42)

In [31]: data_train = fetch_20newsgroups(subset='train',shuffle=True, random_s
    ...: tate=42)

sklearn.datasets.fetch_20newsgroups_vectorized
参数:

class sklearn.datasets.fetch_20newsgroups_vectorized(subset='train', remove=(), data_home=None)
  """
  加载20个新闻组数据集并将其转换为tf-idf向量,这是一个方便的功能; 使用sklearn.feature_extraction.text.Vectorizer的默认设置完成tf-idf 转换。对于更高级的使用(停止词过滤,n-gram提取等),将fetch_20newsgroup与自定义Vectorizer或CountVectorizer组合在一起

  :param subset: 'train'或者'test','all',可选,选择要加载的数据集:训练集的“训练”,测试集的“测试”,两者的“全部”,具有洗牌顺序

  :param data_home: 可选,默认值:无,指定数据集的下载和缓存文件夹。如果没有,所有scikit学习数据都存储在'〜/ scikit_learn_data'子文件夹中

  :param remove: 元组
  """

实现:

In [57]: from sklearn.datasets import fetch_20newsgroups_vectorized

In [58]: bunch = fetch_20newsgroups_vectorized(subset='all')

In [59]: from sklearn.utils import shuffle

In [60]: X, y = shuffle(bunch.data, bunch.target)
    ...: offset = int(X.shape[0] * 0.8)
    ...: X_train, y_train = X[:offset], y[:offset]
    ...: X_test, y_test = X[offset:], y[offset:]
    ...:

模型检验-调优

一般在进行模型的测试时,我们会将数据分为训练集和测试集。在给定的样本空间中,拿出大部分样本作为训练集来训练模型,剩余的小部分样本使用刚建立的模型进行预测。

训练集与测试集

训练集与测试集的分割可以使用cross_validation中的train_test_split方法,大部分的交叉验证迭代器都内建一个划分数据前进行数据索引打散的选项,train_test_split 方法内部使用的就是交叉验证迭代器。默认不会进行打散,包括设置cv=some_integer(直接)k折叠交叉验证的cross_val_score会返回一个随机的划分。如果数据集具有时间性,千万不要打散数据再划分!

sklearn.model_selection.train_test_split 参数介绍:

def train_test_split(*arrays,**options)
  """
  :param arrays:允许的输入是列表,数字阵列

  :param test_size:float,int或None(默认为无),如果浮点数应在0.0和1.0之间,并且表示要包括在测试拆分中的数据集的比例。如果int,表示测试样本的绝对数

  :param train_size:float,int或None(默认为无),如果浮点数应在0.0到1.0之间,表示数据集包含在列车拆分中的比例。如果int,表示列车样本的绝对数

  :param random_state:int或RandomState,用于随机抽样的伪随机数发生器状态,参数 random_state 默认设置为 None,这意为着每次打散都是不同的。
  """

实例1:

from sklearn.model_selection import  train_test_split
from sklearn import datasets

iris = datasets.load_iris()
print(iris.data.shape,iris.target.shape)
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.4, random_state=42)
print(X_train.shape,y_train.shape)
print(X_test.shape,y_test.shape)

实例2:

from sklearn.model_selection import  train_test_split
from sklearn.datasets import load_iris


li=load_iris()
'''
注意返回值:
训练集train 表示训练集 ,x_train 训练集的特征值,y_train训练集的目标值   
测试集  test 表示测试集, x_test 测试集的特征值,y_test 是测试集的目标值 
'''
x_train,x_test,y_train,y_test=train_test_split(li.data,li.target,test_size=0.25) # test_size 测试集占百分之25

print("训练集特征值和目标值:",x_train,y_train)
print('测试集的特征值和目标值:',x_test,y_test)

k-折交叉验证

K折交叉验证,初始采样分割成K个子样本,一个单独的子样本被保留作为验证模型的数据,其他K-1个样本用来训练。交叉验证重复K次,每个子样本验证一次,平均K次的结果或者使用其它结合方式,最终得到一个单一估测。这个方法的优势在于,同时重复运用随机产生的子样本进行训练和验证,每次的结果验证一次,10折交叉验证是最常用的。
sklearn.model_selection.cross_val_score参数

def cross_val_score(estimator, X, y=None, groups=None, scoring=None, cv=None, n_jobs=1, verbose=0, fit_params=None, pre_dispatch='2*n_jobs')
  """
  :param estimator:模型估计器

  :param X:特征变量集合

  :param y:目标变量

  :param cv:int,使用默认的3折交叉验证,整数指定一个(分层)KFold中的折叠数

  :return :预估系数
  """

例子1

from sklearn.model_selection import cross_val_score
from sklearn import datasets
from sklearn import linear_model

diabetes = datasets.load_diabetes()
X = diabetes.data[:150]
y = diabetes.target[:150]
lasso = linear_model.Lasso()
li=cross_val_score(lasso, X, y,cv=10)# 这个是每次交叉验证的概率列表,
# cv:选择每次测试折数
print(li)
print(li.mean())

例子2:

from sklearn import datasets	#自带数据集
from sklearn.model_selection import train_test_split,cross_val_score	#划分数据 交叉验证
from sklearn.neighbors import KNeighborsClassifier  #一个简单的模型,只有K一个参数,类似K-means
import matplotlib.pyplot as plt
iris = datasets.load_iris()		#加载sklearn自带的数据集
X = iris.data 			#这是数据
y = iris.target 		#这是每个数据所对应的标签
train_X,test_X,train_y,test_y = train_test_split(X,y,test_size=1/3,random_state=3)	#这里划分数据以1/3的来划分 训练集训练结果 测试集测试结果
k_range = range(1,31)
cv_scores = []		#用来放每个模型的结果值
for n in k_range:
    knn = KNeighborsClassifier(n)   #knn模型,这里一个超参数可以做预测,当多个超参数时需要使用另一种方法GridSearchCV
    scores = cross_val_score(knn,train_X,train_y,cv=10,scoring='accuracy')  # 第一个参数是模型对象 cv:选择每次测试折数  accuracy:评价指标是准确度,可以省略使用默认值,具体使用参考下面。
    cv_scores.append(scores.mean())
plt.plot(k_range,cv_scores)
plt.xlabel('K')
plt.ylabel('Accuracy')		#通过图像选择最好的参数
plt.show()
best_knn = KNeighborsClassifier(n_neighbors=3)	# 选择最优的K=3传入模型
best_knn.fit(train_X,train_y)			#训练模型
print(best_knn.score(test_X,test_y))	#看看评分

使用交叉验证方法的目的主要有2个:

  • 从有限的学习数据中获取尽可能多的有效信息;
  • 可以在一定程度上避免过拟合问题

超参数搜索-网格搜索(找好的参数)

sklearn.model_selection.GridSearchCV
sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)

  • 对估计器的指定参数值进行详尽搜索

    • estimator:估计器对象
    • param_grid:估计器参数(dict){“n_neighbors”:[1,3,5]}
    • cv:指定几折交叉验证
    • fit:输入训练数据
    • score:准确率
  • 结果分析:

    • best_score_:在交叉验证中测试的最好结果
    • best_estimator_:最好的参数模型
    • cv_results_:每次交叉验证后的测试集准确率结果和训练集准确率结果
'''
这个程序不能运行,只说明过程
'''
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import  GridSearchCV

knn = KNeighborsClassifier() # 建立KNN算法的对象,

# 构造一些参数的值进行搜索,找到好的参数
param = {"n_neighbors": [3, 5, 10]}
# 这里假设训练数据
x_train, y_train=[],[]
# 进行网格搜索,自动交叉验证
# 这里传入需要验证的 算法,param_grid: 验证参数,cv是交叉验证分成几个
gc = GridSearchCV(knn, param_grid=param, cv=2)

gc.fit(x_train, y_train)

# 预测准确率,与交叉验证没有关系
# print(gc.predict(x_test))
# 这里假设测试数据
x_test=[]
y_test=[]
print("在测试集上准确率:", gc.score(x_test, y_test))

print("在交叉验证当中最好的结果:", gc.best_score_)

print("选择最好的模型是:", gc.best_estimator_)

print("每个超参数每次交叉验证的结果:", gc.cv_results_)

estimator的工作流程

在sklearn中,估计器(estimator)是一个重要的角色,分类器和回归器都属于estimator。在估计器中有有两个重要的方法是fit和transform。

  • fit方法用于从训练集中学习模型参数
  • transform用学习到的参数转换数据
  • 调用fit_transform(对于文档建立分类词频矩阵,不能同时调用)
    -在这里插入图片描述
;