【推荐算法 学习与复现】-- 逻辑回归算法族 -- LR

        协同过滤仅仅使用有限的用户行为信息,逻辑回归算法模型大多引入用户行为、用户特征、物品特征和上下文特征等,从CF逐步过渡到综合不同特征的机器学习模型。

(1)逻辑回归模型

        将用户特征(年龄、性别等)、用户行为(收藏、浏览等)、物品特征(属性、描述等)和上下文特征(当前时间、地点等)转化成数值型特征向量;以点击率为优化目标;利用已有数据进行训练学习模型参数;利用学习完成的模型进行推理预测用户点击率。

y=sigmoid(x^Tw)

代码编写原理参考大多参照《深度学习推荐系统》书籍内容,原理见后面附录。

(2)POLY2模型--特征交叉的开始

        防止“辛普森悖论”(数据在分组研究与总体研究时产生的结论可能是相悖的),改造逻辑回归模型,使其具备特征交叉能力。但是人工难以设计最优特征组合,POLY2采用暴力组合方式。

POLY(w,x)=w_0+\sum_{i=1}^nw_ix_i+\sum_{j_1=1}^{n-1}\sum_{j_2=j_1+1}^nw_{h(j_1,j_2)}x_{j_1}x_{j_2}

但是无差别的特征交叉使得原本稀疏的特征变得更加稀疏,权重参数量级也由 n 上升到 n^2

(3)FM模型 -- 隐向量特征交叉

        将交叉特征权重换成隐向量内积形式,减少参数稀疏性和计算复杂度

POLY(w,x)=w_0+\sum_{i=1}^nw_ix_i+\sum_{j_1=1}^{n-1}\sum_{j_2=j_1+1}^n(w_{j_1}w_{j_2})x_{j_1}x_{j_2}

(4) FFM模型 -- 引入特征域的概念

FFF在模型训练过程中,需要学习 n 个特征在 f 个域上的 k 维隐向量,使每个特征在与不同域的特征交叉时采用不同的隐向量

POLY(w,x)=\sum_{j_1=1}^{n-1}\sum_{j_2=j_1+1}^n(w_{j_1,f_2}*w_{j_2,f_1})x_{j_1}x_{j_2}

(5) GBDT+LR -- 特征工程模型化的开端

        LR模型将推荐问题转换为CTR预测分类问题,但是特征工程构建复杂,特征交叉方式也仅能做到二阶(提高交叉维度会产生组合爆炸问题);GBDT进行特征筛选与组合,生成新的离散特征向量;将生成特征作为LR模型输入特征。

  • 引入GBDT,但是树模型不适应高维离散特征
    • 树模型的正则项一般为深度和叶子节点数
    • LR模型对参数W进行正则化,约束了w不可能过大,即不会聚焦个别特征
    • 针对高位离散特征,树模型很有可能根据训练集某些个别特征巧合的实现数据划分

代码复现:

import numpy as np
import pandas as pd
from tqdm import tqdm
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
from sklearn.metrics import roc_auc_score
from matplotlib import pyplot as plt
from sklearn.datasets import make_classification


class LogisticRegresion:
    def __init__(self, N):
        
        self.theta = np.zeros((1, N))
        self.N = N

    def __gradient(self, X, y):
        grad = np.zeros(self.theta.shape)
        error = (self.forward(X).ravel() - y)
        for j in range(self.N):
            grad[0, j] = np.sum(np.multiply(error, X[:, j])) / len(X)
        return grad

    def __Jw(self, X, y):
        """这个是极大似然估计的目标函数,计算上就是求其最大值~~~
            但是编程中并不是直接求解,而是利用SGD对齐偏导方向做下降
        """
        part1 = np.multiply(y, np.log(self.forward(X)))
        part2 = np.multiply(1 - y, np.log(1 - self.forward(X)))
        return - np.sum(part1 + part2) / len(X)
    
    def cross_entropy_loss(self, y, y_):
        return -np.sum(y * np.log(y_) + (1 - y) * np.log(1 - y_))

    def __sigmoid(self, y):
        return 1 / (1 + np.exp(-y))

    def train(self, data, label, bath_size, alpha, epochs, loss_thresh=0.001):

        for epoch in tqdm(range(epochs)):
            for bs in range(len(data) // bath_size - 1):
                X = data[bs*bath_size : (bs+1)*bath_size]
                y = label[bs*bath_size : (bs+1)*bath_size]

                grad = self.__gradient(X, y)
                self.theta -= alpha*grad
            
            # print(self.cross_entropy_loss(label, self.forward(data)))

            # 提前终止训练,事实上数据是整体做的交叉熵并求和,loss很难特别小
            if self.cross_entropy_loss(label, self.forward(data)) < loss_thresh:
                break
        
    def forward(self, X):
        return np.squeeze(self.__sigmoid(np.dot(X, self.theta.T)))

    def predict(self, X):
        return [1 if x >= 0.5 else 0 for x in self.forward(X)]


X, y = make_classification(n_samples=1000, n_features=20, n_clusters_per_class=1)
data = [ {v: k for k, v in dict(zip(i, range(len(i)))).items()}  for i in X]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)


def eval_model(y_pred, y_true):
    print(f"accuracy_score = {accuracy_score(y_true, y_pred)}")
    print(f"precision_score = {precision_score(y_true, y_pred)}")
    print(f"recall_score = {recall_score(y_true, y_pred)}")
    print(f"f1_score = {f1_score(y_true, y_pred)}")
    print(f"auc = {roc_auc_score(y_true, y_pred)}")


lr_model = LogisticRegresion(N=20)
lr_model.train(X_train, y_train, 100, 0.001, 50000)
eval_model(lr_model.predict(X_test), y_test)

# 与sklearn库中的 LogisticRegression 对比
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(solver="liblinear")
lr.fit(X_train, y_train)
y_predict_lr = lr.predict(X_test)
eval_model(y_predict_lr, y_test)

红框是自己编写的结果,蓝框是sklearn自带库,相比下,效果还不错~

附录

参考:

1. 《深度学习推荐系统》

2. https://datawhalechina.github.io/fun-rec/

3. 逻辑回归及python代码实现_zacharyzlj的博客-CSDN博客_逻辑回归python代码

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值