tf.feature_column详解

 

 

tensorflow2.0 环境下的tfrecord读写及tf.io.parse_example和tf.io.parse_single_example的区别中已经讲到了从tfrecord 中读取数据需要提供一个dict,里面包含了特征名称和特征的类型,如果我们特征很少,只需要手写这个dict就可以。但是当特征非常多的时候,就需要更方便的工具来生成这个dict。这个工具的就是tf.feature_column,同时tf.feature_column也是一个特征工程的工具,可以用来自动one-hot处理,还有hash分桶等处理。

tf.feature_column中的函数主要包括以下的的函数,下面会分别进行讲解

数值类型tf.feature_column.numeric_column

tf.feature_column.numeric_column(
    key, shape=(1,), default_value=None, dtype=tf.dtypes.float32, normalizer_fn=None
)

tf.feature_column.numeric_column用于抽取数值类型的特征,即dense特征,在tensorflow2.0 环境下的tfrecord读写及tf.io.parse_example和tf.io.parse_single_example的区别 中,7日内的消费和7日内打开淘宝的天数都用该函数定义:

pay = tf.feature_column.numeric_column('pay',shape=(1,), default_value=None, dtype=tf.dtypes.float32, normalizer_fn=None)
use_day = tf.feature_column.numeric_column("use_day",shape=(1,), default_value=None, dtype=tf.dtypes.int64, normalizer_fn=None)

应该注意的是key必须和tfrecord 中的key对应。shape必须与tfrecord中的shape对应,如果我们还有一个特征,是用户连续几天的消费金额[99.9, 249, 33] ,那么shape就要被定义成(3, )

类别特征系列

解析类别特征的方法最常用的有

方法生成的子类
categorical_column_with_identityCategoricalColumn
categorical_column_with_vocabulary_listCategoricalColumn,存有vocabulary_list
categorical_column_with_vocabulary_fileCategoricalColumn,存有vocabulary_file
categorical_column_with_hash_bucketHashedCategoricalColumn

 

 

categorical_column_with_vocabulary_list

根据sparse特征列表定义特征

city = tf.feature_column.categorical_column_with_vocabulary_list("city",["shanghai","beijing","guangzhou","tianjin","shenzhen"])

这种方法的缺点是只能用于数量较少的种类,比如性别,省份等。种类非常多的catogery,例如店铺id,就非常不适合这种方法了。

categorical_column_with_identity

这个方法用于已经编码的sparse特征,例如,店铺id虽然数量非常大,但是已经把每个店铺id都从0开始编码,那么就可以用

poi = tf.feature_column.categorical_column_with_identity("poi", num_buckets=10, default_value=0)

其中,num_bucket是最大编号

tf.feature_column.categorical_column_with_vocabulary_file

前面已经说了,当sparse特征的种类数量非常巨大的时候,就不能用用categorical_column_with_vocabulary_list了,用categorical_column_with_identity 又需要事先对sparse特征编码,这时候可以用tf.feature_column.categorical_column_with_vocabulary_file命令,读取sparse特征的所有可能取值。当然这种方法的效率也是比较低的,在要求低延迟的线上是不太划算的。

tf.feature_column.categorical_column_with_vocabulary_file(
    key, vocabulary_file, vocabulary_size=None, dtype=tf.dtypes.string,
    default_value=None, num_oov_buckets=0
)

categorical_column_with_hash_bucket

如果sparse特征非常庞大,例如上面的poi可以写成

poi = tf.feature_column.categorical_column_with_hash_bucket("poi", hash_bucket_size=10, dtype=tf.dtypes.int64)

但是应该注意的是,hash_bucket_size的大小应该留有充分的冗余量,否则非常容易出现hash冲突,在这个例子中,一共有3个店铺,把hash_bucket_size设定为10,仍然得到了hash冲突的结果,这样poi的信息就被丢失了一些信息

 

tf.feature_column.indicator column 

tf.feature_column.indicator column  是一个onehot工具,用于把sparse特征进行onehot 变换,用于把categorical_column_with_*工具生成的特征变成onehot 编码

tf.feature_column.indicator column 的入参非只有一个,就是categorical_column_with_*的结果。

poi = tf.feature_column.categorical_column_with_hash_bucket("poi", hash_bucket_size=15, dtype=tf.dtypes.int64)
poi_idc = tf.feature_column.indicator_column(poi)

这里还有一个有趣的细节,在tensorflow2.0 环境下的tfrecord读写及tf.io.parse_example和tf.io.parse_single_example的区别中我们已经提到了tf.io.parse_example和tf.io.parse_single_example的区别。在这里他们还有另一个区别

poi = tf.feature_column.categorical_column_with_hash_bucket("poi", hash_bucket_size=15, dtype=tf.dtypes.int64)   #创建poi特征
poi_idc = tf.feature_column.indicator_column(poi)  #onehot处理
feature_column = [poi_idc] 
feature = tf.feature_column.make_parse_example_spec(feature_column)  #生成poi的featuredict
path = "./tfrecord"
data = tf.data.TFRecordDataset(path)  #读取tfrecord
#分别用tf.io.parse_example 和 tf.io.parse_single_example 解析数据
data2 = data.map(lambda x : tf.io.parse_example(tf.reshape(x,[1]), features = feature))
data3 = data.map(lambda x : tf.io.parse_single_example(x, features = feature))

tf.io.parse_example得到的poi是一个形状为[1 3]的张量,而tf.io.parse_single_example得到的是一个形状为[3]的张量,这个区别就直接决定了

for batch in data2:
    tensor = tf.compat.v1.feature_column.input_layer(batch,feature_column)  #可以执行
for batch2 in data3:
    tensor2 = tf.compat.v1.feature_column.input_layer(batch2,feature_column)  #报错
 

如果看不懂也没关系,只需要记住tf.io.parse_example的结果,在用tf.compat.v1.feature_column.input_layer生成输入时,可以把所有的特征一起生成

而记住tf.io.parse_single_example的结果,只能对sparse特征逐个生成,然后合并成起来。

tf.feature_column.embedding_column

用于生成embedding后的张量

tf.feature_column.embedding_column(
    categorical_column, dimension, combiner='mean', initializer=None,
    ckpt_to_load_from=None, tensor_name_in_ckpt=None, max_norm=None, trainable=True,
    use_safe_embedding_lookup=True
)

他的几个入参意义分别是

categorical_column: categorical_column_with_* 工具的结果

dimension:embedding后的维度

combiner:对于多种类的sparse特征怎么组合,Currently 'mean', 'sqrtn' and 'sum' are supported

其他配置全部用默认就好了,绝大部分情况都不会有什么影响

应该注意的是,与indicator的一样,用tf.io.parse_single_example会生成一个embedding后的举证,而tf.io.parse_example会得到一个向量。例如

poi = tf.feature_column.categorical_column_with_hash_bucket("poi", hash_bucket_size=15, dtype=tf.dtypes.int64)
poi_ebd = tf.feature_column.embedding_column(poi,dimension = 3,combiner = "mean")
feature_column = [poi_ebd]
feature = tf.feature_column.make_parse_example_spec(feature_column)
path = "./tfrecord"
data = tf.data.TFRecordDataset(path)
data2 = data.map(lambda x : tf.io.parse_example(tf.reshape(x,[1]), features = feature))
data3 = data.map(lambda x : tf.io.parse_single_example(x, features = feature))
for batch in data2:
    tensor = tf.compat.v1.feature_column.input_layer(batch,feature_column)
for batch2 in data3:
    tensor2 = tf.compat.v1.feature_column.input_layer(batch2,feature_column)
print(tensor)
print(tensor2)

result:
tf.Tensor([[0.00952441 0.01638425 0.29906932]], shape=(1, 3), dtype=float32)
tf.Tensor(
[[-0.59089464 -0.52776134  0.3303768 ]
 [ 0.74979115  0.11539479  0.3902657 ]
 [ 0.08098221  0.21678661 -0.11189163]], shape=(3, 3), dtype=float32)

tf.feature_column.make_parse_example_spec

tf.io.parse_example和tf.io.parse_single_example需要一个dict,定义特征名称和特征类型(fixedlenfeature还是varlenfeature)

tf.feature_column.make_parse_example_spec用于生成这个dict,他的入参必须是个可迭代对象,一般都是一个list,list的元素是上面讲过的所有函数的result。

这里应该非常注意的是,tf.feature_column.indicator column 和tf.feature_column.embedding_column 并不影响tf.feature_column.make_parse_example_spec,也就是说,一个特征是否经过了tf.feature_column.indicator column 和tf.feature_column.embedding_column 后tf.feature_column.make_parse_example_spec的结果是一样的,tf.io.parse_example和tf.io.parse_single_example的结果也是一样的。

例子:

poi = tf.feature_column.categorical_column_with_hash_bucket("poi", hash_bucket_size=15, dtype=tf.dtypes.int64)  #定义poi特征
poi_ebd = tf.feature_column.embedding_column(poi,dimension = 3,combiner = "mean") #poi做embedding
poi_idc = tf.feature_column.indicator_column(poi)  #poi做indicator


feature_column = [poi]
feature_column2 = [poi_ebd]
feature_column3 = [poi_idc]

feature = tf.feature_column.make_parse_example_spec(feature_column)
feature2 = tf.feature_column.make_parse_example_spec(feature_column2)
feature3 = tf.feature_column.make_parse_example_spec(feature_column3)

print(feature)
print(feature2)
print(feature3)

===============================================================

result:
{'poi': VarLenFeature(dtype=tf.int64)}
{'poi': VarLenFeature(dtype=tf.int64)}
{'poi': VarLenFeature(dtype=tf.int64)}

===============================================================

path = "./tfrecord"
data = tf.data.TFRecordDataset(path)
data2 = data.map(lambda x : tf.io.parse_example(tf.reshape(x,[1]), features = feature))
data3 = data.map(lambda x : tf.io.parse_example(tf.reshape(x,[1]), features = feature2))
data4 = data.map(lambda x : tf.io.parse_example(tf.reshape(x,[1]), features = feature3))

for batch in data2:
    tensor = tf.compat.v1.feature_column.input_layer(batch,feature_column)
    print(tf.sparse.to_dense(batch["poi"]))
for batch2 in data3:
    tensor2 = tf.compat.v1.feature_column.input_layer(batch2,feature_column)
    print(tf.sparse.to_dense(batch2["poi"]))
for batch3 in data4:
    tensor3 = tf.compat.v1.feature_column.input_layer(batch3,feature_column)
    print(tf.sparse.to_dense(batch2["poi"]))



result:
tf.Tensor([[1 3 2]], shape=(1, 3), dtype=int64)
tf.Tensor([[1 3 2]], shape=(1, 3), dtype=int64)
tf.Tensor([[1 3 2]], shape=(1, 3), dtype=int64)

特征工程

可以看到tf.feature_column.make_parse_example_spec和tf.io.parse_example和tf.io.parse_single_example 仅仅是从tfrecord 中读取数据,并不会对数据做任何的特征工程的处理。

那么特征工程在哪个环节进行呢?

poi = tf.feature_column.categorical_column_with_hash_bucket("poi", hash_bucket_size=15, dtype=tf.dtypes.int64)  #定义poi特征
poi_ebd = tf.feature_column.embedding_column(poi,dimension = 3,combiner = "mean") #poi做embedding



feature_column2 = [poi_ebd]

feature2 = tf.feature_column.make_parse_example_spec(feature_column2)



print(feature2)


===============================================================

result:
{'poi': VarLenFeature(dtype=tf.int64)}


===============================================================

path = "./tfrecord"
data = tf.data.TFRecordDataset(path)

data2 = data.map(lambda x : tf.io.parse_example(tf.reshape(x,[1]), features = feature2))


for batch in data2:
    tensor = tf.compat.v1.feature_column.input_layer(batch,feature_column2)
    print(tf.sparse.to_dense(batch["poi"]))




result:
tf.Tensor([[1 1 1]], shape=(1, 3), dtype=int64)

从上面的代码可以看到categorical_column_with_identity、categorical_column_with_vocabulary_list、categorical_column_with_vocabulary_file、categorical_column_with_hash_bucket 保存了数值化方式,

embedding_column, bucketized_column, indicator_column,保存了特征工程方式,

最后通过调用feature_column.input_layer,实现了特征工程的处理

 

  • 13
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值