分桶與特徵交叉

日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度學習實戰(不定時更新)


8.6 分桶與特徵交叉

學習目標

  • 目標
    • 瞭解分桶方式和作用
  • 應用

8.6.1 通過分桶將連續特徵變成類別特徵

有時,連續特徵與標籤不是線性關係。例如,年齡和收入 - 一個人的收入在其職業生涯早期階段會增長,然後在某一階段,增長速度減慢,最後,在退休後減少。在這種情況下,使用原始 age 作爲實值特徵列也許並非理想之選,因爲模型只能學習以下三種情況之一:

  1. 收入始終隨着年齡的增長而以某一速率增長(正相關);
  2. 收入始終隨着年齡的增長而以某一速率減少(負相關);或者
  3. 無論年齡多大,收入都保持不變(不相關)。

如果我們要分別學習收入與各個年齡段之間的精細關係,則可以採用分桶技巧。分桶是將整個連續特徵範圍分割爲一組連續分桶,然後根據值所在的分桶將原數值特徵轉換爲分桶 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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章