日萌社
人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度學習實戰(不定時更新)
8.6 分桶與特徵交叉
學習目標
- 目標
- 瞭解分桶方式和作用
- 應用
- 無
8.6.1 通過分桶將連續特徵變成類別特徵
有時,連續特徵與標籤不是線性關係。例如,年齡和收入 - 一個人的收入在其職業生涯早期階段會增長,然後在某一階段,增長速度減慢,最後,在退休後減少。在這種情況下,使用原始 age
作爲實值特徵列也許並非理想之選,因爲模型只能學習以下三種情況之一:
- 收入始終隨着年齡的增長而以某一速率增長(正相關);
- 收入始終隨着年齡的增長而以某一速率減少(負相關);或者
- 無論年齡多大,收入都保持不變(不相關)。
如果我們要分別學習收入與各個年齡段之間的精細關係,則可以採用分桶技巧。分桶是將整個連續特徵範圍分割爲一組連續分桶,然後根據值所在的分桶將原數值特徵轉換爲分桶 ID(作爲類別特徵)的過程。因此,我們可以針對 age
將 bucketized_column
定義爲:
age_buckets = tf.feature_column.bucketized_column(
age, boundaries=[18, 25, 30, 35, 40, 45, 50, 55, 60, 65])
8.6.2 通過特徵組合學習複雜關係
單獨使用各個基準特徵列可能不足以解釋數據。例如,對於不同的職業,受教育程度和標籤(收入超過 5 萬美元)之間的相關性可能各不相同。因此,如果我們僅學習 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)
我們還可以針對兩個以上的列創建一個 crossed_column
。每個組成列可以是類別基準特徵列 (SparseColumn
)、分桶實值特徵列,也可以是其他 CrossColumn
。例如:
age_buckets_x_education_x_occupation = tf.feature_column.crossed_column([age_buckets, 'education', 'occupation'], hash_bucket_size=1000)
注:做交叉時,只返回一個column,表示若干個特徵交叉成一個。
8.6.3 案例:普查數據分類-添加交叉特徵
效果提高
baseline | Feature intersection | |
---|---|---|
accuracy | 0.8323813 | 0.8401818 |
auc | 0.87850624 | 0.89078486 |
{'accuracy': 0.8323813, 'accuracy_baseline': 0.76377374, 'auc': 0.87850624, 'auc_precision_recall': 0.66792196, 'average_loss': 0.5613808, 'label/mean': 0.23622628, 'loss': 17.956465, 'precision': 0.6553547, 'prediction/mean': 0.24526471, 'recall': 0.61258453, 'global_step': 3053}
{'accuracy': 0.8401818, 'accuracy_baseline': 0.76377374, 'auc': 0.89078486, 'auc_precision_recall': 0.71612483, 'average_loss': 0.3730738, 'label/mean': 0.23622628, 'loss': 11.93323, 'precision': 0.7046053, 'prediction/mean': 0.22067882, 'recall': 0.5569423, 'global_step': 3053}
特徵列版本
def get_feature_column_v2():
"""特徵交叉與分桶
:return:
"""
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')
numeric_columns = [age, education_num, capital_gain, capital_loss, hours_per_week]
# 類別型特徵
# categorical_column_with_vocabulary_list, 將字符串轉換成ID
relationship = tf.feature_column.categorical_column_with_vocabulary_list(
'relationship',
['Husband', 'Not-in-family', 'Wife', 'Own-child', 'Unmarried', 'Other-relative'])
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'])
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'])
# categorical_column_with_hash_bucket--->哈希列
# 對不確定類別數量以及字符時,哈希列進行分桶
occupation = tf.feature_column.categorical_column_with_hash_bucket(
'occupation', hash_bucket_size=1000)
categorical_columns = [relationship, marital_status, workclass, occupation]
# 分桶,交叉特徵
age_buckets = tf.feature_column.bucketized_column(
age, boundaries=[18, 25, 30, 35, 40, 45, 50, 55, 60, 65])
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),
]
return numeric_columns + categorical_columns + crossed_columns
模型訓練
# 分桶與特徵交叉
# # 構造模型
feature_v2 = get_feature_column_v2()
classifiry = tf.estimator.LinearClassifier(feature_columns=feature_v2)
# train輸入的input_func,不能調用傳入
# 1、input_func,構造的時候不加參數,但是這樣不靈活, 裏面參數不能固定的時候
# 2、functools.partial
train_func = functools.partial(input_func, train_file, epoches=3, batch_size=32)
test_func = functools.partial(input_func, test_file, epoches=1, batch_size=32)
classifiry.train(train_func)
result = classifiry.evaluate(test_func)
print(result)
兩次模型訓練需要充分之後,可以選擇一直訓練或者多個epoch:
lr 訓練的模型評估:
accuracy: 0.8301087
accuracy_baseline: 0.76377374
auc: 0.8780217
auc_precision_recall: 0.6530893
average_loss: 1.9535114
global_step: 3053
label/mean: 0.23622628
loss: 62.4855
precision: 0.6731879
prediction/mean: 0.22214794
recall: 0.5457618
WARNING:tensorflow:Using temporary folder as model directory: /tmp/tmpfh9cm_47
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.
lr + crossed 訓練的模型評估:
accuracy: 0.84227014
accuracy_baseline: 0.76377374
auc: 0.8945431
auc_precision_recall: 0.728271
average_loss: 0.36445677
global_step: 3053
label/mean: 0.23622628
loss: 11.657604
precision: 0.708279
prediction/mean: 0.2177045
recall: 0.5650026