TensorFlow 二元分类:线性分类器示例
两种最常见的 监督学习 任务是线性回归和线性分类器。线性回归预测一个值,而线性分类器预测一个类。本教程重点介绍线性分类器。
什么是线性分类器?
A 线性分类器 机器学习中的线性分类器是一种根据对象的特征查找其类别以进行统计分类的方法。它根据对象特征的线性组合值做出分类决策。线性分类器用于文档分类等实际问题以及具有许多变量的问题。
分类问题约占机器学习任务的 80%。分类旨在根据一组输入预测每个类别的概率。标签(即因变量)是一个离散值,称为类别。
- 如果标签只有两个类,则学习算法就是二元分类器。
- 多类分类器处理具有两个以上类别的标签。
例如,典型的二分类问题是预测客户进行第二次购买的可能性。预测图片上显示的动物类型是多类分类问题,因为存在两种以上的动物。
本教程的理论部分主要关注二分类。您将在未来的教程中了解有关多分类输出函数的更多信息。
二元分类器如何工作?
您在上一节中了解到,函数由两种变量组成,即因变量和一组特征(独立变量)。在线性回归中,因变量是没有范围的实数。主要目标是通过最小化均方误差来预测其值。
对于 TensorFlow 二元分类器,标签可以有两个可能的整数值。在大多数情况下,它要么是 [0,1],要么是 [1,2]。例如,目标是预测客户是否会购买产品。标签定义如下:
- Y = 1(客户购买了该产品)
- Y = 0(客户不购买该产品)
该模型利用特征X将每个顾客划分为其最有可能所属的类别,即潜在买家或非潜在买家。
成功概率计算如下 逻辑回归。该算法将根据特征 X 计算概率,并预测当该概率高于 50% 时会成功。更正式地说,概率的计算方式如下面 TensorFlow 二元分类示例所示:
其中 0 是权重集合,即特征,b 是偏差。
该函数可以分解为两部分:
- 线性模型
- 逻辑函数
线性模型
你已经熟悉了权重的计算方式。权重是使用点积计算的: Y 是所有特征 x 的线性函数i如果模型没有特征,预测就等于偏差b。
权重表示特征 x 之间的相关性方向i 和标签 y。正相关会增加正类的概率,而负相关会使概率更接近 0(即负类)。
线性模型只返回实数,这与范围 [0,1] 的概率测度不一致。需要逻辑函数将线性模型输出转换为概率,
逻辑函数
逻辑函数或 S 形函数具有 S 形,并且该函数的输出始终在 0 和 1 之间。
将线性回归的输出代入 S 型函数很容易。它会产生一个概率在 0 到 1 之间的新数字。
分类器可以将概率转化为类别
- 0 至 0.49 之间的值归为 0 类
- 0.5 至 1 之间的值归为 1 类
如何衡量线性分类器的性能?
准确性
分类器的整体性能通过准确度指标来衡量。准确度是指所有正确值除以总观察次数。例如,准确度值为 80% 表示模型在 80% 的情况下是正确的。
您可以注意到此指标的一个缺点,尤其是对于不平衡类。当每组的观察值数量不相等时,就会出现不平衡数据集。假设您尝试使用逻辑函数对罕见事件进行分类。想象一下,分类器试图估计患者患病后的死亡率。在数据中,5%的患者去世。您可以训练分类器来预测死亡人数,并使用准确度指标来评估性能。如果分类器预测整个数据集的死亡人数为 0,则在 95% 的情况下它将是正确的。
混淆矩阵
评估分类器性能的更好方法是查看混淆矩阵。
- 混淆矩阵 通过比较实际类别和预测类别来可视化分类器的准确性,如上面的线性分类器示例所示。二元混淆矩阵由正方形组成:
- TP:真阳性:预测值正确预测为实际阳性
- FP:预测值错误地预测了实际的正值。即,将负值预测为正值
- FN:假阴性:将正值预测为负值
- TN:真阴性:预测值正确预测为实际阴性
从混淆矩阵中,很容易比较实际类别和预测类别。
精度和灵敏度
混淆矩阵可以很好地洞察真阳性和假阳性。在某些情况下,最好有一个更简洁的指标。
平台精度
精度指标显示了正类的准确度。它衡量正类预测的正确性。
当分类器完美地分类所有正值时,最高分数为 1。单凭精度并没有多大帮助,因为它忽略了负类。该指标通常与召回率指标配对。召回率也称为敏感度或真阳性率。
灵敏度
敏感度计算正确检测到的正类的比例。该指标表明模型识别正类的能力有多强。
使用 TensorFlow 的线性分类器
在本教程中,我们将使用人口普查数据集。目的是使用人口普查数据集中的变量来预测收入水平。请注意,收入是一个二元变量
- 如果收入 > 1k,则值为 50
- 如果收入 < 0k,则为 50。
此变量是你的标签
该数据集包括八个分类变量:
- 工作场所
- 教育
- 婚姻
- 占用
- 关系
- 种族
- 性别
- 祖国
此外,还有六个连续变量:
- 年龄
- 风车
- 教育编号
- 资本收益
- 资本损失
- hours_week
通过这个 TensorFlow 分类示例,您将了解如何使用 TensorFlow 估计器训练线性 TensorFlow 分类器以及如何提高准确度指标。
我们将按照以下步骤进行:
- 步骤1)导入数据
- 步骤2)数据转换
- 步骤3)训练分类器
- 步骤4)改进模型
- 步骤5)超参数:Lasso&Ridge
步骤1)导入数据
首先导入教程中使用的库。
import tensorflow as tf import pandas as pd
接下来,从 UCI 的档案中导入数据并定义列名。您将使用 COLUMNS 来命名 pandas 数据框中的列。
请注意,您将使用 Pandas 数据框训练分类器。
## Define path data COLUMNS = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country', 'label'] PATH = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data" PATH_test = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.test"
在线存储的数据已经分为训练集和测试集。
df_train = pd.read_csv(PATH, skipinitialspace=True, names = COLUMNS, index_col=False) df_test = pd.read_csv(PATH_test,skiprows = 1, skipinitialspace=True, names = COLUMNS, index_col=False)
训练集包含 32,561 个观测值,测试集包含 16,281 个观测值
print(df_train.shape, df_test.shape) print(df_train.dtypes) (32561, 15) (16281, 15) age int64 workclass object fnlwgt int64 education object education_num int64 marital object occupation object relationship object race object sex object capital_gain int64 capital_loss int64 hours_week int64 native_country object label object dtype: object
Tensorflow 需要一个布尔值来训练分类器。您需要将值从字符串转换为整数。标签存储为对象,但您需要将其转换为数值。下面的代码创建一个字典,其中包含要转换的值并循环遍历列项。请注意,您执行此操作两次,一次用于训练测试,一次用于测试集
label = {'<=50K': 0,'>50K': 1} df_train.label = [label[item] for item in df_train.label] label_t = {'<=50K.': 0,'>50K.': 1} df_test.label = [label_t[item] for item in df_test.label]
在训练数据中,有 24,720 人的收入低于 50k,有 7841 人的收入高于 XNUMXk。测试集的比例几乎相同。有关更多信息,请参阅 Facets 上的本教程。
print(df_train["label"].value_counts()) ### The model will be correct in atleast 70% of the case print(df_test["label"].value_counts()) ## Unbalanced label print(df_train.dtypes) 0 24720 1 7841 Name: label, dtype: int64 0 12435 1 3846 Name: label, dtype: int64 age int64 workclass object fnlwgt int64 education object education_num int64 marital object occupation object relationship object race object sex object capital_gain int64 capital_loss int64 hours_week int64 native_country object label int64 dtype: object
步骤2)数据转换
在使用 Tensorflow 训练线性分类器之前,需要执行几个步骤。您需要准备要包含在模型中的特征。在基准回归中,您将使用原始数据而不应用任何转换。
估算器需要有特征列表来训练模型。因此,列的数据需要转换为张量。
一个好的做法是根据特征的类型定义两个特征列表,然后将它们传递到估算器的 feature_columns 中。
您将首先转换连续特征,然后使用分类数据定义一个存储桶。
数据集的特征有两种格式:
- 整数
- 摆件
每个特征根据其类型列在接下来的两个变量中。
## Add features to the bucket: ### Define continuous list CONTI_FEATURES = ['age', 'fnlwgt','capital_gain', 'education_num', 'capital_loss', 'hours_week'] ### Define the categorical list CATE_FEATURES = ['workclass', 'education', 'marital', 'occupation', 'relationship', 'race', 'sex', 'native_country']
feature_column 配备了一个对象 numeric_column,用于帮助将连续变量转换为张量。在下面的代码中,您将 CONTI_FEATURES 中的所有变量转换为具有数值的张量。这是构建模型的必需操作。所有独立变量都需要转换为适当类型的张量。
下面我们写一段代码让你看看 feature_column.numeric_column 背后发生了什么。我们将打印年龄的转换值。这只是为了解释目的,因此不需要理解 Python 代码。你可以参考官方文档来理解代码。
def print_transformation(feature = "age", continuous = True, size = 2): #X = fc.numeric_column(feature) ## Create feature name feature_names = [ feature] ## Create dict with the data d = dict(zip(feature_names, [df_train[feature]])) ## Convert age if continuous == True: c = tf.feature_column.numeric_column(feature) feature_columns = [c] else: c = tf.feature_column.categorical_column_with_hash_bucket(feature, hash_bucket_size=size) c_indicator = tf.feature_column.indicator_column(c) feature_columns = [c_indicator] ## Use input_layer to print the value input_layer = tf.feature_column.input_layer( features=d, feature_columns=feature_columns ) ## Create lookup table zero = tf.constant(0, dtype=tf.float32) where = tf.not_equal(input_layer, zero) ## Return lookup tble indices = tf.where(where) values = tf.gather_nd(input_layer, indices) ## Initiate graph sess = tf.Session() ## Print value print(sess.run(input_layer)) print_transformation(feature = "age", continuous = True) [[39.] [50.] [38.] ... [58.] [22.] [52.]]
这些值与 df_train 中的值完全相同
continuous_features = [tf.feature_column.numeric_column(k) for k in CONTI_FEATURES]
根据 TensorFlow 文档,有多种方法可以转换分类数据。如果某个特征的词汇表已知且没有足够多的值,则可以使用 categorical_column_with_vocabulary_list 创建分类列。它将为所有唯一词汇表分配一个 ID。
例如,如果变量状态有三个不同的值:
- 丈夫
- 妻子
- 集成的
然后将归类为三个 ID。例如,丈夫的 ID 为 1,妻子的 ID 为 2,依此类推。
为了说明目的,您可以使用此代码将对象变量转换为 TensorFlow 中的分类列。
特征 sex 只能有两个值:男性或女性。当我们转换特征 sex 时,Tensorflow 将创建 2 个新列,一个用于男性,一个用于女性。如果 sex 等于男性,则新列 male 将等于 1,female 将等于 0。此示例显示在下表中:
行 | 性别 | 改造后 | 男 | 女 |
---|---|---|---|---|
1 | 男 | => | 1 | 0 |
2 | 男 | => | 1 | 0 |
3 | 女 | => | 0 | 1 |
在 TensorFlow 中:
print_transformation(feature = "sex", continuous = False, size = 2) [[1. 0.] [1. 0.] [1. 0.] ... [0. 1.] [1. 0.] [0. 1.]] relationship = tf.feature_column.categorical_column_with_vocabulary_list( 'relationship', [ 'Husband', 'Not-in-family', 'Wife', 'Own-child', 'Unmarried', 'Other-relative'])
下面,我们添加了 Python 代码来打印编码。同样,你不需要理解代码,目的是为了看到转换
但是,转换数据的更快方法是使用 categorical_column_with_hash_bucket 方法。更改稀疏矩阵中的字符串变量将很有用。稀疏矩阵是一个大部分为零的矩阵。该方法会处理所有事情。您只需要指定存储桶的数量和关键列。存储桶的数量是 Tensorflow 可以创建的最大组数。关键列只是要转换的列的名称。
在下面的代码中,您将创建一个覆盖所有分类特征的循环。
categorical_features = [tf.feature_column.categorical_column_with_hash_bucket(k, hash_bucket_size=1000) for k in CATE_FEATURES]
步骤3)训练分类器
TensorFlow 目前为线性回归和线性分类提供了估计器。
- 线性回归:LinearRegressor
- 线性分类:LinearClassifier
线性分类器的语法与教程中的相同 线性回归 除了一个参数 n_class。您需要定义特征列、模型目录,并与线性回归器进行比较;您必须定义类的数量。对于逻辑回归,类的数量等于 2。
该模型将计算连续特征(continuous_features)和分类特征(categorical_features)中包含的列的权重。
model = tf.estimator.LinearClassifier( n_classes = 2, model_dir="ongoing/train", feature_columns=categorical_features+ continuous_features)
输出
INFO:tensorflow:Using default config. INFO:tensorflow:Using config: {'_model_dir': 'ongoing/train', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x181f24c898>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}
现在已定义分类器,您可以创建输入函数。方法与线性回归器教程中的方法相同。在这里,您使用 128 的批处理大小并对数据进行混洗。
FEATURES = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country'] LABEL= 'label' def get_input_fn(data_set, num_epochs=None, n_batch = 128, shuffle=True): return tf.estimator.inputs.pandas_input_fn( x=pd.DataFrame({k: data_set[k].values for k in FEATURES}), y = pd.Series(data_set[LABEL].values), batch_size=n_batch, num_epochs=num_epochs, shuffle=shuffle)
你可以创建一个函数,其中包含线性估计器所需的参数,即时期数、批次数,然后对数据集或注释进行打乱。由于你使用 熊猫 方法将数据传递到模型中,您需要将 X 变量定义为 pandas 数据框。请注意,您要循环遍历 FEATURES 中存储的所有数据。
让我们使用对象 model.train 来训练模型。使用之前定义的函数为模型提供适当的值。请注意,将批处理大小设置为 128,将 epoch 数设置为 None。该模型将经过一千步的训练。
model.train(input_fn=get_input_fn(df_train, num_epochs=None, n_batch = 128, shuffle=False), steps=1000)
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Create CheckpointSaverHook. INFO:tensorflow: Graph was finalized. INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Saving checkpoints for 1 into ongoing/train/model.ckpt. INFO:tensorflow:loss = 88.722855, step = 1 INFO:tensorflow:global_step/sec: 65.8282 INFO:tensorflow:loss = 52583.64, step = 101 (1.528 sec) INFO:tensorflow:global_step/sec: 118.386 INFO:tensorflow:loss = 25203.816, step = 201 (0.837 sec) INFO:tensorflow:global_step/sec: 110.542 INFO:tensorflow:loss = 54924.312, step = 301 (0.905 sec) INFO:tensorflow:global_step/sec: 199.03 INFO:tensorflow:loss = 68509.31, step = 401 (0.502 sec) INFO:tensorflow:global_step/sec: 167.488 INFO:tensorflow:loss = 9151.754, step = 501 (0.599 sec) INFO:tensorflow:global_step/sec: 220.155 INFO:tensorflow:loss = 34576.06, step = 601 (0.453 sec) INFO:tensorflow:global_step/sec: 199.016 INFO:tensorflow:loss = 36047.117, step = 701 (0.503 sec) INFO:tensorflow:global_step/sec: 197.531 INFO:tensorflow:loss = 22608.148, step = 801 (0.505 sec) INFO:tensorflow:global_step/sec: 208.479 INFO:tensorflow:loss = 22201.918, step = 901 (0.479 sec) INFO:tensorflow:Saving checkpoints for 1000 into ongoing/train/model.ckpt. INFO:tensorflow:Loss for final step: 5444.363. <tensorflow.python.estimator.canned.linear.LinearClassifier at 0x181f223630>
请注意,在最后 100 步中,损失随后减少,即从 901 减少到 1000。
一千次迭代后的最终损失为 5444。您可以在测试集上估算您的模型并查看其性能。要评估模型的性能,您需要使用对象评估。您将测试集输入到模型中,并将 epoch 数设置为 1,即数据只会进入模型一次。
model.evaluate(input_fn=get_input_fn(df_test, num_epochs=1, n_batch = 128, shuffle=False), steps=1000)
INFO:tensorflow:Calling model_fn. WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead. WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Starting evaluation at 2018-06-02-08:28:22 INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from ongoing/train/model.ckpt-1000 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Evaluation [100/1000] INFO:tensorflow:Finished evaluation at 2018-06-02-08:28:23 INFO:tensorflow:Saving dict for global step 1000: accuracy = 0.7615626, accuracy_baseline = 0.76377374, auc = 0.63300294, auc_precision_recall = 0.50891197, average_loss = 47.12155, global_step = 1000, label/mean = 0.23622628, loss = 5993.6406, precision = 0.49401596, prediction/mean = 0.18454961, recall = 0.38637546 {'accuracy': 0.7615626, 'accuracy_baseline': 0.76377374, 'auc': 0.63300294, 'auc_precision_recall': 0.50891197, 'average_loss': 47.12155, 'global_step': 1000, 'label/mean': 0.23622628, 'loss': 5993.6406, 'precision': 0.49401596, 'prediction/mean': 0.18454961, 'recall': 0.38637546}
TensorFlow 返回了您在理论部分学到的所有指标。由于标签不平衡,准确率很高,这一点毫不奇怪。实际上,该模型的表现略好于随机猜测。假设该模型预测所有家庭收入低于 50K,那么该模型的准确率为 70%。仔细分析后,您会发现预测和召回率相当低。
步骤4)改进模型
现在您有了一个基准模型,您可以尝试改进它,即提高准确性。在上一个教程中,您学习了如何使用交互项来提高预测能力。在本教程中,您将通过向回归添加多项式项来重新审视这个想法。
当数据中存在非线性时,多项式回归很有用。有两种方法可以捕获数据中的非线性。
- 添加多项式项
- 将连续变量分类为分类变量
多项式项
从下图中,你可以看到什么是多项式回归。它是一个具有不同幂的 X 个变量的方程。二次多项式回归有两个变量,X 和 X 平方。三次多项式回归有三个变量,X、X2,和 X3
下面,我们用两个变量 X 和 Y 构建了一个图表。很明显,这种关系不是线性的。如果我们添加线性回归,我们可以看到模型无法捕捉到这种模式(左图)。
现在,看下面图片中的左图,我们在回归中添加了五项(即 y=x+x2+x3+x4+x5。该模型现在可以更好地捕捉模式。这就是多项式回归的力量。
让我们回到我们的例子。年龄与收入不是线性关系。早年的收入可能接近于零,因为孩子或年轻人不工作。然后,随着工作年龄的增长,收入会增加,退休后收入会减少。它通常呈倒 U 形。捕捉这种模式的一种方法是将幂 2 添加到回归中。
让我们看看它是否提高了准确性。
您需要将此新特征添加到数据集和连续特征列表中。
你在训练和测试数据集中添加新的变量,这样编写函数更加方便。
def square_var(df_t, df_te, var_name = 'age'): df_t['new'] = df_t[var_name].pow(2) df_te['new'] = df_te[var_name].pow(2) return df_t, df_te
该函数有 3 个参数:
- df_t:定义训练集
- df_te:定义测试集
- var_name = 'age':定义要转换的变量
您可以使用对象 pow(2) 来对变量 age 求平方。请注意,新变量名为“new”
现在已经编写了函数 square_var,您可以创建新的数据集。
df_train_new, df_test_new = square_var(df_train, df_test, var_name = 'age')
可以看到,新的数据集多了一个特征。
print(df_train_new.shape, df_test_new.shape) (32561, 16) (16281, 16)
平方变量在数据集中被称为新变量。您需要将其添加到连续特征列表中。
CONTI_FEATURES_NEW = ['age', 'fnlwgt','capital_gain', 'education_num', 'capital_loss', 'hours_week', 'new'] continuous_features_new = [tf.feature_column.numeric_column(k) for k in CONTI_FEATURES_NEW]
备注 您更改了 Graph 的目录。您不能在同一个目录中训练不同的模型。这意味着您需要更改参数 model_dir 的路径。如果不这样做,TensorFlow 会抛出错误。
model_1 = tf.estimator.LinearClassifier( model_dir="ongoing/train1", feature_columns=categorical_features+ continuous_features_new)
INFO:tensorflow:Using default config. INFO:tensorflow:Using config: {'_model_dir': 'ongoing/train1', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1820f04b70>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1} FEATURES_NEW = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country', 'new'] def get_input_fn(data_set, num_epochs=None, n_batch = 128, shuffle=True): return tf.estimator.inputs.pandas_input_fn( x=pd.DataFrame({k: data_set[k].values for k in FEATURES_NEW}), y = pd.Series(data_set[LABEL].values), batch_size=n_batch, num_epochs=num_epochs, shuffle=shuffle)
现在,分类器已经使用新的数据集设计好了,您可以训练和评估模型。
model_1.train(input_fn=get_input_fn(df_train, num_epochs=None, n_batch = 128, shuffle=False), steps=1000)
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Create CheckpointSaverHook. INFO:tensorflow:Graph was finalized. INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Saving checkpoints for 1 into ongoing/train1/model.ckpt. INFO:tensorflow:loss = 88.722855, step = 1 INFO:tensorflow:global_step/sec: 81.487 INFO:tensorflow:loss = 70077.66, step = 101 (1.228 sec) INFO:tensorflow:global_step/sec: 111.169 INFO:tensorflow:loss = 49522.082, step = 201 (0.899 sec) INFO:tensorflow:global_step/sec: 128.91 INFO:tensorflow:loss = 107120.57, step = 301 (0.776 sec) INFO:tensorflow:global_step/sec: 132.546 INFO:tensorflow:loss = 12814.152, step = 401 (0.755 sec) INFO:tensorflow:global_step/sec: 162.194 INFO:tensorflow:loss = 19573.898, step = 501 (0.617 sec) INFO:tensorflow:global_step/sec: 204.852 INFO:tensorflow:loss = 26381.986, step = 601 (0.488 sec) INFO:tensorflow:global_step/sec: 188.923 INFO:tensorflow:loss = 23417.719, step = 701 (0.529 sec) INFO:tensorflow:global_step/sec: 192.041 INFO:tensorflow:loss = 23946.049, step = 801 (0.521 sec) INFO:tensorflow:global_step/sec: 197.025 INFO:tensorflow:loss = 3309.5786, step = 901 (0.507 sec) INFO:tensorflow:Saving checkpoints for 1000 into ongoing/train1/model.ckpt. INFO:tensorflow:Loss for final step: 28861.898. <tensorflow.python.estimator.canned.linear.LinearClassifier at 0x1820f04c88>
model_1.evaluate(input_fn=get_input_fn(df_test_new, num_epochs=1, n_batch = 128, shuffle=False), steps=1000)
INFO:tensorflow:Calling model_fn. WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead. WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Starting evaluation at 2018-06-02-08:28:37 INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from ongoing/train1/model.ckpt-1000 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Evaluation [100/1000] INFO:tensorflow:Finished evaluation at 2018-06-02-08:28:39 INFO:tensorflow:Saving dict for global step 1000: accuracy = 0.7944229, accuracy_baseline = 0.76377374, auc = 0.6093755, auc_precision_recall = 0.54885805, average_loss = 111.0046, global_step = 1000, label/mean = 0.23622628, loss = 14119.265, precision = 0.6682401, prediction/mean = 0.09116262, recall = 0.2576703 {'accuracy': 0.7944229, 'accuracy_baseline': 0.76377374, 'auc': 0.6093755, 'auc_precision_recall': 0.54885805, 'average_loss': 111.0046, 'global_step': 1000, 'label/mean': 0.23622628, 'loss': 14119.265, 'precision': 0.6682401, 'prediction/mean': 0.09116262, 'recall': 0.2576703}
平方变量将准确率从 0.76 提高到了 0.79。让我们看看能否通过将分桶和交互项结合起来来取得更好的效果。
分类和交互
如前所述,线性分类器无法正确捕捉年龄-收入模式。这是因为它为每个特征学习一个权重。为了让分类器更容易,你可以做的一件事就是对特征进行分组。分组会根据数字特征所属的范围将其转换为几个特定的特征,每个新特征都表明一个人的年龄是否在该范围内。
有了这些新特征,线性模型可以通过学习每个桶的不同权重来捕捉关系。
在 TensorFlow 中,这是通过 bucketized_column 完成的。您需要在边界中添加值的范围。
age = tf.feature_column.numeric_column('age') age_buckets = tf.feature_column.bucketized_column( age, boundaries=[18, 25, 30, 35, 40, 45, 50, 55, 60, 65])
您已经知道年龄与收入呈非线性关系。改进模型的另一种方法是通过交互。用 TensorFlow 的话来说,这就是特征交叉。特征交叉是一种创建现有特征组合的新特征的方法,这对于无法模拟特征之间交互的线性分类器很有帮助。
您可以使用教育等其他特征来细分年龄。也就是说,一些群体可能收入较高,而另一些群体收入较低(想想博士生)。
education_x_occupation = [tf.feature_column.crossed_column( ['education', 'occupation'], hash_bucket_size=1000)] age_buckets_x_education_x_occupation = [tf.feature_column.crossed_column( [age_buckets, 'education', 'occupation'], hash_bucket_size=1000)]
要创建交叉特征列,可以使用 crossed_column 并将要交叉的变量放在括号中。hash_bucket_size 表示最大交叉可能性。要创建变量之间的交互(至少一个变量需要是分类变量),可以使用 tf.feature_column.crossed_column。要使用此对象,需要在方括号中添加要交互的变量和第二个参数,即 bucket 大小。bucket 大小是变量中可能的最大组数。这里您将其设置为 1000,因为您不知道确切的组数
age_buckets 需要先求平方,然后才能将其添加到特征列中。您还可以将新特征添加到特征列并准备估算器
base_columns = [ age_buckets, ] model_imp = tf.estimator.LinearClassifier( model_dir="ongoing/train3", feature_columns=categorical_features+base_columns+education_x_occupation+age_buckets_x_education_x_occupation)
输出
INFO:tensorflow:Using default config. INFO:tensorflow:Using config: {'_model_dir': 'ongoing/train3', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1823021be0>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}
FEATURES_imp = ['age','workclass', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'native_country', 'new'] def get_input_fn(data_set, num_epochs=None, n_batch = 128, shuffle=True): return tf.estimator.inputs.pandas_input_fn( x=pd.DataFrame({k: data_set[k].values for k in FEATURES_imp}), y = pd.Series(data_set[LABEL].values), batch_size=n_batch, num_epochs=num_epochs, shuffle=shuffle)
您已准备好评估新模型并查看它是否可以提高准确性。
model_imp.train(input_fn=get_input_fn(df_train_new, num_epochs=None, n_batch = 128, shuffle=False), steps=1000)
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Create CheckpointSaverHook. INFO:tensorflow:Graph was finalized. INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Saving checkpoints for 1 into ongoing/train3/model.ckpt. INFO:tensorflow:loss = 88.722855, step = 1 INFO:tensorflow:global_step/sec: 94.969 INFO:tensorflow:loss = 50.334488, step = 101 (1.054 sec) INFO:tensorflow:global_step/sec: 242.342 INFO:tensorflow:loss = 56.153225, step = 201 (0.414 sec) INFO:tensorflow:global_step/sec: 213.686 INFO:tensorflow:loss = 45.792007, step = 301 (0.470 sec) INFO:tensorflow:global_step/sec: 174.084 INFO:tensorflow:loss = 37.485672, step = 401 (0.572 sec) INFO:tensorflow:global_step/sec: 191.78 INFO:tensorflow:loss = 56.48449, step = 501 (0.524 sec) INFO:tensorflow:global_step/sec: 163.436 INFO:tensorflow:loss = 32.528934, step = 601 (0.612 sec) INFO:tensorflow:global_step/sec: 164.347 INFO:tensorflow:loss = 37.438057, step = 701 (0.607 sec) INFO:tensorflow:global_step/sec: 154.274 INFO:tensorflow:loss = 61.1075, step = 801 (0.647 sec) INFO:tensorflow:global_step/sec: 189.14 INFO:tensorflow:loss = 44.69645, step = 901 (0.531 sec) INFO:tensorflow:Saving checkpoints for 1000 into ongoing/train3/model.ckpt. INFO:tensorflow:Loss for final step: 44.18133. <tensorflow.python.estimator.canned.linear.LinearClassifier at 0x1823021cf8>
model_imp.evaluate(input_fn=get_input_fn(df_test_new, num_epochs=1, n_batch = 128, shuffle=False), steps=1000)
INFO:tensorflow:Calling model_fn. WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead. WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Starting evaluation at 2018-06-02-08:28:52 INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from ongoing/train3/model.ckpt-1000 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Evaluation [100/1000] INFO:tensorflow:Finished evaluation at 2018-06-02-08:28:54 INFO:tensorflow:Saving dict for global step 1000: accuracy = 0.8358209, accuracy_baseline = 0.76377374, auc = 0.88401634, auc_precision_recall = 0.69599575, average_loss = 0.35122654, global_step = 1000, label/mean = 0.23622628, loss = 44.67437, precision = 0.68986726, prediction/mean = 0.23320661, recall = 0.55408216 {'accuracy': 0.8358209, 'accuracy_baseline': 0.76377374, 'auc': 0.88401634, 'auc_precision_recall': 0.69599575, 'average_loss': 0.35122654, 'global_step': 1000, 'label/mean': 0.23622628, 'loss': 44.67437, 'precision': 0.68986726, 'prediction/mean': 0.23320661, 'recall': 0.55408216}
新的准确率达到 83.58%,比之前的模型高出 XNUMX%。
最后,可以添加正则化项来防止过度拟合。
步骤5)超参数:Lasso&Ridge
您的模型可能会受到以下影响 过度拟合 or 不合身.
- 过度拟合:模型无法将预测推广到新数据
- 欠拟合:模型无法捕捉数据的模式。即当数据为非线性时,进行线性回归
当模型具有大量参数和相对较少的数据量时,会导致预测不佳。想象一下,一个组只有三个观测值;模型将为该组计算权重。权重用于进行预测;如果该特定组的测试集观测值与训练集完全不同,则模型将做出错误的预测。在使用训练集进行评估时,准确率很好,但使用测试集时准确率并不好,因为计算出的权重不是概括模式的真实权重。在这种情况下,它无法对看不见的数据做出合理的预测。
为了防止过度拟合,正则化可以让你控制这种复杂性并使其更具通用性。有两种正则化技术:
- L1:套索
- L2:山脊
在 TensorFlow 中,您可以在优化器中添加这两个超参数。例如,超参数 L2 越高,权重往往越低,接近于零。拟合线将非常平坦,而接近于零的 L2 意味着权重接近常规线性回归。
你可以自己尝试不同的超参数值,看看是否可以提高准确率。
备注 如果更改超参数,则需要删除文件夹 progressive/train4,否则模型将从之前训练的模型开始。
让我们看看炒作的准确性如何
model_regu = tf.estimator.LinearClassifier( model_dir="ongoing/train4", feature_columns=categorical_features+base_columns+education_x_occupation+age_buckets_x_education_x_occupation, optimizer=tf.train.FtrlOptimizer( learning_rate=0.1, l1_regularization_strength=0.9, l2_regularization_strength=5))
输出
INFO:tensorflow:Using default config. INFO:tensorflow:Using config: {'_model_dir': 'ongoing/train4', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1820d9c128>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}
model_regu.train(input_fn=get_input_fn(df_train_new, num_epochs=None, n_batch = 128, shuffle=False), steps=1000)
输出
INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Create CheckpointSaverHook. INFO:tensorflow:Graph was finalized. INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Saving checkpoints for 1 into ongoing/train4/model.ckpt. INFO:tensorflow:loss = 88.722855, step = 1 INFO:tensorflow:global_step/sec: 77.4165 INFO:tensorflow:loss = 50.38778, step = 101 (1.294 sec) INFO:tensorflow:global_step/sec: 187.889 INFO:tensorflow:loss = 55.38014, step = 201 (0.535 sec) INFO:tensorflow:global_step/sec: 201.895 INFO:tensorflow:loss = 46.806694, step = 301 (0.491 sec) INFO:tensorflow:global_step/sec: 217.992 INFO:tensorflow:loss = 38.68271, step = 401 (0.460 sec) INFO:tensorflow:global_step/sec: 193.676 INFO:tensorflow:loss = 56.99398, step = 501 (0.516 sec) INFO:tensorflow:global_step/sec: 202.195 INFO:tensorflow:loss = 33.263622, step = 601 (0.497 sec) INFO:tensorflow:global_step/sec: 216.756 INFO:tensorflow:loss = 37.7902, step = 701 (0.459 sec) INFO:tensorflow:global_step/sec: 240.215 INFO:tensorflow:loss = 61.732605, step = 801 (0.416 sec) INFO:tensorflow:global_step/sec: 220.336 INFO:tensorflow:loss = 46.938225, step = 901 (0.456 sec) INFO:tensorflow:Saving checkpoints for 1000 into ongoing/train4/model.ckpt. INFO:tensorflow:Loss for final step: 43.4942. <tensorflow.python.estimator.canned.linear.LinearClassifier at 0x181ff39e48>
model_regu.evaluate(input_fn=get_input_fn(df_test_new, num_epochs=1, n_batch = 128, shuffle=False), steps=1000)
输出
INFO:tensorflow:Calling model_fn. WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead. WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Starting evaluation at 2018-06-02-08:29:07 INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from ongoing/train4/model.ckpt-1000 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. INFO:tensorflow:Evaluation [100/1000] INFO:tensorflow:Finished evaluation at 2018-06-02-08:29:09 INFO:tensorflow:Saving dict for global step 1000: accuracy = 0.83833915, accuracy_baseline = 0.76377374, auc = 0.8869794, auc_precision_recall = 0.7014905, average_loss = 0.34691378, global_step = 1000, label/mean = 0.23622628, loss = 44.12581, precision = 0.69720596, prediction/mean = 0.23662092, recall = 0.5579823 {'accuracy': 0.83833915, 'accuracy_baseline': 0.76377374, 'auc': 0.8869794, 'auc_precision_recall': 0.7014905, 'average_loss': 0.34691378, 'global_step': 1000, 'label/mean': 0.23622628, 'loss': 44.12581, 'precision': 0.69720596, 'prediction/mean': 0.23662092, 'recall': 0.5579823}
使用此超参数,您可以稍微提高准确度指标。在下一个教程中,您将学习如何使用核方法改进线性分类器。
总结
要训练模型,您需要:
- 定义特征:独立变量:X
- 定义标签:因变量:y
- 构建训练/测试集
- 定义初始权重
- 定义损失函数:MSE
- 优化模型:梯度下降
- 定义:
- 学习率
- 历元数
- 批量大小
- 班级人数
在本教程中,您学习了如何使用线性回归分类器的高级 API。您需要定义:
- 特征列。如果是连续的:tf.feature_column.numeric_column()。你可以使用 python 列表推导填充列表
- 估计器:tf.estimator.LinearClassifier(feature_columns,model_dir,n_classes = 2)
- 导入数据、批次大小和时期的函数:input_fn()
之后,您就可以使用 train()、evaluate() 和 predict() 进行训练、评估和预测了。
为了提高模型的性能,您可以:
- 使用多项式回归
- 交互项:tf.feature_column.crossed_column
- 添加正则化参数