【推薦系統篇】--推薦系統之之特徵工程部分---構建訓練集流程

LHBlog發表於2018-03-26

一、前述

根據前文中架構,本文我們討論線下部分構建訓練集部分。因為我們離線部分模型的選擇是邏輯迴歸,所以我們資料必須有x和y.

二、具體流程

1.從資料庫中分離出我們需要的資料。

    使用者行為表(日誌)

   使用者歷史下載表

  

   商品詞表(商品的基本特徵)

 

2.構建訓練集中的關聯特徵

流程:

2.構建訓練集中的基本特徵

 

總結:注意特徵名離散化因為如果特徵不離散化會造成資料之間有關係。

三、具體構建過程

1、hive建表

真實的生產場景涉及到大概五十張表的欄位,這裡全部簡化流程,直接給出最終的三張表:

應用詞表:

CREATE EXTERNAL TABLE IF NOT EXISTS dim_rcm_hitop_id_list_ds
(
    hitop_id    STRING,
    name        STRING,
    author      STRING,
    sversion    STRING,
    ischarge    SMALLINT,
    designer    STRING,
    font        STRING,
    icon_count  INT,
    stars       DOUBLE,
    price       INT,
    file_size   INT,     
    comment_num INT,
    screen      STRING,
    dlnum       INT
)row format delimited fields terminated by '\t';
/**
*
*模擬app的商品詞表
hitop_id STRING, 應用軟體ID
name STRING, 名稱
author STRING, 作者
sversion STRING, 版本號
ischarge SMALLINT, 收費軟體
designer STRING, 設計者
font STRING, 字型
icon_count INT, 有幾張配圖
stars DOUBLE, 評價星級
price INT, 價格
file_size INT, 大小
comment_num INT, 評論資料
screen STRING, 解析度
dlnum INT 下載數量
*/

 
使用者歷史下載表:

CREATE EXTERNAL TABLE IF NOT EXISTS dw_rcm_hitop_userapps_dm
(
    device_id           STRING,
    devid_applist       STRING,
    device_name         STRING,
    pay_ability         STRING
)row format delimited fields terminated by '\t';
/**
*使用者下載歷史表 這裡沒有使用者這個概念 手機裝置ID就是userId
* device_id STRING, 手機裝置ID
devid_applist STRING, 下載過軟體列表
device_name STRING, 裝置名稱
pay_ability STRING 支付能力
*/

 


正負例樣本(使用者當前行為即日誌)表:

CREATE EXTERNAL TABLE IF NOT EXISTS dw_rcm_hitop_sample2learn_dm
(
    label       STRING,
    device_id   STRING,
    hitop_id    STRING,
    screen      STRING,
    en_name     STRING,
    ch_name     STRING,
    author      STRING,
    sversion    STRING,
    mnc         STRING,
    event_local_time STRING,
    interface   STRING,
    designer    STRING,
    is_safe     INT,
    icon_count  INT,
    update_time STRING,
    stars       DOUBLE,
    comment_num INT,
    font        STRING,
    price       INT,
    file_size   INT,
    ischarge    SMALLINT,
    dlnum       INT
)row format delimited fields terminated by '\t';
/**
* 正負例樣本表 = 瀏覽記錄+標籤
label STRING, Y列,-11代表正負例 label值實際上是批處理得出來的,使用者瀏覽了並在一段時間內下載為正例
device_id STRING, 裝置ID
hitop_id STRING, 應用ID
screen STRING, 手機軟體需要的解析度
en_name STRING, 英文名
ch_name STRING, 中文名
author STRING, 作者
sversion STRING, 版本
mnc STRING, Mobile Network Code,行動網路號碼
event_local_time STRING, 瀏覽的時間
interface STRING,
designer STRING,
is_safe INT,
icon_count INT,
update_time STRING,
stars DOUBLE,
comment_num INT,
font STRING,
price INT,
file_size INT,
ischarge SMALLINT,
dlnum INT
*/

 2、load資料

分別往三張表load資料:

商品詞表:

load data local inpath '/opt/sxt/recommender/script/applist.txt' into table dim_rcm_hitop_id_list_ds;

使用者歷史下載表:

load data local inpath '/opt/sxt/recommender/script/userdownload.txt' into table dw_rcm_hitop_userapps_dm;

正負例樣本表:

load data local inpath '/opt/sxt/recommender/script/sample.txt' into table dw_rcm_hitop_sample2learn_dm;

 

3、構建訓練資料

3.1建立臨時表

建立處理資料時所需要的臨時表
CREATE TABLE IF NOT EXISTS tmp_dw_rcm_hitop_prepare2train_dm    
(
    device_id           STRING,
    label               STRING,
    hitop_id            STRING,
    screen              STRING,
    ch_name             STRING,
    author              STRING,
    sversion            STRING,
    mnc                 STRING,
    interface           STRING,
    designer            STRING,
    is_safe             INT,
    icon_count          INT,
    update_date         STRING,
    stars               DOUBLE,
    comment_num         INT,
    font                STRING,
    price               INT,
    file_size           INT,
    ischarge            SMALLINT,
    dlnum               INT,
    idlist              STRING,
    device_name         STRING,
    pay_ability         STRING
)row format delimited fields terminated by '\t';

最終儲存訓練集的表
CREATE TABLE IF NOT EXISTS dw_rcm_hitop_prepare2train_dm
(
    label                   STRING,
    features       STRING
)row format delimited fields terminated by '\t';

3.2 訓練資料預處理過程

首先將資料從正負例樣本和使用者歷史下載表資料載入到臨時表中

INSERT OVERWRITE TABLE tmp_dw_rcm_hitop_prepare2train_dm
SELECT
    t2.device_id,
    t2.label,
    t2.hitop_id,
    t2.screen,
    t2.ch_name,
    t2.author,
    t2.sversion,
    t2.mnc,
    t2.interface,
    t2.designer,
    t2.is_safe,
    t2.icon_count,
    to_date(t2.update_time),
    t2.stars,
    t2.comment_num,
    t2.font,
    t2.price,
    t2.file_size,
    t2.ischarge,
    t2.dlnum,
    t1.devid_applist,
    t1.device_name,
    t1.pay_ability
FROM
(
    SELECT
        device_id,
        devid_applist,
        device_name,
        pay_ability
    FROM
        dw_rcm_hitop_userapps_dm
) t1
RIGHT OUTER JOIN
(
    SELECT
        device_id,
        label,
        hitop_id,
        screen,
        ch_name,
        author,
        sversion,
        IF (mnc IN ('00','01','02','03','04','05','06','07'), mnc,'x')      AS   mnc,
        interface,
        designer,
        is_safe,
        IF (icon_count <= 5,icon_count,6)                                   AS   icon_count,
        update_time,
        stars,
        IF ( comment_num IS NULL,0,
        IF ( comment_num <= 10,comment_num,11))                             AS   comment_num,
        font,
        price,
        IF (file_size <= 2*1024*1024,2,
        IF (file_size <= 4*1024*1024,4,
        IF (file_size <= 6*1024*1024,6,
        IF (file_size <= 8*1024*1024,8,
        IF (file_size <= 10*1024*1024,10,
        IF (file_size <= 12*1024*1024,12,
        IF (file_size <= 14*1024*1024,14,
        IF (file_size <= 16*1024*1024,16,
        IF (file_size <= 18*1024*1024,18,
        IF (file_size <= 20*1024*1024,20,21))))))))))    AS    file_size,
        ischarge,
        IF (dlnum IS NULL,0,
        IF (dlnum <= 50,50,
        IF (dlnum <= 100,100,
        IF (dlnum <= 500,500,
        IF (dlnum <= 1000,1000,
        IF (dlnum <= 5000,5000,
        IF (dlnum <= 10000,10000,
        IF (dlnum <= 20000,20000,20001))))))))          AS      dlnum
    FROM
        dw_rcm_hitop_sample2learn_dm
) t2
ON (t1.device_id = t2.device_id);

選擇右外關聯的原因是因為以使用者行為為基準。

這張表得到的資料就是關聯特徵中的資料,截圖如下:


然後再利用python指令碼處理格式
這裡要先講python指令碼載入到hive中
ADD FILE /opt/sxt/recommender/script/dw_rcm_hitop_prepare2train_dm.py;
可以通過list files;檢視是不是python檔案載入到了hive

在hive中使用python指令碼處理資料的原理:
Hive會以輸出流的形式將資料交給python指令碼,python指令碼以輸入流的形式來接受資料,接受來資料以後,在python中就行一系列的資料處理,處理完畢後,又以輸出流的形式交給Hive,交給了hive就說明了就處理後的資料成功儲存到hive表中了。

INSERT OVERWRITE TABLE dw_rcm_hitop_prepare2train_dm
SELECT
TRANSFORM (t.*)
USING 'python dw_rcm_hitop_prepare2train_dm.py'
AS (label,features)
FROM
(
    SELECT 
        label,
        hitop_id,
        screen,
        ch_name,
        author,
        sversion,
        mnc,
        interface,
        designer,
        icon_count,
        update_date,
        stars,
        comment_num,
        font,
        price,
        file_size,
        ischarge,
        dlnum,
        idlist,
        device_name,
        pay_ability
    FROM 
        tmp_dw_rcm_hitop_prepare2train_dm
) t;

 python處理流程:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# ----------------------------------------------------------------------------
#  File Name: dw_rcm_hitop_prepare2train_dm.py
#  Copyright(C)Huawei Technologies Co.,Ltd.1998-2014.All rights reserved.
#  Describe: 
#  Input:  tmp_dw_rcm_hitop_prepare2train_dm
#  Output: dw_rcm_hitop_prepare2train_dm

import sys
import codecs
import random
import math
import time
import datetime

if __name__ == "__main__":
    random.seed(time.time())
    for l in sys.stdin:
        d = l.strip().split('\t')
        if len(d) != 21:
            continue

        # Extract data from the line
        label = d.pop(0)
        hitop_id = d.pop(0)
        screen = d.pop(0)
        ch_name = d.pop(0)
        author = d.pop(0)
        sversion = d.pop(0)
        mnc = d.pop(0)
        interface = d.pop(0)
        designer = d.pop(0)
        icon_count = d.pop(0)
        update_date = d.pop(0)
        stars = d.pop(0)
        comment_num = d.pop(0)
        font = d.pop(0)
        price = d.pop(0)
        file_size = d.pop(0)
        ischarge = d.pop(0)
        dlnum = d.pop(0)
        hitopids = d.pop(0)
        device_name = d.pop(0)
        pay_ability = d.pop(0)

        # Construct feature vector
        features = []
        features.append(("Item.id,%s" % hitop_id, 1))
        features.append(("Item.screen,%s" % screen, 1))
        features.append(("Item.name,%s" % ch_name, 1))
        features.append(("All,0",1))
        features.append(("Item.author,%s" % author, 1))
        features.append(("Item.sversion,%s" % sversion, 1))
        features.append(("Item.network,%s" % mnc, 1))
        features.append(("Item.dgner,%s" % designer, 1))
        features.append(("Item.icount,%s" % icon_count, 1))
        features.append(("Item.stars,%s" % stars, 1))
        features.append(("Item.comNum,%s" % comment_num,1))
        features.append(("Item.font,%s" % font,1))
        features.append(("Item.price,%s" % price,1))
        features.append(("Item.fsize,%s" % file_size,1))
        features.append(("Item.ischarge,%s" % ischarge,1))
        features.append(("Item.downNum,%s" % dlnum,1))

        ####User.Item and User.Item*Item
        idlist = hitopids[:-2].split(',')
        idCT = 0;
        for id in idlist:
            features.append(("User.Item*Item,%s" % id +'*'+hitop_id, 1))
            idCT += 1
            if idCT >= 3: #取每一個使用者的前3個下載歷史進行關聯,因為使用者量比較多,所以這裡最後結果覆蓋還是比較全的。
                break;
        features.append(("User.phone*Item,%s" % device_name + '*' + hitop_id,1))#升維
        features.append(("User.pay*Item.price,%s" % pay_ability + '*' + price,1))

        # Output

        output = "%s\t%s" % (label, ",".join([ "%s:%d" % (f, v) for f, v in features ]))#這裡join相當於是把list中的資料進行拆分,然後新增上分號。
        print output

 

經過上述處理之後的資料如圖所示:

 

 特徵工程部分前期準別結束。

相關文章