人工智能小白日记之10 ML学习篇之6特征组合

前言

前面处理的都是线性问题,比如这样的
人工智能小白日记之10 ML学习篇之6特征组合
可以用一个简单的线性模型来实现分类。
y = w1x1+w2x2+b.
但是如果是这样的呢?
人工智能小白日记之10 ML学习篇之6特征组合
不能用简单的线性模型来处理,怎么处理呢?可以引入合成特征

课程内容

1 利用合成特征学习非线性规律

这里观察蓝点和红点的分布,是有规律的。第一和第三象限的
x1x2乘积为负,二四象限的乘积为正,利用这个特征交叉特征交叉乘积),可以在线性模型中学习非线性规律。这样可以创建组合特征x1x2,给它一个权重w3,更新公式为:
人工智能小白日记之10 ML学习篇之6特征组合
事实上,多年来线性学习器是我们真正拥有的 可以扩展到数十亿或数千亿规模数据集的唯一方法。现在我们还有扩展效果不错的深度神经网络, 这是另一种方案。

2 组合独热矢量

现实中很多特征是非数值型的,假设我们具有以下两个特征:国家/地区和语言,他们都是字符串。前面的学习让我们知道要采用独热编码,比如上节例子中的latitude,经过分桶,我们得到了10个桶,这10个特征构成了一个矢量。
人工智能小白日记之10 ML学习篇之6特征组合

3 Playground 练习1

任务:尝试创建一个能够通过手动更改以下三个输入特征的权重将蓝点与橙点分开的模型:

  • x1
  • x2
  • x1 x2(特征组合)
    人工智能小白日记之10 ML学习篇之6特征组合
    分析:这题属于简单题,刚才已经分析过了,一三象限的
    x1x2乘积为负,二四象限的乘积为正,能很干脆的划分出来。所以x1x2应该给予最高权重,三个权重给0.1,0.1,0.8看看效果。
    人工智能小白日记之10 ML学习篇之6特征组合
    基本ok

4 Playground 练习2

现在,我们来使用一些高级特征组合。此 Playground 练习中的数据集看起来有点像飞镖游戏中的飞镖击中位置,中间是蓝点,外圈是橙点。
人工智能小白日记之10 ML学习篇之6特征组合
分析:圆形很容易让人想起一个特点,半径固定,如果我们把蓝色点的分布位置想象成一个圆,那么x12+x22<=r2。所以这里,果断选这两个作为特征。

任务 1

按照指定方式运行此线性模型。花一两分钟时间(不再更多)尝试不同的学习速率设置,看看是否出现任何改进。线性模型可以针对此数据集得出有效结果吗?

ps:指定方式就是x1和x2作为特征,不看好结果
人工智能小白日记之10 ML学习篇之6特征组合
看吧,损失达到了一半以上,毕竟画直线肯定无法完成任务。

任务 2

现在,尝试添加向量积特征(例如 x1x2),以尝试优化效果。

  • 哪些特征最有帮助?
  • 您可以实现的最佳效果是什么?

ps:加乘积肯定也没啥卵用
人工智能小白日记之10 ML学习篇之6特征组合
损失也在一半以上。哪些特征最有用?一开始就分析了,就是那两个平方x12和x22。全部加上看效果
人工智能小白日记之10 ML学习篇之6特征组合
损失显著降低,其实我们用这两个特征,顺便调节下学习速率,达到最佳效果:
人工智能小白日记之10 ML学习篇之6特征组合
训练损失只有0.164

任务 3

如果您有一个出色的模型,请检查该模型的输出面(以背景颜色显示)。

  • 看起来像线性模型吗?不像
  • 您会如何描述该模型?

编程练习

进入该节的练习
人工智能小白日记之10 ML学习篇之6特征组合
人工智能小白日记之10 ML学习篇之6特征组合
看来还是在之前的基础上做优化

1 FTRL 优化算法

高维度线性模型可受益于使用一种基于梯度的优化方法,叫做 FTRL。该算法的优势是针对不同系数以不同方式调整学习速率,如果某些特征很少采用非零值,该算法可能比较实用(也非常适合支持 L1 正则化)。我们可以使用 FtrlOptimizer 来应用 FTRL。
ps:这里告诉我们可以采用新的评估器了,之前采用的GradientDescentOptimizer。这里就涉及比较高端的东西了,我大概查了一下,不是当前做应用能看懂的,比如这样的,随便感受一下哈,http://www.cnblogs.com/EE-NovRain/p/3810737.html。
我们知道有这个东西就行了,以后慢慢加深学习。

2 离散特征的独热编码

通常,在训练逻辑回归模型之前,离散(即字符串、枚举、整数)特征会转换为二元特征系列。

字符串的我们见过了,枚举和整型的,比如有个特征的值是1,2,3,4,5中的一个,那么我们可以用log2(5)<3个特征来表示,每个特征的值只有0或者1。比如5可以表示为(1,1,1)。

3 分桶(分箱)特征

分桶之前聊过,但是那种方式是透明的,我们先打印了整个随机抽样数据知道latitude的范围32-44,然后再做的分桶。原文中也再次举例:
人工智能小白日记之10 ML学习篇之6特征组合
这里有必要贴出来,因为这里是分桶索引。没错,最后的特征矢量,是以索引的方式存在。比如[42004]是属于>25000的范围,所以归属于bucket_2,索引为2。这些索引被视为离散特征,一般来说需要将[[1], [2], [0], [1]]这些离线特征,用第2点中的独热编码来表示。

3-1 分桶特征的特征列

前面,我们构建数值类型的特征列用的是numeric_column
人工智能小白日记之10 ML学习篇之6特征组合
对于分桶特征,用的是
bucketized_column(
source_column, # 必须是numeric_column
boundaries
)
根据这个函数,我们需要先定义数值特征列,然后提供它的分桶边界,比如之前的latitude是以整数33,34,35等为分桶边界的。

3-2 计算分桶边界

原文中给了方法

def get_quantile_based_boundaries(feature_values, num_buckets):
  boundaries = np.arange(1.0, num_buckets) / num_buckets
  quantiles = feature_values.quantile(boundaries)
  return [quantiles[q] for q in quantiles.keys()]

我们利用打印大法来研究一下这个函数做了啥。
为了方便,我们加上输出,然后用之前用过的latitude试试

def get_quantile_based_boundaries(feature_values, num_buckets):
  boundaries = np.arange(1.0, num_buckets) / num_buckets
  print(boundaries)
  quantiles = feature_values.quantile(boundaries)
  print(quantiles)
  return [quantiles[q] for q in quantiles.keys()]

latitude_boundaries=get_quantile_based_boundaries(
    california_housing_dataframe["latitude"], 10)

print(latitude_boundaries)

人工智能小白日记之10 ML学习篇之6特征组合

知识扩展
1)np.arange(1.0, num_buckets) / num_buckets 这里根据你输入的分桶数量,均分生成边界点的位置比例
2)feature_values.quantile(boundaries),其实原型是
人工智能小白日记之10 ML学习篇之6特征组合
这里q传入了boundaries数组,interpolation则使用了默认的线性插值。最后根据q,返回对应的分位点。
人工智能小白日记之10 ML学习篇之6特征组合
比如这个例子,当q=0.5时,分位点2.5利用默认线性插值怎么算的呢?(max-min)*q+min
所以q=0.5 返回(4-1)*0.5+1 = 2.5
q=0.25 时,返回(4-1)*0.25+1 = 1.75
q=0.75 时,返回(4-1)*0.75+1 = 3.25
所以,我们用latitude也是这么算出来对应的分位点

3-3 分桶特征的特征列

根据以上原理,分别得到households和longitude的特征列

def get_quantile_based_boundaries(feature_values, num_buckets):
  boundaries = np.arange(1.0, num_buckets) / num_buckets
  quantiles = feature_values.quantile(boundaries)
  return [quantiles[q] for q in quantiles.keys()]

# Divide households into 7 buckets.
households = tf.feature_column.numeric_column("households")
bucketized_households = tf.feature_column.bucketized_column(
  households, boundaries=get_quantile_based_boundaries(
    california_housing_dataframe["households"], 7))

# Divide longitude into 10 buckets.
longitude = tf.feature_column.numeric_column("longitude")
bucketized_longitude = tf.feature_column.bucketized_column(
  longitude, boundaries=get_quantile_based_boundaries(
    california_housing_dataframe["longitude"], 10))

输出结果为:
人工智能小白日记之10 ML学习篇之6特征组合

任务 1:使用分桶特征列训练模型

在前面的代码块中,两个实值列(即 householdslongitude)已被转换为分桶特征列。您的任务是对其余的列进行分桶,然后运行代码来训练模型。您可以采用各种启发法来确定分桶的范围。本练习使用了分位数技巧,通过这种方式选择分桶边界后,每个分桶将包含相同数量的样本。

分析:这个任务简单,复制一下代码就可以完成了

def construct_feature_columns():
  """Construct the TensorFlow Feature Columns.

  Returns:
    A set of 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))

  #
  # YOUR CODE HERE: bucketize the following columns, following the example above:
  #
  bucketized_latitude = tf.feature_column.bucketized_column(
    latitude, boundaries=get_quantile_based_boundaries(
      training_examples["latitude"], 10))
  bucketized_housing_median_age = tf.feature_column.bucketized_column(
    housing_median_age, boundaries=get_quantile_based_boundaries(
      training_examples["housing_median_age"], 10))
  bucketized_median_income =tf.feature_column.bucketized_column(
    median_income, boundaries=get_quantile_based_boundaries(
      training_examples["median_income"], 10))
  bucketized_rooms_per_person =tf.feature_column.bucketized_column(
    rooms_per_person, boundaries=get_quantile_based_boundaries(
      training_examples["rooms_per_person"], 10))
  
  
  feature_columns = set([
    bucketized_longitude,
    bucketized_latitude,
    bucketized_housing_median_age,
    bucketized_households,
    bucketized_median_income,
    bucketized_rooms_per_person])
  
  return feature_columns

不过这里分桶个数,怎么定,我还不清楚,都放了10上去
人工智能小白日记之10 ML学习篇之6特征组合

任务 2:使用特征组合训练模型

longitude 与 latitude 组合,产生的组合特征则代表一个明确的城市街区。目前,特征列 API 仅支持组合离散特征。要组合两个连续的值(比如 latitude 或 longitude),我们可以对其进行分桶。

如果我们组合 latitude 和 longitude 特征(例如,假设 longitude 被分到 2 个分桶中,而 latitude 有 3 个分桶),我们实际上会得到 6 个组合的二元特征。当我们训练模型时,每个特征都会分别获得自己的权重。

请参阅有关 crossed_column() 的 TensorFlow API 文档,了解如何为您的组合构建特征列。hash_bucket_size 可以设为 1000。

**分析:也就是说分桶的特征进行组合的特征列要用到crossed_column,有点乱啊,貌似针对不同的特征需要用到对应的方法生成特征列。撸一下,我们现在遇到了三种,一种是数值特征用的num_column,一种是分桶特征用的bucketized_column,现在是第三种特征组合要用到crossed_column。**我们来看看官方api:
人工智能小白日记之10 ML学习篇之6特征组合
人工智能小白日记之10 ML学习篇之6特征组合
keys:需要传入被cross的特征,可以是字符串,也可以是_CategoricalColumn特征列。我们现在的bucketized_latitude和bucketized_longitude,就是符合条件的分桶特征列。

hash_bucket_size:桶数量,为啥要设1000呢?
hash_key:这个忽略了,fingerprintcat64函数都不知道是啥

打印一下:
人工智能小白日记之10 ML学习篇之6特征组合
有戏。更新特征列代码:

def construct_feature_columns():
  """Construct the TensorFlow Feature Columns.

  Returns:
    A set of 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))
  
  # YOUR CODE HERE: Make a feature column for the long_x_lat feature cross
  long_x_lat = tf.feature_column.crossed_column([bucketized_latitude, bucketized_longitude], 1000)
  
  feature_columns = set([
    bucketized_longitude,
    bucketized_latitude,
    bucketized_housing_median_age,
    bucketized_households,
    bucketized_median_income,
    bucketized_rooms_per_person,
    long_x_lat])
  
  return feature_columns

训练结果:
人工智能小白日记之10 ML学习篇之6特征组合

小结

本篇描述了特征组合,在加利福利亚州的案例中进行了应用,由于latitude和longitude是连续型数据,需要进行分桶后再进行组合,组合方式是cross,类似笛卡尔积。