【2】监督学习--1--分类

一、监督学习的目标

利用一组带有标签的数据,学习从输入到输出的映射,然后将这种映射 关系应用到未知数据上,达到分类或回归的目的。

分类:当输出是离散的,学习任务为分类任务。

回归:当输出是连续的,学习任务为回归任务。

二、分类学习

输入:一组有标签的训练数据(也称观察和评估),标签表明了这些数 据(观察)的所署类别。

输出:分类模型根据这些训练数据,训练自己的模型参数,学习出一个

适合这组数据的分类器,当有新数据(非训练数据)需要进行类别判断,就 可以将这组新数据作为输入送给学好的分类器进行判断。

1.分类学习-评价

  • 训练集(training set):顾名思义用来训练模型的已标注数据,用来建 立模型,发现规律。
  • 测试集(testing set):也是已标注数据,通常做法是将标注隐藏,输送 给训练好的模型,通过结果与真实标注进行对比,评估模型的学习能力。 训练集/测试集的划分方法:根据已有标注数据,随机选出一部分数据 (70%)数据作为训练数据,余下的作为测试数据,此外还有交叉验证法, 自助法用来评估分类模型

2.分类学习-评价标准

精确率:精确率是针对我们预测结果而言的,(以二分类为例)它表示 的是预测为正的样本中有多少是真正的正样本。那么预测为正就有两种可能 了,一种就是把正类预测为正类(TP),另一种就是把负类预测为正类(FP), 也就是

P = (TP)/(TP+FP)

召回率:是针对我们原来的样本而言的,它表示的是样本中的正例有多 少被预测正确了。那也有两种可能,一种是把原来的正类预测成正类(TP), 另一种就是把原来的正类预测为负类(FN),也就是

R = TP/(TP+RN)

假设我们手上有60个正样本,40个负样本,我们要找出所有的正样本,分 类算法查找出50个,其中只有40个是真正的正样本,

TP: 将正类预测为正 类数 40;FN: 将正类预测为负类数 20;
FP: 将负类预测为正类数 10; TN: 将负类预测为负类数 30
准确率(accuracy)=预测对的/所有 = (TP+TN)/(TP+FN+FP+TN) = 70% 
精确率(precision)=?
召回率(recall)=?

3.Sklearn vs. 分类

与聚类算法被统一封装在sklearn.cluster 模块不同,sklearn库中的分类算法并未被统一 封装在一个子模块中,因此对分类算法的import 方式各有不同。

Sklearn提供的分类函数包括:

  • k近邻(knn)
  • 朴素贝叶斯(naivebayes),
  • 支持向量机(svm),
  • 决策树 (decision tree)
  • 神经网络模型(Neural networks)等
  • 这其中有线性分类器,也有非线性分类器

4.分类算法的应用

金融:贷款是否批准进行评估

  • 医疗诊断:判断一个肿瘤是恶性还是良性
  • 欺诈检测:判断一笔银行的交易是否涉嫌欺诈
  • 网页分类:判断网页的所属类别,财经或者是娱乐?

5.案例分析

##人体运动状态预测-实例分析

5.1 背景介绍

  • 可穿戴式设备的流行,让我们可以更便利地使用传感器获取人体的各项数据, 甚至生理数据。
  • 当传感器采集到大量数据后,我们就可以通过对数据进行分析和建模,通过 各项特征的数值进行用户状态的判断,根据用户所处的状态提供给用户更加 精准、便利的服务

5.2 数据介绍

  • 我们现在收集了来自 A,B,C,D,E 5位用户的可穿戴设备上的传感器数据, 每位用户的数据集包含一个特征文件(a.feature)和一个标签文件 (a.label)。
  • 特征文件中每一行对应一个时刻的所有传感器数值,标签文件中每行记录了 和特征文件中对应时刻的标记过的用户姿态,两个文件的行数相同,相同行 之间互相对应。

特征文件的各项特征具体如下表所示

1 |2 |3-15 | 16-28 | 29-41 时间戳 | 心率 | 传感器1 | 传感器2 | 传感器3

在传感器1对应的13列数据特征中,包含:1项温度数据、3项一型三轴加速 度数据、3项二型三轴加速度数据、3项三轴陀螺仪数据和3项三轴磁场数据

3 |4-6 | 7-9 | 10-12 | 13-15 温度 |一型三轴加速度二型三轴加速度 | 三轴陀螺仪| 三轴磁场

人体的温度数据可以反映当前活动的剧烈程度,一般在静止状态时,体温趋 于稳定在36.5度上下;当温度高于37度时,可能是进行短时间的剧烈运动,比 如跑步和骑行。

在数据中有两个型号的加速度传感器,可以通过互相印证的方式,保证数据 的完整性和准确性。通过加速度传感器对应的三个数值,可以知道空间中x、y、 z三个轴上对应的加速度,而空间上的加速度和用户的姿态有密切的关系,比如 用户向上起跳时,z轴上的加速度会激增。

陀螺仪是角运动检测的常用仪器,可以判断出用户佩戴传感器时的身体角度 是水平、倾斜还是垂直。直观地,通过这些数值都是推断姿态的重要指标。

磁场传感器可以检测用户周围的磁场强度和数值大小,这些数据可以帮助我 们理解用户所处的环境。比如在一个办公场所,用户座位附近的磁场是大体上固 定的,当磁场发生改变时,我们可以推断用户的位置和场景发生了变化。

标签文件内容如图所示,每一行代表与特征文件中对应行的用户姿态类别。 总共有0-24共25种身体姿态,如,无活动状态,坐态、跑态等。标签文件作为 训练集的标准参考准则,可以进行特征的监督学习。

5.3任务介绍

假设现在出现了一个新用户,但我们只有传感器采集的数据,那么该如何得到 这个新用户的姿态呢? 又或者对同一用户如果传感器采集了新的数据,怎么样根据新的数据判断当前 用户处于什么样的姿态呢?

在明确这是一个分类问题的情况下,我们可以选定某种分类模型(或者说是 算法),通过使用训练数据进行模型学习,然后对每个测试样本给出对应的分类 结果。

机器学习的分类算法众多,在接下来的学习中我们将会详细介绍经典的分类 算法,如K近邻、决策树和朴素贝叶斯的原理和实现。

基本分类模型

##K近邻分类器(KNN)

KNN:通过计算待分类数据点,与 已有数据集中的所有数据点的距离。取 距离最小的前K个点,根据“少数服从 多数“的原则,将这个数据点划分为出 现次数最多的那个类别。

sklearn中的K近邻分类器

在sklearn库中,可以使用sklearn.neighbors.KNeighborsClassifier 创建一个K近邻分类器,主要参数有:

  • n_neighbors:用于指定分类器中K的大小(默认值为5,注意与 kmeans的区别)
  • weights:设置选中的K个点对分类结果影响的权重(默认值为平均 权重“uniform”,可以选择“distance”代表越近的点权重越高, 或者传入自己编写的以距离为参数的权重计算函数)

它的主要参数还有:

  • algorithm:设置用于计算临近点的方法,因为当数据量很大的情况 下计算当前点和所有点的距离再选出最近的k各点,这个计算量是很 费时的,所以(选项中有ball_tree、kd_tree和brute,分别代表不 同的寻找邻居的优化算法,默认值为auto,根据训练数据自动选择)

K近邻分类器的使用 创建一组数据 X 和它对应的标签 y:

X = [[0], [1], [2], [3]] 
y = [0, 0, 1, 1]

使用 import 语句导入 K 近邻分类器。

from sklearn.neighbors import KNeighborsClassifier

参数 n_neighbors 设置为 3,即使用最近的3个邻居作为分类的依据,其他参 数保持默认值,并将创建好的实例赋给变量 neigh。

>>> neigh = KNeighborsClassifier(n_neighbors=3)

调用 fit() 函数,将训练数据 X 和 标签 y 送入分类器进行学习。

>>> neigh.fit(X, y)

调用 predict() 函数,对未知分类样本 [1.1] 分类,可以直接并将需要分类 的数据构造为数组形式作为参数传入,得到分类标签作为返回值。

>>> print(neigh.predict([[1.1]]))
[0]

样例输出值是 0,表示K近邻分类器通过计算样本 [1.1] 与训练数据的距离, 取 0,1,2 这 3 个邻居作为依据,根据“投票法”最终将样本分为类别 0。

KNN的使用经验

在实际使用时,我们可以使用所有训练数据构成特征 X 和标签 y,使用 fit() 函数进行训练。在正式分类时,通过一次性构造测试集或者一个一个输入 样本的方式,得到样本对应的分类结果。有关K 的取值:

  • 如果较大,相当于使用较大邻域中的训练实例进行预测,可以减小估计误差,但是距离较远的样本也会对预测起作用,导致预测错误。
  • 相反地,如果 K 较小,相当于使用较小的邻域进行预测,如果邻居恰好是噪声点,会导致过拟合。
  • 一般情况下,K 会倾向选取较小的值,并使用交叉验证法选取最优 K 值。

决策树

决策树是一种树形结构的分类器,通过顺序询问分类点的属性决定分类点最终的类别。通常 根据特征的信息增益或其他指标,构建一颗决策树。在分类时,只需要按照决策树中的结点依次 进行判断,即可得到样本所属类别。 例如,根据右图这个构造好的分类决策树,一个无房产,单身,年收入55K的人的会被归入 无法偿还信用卡这个类别。

sklearn中的决策树

在sklearn库中,可以使用sklearn.tree.DecisionTreeClassifier创 建一个决策树用于分类,其主要参数有:

  • criterion :用于选择属性的准则,可以传入“gini”代表基尼 系数,或者“entropy”代表信息增益。
  • max_features :表示在决策树结点进行分裂时,从多少个特征 中选择最优特征。可以设定固定数目、百分比或其他标准。它 的默认值是使用所有特征个数

决策树的使用 首先,我们导入 sklearn 内嵌的鸢尾花数据集:

>>> from sklearn.datasets import load_iris

接下来,我们使用 import 语句导入决策树分类器,同时导入计算交叉验 证值的函数 cross_val_score。

>>> from sklearn.tree import DecisionTreeClassifier
>>> from sklearn.model_selection import cross_val_score

我们使用默认参数,创建一颗基于基尼系数的决策树,并将该决策树分类 器赋值给变量 clf。

>>> clf = DecisionTreeClassifier()

将鸢尾花数据赋值给变量 iris。

>>> iris = load_iris()

这里我们将决策树分类器做为待评估的模型,iris.data鸢尾花数据做为特征, iris.target鸢尾花分类标签做为目标结果,通过设定cv为10,使用10折交叉验 证。得到最终的交叉验证得分。

>>> cross_val_score(clf, iris.data, iris.target, cv=10) ...
array([ 1. , 0.93..., 0.86..., 0.93..., 0.93...,
0.93..., 0.93..., 1. , 0.93..., 1. ])

以仿照之前 K近邻分类器的使用方法,利用 fit() 函数训练模型并使用 predict() 函数预测:

>>> clf.fit(X, y) 
>>> clf.predict(x)
  • 决策树本质上是寻找一种对特征空间上的划分,旨在构建一个训练数据拟合的 好,并且复杂度小的决策树。
  • 在实际使用中,需要根据数据情况,调整DecisionTreeClassifier类中传入的 参数,比如选择合适的criterion,设置随机变量等。

朴素贝叶斯

朴素贝叶斯分类器是一个以贝叶斯定理为基础的多分类的分类器。 对于给定数据,首先基于特征的条件独立性假设,学习输入输出的联合概率分布,然后基于此模 型,对给定的输入x,利用贝叶斯定理求出后验概率最大的输出y。

sklearn中的朴素贝叶斯

在sklearn库中,实现了三个朴素贝叶斯分类器,如下表所示:

分类器 描述 naive_bayes.GussianNB 高斯朴素贝叶斯 naive_bayes.MultinomialNB 针对多项式模型的朴素贝叶斯分类器 naive_bayes.BernoulliNB 针对多元伯努利模型的朴素贝叶斯分类器

区别在于假设某一特征的所有属于某个类别的观测值符合特定分布,如,分 类问题的特征包括人的身高,身高符合高斯分布,这类问题适合高斯朴素贝叶斯

sklearn中的朴素贝叶斯

sklearn库中,可以使用sklearn.naive_bayes.GaussianNB创建一个高斯 朴素贝叶斯分类器,其参数有:

  • priors :给定各个类别的先验概率。如果为空,则按训练数据的实际情况 进行统计;如果给定先验概率,则在训练过程中不能更改。

朴素贝叶斯的使用

例1:导入 numpy 库,并构造训练数据 X 和 y。

>>> import numpy as np
>>> X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]]) 
>>> Y = np.array([1, 1, 1, 2, 2, 2])

使用 import 语句导入朴素贝叶斯分类器。

from sklearn.naive_bayes import GaussianNB

使用默认参数,创建一个高斯朴素贝叶斯分类器,并将该分类器赋给变量 clf。

>>> clf = GaussianNB(priors=None)

类似的,使用 fit() 函数进行训练,并使用 predict() 函数进行预测,得到 预测结果为 1。(测试时可以构造二维数组达到同时预测多个样本的目的)

>>> clf.fit(X, Y)
>>> print(clf.predict([[-0.8, -1]]))
[1]

朴素贝叶斯是典型的生成学习方法,由训练数据学习联合概率分布,并求得 后验概率分布。 朴素贝叶斯一般在小规模数据上的表现很好,适合进行多分类任务。

算法流程

  • 需要从特征文件和标签文件中将所有数据加载到内存中,由于存在缺失值,此步骤还需要进行简单的数据 预处理。
  • 创建对应的分类器,并使用训练数据进行训练。
  • 利用测试集预测,通过使用真实值和预测值的比对,
  • 计算模型整体的准确率和召回率,来评测模型。

代码:

import pandas as pd
import numpy as np  

from sklearn.preprocessing import Imputer
from sklearn.cross_validation import train_test_split 
from sklearn.metrics import classification_report #导入预测结果评估模块classification_report

from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB

def load_datasets(feature_paths, label_paths):
    feature = np.ndarray(shape=(0,41))
    label = np.ndarray(shape=(0,1))
    for file in feature_paths:
        df = pd.read_table(file, delimiter=',', na_values='?', header=None)
        imp = Imputer(missing_values='NaN', strategy='mean', axis=0)
        imp.fit(df)
        df = imp.transform(df)
        feature = np.concatenate((feature, df))

    for file in label_paths:
        df = pd.read_table(file, header=None)
        label = np.concatenate((label, df))

    label = np.ravel(label)
    return feature, label

if __name__ == '__main__':
    ''' 数据路径 '''
    featurePaths = ['A/A.feature','B/B.feature','C/C.feature','D/D.feature','E/E.feature']
    labelPaths = ['A/A.label','B/B.label','C/C.label','D/D.label','E/E.label']
    ''' 读入数据  '''
    x_train,y_train = load_datasets(featurePaths[:4],labelPaths[:4])
    x_test,y_test = load_datasets(featurePaths[4:],labelPaths[4:])
    x_train, x_, y_train, y_ = train_test_split(x_train, y_train, test_size = 0.0)

    print('Start training knn')
    knn = KNeighborsClassifier().fit(x_train, y_train)
    print('Training done')
    answer_knn = knn.predict(x_test)
    print('Prediction done')

    print('Start training DT')
    dt = DecisionTreeClassifier().fit(x_train, y_train)
    print('Training done')
    answer_dt = dt.predict(x_test)
    print('Prediction done')

    print('Start training Bayes')
    gnb = GaussianNB().fit(x_train, y_train)
    print('Training done')
    answer_gnb = gnb.predict(x_test)
    print('Prediction done')

    print('\n\nThe classification report for knn:')
    print(classification_report(y_test, answer_knn))
    print('\n\nThe classification report for DT:')
    print(classification_report(y_test, answer_dt))
    print('\n\nThe classification report for Bayes:')
    print(classification_report(y_test, answer_gnb))
  • 在所有的特征数据中,可能存在缺失值或者冗余特征。如果将这些特征不加处 理地送入后续的计算,可能会导致模型准确度下降并且增大计算量。
  • 在特征选择阶段,通常需要借助辅助软件(例如Weka)将数据进行可视化并进 行统计。
  • 请大家可以通过课外学习思考如何筛选冗余特征,提高模型训练效率,也可以 尝试调用sklearn提供的其他分类器进行数据预测。

案例:上证指数涨跌预测

数据介绍:

上证指数涨跌预测 网易财经上获得的上证指数的历史数据,爬取了20年的上证指数数据。 实验目的: 根据给出当前时间前150天的历史数据,预测当天上证指数的涨跌。

技术路线:sklearn.svm.SVC

import pandas as pd
import numpy as np
from sklearn import svm
from sklearn import cross_validation

data=pd.read_csv('stock/000777.csv',encoding='gbk',parse_dates=[0],index_col=0) #(数据源, encoding=编码格式为gbk, parse_dates=第0列解析为日期, index_col= 用作行索引的列编号)
data.sort_index(0,ascending=True,inplace=True) #详细解释( http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.sort_index.html ) DataFrame.sort_index(axis=0 (按0列排), ascending=True(升序), inplace=False(排序后是否覆盖原 数据))data 按照时间升序排列

dayfeature=150
featurenum=5*dayfeature
x=np.zeros((data.shape[0]-dayfeature,featurenum+1))
y=np.zeros((data.shape[0]-dayfeature))

#参数解释:
选取5列数据作为特征:收盘价 最高价 最低价 开盘价 成交量 dayfeature:选取150天的数据 featurenum:选取的5个特征*天数 x:记录150天的5个特征值
y:记录涨或者跌
data.shape[0]-dayfeature意思是因为我们要用150天数据做训练,对于条目为200条的数据,只有50条数 据是有前150天的数据来训练的,所以训练集的大小就是200-150, 对于每一条数据,他的特征是前150 天的所有特征数据,即150*5, +1是将当天的开盘价引入作为一条特征数据



for i in range(0,data.shape[0]-dayfeature):
    x[i,0:featurenum]=np.array(data[i:i+dayfeature] \
          [[u'收盘价',u'最高价',u'最低价',u'开盘价',u'成交量']]).reshape((1,featurenum))
    x[i,featurenum]=data.ix[i+dayfeature][u'开盘价']

for i in range(0,data.shape[0]-dayfeature):
    if data.ix[i+dayfeature][u'收盘价']>=data.ix[i+dayfeature][u'开盘价']:
        y[i]=1
    else:
        y[i]=0          

clf=svm.SVC(kernel='rbf')  #
//调用svm函数,并设置kernel参数,默认是rbf,其它:‘linear ’‘poly’‘sigmoid’

result = []
for i in range(5):
    x_train, x_test, y_train, y_test = \
                cross_validation.train_test_split(x, y, test_size = 0.2) #//x和y的验证集和测试集,切分80-20%的测试集
    clf.fit(x_train, y_train)
    result.append(np.mean(y_test == clf.predict(x_test)))  #/将预测数据和测试集的验证数据比对
print("svm classifier accuacy:")
print(result)

交叉验证

基本思想:

交叉验证法先将数据集D划分为k个大小相似的互斥子集,每个自己都尽可能保持数 据分布的一致性,即从D中通过分层采样得到。然后,每次用k-1个子集的并集作为 训练集,余下的那个子集作为测试集;这样就可获得k组训练/测试集,从而可进行k 次训练和测试,最终返回的是这个k个测试结果的均值。通常把交叉验证法称为“k者 交叉验证”, k最常用的取值是10,此时称为10折交叉验证。

个人公众号,比较懒,很少更新,可以在上面提问题:

更多精彩,请移步公众号阅读:

Sam avatar
About Sam
专注生物信息 专注转化医学