机器学习入门(八)sklearn

--------韦访 20181101

1、概述

这一讲我们来学习机器学习中常用的一个库sklearn,用sklearn中的线性回归、逻辑回归和随机森林来预测泰坦尼克号人员获救情况。

2、安装sklearn

第一步,先安装sklearn库,如果还没安装sklearn库的话,使用下面的命令进行安装,

sudo pip install -U scikit-learn 

再执行下面的命令安装可视化工具,

sudo pip install pydotplus

sudo apt-get install graphviz

Sklearn的官网是:http://scikit-learn.org/stable/

上面有很多例子和示例代码,不过都是英文的,

 

3、泰坦尼克号数据分析

先来分析一下泰坦尼克号的数据,先来看一下数据结构,

 

如上图所示,泰坦数据供有12列,下面从左往右解释这些数据的含义,

PassengerId:乘客ID,其实也可以理解为行号,每一行代表一个乘客的数据,ID是唯一标示,没有重复的。

Survived:是否幸存下来,1表示幸存,0表示不幸。

Pclass:船舱等级,分为1、2、3等,根据后面对应的票价,1等舱是最贵的。

Name:乘客名字。

Sex:性别,male是男性,female是女性。

Age:年龄。

SibSp:兄弟姐妹、配偶在泰坦船上的数量。

Parch:父母、小孩在泰坦船上的数量。

Ticket:船票号。

Fare:船票价。

Cabin:仓号,很多乘客都没有这个数据。

Embarked:表示乘客在哪个港口上船的,共3个港口,分别为S、C、Q。

 

泰坦尼克号一共有1309个乘客的数据,我们将其分为训练数据titanic_train.csv和测试数据test.csv,其中,训练数据有891个,测试数据有418个。

4、数据预处理

第一列数据PassengerId,这个对是否获救没有什么影响的,舍弃。

第二列数据Survived表示乘客是否获救,我们来看看是否有哪些乘客的这个数据是空的。

import pandas as pd

def is_null_count(data, key):
    col_datas = data[key]
    is_null_data = col_datas[pd.isnull(col_datas)]
    return len(is_null_data)

taitan_data = pd.read_csv('titanic_train.csv')
print(is_null_count(taitan_data, 'Survived'))

运行结果,

0

说明这列数据都没有空缺。

第三列数据Pclass,表示船舱等级,看看是否完整,

import pandas as pd

def is_null_count(data, key):
    col_datas = data[key]
    is_null_data = col_datas[pd.isnull(col_datas)]
    return len(is_null_data)

taitan_data = pd.read_csv('titanic_train.csv')
print(is_null_count(taitan_data, 'Pclass'))
print(taitan_data['Pclass'].unique())

 运行结果:

没有缺失数据,并且船舱等级只有1、2、3等。

第四列数据Name,表示乘客名,名字也能影响获救情况吗?暂时不管。

第五列数据Sex,表示性别,这里都是用male和female来表示男女,但是这样的表示不方便我们处理,所以,对这列数据进行一下预处理,male用1表示,female用0表示,先借鉴上面的方法查看数据的完整性。然后,使用下面的代码对数据进行转换,

import pandas as pd

def is_null_count(data, key):
    col_datas = data[key]
    is_null_data = col_datas[pd.isnull(col_datas)]
    return len(is_null_data)

taitan_data = pd.read_csv('titanic_train.csv')
# print(is_null_count(taitan_data, 'Survived'))
print(is_null_count(taitan_data, 'Sex'))
print(taitan_data['Sex'].unique())
taitan_data.loc[taitan_data['Sex'] == 'male', 'Sex'] = 1
taitan_data.loc[taitan_data['Sex'] == 'female', 'Sex'] = 0
print(taitan_data['Sex'])

运行结果,

 第六列数据Age,表示年龄,也先来看看数据完整性,

import pandas as pd

def is_null_count(data, key):
    col_datas = data[key]
    is_null_data = col_datas[pd.isnull(col_datas)]
    return len(is_null_data)

taitan_data = pd.read_csv('titanic_train.csv')
print(is_null_count(taitan_data, 'Age'))

运行结果:

177

我靠,缺失177个,占比19.86%,这种情况下,要么对这列数据完全舍弃,要么为缺失的数据进行填充,我们能用的特征本来就少,那么,就用年龄的均值进行填充好了。代码如下,

import pandas as pd

def is_null_count(data, key):
    col_datas = data[key]
    is_null_data = col_datas[pd.isnull(col_datas)]
    return len(is_null_data)

taitan_data = pd.read_csv('titanic_train.csv')
is_null_age = pd.isnull(taitan_data['Age'])
taitan_data['Age'] = taitan_data['Age'].fillna(taitan_data['Age'].mean())
print(is_null_count(taitan_data, 'Age'))
print(taitan_data[is_null_age]['Age'])

运行结果:

第七列数据SibSp,表示兄弟姐妹、配偶在泰坦船上的数量。

第八列数据Parch,表示父母、小孩在泰坦船上的数量,

老规矩先看看数据是否有缺失,

import pandas as pd

def is_null_count(data, key):
    col_datas = data[key]
    is_null_data = col_datas[pd.isnull(col_datas)]
    return len(is_null_data)

taitan_data = pd.read_csv('titanic_train.csv')
print(is_null_count(taitan_data, 'SibSp'))
print(is_null_count(taitan_data, 'Parch'))

 

运行结果:

0

0

第九列数据Ticket,表示船票号,难道还有幸运数字一说吗?

第十列数据Fare,票价,这个其实跟船舱等级有点挂钩的,票价贵等级自然也贵。

第十一列数据Cabin,仓号,看看缺失数量的占比,

import pandas as pd

def is_null_count(data, key):
    col_datas = data[key]
    is_null_data = col_datas[pd.isnull(col_datas)]
    return len(is_null_data)

taitan_data = pd.read_csv('titanic_train.csv')
print(float(is_null_count(taitan_data, 'Cabin'))/len(taitan_data['SibSp']))

运行结果:

0.771043771044

缺失了77.1%,这个占比太大了,所以对于这种缺失太多的数据,宁可舍弃也不要使用。

第十二列数据Embarked,在哪个港口上船。分别为S、C、Q。我们也用0、1、2代替,

import pandas as pd

def is_null_count(data, key):
    col_datas = data[key]
    is_null_data = col_datas[pd.isnull(col_datas)]
    return len(is_null_data)

taitan_data = pd.read_csv('titanic_train.csv')
taitan_data.loc[taitan_data['Embarked'] == 'S', 'Embarked'] = 0
taitan_data.loc[taitan_data['Embarked'] == 'C', 'Embarked'] = 1
taitan_data.loc[taitan_data['Embarked'] == 'Q', 'Embarked'] = 2
print(taitan_data['Embarked'])
print(is_null_count(taitan_data, 'Embarked'))

运行结果:

Traceback (most recent call last):

  File "/home/insounds905/rookie/opencv/demo/unit5/demo1.py", line 9, in <module>

    taitan_data.loc[taitan_data['Embarked'] == 'S', 'Embarked'] = 0

  File "/usr/lib/python2.7/dist-packages/pandas/core/ops.py", line 576, in wrapper

    res[mask] = masker

  File "/usr/lib/python2.7/dist-packages/pandas/core/series.py", line 635, in __setitem__

    self.where(~key, value, inplace=True)

  File "/usr/lib/python2.7/dist-packages/pandas/core/generic.py", line 3026, in where

    cond = -(cond.fillna(True).astype(bool))

  File "/usr/lib/python2.7/dist-packages/pandas/core/series.py", line 1001, in __neg__

    arr = operator.neg(self.values)

TypeError: The numpy boolean negative, the `-` operator, is not supported, use the `~` operator or the logical_not function instead.

 

Process finished with exit code 1

出错了,提示说要用~来代替-,那我们试试,修改/usr/lib/python2.7/dist-packages/pandas/core/generic.py文件的第3026行,将-改为~,再运行,

 有两个数据是缺失的,那么,哪个数据最多我们就填充哪个。先来看哪个只最多,使用下面代码查看,

print(taitan_data['Embarked'].value_counts())

运行结果:

S    644

C    168

Q     77

可以看到,S最多,那么对缺失数据填充S好了。

import pandas as pd

def is_null_count(data, key):
    col_datas = data[key]
    is_null_data = col_datas[pd.isnull(col_datas)]
    return len(is_null_data)

taitan_data = pd.read_csv('titanic_train.csv')
print(taitan_data['Embarked'].value_counts())
taitan_data['Embarked'] = taitan_data['Embarked'].fillna('S')

taitan_data.loc[taitan_data['Embarked'] == 'S', 'Embarked'] = 0
taitan_data.loc[taitan_data['Embarked'] == 'C', 'Embarked'] = 1
taitan_data.loc[taitan_data['Embarked'] == 'Q', 'Embarked'] = 2
print(taitan_data['Embarked'])
print(is_null_count(taitan_data, 'Embarked'))

运行结果:

到这里,数据预处理完成,接下来分别使用线性回归、逻辑回归、随机森林来进行预测。

 

5、交叉验证

在将模型之前,先将一个概念-----交叉验证

假设我们有一堆数据,一般都是将其分为train数据和test数据,train数据用来训练模型,test数据用来测试模型的。如下图所示,

 

 交叉验证呢,就是再将train数据分成几份,比如分成3份,分别为A、B、C,然后,先用A、B作为train数据,C作为test数据;再用A、C作为train数据,B作为test数据;再用B、C作为train数据,A作为test数据。最后,记录每次训练的误差Ei,取其平均值作为总误差。模型如下图所示,

交叉验证有很多种,我这里以k折交叉验证法作为例子,说明一下sklearn中怎么使用,

代码如下,

from sklearn.model_selection import KFold
import numpy as np
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [5, 6], [7, 8], [5, 6], [7, 8], [5, 6], [7, 8], [5, 6], [7, 8]])
y = np.array([9, 10, 11, 12, 9, 10, 11, 12, 9, 10, 9, 10])
kf = KFold(n_splits=4)
kf.get_n_splits(X)

print(kf)

for train_index, test_index in kf.split(X):
    print("TRAIN:", train_index, "TEST:", test_index)

 运行结果,

从运行结果可以看出,其将数据分成了4等份,然后,每一等分都会成为test数据集,而且,如果它是test数据集时,不会同时为train数据集。

6、使用线性回归预测

首先,导入sklearn的线性回归模块和k折交叉验证模块,

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold

然后,使用第四步的代码进行数据预处理,这里就不贴代码了,

接着,选择使用哪些特征,对线性回归和交叉验证进行一些设置,

#使用到的特征
predictors = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]
#线性回归
alg = LinearRegression()
#k折交叉验证,将数据分为3段
kf = KFold(n_splits=3)

 然后,开始训练和评估模型,

#开始训练和评估模型
predictions = []
for train, test in kf.split(taitan_data):
    train_predictors = (taitan_data[predictors].iloc[train,:])
    # print(train_predictors)
    # print('---------')
    train_target = taitan_data["Survived"].iloc[train]
    # print(train_target)
    alg.fit(train_predictors, train_target)
    test_predictions = alg.predict(taitan_data[predictors].iloc[test,:])
    predictions.append(test_predictions)

 最后,输出评估结果,

#输出评估结果
predictions = np.concatenate(predictions, axis=0)
predictions[predictions > .5] = 1
predictions[predictions <=.5] = 0
accuracy = sum(predictions[predictions == taitan_data["Survived"]]) / len(predictions)
print accuracy

运行结果,

0.2615039281705948

才0.26? 会不会是选择的分界点有问题?那么,从0到1,每次提升0.1,作为分界点试试看?代码如下,

#输出评估结果
predictions = np.concatenate(predictions, axis=0)

for i in np.arange(0, 1, 0.1):
    tmp = predictions.copy()
    tmp[tmp > i] = 1
    tmp[tmp <= i] = 0
    accuracy = sum(tmp[tmp == taitan_data["Survived"]]) / len(tmp)
    print(i)
    print accuracy
    print('---------')

运行结果,

准确率也不是很高,我去百度拿别人的代码来运行,也是一样,不知道为什么这么低?哪位大神知道的话能否告知?谢谢。虽然这个预测结果不理想,完整的代码还是要贴一下,代码如下,

 

#encoding:utf-8

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold

import pandas as pd
import numpy as np

#检测数据为空的个数
def is_null_count(data, key):
    col_datas = data[key]
    is_null_data = col_datas[pd.isnull(col_datas)]
    return len(is_null_data)

#读取csv文件
taitan_data = pd.read_csv('titanic_train.csv')

#查看获救数据完整性
# print(is_null_count(taitan_data, 'Survived'))

#查看船舱等级数据完整性
# print(is_null_count(taitan_data, 'Pclass'))
# print(taitan_data['Pclass'].unique())

#查看性别的数据完整性,并将male转成1,female转成0
# print(is_null_count(taitan_data, 'Sex'))
# print(taitan_data['Sex'].unique())
taitan_data.loc[taitan_data['Sex'] == 'male', 'Sex'] = 0
taitan_data.loc[taitan_data['Sex'] == 'female', 'Sex'] = 1
# print(taitan_data['Sex'])

#查看年龄的数据完整性,对于空缺的年龄,使用平均年龄填充
is_null_age = pd.isnull(taitan_data['Age'])
taitan_data['Age'] = taitan_data['Age'].fillna(taitan_data['Age'].median())
# print(is_null_count(taitan_data, 'Age'))
# print(taitan_data[is_null_age]['Age'])

#查看SibSp和Parch的数据完整性
# print(is_null_count(taitan_data, 'SibSp'))
# print(is_null_count(taitan_data, 'Parch'))

#查看缺失数据占比
# print(float(is_null_count(taitan_data, 'Cabin'))/len(taitan_data['SibSp']))

#上船港口,将S、C、Q分别用0、1、2表示
# print(taitan_data['Embarked'].value_counts())
taitan_data['Embarked'] = taitan_data['Embarked'].fillna('S')
taitan_data.loc[taitan_data['Embarked'] == 'S', 'Embarked'] = 0
taitan_data.loc[taitan_data['Embarked'] == 'C', 'Embarked'] = 1
taitan_data.loc[taitan_data['Embarked'] == 'Q', 'Embarked'] = 2
# print(taitan_data['Embarked'])
# print(is_null_count(taitan_data, 'Embarked'))

#使用到的特征
predictors = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]

#线性回归
alg = LinearRegression()
#k折交叉验证,将数据分为3段
kf = KFold(n_splits=3)

#开始训练和评估模型
predictions = []
for train, test in kf.split(taitan_data):
    train_predictors = (taitan_data[predictors].iloc[train,:])
    # print(train_predictors)
    # print('---------')
    train_target = taitan_data["Survived"].iloc[train]
    # print(train_target)
    alg.fit(train_predictors, train_target)
    test_predictions = alg.predict(taitan_data[predictors].iloc[test,:])
    predictions.append(test_predictions)

#输出评估结果
predictions = np.concatenate(predictions, axis=0)

for i in np.arange(0, 1, 0.1):
    tmp = predictions.copy()
    tmp[tmp > i] = 1
    tmp[tmp <= i] = 0
    accuracy = sum(tmp[tmp == taitan_data["Survived"]]) / len(tmp)
    print(i)
    print accuracy
    print('---------')

7、使用逻辑回归预测

既然线性回归预测的准确率很低,那用逻辑回归呢?

逻辑回归的代码也很简单,上面数据预处理的代码就不重复写了,直接给主代码,

#逻辑回归
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression

alg = LogisticRegression(random_state=1)
scores = cross_val_score(alg, taitan_data[predictors], taitan_data["Survived"], cv=3)
print(scores.mean())

运行结果,

0.7878787878787877

准确率为0.78多,比上面的线性回归好很多了。

8、使用随机森林预测

使用sklearn实现随机森林也很简单,

#随机森林
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.ensemble import RandomForestClassifier
alg = RandomForestClassifier(random_state=1, n_estimators=10, min_samples_split=2, min_samples_leaf=1)
kf = KFold(n_splits=3, random_state=1)
scores = cross_val_score(alg, taitan_data[predictors], taitan_data["Survived"], cv=kf)
print(scores.mean())

运行结果:

0.7856341189674523

跟逻辑回归的准确率差不多?别急,上面建森林时,只用了10棵树,我们将树的数量加到200棵,且将min_samples_split改为10看看,

#随机森林
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.ensemble import RandomForestClassifier

alg = RandomForestClassifier(random_state=1, n_estimators=200, min_samples_split=10, min_samples_leaf=1)

kf = KFold(n_splits=3, random_state=1)
scores = cross_val_score(alg, taitan_data[predictors], taitan_data["Survived"], cv=kf)

print(scores.mean())

运行结果,

0.8249158249158249

9、对比特征重要程度

#查看特征的重要性
from sklearn.feature_selection import SelectKBest, f_classif
import matplotlib.pyplot as plt

selector = SelectKBest(f_classif, k=5)
selector.fit(taitan_data[predictors], taitan_data["Survived"])

scores = -np.log10(selector.pvalues_)

plt.bar(range(len(predictors)), scores)
plt.xticks(range(len(predictors)), predictors, rotation='vertical')
plt.show()

运行结果,

可以看到,性别特征对获救的影响是最大的,其次是仓位,看过泰坦尼克号的电影也看到,老人和女人是优先获救的,那时候的人还是比较绅士的。

 

如果您感觉本篇博客对您有帮助,请打开支付宝,领个红包支持一下,祝您扫到99元,谢谢~~

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值