python学习笔记第二十四天--------sklearn与特征工程

文章目录

  • 1. sklearn与特征工程
    • 1.1 数据的特征工程
    • 1.2 特征工程的意义
    • 1.3 特征工程之特征处理
    • 1.4 特征工程之特征抽取与特征选择
  • 2. 数据
    • 2.1 数据的类型
    • 2.2 数据的特征抽取
      • 2.2.1 分类特征变量提取
      • 2.2.2 文本特征提取
    • 2.3 数据的特征预处理
      • 2.3.1 单个特征
      • 2.3.2 多个特征
    • 2.4 数据的特征选择
  • 3. sklearn数据集与机器学习组成
    • 3.1 scikit-learn数据集
      • 3.1.1 sklearn.datasets
      • 3.1.2 获取小数据集
      • 3.1.3 获取大数据集
      • 3.1.4 获取本地生成数据
    • 3.2 模型的选择
      • 3.2.1 如何选择合适的算法模型
      • 3.2.2 监督学习中三类问题的解释
    • 3.3 模型检验-交叉验证
      • 3.3.1 训练集与测试集
      • 3.3.2 holdout method
      • 3.3.3 k-折交叉验证
    • 3.4 estimator的工作流程

1. sklearn与特征工程

​ “数据决定了机器学习的上限,而算法只是尽可能逼近这个上限”,这句话很好的阐述了数据在机器学习中的重要性。大部分直接拿过来的数据都是特征不明显的、没有经过处理的或者说是存在很多无用的数据,那么需要进行一些特征处理,特征的缩放等等,满足训练数据的要求。

Scikit-learn

  • Python语言的机器学习工具
  • 所有人都适用,可在不同的上下文中重用
  • 基于NumPy、SciPy和matplotlib构建
  • 开源、商业可用 - BSD许可
  • 目前稳定版本0.18

自2007年发布以来,scikit-learn已经成为最给力的Python机器学习库(library)了。scikit-learn支持的机器学习算法包括分类,回归,降维和聚类。还有一些特征提取(extracting features)、数据处理(processing data)和模型评估(evaluating models)的模块。作为Scipy库的扩展,scikit-learn也是建立在Python的NumPy和matplotlib库基础之上。NumPy可以让Python支持大量多维矩阵数据的高效操作,matplotlib提供了可视化工具,SciPy带有许多科学计算的模型。     scikit-learn文档完善,容易上手,丰富的API,使其在学术界颇受欢迎。开发者用scikit-learn实验不同的算法,只要几行代码就可以搞定。scikit-learn包括许多知名的机器学习算法的实现,包括LIBSVM和LIBLINEAR。还封装了其他的Python库,如自然语言处理的NLTK库。另外,scikit-learn内置了大量数据集,允许开发者集中于算法设计,节省获取和整理数据集的时间。

安装的话参考下面步骤: 创建一个基于Python3的虚拟环境:

mkvirtualenv -p /usr/local/bin/python3.6 ml3

在Centos7.5 的虚拟环境当中运行以下命令

pip3 install Scikit-learn

然后通过导入命令查看是否可以使用:

import sklearn

1.1 数据的特征工程

从数据中抽取出来的对预测结果有用的信息,通过专业的技巧进行数据处理,是的特征能在机器学习算法中发挥更好的作用。优质的特征往往描述了数据的固有结构。 最初的原始特征数据集可能太大,或者信息冗余,因此在机器学习的应用中,一个初始步骤就是选择特征的子集,或构建一套新的特征集,减少功能来促进算法的学习,提高泛化能力和可解释性。

例如:你要查看不同地域女性的穿衣品牌情况,预测不同地域的穿衣品牌。如果其中含有一些男性的数据,是不是要将这些数据给去除掉

1.2 特征工程的意义

  • 更好的特征意味着更强的鲁棒性
  • 更好的特征意味着只需用简单模型
  • 更好的特征意味着更好的结果

1.3 特征工程之特征处理

特征工程中最重要的一个环节就是特征处理,特征处理包含了很多具体的专业技巧

  • 特征预处理
    • 单个特征
      • 归一化
      • 标准化
      • 缺失值
    • 多个特征
      • 降维
        • PCA

1.4 特征工程之特征抽取与特征选择

如果说特征处理其实就是在对已有的数据进行运算达到我们目标的数据标准。特征抽取则是将任意数据格式(例如文本和图像)转换为机器学习的数字特征。而特征选择是在已有的特征中选择更好的特征。

2. 数据

2.1 数据的类型

按照机器学习的数据分类我们可以将数据分成:

  • 标称型:标称型目标变量的结果只在有限目标集中取值,如真与假(标称型目标变量主要用于分类)
  • 数值型:数值型目标变量则可以从无限的数值集合中取值,如0.100,42.001等 (数值型目标变量主要用于回归分析)

按照数据的本身分布特性

  • 离散型
  • 连续型

那么什么是离散型和连续型数据呢?首先连续型数据是有规律的,离散型数据是没有规律的

  • 离散变量是指其数值只能用自然数或整数单位计算的则为离散变量.例如,班级人数、进球个数、是否是某个类别等等
  • 连续型数据是指在指定区间内可以是任意一个数值,例如,票房数据、花瓣大小分布数据

2.2 数据的特征抽取

​ 现实世界中多数特征都不是连续变量,比如分类、文字、图像等,为了对非连续变量做特征表述,需要对这些特征做数学化表述,因此就用到了特征提取. sklearn.feature_extraction提供了特征提取的很多方法

2.2.1 分类特征变量提取

我们将城市和环境作为字典数据,来进行特征的提取。

sklearn.feature_extraction.DictVectorizer(sparse = True)

将映射列表转换为Numpy数组或scipy.sparse矩阵

  • sparse 是否转换为scipy.sparse矩阵表示,默认开启

方法

fit_transform(X,y)

应用并转化映射列表X,y为目标类型

inverse_transform(X[, dict_type])

将Numpy数组或scipy.sparse矩阵转换为映射列表

from sklearn.feature_extraction import DictVectorizer
onehot = DictVectorizer() # 如果结果不用toarray,请开启sparse=False
instances = [{'city': '北京','temperature':100},{'city': '上海','temperature':60}, {'city': '深圳','temperature':30}]
X = onehot.fit_transform(instances).toarray()
print(onehot.inverse_transform(X))

2.2.2 文本特征提取

文本的特征提取应用于很多方面,比如说文档分类、垃圾邮件分类和新闻分类。那么文本分类是通过词是否存在、以及词的概率(重要性)来表示。

(1)文档的中词的出现

数值为1表示词表中的这个词出现,为0表示未出现

sklearn.feature_extraction.text.CountVectorizer()

将文本文档的集合转换为计数矩阵(scipy.sparse matrices)

方法

fit_transform(raw_documents,y)

学习词汇词典并返回词汇文档矩阵

from sklearn.feature_extraction.text import CountVectorizer
content = ["life is short,i like python","life is too long,i dislike python"]
vectorizer = CountVectorizer()
print(vectorizer.fit_transform(content).toarray())

需要toarray()方法转变为numpy的数组形式

温馨提示:每个文档中的词,只是整个语料库中所有词,的很小的一部分,这样造成特征向量的稀疏性(很多值为0)为了解决存储和运算速度的问题,使用Python的scipy.sparse矩阵结构

(2)TF-IDF表示词的重要性

TfidfVectorizer会根据指定的公式将文档中的词转换为概率表示。(朴素贝叶斯介绍详细的用法)

class sklearn.feature_extraction.text.TfidfVectorizer()

方法

fit_transform(raw_documents,y)

学习词汇和idf,返回术语文档矩阵。

from sklearn.feature_extraction.text import TfidfVectorizer
content = ["life is short,i like python","life is too long,i dislike python"]
vectorizer = TfidfVectorizer(stop_words='english')
print(vectorizer.fit_transform(content).toarray())
print(vectorizer.vocabulary_)

2.3 数据的特征预处理

2.3.1 单个特征

(1)归一化

归一化首先在特征(维度)非常多的时候,可以防止某一维或某几维对数据影响过大,也是为了把不同来源的数据统一到一个参考区间下,这样比较起来才有意义,其次可以程序可以运行更快。 例如:一个人的身高和体重两个特征,假如体重50kg,身高175cm,由于两个单位不一样,数值大小不一样。如果比较两个人的体型差距时,那么身高的影响结果会比较大,k-临近算法会有这个距离公式。

min-max方法

常用的方法是通过对原始数据进行线性变换把数据映射到[0,1]之间,变换的函数为:

X^{’}{=}\frac{x-min}{max-min}X′=max−minx−min

其中min是样本中最小值,max是样本中最大值,注意在数据流场景下最大值最小值是变化的,另外,最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性较差,只适合传统精确小数据场景。

  • min-max自定义处理

这里我们使用相亲约会对象数据在MatchData.txt,这个样本时男士的数据,三个特征,玩游戏所消耗时间的百分比、每年获得的飞行常客里程数、每周消费的冰淇淋公升数。然后有一个 所属类别,被女士评价的三个类别,不喜欢、魅力一般、极具魅力。 首先导入数据进行矩阵转换处理

import numpy as np

def data_matrix(file_name):
  """
  将文本转化为matrix
  :param file_name: 文件名
  :return: 数据矩阵
  """
  fr = open(file_name)
  array_lines = fr.readlines()
  number_lines = len(array_lines)
  return_mat = zeros((number_lines, 3))
  # classLabelVector = []
  index = 0
  for line in array_lines:
    line = line.strip()
    list_line = line.split('\t')
    return_mat[index,:] = list_line[0:3]
    # if(listFromLine[-1].isdigit()):
    #     classLabelVector.append(int(listFromLine[-1]))
    # else:
    #     classLabelVector.append(love_dictionary.get(listFromLine[-1]))
    # index += 1
  return return_mat

输出结果为

[[  4.09200000e+04   8.32697600e+00   9.53952000e-01]
 [  1.44880000e+04   7.15346900e+00   1.67390400e+00]
 [  2.60520000e+04   1.44187100e+00   8.05124000e-01]
 ...,
 [  2.65750000e+04   1.06501020e+01   8.66627000e-01]
 [  4.81110000e+04   9.13452800e+00   7.28045000e-01]
 [  4.37570000e+04   7.88260100e+00   1.33244600e+00]]

我们查看数据集会发现,有的数值大到几万,有的才个位数,同样如果计算两个样本之间的距离时,其中一个影响会特别大。也就是说飞行里程数对于结算结果或者说相亲结果影响较大,但是统计的人觉得这三个特征同等重要,所以需要将数据进行这样的处理。

这样每个特征任意的范围将变成[0,1]的区间内的值,或者也可以根据需求处理到[-1,1]之间,我们再定义一个函数,进行这样的转换。

def feature_normal(data_set):
    """
    特征归一化
    :param data_set:
    :return:
    """
    # 每列最小值
    min_vals = data_set.min(0)
    # 每列最大值
    max_vals = data_set.max(0)
    ranges = max_vals - min_vals
    norm_data = np.zeros(np.shape(data_set))
    # 得出行数
    m = data_set.shape[0]
    # 矩阵相减
    norm_data = data_set - np.tile(min_vals, (m,1))
    # 矩阵相除
    norm_data = norm_data/np.tile(ranges, (m, 1)))
    return norm_data

输出结果为

[[ 0.44832535  0.39805139  0.56233353]
 [ 0.15873259  0.34195467  0.98724416]
 [ 0.28542943  0.06892523  0.47449629]
 ...,
 [ 0.29115949  0.50910294  0.51079493]
 [ 0.52711097  0.43665451  0.4290048 ]
 [ 0.47940793  0.3768091   0.78571804]]

这样得出的结果都非常相近,这样的数据可以直接提供测试验证了

  • min-max的scikit-learn处理

scikit-learn.preprocessing中的类MinMaxScaler,将数据矩阵缩放到[0,1]之间

>>> X_train = np.array([[ 1., -1.,  2.],
...                     [ 2.,  0.,  0.],
...                     [ 0.,  1., -1.]])
...
>>> min_max_scaler = preprocessing.MinMaxScaler()
>>> X_train_minmax = min_max_scaler.fit_transform(X_train)
>>> X_train_minmax
array([[ 0.5       ,  0.        ,  1.        ],
       [ 1.        ,  0.5       ,  0.33333333],
       [ 0.        ,  1.        ,  0.        ]])

(3)标准化

常用的方法是z-score标准化,经过处理后的数据均值为0,标准差为1,处理方法是:

X^{’}{=}\frac{x-\mu}{\sigma}X′=σx−μ

其中\muμ是样本的均值,\sigmaσ是样本的标准差,它们可以通过现有的样本进行估计,在已有的样本足够多的情况下比较稳定,适合嘈杂的数据场景

sklearn中提供了StandardScalar类实现列标准化:

In [2]: import numpy as np

In [3]: X_train = np.array([[ 1., -1.,  2.],[ 2.,  0.,  0.],[ 0.,  1., -1.]])

In [4]: from sklearn.preprocessing import StandardScaler

In [5]: std = StandardScaler()

In [6]: X_train_std = std.fit_transform(X_train)

In [7]: X_train_std
Out[7]:
array([[ 0.        , -1.22474487,  1.33630621],
       [ 1.22474487,  0.        , -0.26726124],
       [-1.22474487,  1.22474487, -1.06904497]])

(3)缺失值

由于各种原因,许多现实世界的数据集包含缺少的值,通常编码为空白,NaN或其他占位符。然而,这样的数据集与scikit的分类器不兼容,它们假设数组中的所有值都是数字,并且都具有和保持含义。使用不完整数据集的基本策略是丢弃包含缺失值的整个行和/或列。然而,这是以丢失可能是有价值的数据(即使不完整)的代价。更好的策略是估算缺失值,即从已知部分的数据中推断它们。

(1)填充缺失值 使用sklearn.preprocessing中的Imputer类进行数据的填充

class Imputer(sklearn.base.BaseEstimator, sklearn.base.TransformerMixin)
    """
    用于完成缺失值的补充

    :param param missing_values: integer or "NaN", optional (default="NaN")
        丢失值的占位符,对于编码为np.nan的缺失值,使用字符串值“NaN”

    :param strategy: string, optional (default="mean")
        插补策略
        如果是“平均值”,则使用沿轴的平均值替换缺失值
        如果为“中位数”,则使用沿轴的中位数替换缺失值
        如果“most_frequent”,则使用沿轴最频繁的值替换缺失

    :param axis: integer, optional (default=0)
        插补的轴
        如果axis = 0,则沿列排列
        如果axis = 1,则沿行排列
    """
>>> import numpy as np
>>> from sklearn.preprocessing import Imputer
>>> imp = Imputer(missing_values='NaN', strategy='mean', axis=0)
>>> imp.fit([[1, 2], [np.nan, 3], [7, 6]])
Imputer(axis=0, copy=True, missing_values='NaN', strategy='mean', verbose=0)
>>> X = [[np.nan, 2], [6, np.nan], [7, 6]]
>>> print(imp.transform(X))                          
[[ 4.          2.        ]
 [ 6.          3.666...]
 [ 7.          6.        ]]

2.3.2 多个特征

降维

PCA(Principal component analysis),主成分分析。特点是保存数据集中对方差影响最大的那些特征,PCA极其容易受到数据中特征范围影响,所以在运用PCA前一定要做特征标准化,这样才能保证每维度特征的重要性等同。

sklearn.decomposition.PCA

class PCA(sklearn.decomposition.base)
   """
   主成成分分析

   :param n_components: int, float, None or string
       这个参数可以帮我们指定希望PCA降维后的特征维度数目。最常用的做法是直接指定降维到的维度数目,此时n_components是一个大于1的整数。
       我们也可以用默认值,即不输入n_components,此时n_components=min(样本数,特征数)

   :param whiten: bool, optional (default False)
      判断是否进行白化。所谓白化,就是对降维后的数据的每个特征进行归一化。对于PCA降维本身来说一般不需要白化,如果你PCA降维后有后续的数据处理动作,可以考虑白化,默认值是False,即不进行白化

   :param svd_solver:
      选择一个合适的SVD算法来降维,一般来说,使用默认值就够了。
    """

通过一个例子来看

>>> import numpy as np
>>> from sklearn.decomposition import PCA
>>> X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
>>> pca = PCA(n_components=2)
>>> pca.fit(X)
PCA(copy=True, iterated_power='auto', n_components=2, random_state=None,
  svd_solver='auto', tol=0.0, whiten=False)
>>> print(pca.explained_variance_ratio_)
[ 0.99244...  0.00755...]

2.4 数据的特征选择

​ 降维本质上是从一个维度空间映射到另一个维度空间,特征的多少别没有减少,当然在映射的过程中特征值也会相应的变化。举个例子,现在的特征是1000维,我们想要把它降到500维。降维的过程就是找个一个从1000维映射到500维的映射关系。原始数据中的1000个特征,每一个都对应着降维后的500维空间中的一个值。假设原始特征中有个特征的值是9,那么降维后对应的值可能是3。而对于特征选择来说,有很多方法:

  • Filter(过滤式):VarianceThreshold
  • Embedded(嵌入式):正则化、决策树
  • Wrapper(包裹式)

其中过滤式的特征选择后,数据本身不变,而数据的维度减少。而嵌入式的特征选择方法也会改变数据的值,维度也改变。Embedded方式是一种自动学习的特征选择方法,后面讲到具体的方法的时候就能理解了。

特征选择主要有两个功能:

(1)减少特征数量,降维,使模型泛化能力更强,减少过拟合

(2)增强特征和特征值之间的理解

sklearn.feature_selection

去掉取值变化小的特征(删除低方差特征)

VarianceThreshold 是特征选择中的一项基本方法。它会移除所有方差不满足阈值的特征。默认设置下,它将移除所有方差为0的特征,即那些在所有样本中数值完全相同的特征。

假设我们要移除那些超过80%的数据都为1或0的特征

from sklearn.feature_selection import VarianceThreshold
X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
sel.fit_transform(X)
array([[0, 1],
       [1, 0],
       [0, 0],
       [1, 1],
       [1, 0],
       [1, 1]])

3. sklearn数据集与机器学习组成

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

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

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

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

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

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

  • 分类问题

优化:Optimization

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

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

(1)收集数据

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

(2)准备输入数据

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

(3)分析输入数据

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

(4)训练算法

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

(5)测试算法

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

(6)使用算法

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

3.1 scikit-learn数据集

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

删除存储目录中的数据

3.1.2 获取小数据集

用于分类

  • 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)
  """
In [12]: from sklearn.datasets import load_iris
    ...: data = load_iris()
    ...:

In [13]: data.target
Out[13]:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

In [14]: data.feature_names
Out[14]:
['sepal length (cm)',
 'sepal width (cm)',
 'petal length (cm)',
 'petal width (cm)']

In [15]: data.target_names
Out[15]:
array(['setosa', 'versicolor', 'virginica'],
      dtype='|S10')

In [17]: data.target[[1,10, 100]]
Out[17]: array([0, 0, 2])
名称 数量
类别 3
特征 4
样本数量 150
每个类别数量 50
  • 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.]]])
名称 数量
类别 10
特征 64
样本数量 1797

用于回归

  • 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)
  """
In [34]: from sklearn.datasets import load_boston

In [35]: boston = load_boston()

In [36]: boston.data.shape
Out[36]: (506, 13)

In [37]: boston.feature_names
Out[37]:
array(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
       'TAX', 'PTRATIO', 'B', 'LSTAT'],
      dtype='|S7')

In [38]:
名称 数量
目标类别 5-50
特征 13
样本数量 506
  • 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]])
名称 数量
目标范围 25-346
特征 10
样本数量 442

3.1.3 获取大数据集

  • 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:]
    ...:

3.1.4 获取本地生成数据

生成本地分类数据:

  • sklearn.datasets.make_classification

    class make_classification(n_samples=100, n_features=20, n_informative=2, n_redundant=2, n_repeated=0, n_classes=2, n_clusters_per_class=2, weights=None, flip_y=0.01, class_sep=1.0, hypercube=True, shift=0.0, scale=1.0, shuffle=True, random_state=None)
    """
    生成用于分类的数据集
    
    :param n_samples:int,optional(default = 100),样本数量
    
    :param n_features:int,可选(默认= 20),特征总数
    
    :param n_classes:int,可选(default = 2),类(或标签)的分类问题的数量
    
    :param random_state:int,RandomState实例或无,可选(默认=无)
      如果int,random_state是随机数生成器使用的种子; 如果RandomState的实例,random_state是随机数生成器; 如果没有,随机数生成器所使用的RandomState实例np.random
    
    :return :X,特征数据集;y,目标分类值
    """
    
from sklearn.datasets.samples_generator import make_classification
X,y= datasets.make_classification(n_samples=100000, n_features=20,n_informative=2, n_redundant=10,random_state=42)

生成本地回归数据:

  • sklearn.datasets.make_regression
class make_regression(n_samples=100, n_features=100, n_informative=10, n_targets=1, bias=0.0, effective_rank=None, tail_strength=0.5, noise=0.0, shuffle=True, coef=False, random_state=None)
  """
  生成用于回归的数据集

  :param n_samples:int,optional(default = 100),样本数量

  :param  n_features:int,optional(default = 100),特征数量

  :param  coef:boolean,optional(default = False),如果为True,则返回底层线性模型的系数

  :param random_state:int,RandomState实例或无,可选(默认=无)
    如果int,random_state是随机数生成器使用的种子; 如果RandomState的实例,random_state是随机数生成器; 如果没有,随机数生成器所使用的RandomState实例np.random

  :return :X,特征数据集;y,目标值
  """
from sklearn.datasets.samples_generator import make_regression
X, y = make_regression(n_samples=200, n_features=5000, random_state=42)

3.2 模型的选择

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

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

3.2.1 如何选择合适的算法模型

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

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

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

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

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

3.2.2 监督学习中三类问题的解释

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

分类问题包括学习和分类两个过程,在学习过程中,根据已知的训练数据集利用有效的学习方法学习一个分类器,在分类过程中,利用学习的分类器对新的输入实例进行分类。图中(X1,Y1),(X2,Y2)…都是训练数据集,学习系统有训练数据学习一个分类器P(Y|X)或Y=f(X);分类系统通过学习到的分类器对于新输入的实例子Xn+1进行分类,即预测术其输出的雷标记Yn+1

python学习笔记第二十四天--------sklearn与特征工程_第1张图片

分类在于根据其特性将数据“分门别类”,所以在许多领域都有广泛的应用。例如,在银行业务中,可以构建一个客户分类模型,按客户按照贷款风险的大小进行分类;在网络安全领域,可以利用日志数据的分类对非法入侵进行检测;在图像处理中,分类可以用来检测图像中是否有人脸出现;在手写识别中,分类可以用于识别手写的数字;在互联网搜索中,网页的分类可以帮助网页的抓取、索引和排序。

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

(2)回归问题

回归是监督学习的另一个重要问题。回归用于预测输入变量和输出变量之间的关系,特别是当初如变量的值发生变化时,输出变量的值随之发生的变化。回归模型正式表示从输入到输出变量之间映射的函数。回归稳日的学习等价与函数拟合:选择一条函数曲线使其更好的拟合已知数据且很好的预测位置数据

python学习笔记第二十四天--------sklearn与特征工程_第2张图片

回归问题按照输入变量的个数,分为一元回归和多元回归;按照输入变量和输出变量之间关系的类型即模型的类型,分为线性回归和非线性回归。

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

(3)标注问题

标注也是一个监督学习问题。可以认为标注问题是分类问题的一个推广,标注问题又是更复杂的结构预测问题的简单形式。标注问题的输入是一个观测序列,输出是一个标记序列或状态序列。标注问题在信息抽取、自然语言处理等领域广泛应用,是这些领域的基本问题。例如,自然语言处理的词性标注就是一个典型的标注,即对一个单词序列预测其相应的词性标记序

python学习笔记第二十四天--------sklearn与特征工程_第3张图片

当然我们主要关注的是分类和回归问题,并且标注问题的算法复杂

3.3 模型检验-交叉验证

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

3.3.1 训练集与测试集

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

  • sklearn.cross_validation.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,这意为着每次打散都是不同的。
  """
from sklearn.cross_validation 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

上面的方式也有局限。因为只进行一次测试,并不一定能代表模型的真实准确率。因为,模型的准确率和数据的切分有关系,在数据量不大的情况下,影响尤其突出。所以还需要一个比较好的解决方案。

模型评估中,除了训练数据和测试数据,还会涉及到验证数据。使用训练数据与测试数据进行了交叉验证,只有这样训练出的模型才具有更可靠的准确率,也才能期望模型在新的、未知的数据集上,能有更好的表现。这便是模型的推广能力,也即泛化能力的保证。

3.3.2 holdout method

评估模型泛化能力的典型方法是holdout交叉验证(holdout cross validation)。holdout方法很简单,我们只需要将原始数据集分割为训练集和测试集,前者用于训练模型,后者用于评估模型的性能。一般来说,Holdout 验证并非一种交叉验证,因为数据并没有交叉使用。 随机从最初的样本中选出部分,形成交叉验证数据,而剩余的就当做训练数据。 一般来说,少于原本样本三分之一的数据被选做验证数据。所以这种方法得到的结果其实并不具有说服性

3.3.3 k-折交叉验证

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

python学习笔记第二十四天--------sklearn与特征工程_第4张图片

例如5折交叉验证,全部可用数据集分成五个集合,每次迭代都选其中的1个集合数据作为验证集,另外4个集合作为训练集,经过5组的迭代过程。交叉验证的好处在于,可以保证所有数据都有被训练和验证的机会,也尽最大可能让优化的模型性能表现的更加可信。

使用交叉验证的最简单的方法是在估计器和数据集上使用cross_val_score函数。

  • sklearn.cross_validation.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 :预估系数
  """
from sklearn.cross_validation import cross_val_score
diabetes = datasets.load_diabetes()
X = diabetes.data[:150]
y = diabetes.target[:150]
lasso = linear_model.Lasso()
print(cross_val_score(lasso, X, y))

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

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

3.4 estimator的工作流程

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

  • fit方法用于从训练集中学习模型参数
  • transform用学习到的参数转换数据

python学习笔记第二十四天--------sklearn与特征工程_第5张图片

你可能感兴趣的:(机器学习)