Project 4:用户画像的建立

用户画像

目标:通过用户给商品的打标签记录,建立用户画像(显示打标签、亦可为隐式评分:点击率等)

# 使用SimpleTagBased、NormTagBased、TagBased-TFIDF算法对Delicious2K数据进行推荐
# 原始数据集:https://grouplens.org/datasets/hetrec-2011/
# 数据格式:userID     bookmarkID     tagID     timestamp

用户画像的准则

  1. 统一标识: 用户唯一标识是整个用户画像的核心
  2. 给用户打标签:用户标签的4个维度
  3. 基于标签指导业务(标签赋能):业务赋能的3个阶段

用户标签的建立

一、数据初步分析层(一级标签):

首先,需要将用户的数据进行分类,打上一级标签,这涉及到四个维度:
八字原则:用户消费行为分析

  1. 用户标签:性别、年龄、地域、收入、学历、职业等
  2. 消费标签:消费习惯、购买意向、是否对促销敏感
  3. 行为标签:时间段、频次、时长、收藏、点击、喜欢、评分
    (User Behavior可以分成Explicit Behavior显式行为和Implicit Behavior隐式行为)
  4. 内容分析:对用户平时浏览的内容进行分析,比如体育、游戏、八卦
二、算法层(二级标签):

在初步分析基础上,对用户进行聚类分析、标签算法、关联算法的分析,为用户打上二级标签:
用户画像建立、Item特性、产品购买偏好、用户关联关系、热门商品、热门话题支付行为偏好、优惠偏好

三、预测算法层(三级标签):

基于上述两层标签的预测标签:如购买某项产品的预测,用户流失预测等。

标签赋能

为用户建立用户画像后,标签的赋能(对业务的指导)分为用户生命周期(LTV)的三个阶段:获客、粘客、留客。

  1. 获客:如何进行拉新,通过更精准的营销获取客户。 由于前期获客阶段用户的标签不够充分,因此分为两个维度: 用户维度(User)与商品维度(Item)。

1 .商品维度:对本产品中的热门商品(已完善的商品体系)、特色商品(新开发的商品体系)进行广告推荐;
基于商品特色,针对性的向潜在用户群体投放广告,将用户的广告点击行为打上新的标签。
2.用户维度:基于用户已有的标签,推荐相应适合的商品,并根据其点击行为等更新其标签。

  1. 粘客:个性化推荐,搜索排序,场景运营等。对于使用中的客户,拥有充分的标签,因此需要对其进行更加个性化的推荐。以保证其对本商品的粘性。这其中涉及到 协同过滤以及推荐系统的EE问题
  1. 协同过滤算法:通过将与此人相似人群喜欢的事物,对此人进行推荐,实现推荐算法。
  2. EE问题(Explore and Exploit):充分利用已有资源的前提下,针对产品的用户人群推送其他新的未购买过的商品(关联算法),以产生新鲜感。
  1. 留客: 流失率预测,分析关键节点降低流失率。

SimpleTagBased算法

  1. 统计每个用户的常用标签
  2. 对每个标签,统计被打过这个标签次数最多的商品 ( i t e m − t a g s [ t , i ] ) (item-tags[t,i]) (itemtags[t,i])
  3. 对于一个用户,找到他常用的标签,然后找到具有这些标签的最热门物品推荐给他
  4. 用户 u u u 对 商品 i i i 的兴趣得分为:
    S c o r e ( u , i ) = ∑ t u s e r − t a g s [ u , t ] ⋅ i t e m − t a g s [ t , i ] Score(u, i) = \sum_t{user-tags[u,t] \cdot item-tags[t,i]} Score(u,i)=tusertags[u,t]itemtags[t,i]
    ( u s e r − t a g s [ u , t ] ) (user-tags[u,t]) (usertags[u,t]) 用户 u u u 使用过标签 t t t 的次数
    i t e m − t a g s [ t , i ] item-tags[t,i] itemtags[t,i]商品 i i i 被打上标签 t t t 的次数

数据结构定义:
用户打标签记录:records[i] = {user, item, tag}
用户 u 打过标签 t 的数量:user_tags[u][t]
用户 u 给商品 i 打过的标签数量:user_items[u][i]
打上 tag 标签的商品的数量:tag_items[t][i]
tag 标签使用过的用户数量:tag_users[t][u]

数据加载

import pandas as pd
import random 
from collections import defaultdict

#直接传入会出错
def defaultdict_list():
    return defaultdict(list)
#创建一个默认字典
records = defaultdict(defaultdict_list)

#加载数据
def load_data():
    #如何加载 dat 格式文件
    data = pd.read_csv('user_taggedbookmarks-timestamps.dat', sep = '\t')
    for i in range(data.shape[0]):
        records[data.iloc[i, 0]][data.iloc[i, 1]].append(data.iloc[i, 2])
    print('共加载{}条数据'.format(data.shape[0]))
    print('总计{}人'.format(len(records)))

%time load_data()

在这里插入图片描述

数据切分

由于random的生成是均匀分布,因此大样本情况下,满足均匀分布特性。

# 将数据集拆分为训练集和测试集
test_data = {}
train_data = {}

def train_test_split(ratio, seed=100):
    count = 0
    random.seed(seed)
    for u in records.keys():
        for i in records[u].keys():
            # ratio比例设置为测试集
            if random.random()<ratio:
                test_data.setdefault(u,{})
                test_data[u].setdefault(i,[])
                for t in records[u][i]:
                    test_data[u][i].append(t)
                    count += 1
            else:
                train_data.setdefault(u,{})
                train_data[u].setdefault(i,[])
                for t in records[u][i]:
                    train_data[u][i].append(t)  
                    
    print('切分比例:{}'.format(count / 437593))                
    print("训练集用户数 {}, 测试集用户数 {}" .format(len(train_data),len(test_data)))
    
train_test_split(0.2)

在这里插入图片描述

数据结构 “user_tags; user_items; tag_items; tag_users” 初始化

#初始化users-items;users-tags;items-tags矩阵
# 设置矩阵 mat[index, item] = 1
user_tags = {}
user_items = {}
tag_items = {}
tag_users = {}
def addValueToMat(mat, index, item, value=1):
    if index not in mat:
        mat.setdefault(index,{})
        mat[index].setdefault(item,value)
    else:
        if item not in mat[index]:
            mat[index][item] = value
        else:
            mat[index][item] += value

            
# 使用训练集,初始化user_tags, tag_items, user_items
def initStat():
    records=train_data
    for u,items in records.items():
        for i,tags in items.items():
            for tag in tags:
                #print tag
                # 用户和tag的关系
                addValueToMat(user_tags, u, tag, 1)
                # tag和item的关系
                addValueToMat(tag_items, tag, i, 1)
                # 用户和item的关系
                addValueToMat(user_items, u, i, 1)
                #标签和用户的关系
                addValueToMat(tag_users, tag, u, 1)
    print("user_tags, tag_items, user_items, tag_users初始化完成.")
    print("user_tags大小 %d, tag_items大小 %d, user_items大小 %d, tag_users大小 %d" % (len(user_tags), len(tag_items), len(user_items), len(tag_users)))

initStat()

基于SimpleTagBased算法的TOP-N推荐

import operator
# 对用户user推荐Top-N
def simple_recommend(user, N):
    recommend_items = dict()
    # 对Item进行打分,分数为所有的(用户对某标签使用的次数 wut, 乘以 商品被打上相同标签的次数 wti)之和
    tagged_items = user_items[user]
    for tag, wut in user_tags[user].items():
        #print(self.user_tags[user].items())
        for item, wti in tag_items[tag].items():
            #用户标记过的商品不需要再计算分数
            if item in tagged_items:
                continue
            #print('wut = %s, wti = %s' %(wut, wti))
            if item not in recommend_items:
                recommend_items[item] = wut * wti
            else:
                recommend_items[item] = recommend_items[item] + wut * wti
    return  sorted(recommend_items.items(), key = operator.itemgetter(1), reverse=True)[0:N]
# 使用测试集,计算准确率和召回率
def simple_precisionAndRecall(N):
    hit = 0
    h_recall = 0
    h_precision = 0
    for user,items in test_data.items():
        #没有标签的用户无法推荐
        if user not in train_data:
            continue
        # 获取Top-N推荐列表
        rank = simple_recommend(user, N)
#         print(rank)
        for item,rui in rank:
            if item in items:
                hit = hit + 1
        h_recall = h_recall + len(items)
        h_precision = h_precision + N
    #print('一共命中 %d 个, 一共推荐 %d 个, 用户设置tag总数 %d 个' %(hit, h_precision, h_recall))
    # 返回准确率 和 召回率
    return (hit/(h_precision*1.0)), (hit/(h_recall*1.0))

# 使用测试集,对推荐结果进行评估
def simple_testRecommend():
    print("推荐结果评估")
    print("%3s %10s %10s" % ('N',"精确率",'召回率'))
    for n in [5,10,20,40,60,80,100]:
        precision,recall = simple_precisionAndRecall(n)
        print("%3d %10.3f%% %10.3f%%" % (n, precision * 100, recall * 100))        

在这里插入图片描述

改进:基于NormTagBased算法与 TF-IDFBased算法 的TOP-N推荐

由于 SimpleTagBased 使用的方法

  1. 未考虑用户总的打标签总数量,无法看出对此标签的具体喜好程度
  2. 未考虑一个商品总的被打标签的数量,无法看出商品对此标签的适合程度

因此使用 NormTagsBased 做标准化处理:
S c o r e ( u , i ) = ∑ t u s e r − t a g s [ u , t ] ⋅ i t e m − t a g s [ t , i ] u s e r − t a g s [ u s e r ] ⋅ t a g − u s e r s [ t a g ] Score(u, i) =\sum_t \frac{user-tags[u,t] \cdot item-tags[t,i]}{user-tags[user] \cdot tag-users[tag]} Score(u,i)=tusertags[user]tagusers[tag]usertags[u,t]itemtags[t,i]
u s e r − t a g s [ u s e r ] user-tags[user] usertags[user] 表示一个用户使用的标签总类别数量;
t a g − u s e r s [ t a g ] tag-users[tag] tagusers[tag] 表示一个标签 tag 总的用户个数。

由于 u s e r − t a g s [ u , t ] user-tags[u,t] usertags[u,t] 表示一个用户使用某 tag 的数量,若该标签热门,那么可能使用的数量就会越多,因此借助TF-IDF的思想,使用:
l o g ( 1 + ( u s e r − t a g s [ u s e r ] ) ) log(1 + (user-tags[user])) log(1+(usertags[user])) 对公式进行处理。
S c o r e ( u , i ) = ∑ t u s e r − t a g s [ u , t ] ⋅ i t e m − t a g s [ t , i ] l o g ( 1 + ( u s e r − t a g s [ u s e r ] ) ) Score(u, i) =\sum_t \frac{user-tags[u,t] \cdot item-tags[t,i]}{log(1 + (user-tags[user]))} Score(u,i)=tlog(1+(usertags[user]))usertags[u,t]itemtags[t,i]

import operator
import numpy

#标准化:使用 user_tags[user],用户打过的标签类别 总数;
#tag_users[tag], 使用标签 tag 的用户个数:
#写在前面以减少运行时间
# user_tags_class_counts --->> utcc
utcc = dict()
for user in user_tags.keys():
    utcc[user] = len(user_tags[user])
# tag_users_class_counts --->> tucc
tucc = dict()
for tag in tag_users.keys():
    tucc[tag] = len(tag_users[tag])
    
# 对用户user推荐Top-N    
def improve_recommend(method, user, N):
    recommend_items = dict()
    # 对Item进行打分,分数为所有的(用户对某标签使用的次数 wut, 乘以 商品被打上相同标签的次数 wti)之和

    
    #该用户已打分的items
    tagged_items = user_items[user]
    
    for tag, wut in user_tags[user].items():
        #print(self.user_tags[user].items())
        
        for item, wti in tag_items[tag].items():
            #用户标记过的商品不需要进行推荐
            if item in tagged_items:
                continue
                
            #改进算子类型
            norm = utcc[user] * tucc[tag]
            tf_idf = numpy.log(1 + tucc[tag])
            
            way = 0
            if method == 'norm': way = norm
            if method == 'tf_idf': way = tf_idf
            
            #print('wut = %s, wti = %s' %(wut, wti))
            if item not in recommend_items:
                recommend_items[item] = wut * wti / way
            else:
                recommend_items[item] = recommend_items[item] + wut * wti / way
                
    return  sorted(recommend_items.items(), key = operator.itemgetter(1), reverse=True)[0:N]
# 使用测试集,计算准确率和召回率
def precisionAndRecall(method, N):
    hit = 0
    h_recall = 0
    h_precision = 0
    for user,items in test_data.items():
        #未训练过的用户无法进行推荐
        if user not in train_data:
            continue
        # 获取Top-N推荐列表
        rank = improve_recommend(method, user, N)
        for item,rui in rank:
            if item in items:
                hit = hit + 1
        h_recall = h_recall + len(items)
        h_precision = h_precision + N
    #print('一共命中 %d 个, 一共推荐 %d 个, 用户设置tag总数 %d 个' %(hit, h_precision, h_recall))
    # 返回准确率 和 召回率
    return (hit/(h_precision*1.0)), (hit/(h_recall*1.0))

# 使用测试集,对推荐结果进行评估
def testRecommend(method = str()):
    print("{}based 算子推荐结果评估:".format(method))
    print("%3s %10s %10s" % ('N',"精确率",'召回率'))
    for n in [5,10,20,40,60,80,100]:
        precision,recall = precisionAndRecall(method, n)
        print("%3d %10.3f%% %10.3f%%" % (n, precision * 100, recall * 100))  

在这里插入图片描述
通过对用户画像:user_tags; user_items 的建立,对用户进行个性化推荐。可以看到标准化后的结果有着显著的提高。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值