标签:美国 回归 github 关系 com builder step 通过 temporary
在本教程中,我们将使用TensorFlow中的tf.estimator API来解决二进制分类问题:根据年龄,性别,教育和职业(特征)等个人的普查数据,我们将尝试预测人每年赚取5万多美元(目标标签)。我们将训练逻辑回归模型,并给出个人信息,我们的模型将输出0到1之间的数字,这可以解释为个人年收入超过5万美元的可能性。
我们将使用的数据集是 普查收入数据集。您可以 手动下载 培训数据 和测试数据,或使用如下代码:
import tempfile import urllib train_file = tempfile.NamedTemporaryFile() test_file = tempfile.NamedTemporaryFile() urllib.urlretrieve("https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data", train_file.name) urllib.urlretrieve("https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.test", test_file.name)
CSV文件下载后,让我们将它们读入 熊猫数据帧。
由于任务是二进制分类问题,我们将构建一个名为“label”的标签列,如果收入超过50K,则其值为1,否则为0。
train_labels = (df_train["income_bracket"].apply(lambda x: ">50K" in x)).astype(int) test_labels = (df_test["income_bracket"].apply(lambda x: ">50K" in x)).astype(int)
接下来,我们来看看数据框架,看看我们可以使用哪些列来预测目标标签。列可以分为两种类型 - 分类和连续列:
以下是“普查收入”数据集中列的列表:
列名称 | 类型 | 描述 |
---|---|---|
年龄 | 连续 | 个人的年龄 |
workclass | 明确的 | 个人拥有的雇主类型(政府,军事,私人等)。 |
fnlwgt | 连续 | 人口普查员认为观察值(样本重量)的人数。该变量不会被使用。 |
教育 | 明确的 | 为个人所取得的最高水平的教育。 |
education_num | 连续 | 数字形式最高的教育水平。 |
婚姻状况 | 明确的 | 个人的婚姻状况 |
占用 | 明确的 | 个人的职业。 |
关系 | 明确的 | 妻子,自己的孩子,丈夫,不在家,其他相对,未婚。 |
种族 | 明确的 | 白人,亚太岛民族,美印爱斯基摩人,其他黑人。 |
性别 | 明确的 | 女人男人。 |
资本收益 | 连续 | 资本收益记录。 |
capital_loss | 连续 | 资本损失记录。 |
hours_per_week | 连续 | 每周工作时数。 |
祖国 | 明确的 | 个人原籍国。 |
收入 | 明确的 | “> 50K”或“<= 50K”,这意味着该人是否每年赚取超过$ 50,000。 |
构建tf.estimator模型时,通过Input Builder函数指定输入数据。此构建器函数将不会被调用,直到它后来传递给tf.estimator.Estimator方法,如train
和evaluate
。此函数的目的是构造以tf.Tensor
s或tf.SparseTensor
s 形式表示的输入数据。更详细地说,Input Builder函数返回以下对象
feature_cols
:从特征列名称到Tensors
或 SparseTensors
。label
:A Tensor
包含标签列。feature_cols
将在下一节中使用键的构造列。因为我们想用不同的数据调用train
和evaluate
方法,我们定义一个方法,返回基于给定数据的输入函数。请注意,在构建TensorFlow图时,将不会在运行图时调用返回的输入函数。返回的是将输入数据表示为TensorFlow计算的基本单位a Tensor
(或SparseTensor
)。
我们使用该tf.estimator.inputs.pandas_input_fn
方法从熊猫数据帧创建输入函数。火车或测试数据帧中的每个连续列将被转换成一个Tensor
,通常是表示密集数据的良好格式。对于分类数据,我们必须将数据表示为a SparseTensor
。该数据格式适用于表示稀疏数据。代表输入数据的另一种更先进的方法是构造一个 表示文件或其他数据源的输入和读取器,并以TensorFlow运行图形方式遍历文件。
def input_fn(data_file, num_epochs, shuffle): """Input builder function.""" df_data = pd.read_csv( tf.gfile.Open(data_file), names=CSV_COLUMNS, skipinitialspace=True, engine="python", skiprows=1) # remove NaN elements df_data = df_data.dropna(how="any", axis=0) labels = df_data["income_bracket"].apply(lambda x: ">50K" in x).astype(int) return tf.estimator.inputs.pandas_input_fn( x=df_data, y=labels, batch_size=100, num_epochs=num_epochs, shuffle=shuffle, num_threads=5)
选择和制作右侧的特征列是学习有效模型的关键。甲特征柱可以是在原来的数据帧(让我们称它们为原料的列中的任一个基本特征的列)的基础上在一个或多个碱基列(我们称它们限定一些转化或创建任何新列得出的特征列)。基本上,“特征列”是可用于预测目标标签的任何原始或派生变量的抽象概念。
要定义分类功能的功能列,我们可以CategoricalColumn
使用tf.feature_column API 创建一个 。如果您知道列的所有可能的特征值的集合,并且只有其中的几个可以使用categorical_column_with_vocabulary_list
。列表中的每个键将从0开始分配一个自动增量ID。例如,对于gender
列,我们可以通过执行以下操作将特征字符串“Female”分配给整数ID为0,将“Male”分配给1。
gender = tf.feature_column.categorical_column_with_vocabulary_list( "gender", ["Female", "Male"])
如果我们不提前知道一组可能的价值呢?不是问题 我们可以用
categorical_column_with_hash_bucket
occupation = tf.feature_column.categorical_column_with_hash_bucket( "occupation", hash_bucket_size=1000)
将会发生的是,occupation
在训练中遇到这些特征列时,每个可能的值将被哈希到一个整数ID。见下面的示例图:
ID | 特征 |
---|---|
... | |
9 | "Machine-op-inspct" |
... | |
103 | "Farming-fishing" |
... | |
375 | "Protective-serv" |
... |
无论我们选择哪种方式定义一个SparseColumn
,每个特征字符串将通过查找固定映射或散列来映射到整数ID。请注意,散列碰撞是可能的,但可能不会显着影响模型质量。在引擎盖下,LinearModel
该类负责管理映射和创建tf.Variable
以存储每个功能ID的模型参数(也称为模型权重)。模型参数将通过后面的模型训练过程学习。
我们将采取类似的技巧来定义其他分类功能:
education = tf.feature_column.categorical_column_with_vocabulary_list( "education", [ "Bachelors", "HS-grad", "11th", "Masters", "9th", "Some-college", "Assoc-acdm", "Assoc-voc", "7th-8th", "Doctorate", "Prof-school", "5th-6th", "10th", "1st-4th", "Preschool", "12th" ]) marital_status = tf.feature_column.categorical_column_with_vocabulary_list( "marital_status", [ "Married-civ-spouse", "Divorced", "Married-spouse-absent", "Never-married", "Separated", "Married-AF-spouse", "Widowed" ]) relationship = tf.feature_column.categorical_column_with_vocabulary_list( "relationship", [ "Husband", "Not-in-family", "Wife", "Own-child", "Unmarried", "Other-relative" ]) workclass = tf.feature_column.categorical_column_with_vocabulary_list( "workclass", [ "Self-emp-not-inc", "Private", "State-gov", "Federal-gov", "Local-gov", "?", "Self-emp-inc", "Without-pay", "Never-worked" ]) native_country = tf.feature_column.categorical_column_with_hash_bucket( "native_country", hash_bucket_size=1000)
类似地,我们可以NumericColumn
为模型中要使用的每个连续特征列定义一个
age = tf.feature_column.numeric_column("age") education_num = tf.feature_column.numeric_column("education_num") capital_gain = tf.feature_column.numeric_column("capital_gain") capital_loss = tf.feature_column.numeric_column("capital_loss") hours_per_week = tf.feature_column.numeric_column("hours_per_week")
有时,连续特征与标签之间的关系不是线性的。作为一个假设的例子,一个人的收入可能随着职业生涯的早期阶段的年龄而增长,那么增长可能会在某个时候慢一些,最后退休后的收入就会下降。在这种情况下,将raw age
作为实值特征列可能不是一个好的选择,因为模型只能学习三种情况之一:
如果我们想要分别了解收入和每个年龄组之间的细粒度关联,我们可以利用桶化。Bucketization是将连续特征的整个范围划分成一组连续的仓/桶的过程,然后根据该值所在的桶将原始数值特征转换为桶ID(作为分类特征)。因此,我们可以定义一个bucketized_column
以上age
为:
age_buckets = tf.feature_column.bucketized_column(
age, boundaries=[18, 25, 30, 35, 40, 45, 50, 55, 60, 65])
哪里boundaries
是桶边界的列表。在这种情况下,有10个边界,导致11个年龄组的桶(从17岁及以下,18-24,25-29,...,到65岁以上)。
单独使用每个基本特征列可能不足以解释数据。例如,不同职业的教育与标签(赚取> 50,000美元)的相关性可能会有所不同。因此,如果我们只学了一个模型的权重education="Bachelors"
和education="Masters"
,我们就无法捕捉到每一个教育,职业组合(例如区分education="Bachelors" AND occupation="Exec-managerial"
和education="Bachelors" AND occupation="Craft-repair"
)。要了解不同功能组合之间的差异,我们可以向模型添加交叉的特征列。
education_x_occupation = tf.feature_column.crossed_column( ["education", "occupation"], hash_bucket_size=1000)
我们也可以创建CrossedColumn
超过两列。每个构成列可以是基本特征列,分类(SparseColumn
),分段实值特征列(BucketizedColumn
)或甚至另一个CrossColumn
。这里有一个例子:
age_buckets_x_education_x_occupation = tf.feature_column.crossed_column( [age_buckets, "education", "occupation"], hash_bucket_size=1000)
在处理输入数据并定义所有特征列之后,我们现在可以将它们全部放在一起,构建一个Logistic回归模型。在上一节中,我们看到了几种类型的基础和派生的功能列,其中包括:
CategoricalColumn
NumericColumn
BucketizedColumn
CrossedColumn
所有这些都是抽象FeatureColumn
类的子类,并且可以添加到feature_columns
模型的字段中:
base_columns = [ gender, native_country, education, occupation, workclass, relationship, age_buckets, ] crossed_columns = [ tf.feature_column.crossed_column( ["education", "occupation"], hash_bucket_size=1000), tf.feature_column.crossed_column( [age_buckets, "education", "occupation"], hash_bucket_size=1000), tf.feature_column.crossed_column( ["native_country", "occupation"], hash_bucket_size=1000) ] model_dir = tempfile.mkdtemp() m = tf.estimator.LinearClassifier( model_dir=model_dir, feature_columns=base_columns + crossed_columns)
该模型还自动学习一个偏离项,它控制预测,而不需要观察任何特征(参见“逻辑回归如何运作”以获得更多的解释)。学习的模型文件将被存储model_dir
。
在将所有功能添加到模型之后,现在来看看如何实际训练模型。训练一个模型只是一个使用tf.estimator API的单行:
# set num_epochs to None to get infinite stream of data. m.train( input_fn=input_fn(train_file_name, num_epochs=None, shuffle=True), steps=train_steps)
在模型训练后,我们可以评估我们的模型在预测保持数据的标签方面有多好:
results = m.evaluate( input_fn=input_fn(test_file_name, num_epochs=1, shuffle=False), steps=None) print("model directory = %s" % model_dir) for key in sorted(results): print("%s: %s" % (key, results[key]))
输出的第一行应该是这样accuracy: 0.83557522
,这意味着精度是83.6%。随意尝试更多的功能和变革,看看你能做得更好!
如果您希望看到一个有效的端对端示例,您可以下载我们的 示例代码。并设置model_type
标志wide
。
正则化是一种用于避免过度拟合的技术。当您的模型对其进行培训的数据执行情况良好时,会发生过度拟合,但对于模型以前未见过的测试数据(如实时流量)更糟。通常,当模型过于复杂时,通常发生过拟合,例如相对于观察到的训练数据的数量具有太多的参数。正则化允许您控制您的模型的复杂性,并使模型更可概括为看不见的数据。
在线性模型库中,您可以将L1和L2正则化添加到模型中:
m = tf.estimator.LinearClassifier( model_dir=model_dir, feature_columns=base_columns + crossed_columns, optimizer=tf.train.FtrlOptimizer( learning_rate=0.1, l1_regularization_strength=1.0, l2_regularization_strength=1.0), model_dir=model_dir)
L1和L2正则化之间的一个重要区别在于L1正则化趋向于使模型权重保持为零,创建较为稀疏的模型,而L2正则化也试图使模型权重接近零但不一定为零。因此,如果增加L1正则化的强度,则您将具有较小的模型大小,因为许多模型权重将为零。当特征空间非常大但稀疏时,并且当存在阻止您提供太大模型的资源约束时,这通常是希望的。
在实践中,您应该尝试L1,L2正则化强度的各种组合,并找到最佳控制过拟合的最佳参数,并为您提供所需的模型大小。
标签:美国 回归 github 关系 com builder step 通过 temporary
原文地址:http://www.cnblogs.com/yinghuali/p/7750273.html