文章推薦系統(tǒng) | 十一斤寇、基于 LR 模型的離線排序

推薦閱讀:
文章推薦系統(tǒng) | 一、推薦流程設(shè)計(jì)
文章推薦系統(tǒng) | 二乐横、同步業(yè)務(wù)數(shù)據(jù)
文章推薦系統(tǒng) | 三求橄、收集用戶行為數(shù)據(jù)
文章推薦系統(tǒng) | 四、構(gòu)建離線文章畫像
文章推薦系統(tǒng) | 五葡公、計(jì)算文章相似度
文章推薦系統(tǒng) | 六罐农、構(gòu)建離線用戶畫像
文章推薦系統(tǒng) | 七、構(gòu)建離線文章特征和用戶特征
文章推薦系統(tǒng) | 八催什、基于模型的離線召回
文章推薦系統(tǒng) | 九涵亏、基于內(nèi)容的離線及在線召回
文章推薦系統(tǒng) | 十、基于熱門文章和新文章的在線召回

前面蒲凶,我們已經(jīng)完成了召回階段的全部工作气筋,通過召回,我們可以從數(shù)百萬甚至上億的原始物品數(shù)據(jù)中旋圆,篩選出和用戶相關(guān)的幾百宠默、幾千個(gè)可能感興趣的物品。接下來灵巧,我們將要進(jìn)入到排序階段搀矫,對(duì)召回的幾百抹沪、幾千個(gè)物品進(jìn)行進(jìn)一步的篩選和排序。

排序流程包括離線排序和在線排序:

  • 離線排序
    讀取前天(第 T - 2 天)之前的用戶行為數(shù)據(jù)作為訓(xùn)練集艾君,對(duì)離線模型進(jìn)行訓(xùn)練采够;訓(xùn)練完成后,讀取昨天(第 T - 1 天)的用戶行為數(shù)據(jù)作為驗(yàn)證集進(jìn)行預(yù)測(cè)冰垄,根據(jù)預(yù)測(cè)結(jié)果對(duì)離線模型進(jìn)行評(píng)估蹬癌;若評(píng)估通過,當(dāng)天(第 T 天)即可將離線模型更新到定時(shí)任務(wù)中虹茶,定時(shí)執(zhí)行預(yù)測(cè)任務(wù)逝薪;明天(第 T + 1 天)就能根據(jù)今天的用戶行為數(shù)據(jù)來觀察更新后離線模型的預(yù)測(cè)效果。(注意:數(shù)據(jù)生產(chǎn)有一天時(shí)間差蝴罪,第 T 天生成第 T - 1 天的數(shù)據(jù))

  • 在線排序
    讀取前天(第 T - 2 天)之前的用戶行為數(shù)據(jù)作為訓(xùn)練集董济,對(duì)在線模型進(jìn)行訓(xùn)練;訓(xùn)練完成后要门,讀取昨天(第 T - 1 天)的用戶行為數(shù)據(jù)作為驗(yàn)證集進(jìn)行預(yù)測(cè)虏肾,根據(jù)預(yù)測(cè)結(jié)果對(duì)在線模型進(jìn)行評(píng)估;若評(píng)估通過欢搜,當(dāng)天(第 T 天)即可將在線模型更新到線上封豪,實(shí)時(shí)執(zhí)行排序任務(wù);明天(第 T + 1 天)就能根據(jù)今天的用戶行為數(shù)據(jù)來觀察更新后在線模型的預(yù)測(cè)效果炒瘟。

這里再補(bǔ)充一個(gè)數(shù)據(jù)集劃分的小技巧:可以橫向劃分吹埠,隨機(jī)或按用戶或其他樣本選擇策略;也可以縱向劃分疮装,按照時(shí)間跨度缘琅,比如一周的數(shù)據(jù)中,周一到周四是訓(xùn)練集廓推,周五周六是測(cè)試集刷袍,周日是驗(yàn)證集。

利用排序模型可以進(jìn)行評(píng)分預(yù)測(cè)和用戶行為預(yù)測(cè)樊展,通常推薦系統(tǒng)利用排序模型進(jìn)行用戶行為預(yù)測(cè)做个,比如點(diǎn)擊率(CTR)預(yù)估,進(jìn)而根據(jù)點(diǎn)擊率對(duì)物品進(jìn)行排序滚局,目前工業(yè)界常用的點(diǎn)擊率預(yù)估模型有如下 3 種類型:

  • 寬模型 + 特征?程
    LR / MLR + 非 ID 類特征(??離散 / GBDT / FM)居暖,可以使用 Spark 進(jìn)行訓(xùn)練
  • 寬模型 + 深模型
    Wide&Deep,DeepFM藤肢,可以使用 TensorFlow 進(jìn)行訓(xùn)練
  • 深模型:
    DNN + 特征 Embedding太闺,可以使用 TensorFlow 進(jìn)行訓(xùn)練

這里的寬模型即指線性模型,線性模型的優(yōu)點(diǎn)包括:

  • 相對(duì)簡(jiǎn)單嘁圈,訓(xùn)練和預(yù)測(cè)的計(jì)算復(fù)雜度都相對(duì)較低
  • 可以集中精力發(fā)掘新的有效特征省骂,且可以并行化工作
  • 解釋性較好蟀淮,可以根據(jù)特征權(quán)重做解釋

本文我們將采用邏輯回歸作為離線模型,進(jìn)行點(diǎn)擊率預(yù)估钞澳。邏輯回歸(Logistic Regression怠惶,LR)是基礎(chǔ)的二分類模型,也是監(jiān)督學(xué)習(xí)的一種轧粟,通過對(duì)有標(biāo)簽的訓(xùn)練集數(shù)據(jù)進(jìn)行特征學(xué)習(xí)策治,進(jìn)而可以對(duì)測(cè)試集(新數(shù)據(jù))的標(biāo)簽進(jìn)行預(yù)測(cè)。我們這里的標(biāo)簽就是指用戶是否對(duì)文章發(fā)生了點(diǎn)擊行為兰吟。

構(gòu)造訓(xùn)練集

讀取用戶歷史行為數(shù)據(jù)通惫,將 clicked 作為訓(xùn)練集標(biāo)簽

spark.sql("use profile")
user_article_basic = spark.sql("select * from user_article_basic").select(['user_id', 'article_id', 'clicked'])

user_article_basic 結(jié)果如下所示

之前我們已經(jīng)計(jì)算好了文章特征和用戶特征,并存儲(chǔ)到了 Hbase 中混蔼。這里我們遍歷用戶歷史行為數(shù)據(jù)履腋,根據(jù)其中文章 ID 和用戶 ID 分別獲取文章特征和用戶特征,再將標(biāo)簽轉(zhuǎn)為 int 類型惭嚣,這樣就將一條用戶行為數(shù)據(jù)構(gòu)造成為了一個(gè)樣本遵湖,再將所有樣本加入到訓(xùn)練集中

train = []
for user_id, article_id, clicked in user_article_basic:
    try:
        article_feature = eval(hbu.get_table_row('ctr_feature_article', '{}'.format(article_id).encode(), 'article:{}'.format(article_id).encode()))
    except Exception as e:
        article_feature = []
    try:
        user_feature = eval(hbu.get_table_row('ctr_feature_user', '{}'.format(temp.user_id).encode(), 'channel:{}'.format(temp.channel_id).encode()))
    except Exception as e:
        user_feature = []

    if not article_feature:
        article_feature = [0.0] * 111
    if not user_feature:
        user_feature = [0.0] * 10

    sample = []
    sample.append(user_feature)
    sample.append(article_feature)
    sample.append(int(clicked))

    train.append(sample)

接下來,還需要利用 Spark 的 Vectors 將 array<double> 類型的 article_feature 和 user_feature 轉(zhuǎn)為 vector 類型

columns = ['article_feature', 'user_feature', 'clicked']

def list_to_vector(row):
    from pyspark.ml.linalg import Vectors
    
    return Vectors.dense(row[0]), Vectors.dense(row[1]), row[2]

train = train.rdd.map(list_to_vector).toDF(columns) 

再將 article_feature, user_feature 合并為統(tǒng)一輸入到 LR 模型的特征列 features晚吞,這樣就完成訓(xùn)練集的構(gòu)建

train = VectorAssembler().setInputCols(columns[0:1]).setOutputCol('features').transform(train)

模型訓(xùn)練

Spark 已經(jīng)實(shí)現(xiàn)好了 LR 模型奄侠,通過指定訓(xùn)練集 train 的特征列 features 和標(biāo)簽列 clicked,即可對(duì) LR 模型進(jìn)行訓(xùn)練载矿,再將訓(xùn)練好的模型保存到 HDFS

from pyspark.ml.feature import VectorAssembler
from pyspark.ml.classification import LogisticRegression

lr = LogisticRegression()
model = lr.setLabelCol("clicked").setFeaturesCol("features").fit(train)
model.save("hdfs://hadoop-master:9000/headlines/models/lr.obj")

加載訓(xùn)練好的 LR 模型,調(diào)用 transform() 對(duì)訓(xùn)練集做出預(yù)測(cè)(實(shí)際場(chǎng)景應(yīng)該對(duì)驗(yàn)證集和訓(xùn)練集進(jìn)行預(yù)測(cè))

from pyspark.ml.classification import LogisticRegressionModel

online_model = LogisticRegressionModel.load("hdfs://hadoop-master:9000/headlines/models/lr.obj")
sort_res = online_model.transform(train)

預(yù)測(cè)結(jié)果 sort_res 中包括 clicked 和 probability 列烹卒,其中 clicked 為樣本標(biāo)簽的真實(shí)值闷盔,probability 是包含兩個(gè)元素的列表,第一個(gè)元素是預(yù)測(cè)的不點(diǎn)擊概率旅急,第二個(gè)元素則是預(yù)測(cè)的點(diǎn)擊概率逢勾,可以提取點(diǎn)擊率(CTR)

def get_ctr(row):
    return float(row.clicked), float(row.probability[1]) 

score_label = sort_res.select(["clicked", "probability"]).rdd.map(get_ctr)

模型評(píng)估

離線模型評(píng)估指標(biāo)包括:

  • 評(píng)分準(zhǔn)確度
    通常是均方根誤差(RMSE),用來評(píng)估預(yù)測(cè)評(píng)分的效果
  • 排序能力
    通常采用 AUC(Area Under the Curve)藐吮,即 ROC 曲線下方的面積
  • 分類準(zhǔn)確率(Precision)
    表示在 Top K 推薦列表中溺拱,用戶真實(shí)點(diǎn)擊的物品所占的比例
  • 分類召回率(Recall)
    表示在用戶真實(shí)點(diǎn)擊的物品中,出現(xiàn)在 Top K 推薦列表中所占的比例

當(dāng)模型更新后谣辞,還可以根據(jù)商業(yè)指標(biāo)進(jìn)行評(píng)估迫摔,比例類的包括: 點(diǎn)擊率(CTR)、轉(zhuǎn)化率(CVR)泥从,絕對(duì)類的包括:社交關(guān)系數(shù)量句占、用戶停留時(shí)長(zhǎng)、成交總額(GMV)等躯嫉。

推薦系統(tǒng)的廣度評(píng)估指標(biāo)包括:

  • 覆蓋率
    表示被有效推薦(推薦列表長(zhǎng)度大于 c)的用戶占全站用戶的比例纱烘,公式如下:
    Con_{UV}=\frac{N_{l >c}}{N_{UV}}
  • 失效率
    表示被無效推薦(推薦列表長(zhǎng)度為 0)的用戶占全站用戶的比例杨拐,公式如下:
    Lost_{UV}=\frac{N_{l =0}}{N_{UV}}
  • 新穎性
  • 更新率
    表示推薦列表的變化程度,當(dāng)前周期與上個(gè)周期相比擂啥,推薦列表中不同物品的比例
    Update=\frac{N_{diff}}{N_{last}}

推薦系統(tǒng)的健康評(píng)估指標(biāo)包括:

  • 個(gè)性化
    用于衡量推薦的個(gè)性化程度哄陶,是否大部分用戶只消費(fèi)小部分物品,可以計(jì)算所有用戶推薦列表的平均相似度
  • 基尼系數(shù)
    用于衡量推薦系統(tǒng)的馬太效應(yīng)哺壶,反向衡量推薦的個(gè)性化程度屋吨。將物品按照累計(jì)推薦次數(shù)排序,排序位置為 i变骡,推薦次數(shù)占總推薦次數(shù)的比例為 P_i离赫,推薦次數(shù)越不平均,基尼系數(shù)越接近 1塌碌,公式為:
    Gini=\frac{1}{n}\sum_{i=1}^n P_i(2i-n-i)
  • 多樣性
    通常是在類別維度上衡量推薦結(jié)果的多樣性渊胸,可以衡量各個(gè)類別在推薦時(shí)的熵
    Div=\frac{\sum_{i=1}^n-P_i\log(P_i)}{n\log(n)}
    其中,物品共包括 n 個(gè)類別台妆,類別 i 被推薦次數(shù)占總推薦次數(shù)的比例為 P_i翎猛,分母是各個(gè)類別最均勻時(shí)對(duì)應(yīng)的熵,分子是實(shí)際推薦結(jié)果的類別分布熵接剩。這是整體推薦的多樣性切厘,還可以計(jì)算每次推薦和每個(gè)用戶推薦的多樣性。

我們這里主要根據(jù) AUC 進(jìn)行評(píng)估懊缺,首先利用 model.summary.roc 繪制 ROC 曲線

import matplotlib.pyplot as plt

plt.figure(figsize=(5,5))
plt.plot([0, 1], [0, 1], 'r--')
plt.plot(model.summary.roc.select('FPR').collect(),
         model.summary.roc.select('TPR').collect())
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.show()

ROC 曲線如下所示疫稿,曲線下面的面積即為 AUC(Area Under the Curve),AUC 值越大鹃两,排序效果越好

利用 Spark 的 BinaryClassificationMetrics() 計(jì)算 AUC

from pyspark.mllib.evaluation import BinaryClassificationMetrics

metrics = BinaryClassificationMetrics(score_label)
metrics.areaUnderROC

也可以利用 sklearn 的 roc_auc_score() 計(jì)算 AUC遗座,accuracy_score() 計(jì)算準(zhǔn)確率

from sklearn.metrics import accuracy_score, roc_auc_score,
import numpy as np

arr = np.array(score_label.collect())
# AUC
roc_auc_score(arr[:, 0], arr[:, 1]) # 0.719274521004087

# 準(zhǔn)確率
accuracy_score(arr[:, 0], arr[:, 1].round()) # 0.9051438053097345

參考

https://www.bilibili.com/video/av68356229
https://book.douban.com/subject/34872145/
https://pan.baidu.com/s/1-uvGJ-mEskjhtaial0Xmgw(學(xué)習(xí)資源已保存至網(wǎng)盤, 提取碼:eakp)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末俊扳,一起剝皮案震驚了整個(gè)濱河市途蒋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌馋记,老刑警劉巖号坡,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異梯醒,居然都是意外死亡宽堆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門茸习,熙熙樓的掌柜王于貴愁眉苦臉地迎上來日麸,“玉大人,你說我怎么就攤上這事〈” “怎么了墩划?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嗡综。 經(jīng)常有香客問我乙帮,道長(zhǎng),這世上最難降的妖魔是什么极景? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任察净,我火速辦了婚禮,結(jié)果婚禮上盼樟,老公的妹妹穿的比我還像新娘氢卡。我一直安慰自己,他們只是感情好晨缴,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布译秦。 她就那樣靜靜地躺著,像睡著了一般击碗。 火紅的嫁衣襯著肌膚如雪筑悴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天稍途,我揣著相機(jī)與錄音阁吝,去河邊找鬼。 笑死械拍,一個(gè)胖子當(dāng)著我的面吹牛突勇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坷虑,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼甲馋,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了猖吴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤挥转,失蹤者是張志新(化名)和其女友劉穎海蔽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绑谣,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡党窜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了借宵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幌衣。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出豁护,到底是詐尸還是另有隱情哼凯,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布楚里,位于F島的核電站断部,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏班缎。R本人自食惡果不足惜蝴光,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望达址。 院中可真熱鬧蔑祟,春花似錦、人聲如沸沉唠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)右冻。三九已至装蓬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纱扭,已是汗流浹背牍帚。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乳蛾,地道東北人暗赶。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像肃叶,于是被迫代替她去往敵國(guó)和親蹂随。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容