Scikit-learn 是什么

既然我们已经建立了逻辑回归(Logistic Regression)的基础,让我们深入一些代码来构建一个模型。

为此,我们将介绍一个名为 scikit-learn 的 Python 模块。Scikit-learn,通常缩写为 sklearn ,是我们的科学工具包。

所有基本的机器学习算法都已经在 sklearn 中实现。我们将看到,只需几行代码,我们就可以构建几种不同的强大模型。

请注意,scikit-learn 正在不断更新。如果您的计算机上安装的模块版本略有不同,一切仍将正常工作,但您可能会看到与本文中略有不同的值。

Scikit-learn 是 Python 中文档最详尽的模块之一。您可以在 scikit-learn.org 上找到大量的代码示例。

使用 Pandas 准备数据

在我们使用 sklearn 构建模型之前,我们需要使用 Pandas 准备数据。让我们回到完整的数据集并回顾一下 Pandas 命令。

这是一个包含所有列的 Pandas DataFrame 数据:

Survived Pclass Sex Age SibSp Parch Fare
0 0 3 male 22.0 1 0 7.2500
1 1 1 female 38.0 1 0 71.2833
2 1 3 female 26.0 0 0 7.9250
3 1 1 female 35.0 1 0 53.1000
4 0 3 male 35.0 0 0 8.0500

注:SibSp 是 Sibling / Spouses;Parch 是 Parents / Children

首先,我们需要使所有列变成数值型。回顾一下如何为性别创建布尔列。

df['male'] = df['Sex'] == 'male'

现在,让我们将所有特征(features)创建一个名为 X 的 numpy 数组。我们首先选择我们感兴趣的所有列,然后使用 values 方法将其转换为 numpy 数组。

X = df[['Pclass', 'male', 'Age', 'SibSp', 'Parch', 'Fare']].values

现在让我们取目标(targets, Survived 列)并将其存储在变量 y 中。

y = df['Survived'].values

通常,我们习惯将特征的2D数组称为X,将目标值的1D数组称为y。

使用 Sklearn 构建逻辑回归模型

首先,我们需要从 skikit-learn 包中导入逻辑回归模型

from sklearn.linear_model import LogisticRegression

所有 sklearn 中的模型都被构建成了 Python 类,因此我们需要实例化这个类

model = LogisticRegression()

现在,我们可以使用之前准备的数据来训练模型。使用 fit 函数来构建模型,他接受两个参数:X(特征,是一个 2D numpy 数组),y(目标,是一个 1D numpy 数组)。

一切从简,我们使用 Fare 和 Age 作为特征来构建模型,首先我们定义特征和目标数组:

由于我们提供的数据有空值,所以需要对其进行预处理(Preprocessing),这里我们将年龄的空值填补为年龄的平均值,代码如下:

df['Age'].fillna(df['Age'].mean(), inplace=True)
X = df[['Fare', 'Age']].values
y = df['Survived'].values

别忘了加上 values 属性来获取 numpy array!

现在,使用 fit 来构建模型

model.fit(X, y)

拟合模型(Fitting the model)意味着使用数据选择最佳拟合线(a line of best fit)。我们可以使用 coef_intercept_ 属性来查看系数(coefficients)。

print(model.coef_, model.intercept_)

得到的返回值为:

[[ 0.01619443 -0.01738676]] [-0.45768136]

这个数据意味着我们的线性方程为:

所以我们可以再次调用 matplotlib 进行画图,你可以看到它在分割黄色和紫色点方面做得还不错(但不是很好)。通过仅使用2个特征,我们有点自限,所以在接下来的部分中,我们将使用所有特征。

# 获取系数和截距
coef = model.coef_[0]
intercept = model.intercept_[0]

# 计算决策边界上的两个点
x_values = np.array([25, 120])
y_values = (coef[0] * x_values + intercept) / -coef[1]

plt.scatter(df['Fare'], df['Age'], c=df['Survived'])
plt.plot(x_values, y_values)

plt.show()

记住不同 sklearn 模型的导入语句可能有点困难。如果记不住,只需查看 scikit-learn 文档

构建逻辑回归模型完整源码

今天的完整源码:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression

df = pd.read_csv('data/datasets/titanic/train.csv')

model = LogisticRegression()

# 填补缺失值
df['Age'].fillna(df['Age'].mean(), inplace=True)

X = df[['Fare', 'Age']].values
y = df['Survived'].values

model.fit(X, y)

# 获取系数和截距
coef = model.coef_[0]
intercept = model.intercept_[0]

# 计算决策边界上的两个点
x_values = np.array([25, 120])
y_values = (coef[0] * x_values + intercept) / -coef[1]

plt.scatter(df['Fare'], df['Age'], c=df['Survived'])
plt.plot(x_values, y_values)

使用我们构建的模型进行预测

在先前的部分中,我们只使用了两个特征,这实际上对我们的模型造成了一些限制,因此让我们使用所有特征重新构建模型。在这里,我们需要用到 male 字段,同时也要填补 Age 字段的缺省值:

df['male'] = df['Sex'] == 'male'
df['Age'].fillna(df['Age'].mean(), inplace=True)

X = df[['Pclass', 'male', 'Age', 'SibSp', 'Parch', 'Fare']].values
y = df['Survived'].values

model.fit(X, y)

现在,我们可以用 predict(X) 函数进行预测。数据集中的第一位乘客是:

PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
1 0 3 “Braund, Mr. Owen Harris” male 22 1 0 A/5 21171 7.25 S

其中我们要用到的数据为:

[3, True, 22, 1, 0, 7.25]
Survived Pclass male Age SibSp Parch Fare
0 3 True 22 1 0 7.25

这意味着该乘客位于 Pclass 3,男性,年龄22岁,有 1 名兄弟/配偶,0 名父母/子女,支付 7.25 美元。让我们看看模型对于这位乘客的预测结果。请注意,即使有一个数据点,predict 方法也需要一个二维的 numpy 数组并返回一个一维的 numpy 数组。

print(model.predict([[3, True, 22.0, 1, 0, 7.25]])) 

执行结果为 [0]。意味着模型预测的这位乘客并没有生还。

让我们看看模型对前5行数据的预测结果,并将其与目标数组进行比较。我们使用 X[:5] 获取前5行数据,使用 y[:5] 获取目标的前5个值。

print(model.predict(X[:5])) 
# [0 1 1 1 0]
print(y[:5])
# [0 1 1 1 0]

我们看到它全部预测正确!

事实上,训练模型我们需要将训练集与测试集分开,这就是为什么我们同时上传了 训练集测试集

predict 方法返回一个包含 1 和 0 的数组,其中 1 表示模型预测乘客生还,0 表示模型预测乘客没有生还。

使用模型进行预测的完整代码

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression

df = pd.read_csv('data/datasets/titanic/train.csv')

model = LogisticRegression()

df['male'] = df['Sex'] == 'male'
df['Age'].fillna(df['Age'].mean(), inplace=True)

X = df[['Pclass', 'male', 'Age', 'SibSp', 'Parch', 'Fare']].values
y = df['Survived'].values

model.fit(X, y)

print(model.predict([[3, True, 22.0, 1, 0, 7.25]]))

# 预测数据前五个值
print(model.predict(X[:5]))
# [0 1 1 1 0]
print(y[:5])
# [0 1 1 1 0]

评估模型的性能

通过计算模型正确预测的数据点数量,我们可以了解模型的表现好坏。这被称为准确率分数。

让我们创建一个包含预测的y值的数组。

y_pred = model.predict(X)

然后创建一个布尔值数组 y == y_pred,表示我们的模型是否正确预测了每个乘客。要获取其中为真的数量,我们可以使用 numpy 的 sum 方法。

print((y == y_pred).sum())

返回值为:711,这说明在 891 个数据点中,模型对其中的 711 个数据点进行了正确的预测。

为了得到百分比,我们将其除以总乘客数。我们使用 shape 属性获取总乘客数 y.shape[0]。计算准确性的分数如下:

print((y == y_pred).sum() / y.shape[0])
# 0.797979797979798

因此,模型的准确性为 79%。换句话说,模型在 79% 的数据点上做出了正确的预测。

这是一个足够常见的计算,sklearn 已经为我们实现了它。因此,我们可以使用 score 方法得到相同的结果。score 方法使用模型对 X 进行预测,计算匹配 y 的百分比。

print(model.score(X, y))

通过这种替代方法计算准确性,我们得到相同的值,79%。

评估模型性能的完整代码

import pandas as pd
from sklearn.linear_model import LogisticRegression

df = pd.read_csv('data/datasets/titanic/train.csv')

model = LogisticRegression()

df['male'] = df['Sex'] == 'male'
df['Age'].fillna(df['Age'].mean(), inplace=True)

X = df[['Pclass', 'male', 'Age', 'SibSp', 'Parch', 'Fare']].values
y = df['Survived'].values

model.fit(X, y)

y_pred = model.predict(X)

print((y == y_pred).sum())

print((y == y_pred).sum() / y.shape[0])

# 可以替换计算分数的公式
print(model.score(X, y))

练习

鉴于以下代码和输出,模型的准确性是多少?

print(model.predict(X))
print(y)

输出:

[1 0 0 0 1]
[1 1 0 0 0]

  • 60%
  • 20%
  • 80%
  • 40%

在给定的代码和输出中,模型的准确度可以通过比较预测值与实际值来计算。让我们统计正确预测的数量:

因此,正确答案是 $60%$。