使用 Estimators 构建线性模型

在 TensorFlow.org 上查看 在 Google Colab 中运行 在 GitHub 上查看源码 下载笔记本

概览

本端到端演练使用 tf.estimator API 训练逻辑回归模型。该模型通常用作其他更复杂算法的基准。

设置

pip install sklearn
import os
import sys

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import clear_output
from six.moves import urllib

加载泰坦尼克号数据集

你将使用泰坦尼克号数据集,目标(虽然有些令人伤感)是根据乘客的性别、年龄、舱位等特征来预测其生存情况。

import tensorflow.compat.v2.feature_column as fc

import tensorflow as tf
# Load dataset.
dftrain = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/train.csv')
dfeval = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/eval.csv')
y_train = dftrain.pop('survived')
y_eval = dfeval.pop('survived')

探索数据

该数据集包含以下特征

dftrain.head()
dftrain.describe()

训练集和评估集分别包含 627 条和 264 条数据。

dftrain.shape[0], dfeval.shape[0]

大多数乘客的年龄在 20 多岁和 30 多岁。

dftrain.age.hist(bins=20)

船上的男性乘客人数大约是女性乘客的两倍。

dftrain.sex.value_counts().plot(kind='barh')

大多数乘客位于“三等舱”。

dftrain['class'].value_counts().plot(kind='barh')

女性的生还几率远高于男性。这显然是该模型的一个重要预测特征。

pd.concat([dftrain, y_train], axis=1).groupby('sex').survived.mean().plot(kind='barh').set_xlabel('% survive')

模型特征工程

Estimators 使用一种称为特征列 (feature columns) 的系统来描述模型应如何解析每个原始输入特征。Estimator 需要数值输入向量,而特征列描述了模型应如何转换每个特征。

选择和构建合适的特征列集是学习有效模型的关键。特征列可以是原始特征 dict 中的某个原始输入(基础特征列),也可以是使用在一个或多个基础列上定义的转换所创建的新列(派生特征列)。

线性估计器使用数值特征和分类特征。特征列适用于所有 TensorFlow 估计器,其目的是定义用于建模的特征。此外,它们还提供了一些特征工程功能,如独热编码 (one-hot-encoding)、归一化和分桶 (bucketization)。

基础特征列

CATEGORICAL_COLUMNS = ['sex', 'n_siblings_spouses', 'parch', 'class', 'deck',
                       'embark_town', 'alone']
NUMERIC_COLUMNS = ['age', 'fare']

feature_columns = []
for feature_name in CATEGORICAL_COLUMNS:
  vocabulary = dftrain[feature_name].unique()
  feature_columns.append(tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary))

for feature_name in NUMERIC_COLUMNS:
  feature_columns.append(tf.feature_column.numeric_column(feature_name, dtype=tf.float32))

input_function 指定了如何将数据转换为以流式方式馈送输入流水线的 tf.data.Datasettf.data.Dataset 可以接收多种源,例如数据帧 (dataframe)、CSV 格式文件等。

def make_input_fn(data_df, label_df, num_epochs=10, shuffle=True, batch_size=32):
  def input_function():
    ds = tf.data.Dataset.from_tensor_slices((dict(data_df), label_df))
    if shuffle:
      ds = ds.shuffle(1000)
    ds = ds.batch(batch_size).repeat(num_epochs)
    return ds
  return input_function

train_input_fn = make_input_fn(dftrain, y_train)
eval_input_fn = make_input_fn(dfeval, y_eval, num_epochs=1, shuffle=False)

你可以查看数据集

ds = make_input_fn(dftrain, y_train, batch_size=10)()
for feature_batch, label_batch in ds.take(1):
  print('Some feature keys:', list(feature_batch.keys()))
  print()
  print('A batch of class:', feature_batch['class'].numpy())
  print()
  print('A batch of Labels:', label_batch.numpy())

你也可以使用 tf.keras.layers.DenseFeatures 层来查看特定特征列的结果

age_column = feature_columns[7]
tf.keras.layers.DenseFeatures([age_column])(feature_batch).numpy()

DenseFeatures 仅接受稠密张量。要查看分类列,你需要先将其转换为指示列 (indicator column)

gender_column = feature_columns[0]
tf.keras.layers.DenseFeatures([tf.feature_column.indicator_column(gender_column)])(feature_batch).numpy()

将所有基础特征添加到模型后,让我们开始训练模型。使用 tf.estimator API 训练模型只需一条命令

linear_est = tf.estimator.LinearClassifier(feature_columns=feature_columns)
linear_est.train(train_input_fn)
result = linear_est.evaluate(eval_input_fn)

clear_output()
print(result)

派生特征列

现在你达到了 75% 的准确率。单独使用每个基础特征列可能不足以解释数据。例如,年龄与标签之间的相关性在不同性别下可能不同。因此,如果你只为 gender="Male"gender="Female" 学习单一的模型权重,将无法捕获所有年龄-性别组合(例如,无法区分 gender="Male"age="30"gender="Male"age="40" 的区别)。

为了学习不同特征组合之间的差异,你可以向模型添加交叉特征列 (crossed feature columns)(你也可以在交叉列之前对年龄列进行分桶处理)

age_x_gender = tf.feature_column.crossed_column(['age', 'sex'], hash_bucket_size=100)

添加组合特征后,让我们再次训练模型

derived_feature_columns = [age_x_gender]
linear_est = tf.estimator.LinearClassifier(feature_columns=feature_columns+derived_feature_columns)
linear_est.train(train_input_fn)
result = linear_est.evaluate(eval_input_fn)

clear_output()
print(result)

现在准确率达到了 77.6%,比仅使用基础特征训练的结果略有提升。你可以尝试使用更多特征和转换,看看能否取得更好的效果!

现在你可以使用训练好的模型对评估集中的乘客进行预测。TensorFlow 模型已针对批量或一次性预测一组样本进行了优化。之前,eval_input_fn 是使用整个评估集定义的。

pred_dicts = list(linear_est.predict(eval_input_fn))
probs = pd.Series([pred['probabilities'][1] for pred in pred_dicts])

probs.plot(kind='hist', bins=20, title='predicted probabilities')

最后,查看结果的接收者操作特征 (ROC) 曲线,这将使我们更好地了解真阳性率与假阳性率之间的权衡。

from sklearn.metrics import roc_curve
from matplotlib import pyplot as plt

fpr, tpr, _ = roc_curve(y_eval, probs)
plt.plot(fpr, tpr)
plt.title('ROC curve')
plt.xlabel('false positive rate')
plt.ylabel('true positive rate')
plt.xlim(0,)
plt.ylim(0,)