DeepFM(2) 數據集處理


一、數據集

Kaggle的一個競賽數據集:
Preprocess Criteo dataset. This dataset was used for the Display Advertising
Challenge (https://www.kaggle.com/c/criteo-display-ad-challenge).

二、數據集描述

第1列就是標簽(點擊與否用0/1表示,1為點擊,0為沒點擊)。后面的2-40列數據(共39列)是我們的特征變量(指標),也就是原文paper里面提到的“n-field”的概念,這里的n是39。
然后數據內又分了前13列是連續型變量,后26列是類別型變量。

三、訓練集生成

1、連續變量和類別變量特征:[1,13],[14,39]。

continous_features = range(1, 14) # [1,...13]
categorial_features = range(14, 40) # [14,...39]

將39列的每一列做為獨立的輸入之后再合並,所以根據每一列建立索引字典。建立好之后根據索引字典將原始數據(上面的數據視圖呈現那樣)映射到數字空間,即每個值都代表着索引字典里面的索引,可以根據索引找到原來的值。

2、feature_sizes:每個特征的長度,用於構建索引。

首先要知道每個類別特征的特征個數。連續特征的特征個數為1。因為在特征索引中,不同的連續值對應一個特征位,類別特征每種情況對應一個特征位。
1、類別特征維度統計

categorial_features = [14,...39]
num_feature = len(categorial_features)
dicts = []    
for i in range(0, num_feature):
    dicts.append(collections.defaultdict(int)) # defaultdict(int) 如果key不存在的時候,則賦值為int類型,值0。

with open('train.txt', 'r') as f: # 讀取文件,遍歷行,針對所有類別特征,如果有值。則以該值為key的字典的value加1。
     for line in f:
         features = line.rstrip('\n').split('\t')
         for i in range(0, num_feature):
             if features[categorial_features[i]] != '':
                 dicts[i][features[categorial_features[i]]] += 1

得到每個類別特征的個數統計之后,進行后續處理。dicts[i]表示第i個類別特征的統計字典。

for i in range(0, num_feature):
    dicts[i] = filter(lambda x: x[1] >= 2,
                                  dicts[i].items())  # 過濾掉只出現過一次的類別特征。
    dicts[i] = sorted(dicts[i], key=lambda x: (-x[1], x[0])) ## 第二個元素的負數, 如果第二個元素相等,則基於第1個元素。皆為正序
    vocabs, _ = list(zip(*dicts[i])) # vocabs:tuple. 第i種類別特征的所有情況組成的元組。
    dicts[i] = dict(zip(vocabs, range(1, len(vocabs) + 1))) # 得到 {特征:索引}的字典。索引從1開始。
    dicts[i]['<unk>'] = 0 # 賦值未知特征為0,即出現次數少於2次的當做0處理。

dict_size = [len(self.dicts[idx]) for idx in range(0, self.num_feature)] # 26個類別特征,每個特征包含多少個不同的類別。
sizes = [1] * len(continous_features) + dict_sizes
sizes = [str(i) for i in sizes] # sizes 保存了所有特征的維度。
feature_sizes.write(','.join(sizes)) # 保存為feature_sizes.txt。

四、構建feature_index 和 feature_value

前面得到了特征長度,可以構建最后的特征索引和特征值。根據每一列建立索引字典。

with open('train.txt', 'r') as f:
    for line in f:
        features = line.rstrip('\n').split('\t') # 同樣是首先得到原始數據的特征列表。
        continous_vals = [] # 連續特征轉換之后的值
        for i in range(0, len(continous_features)):       
            val = features[continous_features[i]] # 第i個連續特征的原始值
            if val == '': # 原始數據是有存在一些缺少值的,對缺失值采取的手段是填0處理
                value= 0.0
            else:
                val = float(val)
            continous_vals.append("{0:.6f}".format(val).rstrip('0')
                                    .rstrip('.'))
        categorial_vals = [] # 類別特征轉換之后的值,其值為索引。
        for i in range(0, len(categorial_features)):
            key = features[categorial_features[i]] # 第i個類別特征的原始值
            if key not in dicts[i]:
               res = dicts[i]['<unk>']
            else:
               res = dicts[i][key]
           
            categorial_vals.append(str(res)) # 類別特征轉換后的值為其每個類別中的索引。

        continous_vals = ','.join(continous_vals)
        categorial_vals = ','.join(categorial_vals)
        label = features[0]
        out_train.write(','.join([continous_vals, categorial_vals, label]) + '\n') # 保存起來。

總結

最終得到了兩個文件
1、feature_sizes.txt
每個特征的維度:連續特征都為1,類別特征為其類別數,相當於每個field的特征數,用於初始化deepfm模型。

1,1,1,1,1,1,1,1,1,1,1,1,1,10,22,7,6,7,7,3,9,3,5,6,7,7,8,5,7,10,14,4,4,7,3,9,8,11,5

2、train.txt
每行長度為\(13+26+1=40\),13個連續特征為其原始值,26個類別特征,為其類別索引。最后一位為label。

1,1,5,0,1382,4,15,2,181,1,2,0,2,2,3,0,0,1,1,0,3,1,0,0,0,0,3,0,0,1,5,1,3,0,0,2,0,1,0,0
2,0,44,1,102,8,2,2,4,1,1,0,4,2,14,0,0,1,3,0,1,1,0,0,0,0,1,0,0,2,0,1,2,0,0,2,0,1,0,1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM