2018年4月21日

[TF.4]特征工程

本文参考《Google机器学习速成课程》使用TF的基本步骤
点击下载源码

一、将原始数据映射到特征

映射字符串值

  1. 为要表示的所有特征的字符串值定义一个词汇表
  2. 使用该词汇表创建一个独热编码

映射分类(枚举)值

例:Lowland Countries 的特征只包含3个可能值{‘Netherlands’, ‘Belgium’, ‘Luxembourg’}

Id feature_value
0 2
1 0
2 1

则表示为 3 个单独的布尔值特征
x1:是荷兰吗?
x2:是比利时吗?
x3:是卢森堡吗?

Id feature_value_0 feature_value_1 feature_value_2
0 0 0 1
1 1 0 0
2 0 1 0

避免很少使用的离散特征值

良好的特征值应该在数据集中出现大约 5 次以上

清理数据

清查

  • 遗漏值
  • 重复样本
  • 不良标签。 例如,有人错误地将一颗橡树的图片标记为枫树。
  • 不良特征值。 例如,有人输入了多余的位数,或者温度计被遗落在太阳底下。

特征值归一化

指将浮点特征值从自然范围(例如 100 到 900)转换为标准范围(例如 0 到 1 或 -1 到 +1)

特征值缩放

不需要对每个浮点特征进行完全相同的缩放,即使特征 A 的范围是 -1 到 +1,同时特征 B 的范围是 -3 到 +3,也不会产生什么恶劣的影响

#线性缩放
def linear_scale(series):
  min_val = series.min()
  max_val = series.max()
  scale = (max_val - min_val) / 2.0
  return series.apply(lambda x:((x - min_val) / scale) - 1.0)
#
def z_score_normalize(series):
  mean = series.mean()
  std_dv = series.std()
  return series.apply(lambda x:(x - mean) / std_dv)

处理极端离群值

  1. 对每个值取对数
  2. 对特征值设上限

tf4-RoomPerPerson.jpg

#取对数
def log_normalize(series):
  return series.apply(lambda x:math.log(x+1.0))
#设下限
def binary_threshold(series, threshold):
  return series.apply(lambda x:(1 if x > threshold else 0))
#设上下限
def clip(series, clip_to_min, clip_to_max):
  return series.apply(lambda x:(
    min(max(x, clip_to_min), clip_to_max)))

处理分布不均匀特征值

分箱
按整数分箱:简单
按分位数分箱:可以确保每个桶内的样本数量是相等的,完全无需担心离群值

例:更好地利用纬度

绘制 latitude 与 median_house_value 的图形后,发现有几个峰值与洛杉矶和旧金山大致相对应

#对于含有特征median_income和latitude的dataframe
LATITUDE_RANGES = zip(xrange(32, 44), xrange(33, 45))
#[(32, 33), (33, 34),... , (44, 45)]
def select_and_transform_features(source_df):
  selected_examples = pd.DataFrame()
  selected_examples["median_income"] = source_df["median_income"]
  for r in LATITUDE_RANGES:
    selected_examples["latitude_%d_to_%d" % r] = source_df["latitude"].apply(
      lambda l: 1.0 if l >= r[0] and l < r[1] else 0.0)
  return selected_examples
selected_training_examples = select_and_transform_features(training_examples)
selected_validation_examples = select_and_transform_features(validation_examples)

工程化

#修改construct_feature_columns()函数
def construct_feature_columns():
  households = tf.feature_column.numeric_column("households")
  longitude = tf.feature_column.numeric_column("longitude")
  latitude = tf.feature_column.numeric_column("latitude")
  housing_median_age = tf.feature_column.numeric_column("housing_median_age")
  median_income = tf.feature_column.numeric_column("median_income")
  rooms_per_person = tf.feature_column.numeric_column("rooms_per_person")
  # Divide households into 7 buckets.
  bucketized_households = tf.feature_column.bucketized_column(
    households, boundaries=get_quantile_based_boundaries(
      training_examples["households"], 7))
  # Divide longitude into 10 buckets.
  bucketized_longitude = tf.feature_column.bucketized_column(
    longitude, boundaries=get_quantile_based_boundaries(
      training_examples["longitude"], 10))
  # Divide latitude into 10 buckets.
  bucketized_latitude = tf.feature_column.bucketized_column(
    latitude, boundaries=get_quantile_based_boundaries(
      training_examples["latitude"], 10))
  # Divide housing_median_age into 7 buckets.
  bucketized_housing_median_age = tf.feature_column.bucketized_column(
    housing_median_age, boundaries=get_quantile_based_boundaries(
      training_examples["housing_median_age"], 7))
  # Divide median_income into 7 buckets.
  bucketized_median_income = tf.feature_column.bucketized_column(
    median_income, boundaries=get_quantile_based_boundaries(
      training_examples["median_income"], 7))
  # Divide rooms_per_person into 7 buckets.
  bucketized_rooms_per_person = tf.feature_column.bucketized_column(
    rooms_per_person, boundaries=get_quantile_based_boundaries(
      training_examples["rooms_per_person"], 7))
  feature_columns = set([
    bucketized_longitude,
    bucketized_latitude,
    bucketized_housing_median_age,
    bucketized_households,
    bucketized_median_income,
    bucketized_rooms_per_person])
  return feature_columns
#分箱函数
def get_quantile_based_boundaries(feature_values, num_buckets):
  boundaries = np.arange(1.0, num_buckets) / num_buckets
  #将1分成num_buckets份,输出分割点。例分5份为[0.2,0.4,0.6,0.8]
  quantiles = feature_values.quantile(boundaries)
  #得到在数据集中的分割位置
  return [quantiles[q] for q in quantiles.keys()]

二、特征集

相关矩阵

correlation_dataframe.corr()
tf4-corr.jpg

理想情况下,我们希望具有与目标密切相关的特征
此外,我们还希望有一些相互之间的相关性不太密切的特征,以便它们添加独立信息

三、特征组合

特征组合是指通过将两个或多个输入特征相乘来对特征空间中的非线性规律进行编码的合成特征

例:假设对纬度和经度进行分箱,获得单独的独热(one-hot编码) 5元素特征矢量表示如下:

binned_latitude = [0, 0, 0, 1, 0]
binned_longitude = [0, 1, 0, 0, 0]
假设对这两个特征矢量创建了特征组合:
binned_latitude X binned_longitude
此特征组合是一个 25 元素独热矢量(24个0和1个1),该组合中的单个1表示纬度与经度的特定连接,模型就可以了解到有关这种连接的特定关联性。

工程化:

long_x_lat = tf.feature_column.crossed_column(
  set([bucketized_longitude, bucketized_latitude]), hash_bucket_size=1000)

四、优化器

FTRL 优化器

FtrlOptimizer 是一种使用L1正则化的方法,有助于使不相关或几乎不相关的特征的权重正好为 0。该算法的优势是针对不同系数以不同方式调整学习速率,能使高维度线性模型受益。

my_optimizer = tf.train.FtrlOptimizer(learning_rate=learning_rate, l1_regularization_strength=regularization_strength)

AdaGrad 优化器

AdaGrad 的核心是灵活地修改模型中每个系数的学习率,从而单调降低有效的学习率。该优化器对于凸优化问题非常有效,但不一定适合非凸优化问题的神经网络训练。该算法需要初始使用较大的学习率。

my_optimizer=tf.train.AdagradOptimizer(learning_rate=0.5)

Adam 优化器

对于非凸优化问题,Adam 更有效。

my_optimizer=tf.train.AdamOptimizer(learning_rate=0.009)
Share

You may also like...

1 Response

  1. volica说道:

    有两个遗留问题:
    tf.feature_column.bucketized_column的内部逻辑和返回结构
    tf.feature_column.crossed_column中hash_bucket_size的意义

发表评论

您的电子邮箱地址不会被公开。