推荐系统

oleg---人工智能第五期

1 数据探索

  数据来源于kaggle竞赛:Event Reconmendation EngineChallenge

  根据过去用户对他们所看到的活动和他们在app里所点击的活动等,这些用户对活动反应的统计信息,来预测用户对某个活动是否感兴趣。

数据集信息:

train.csv :训练集,共6列,1.5w个样本,没有缺失值

user

event

invited

timestamp

interested

not_interested

用户ID

活动ID

是否被邀请

时间戳

是否感兴趣

是否不感兴趣

 

test.csv: 测试集,共4列,1w+个样本,没有缺失值

user

event

invited

timestamp

用户ID

活动ID

是否被邀请

时间戳

没有interested、not_interested列,其余与训练集相同

 

users.csv 用户数据集,共7维特征,3.8w条数据,有缺失值

user_id

locale

birthyear

gender

joinedAt

location

timezone

用户ID

地区

出生年

性别

加入app时间

地点

时区

 

events.csv 活动数据集,共110维特征(后101列为词频),300w+条数据,有缺失值

event_id

user_id

start_time

city

state

zip

country

lat

lng

c_i

活动ID

用户ID

开始时间

城市

邮编

国家

纬度

经度

词频

后101列中,前100列为最常用的100个词,最后一列count_other为除了这100个词之外其余词出现的次数

 

event_attendees.csv ,活动数据集,共5维特征,2.4w条数据,缺失值很多

event

yes

maybe

invited

no

活动ID

参加的用户

可能参加的用户

被邀请的用户

不参加的用户

 

user_friends.csv,用户社交数据集,共2列,3.8w条数据,有缺失值

user

friends

用户ID

好友ID

 

2 数据预处理

  整个数据集中活动数目太多,我们只找出训练集和测试集中出现的活动和用户数据,得到新的活动和用户数据集

活动数据处理

(1)     从train.csv和test.csv中得到训练集和测试集中出现的活动event_id。

(2)     然后根据event_id,与events.csv数据集融合,得到出现的活动信息,保存为event_cur.csv

 

用户数据处理

(1)     从train.csv和test.csv中得到训练集和测试集中出现的用户user_id。

(2)     然后根据user_id,与user.csv数据集融合,得到参加了活动的用户信息,保存为user_cur.csv

最后得到训练集和测试集中出现的用户有3391条数据、活动有13418条数据

 

建立用户和活动的关系矩阵

(1)     通过哈希表,得到用户ID索引和参加活动的活动ID索引

(2)     然后将用户ID添加到被用户参加的活动usersForEvent集合和活动ID添加到用户参加的活动eventsForUser集合中,并保存。

(3)     将用户是否对该活动感兴趣,根据索引值添加到用户活动得分表中,userEventScores中,并保存

 

建立用户、好友和活动的关系矩阵

我们找出关联用户和关联活动

关联用户:至少在同一个活动event上有行为的用户和好友,组成用户pair,unqiueUserPair

关联活动:至少有同一个用户user有行为的活动,组成活动pair,uniqueEventPair

(1)   对同一个活动,根据活动所对应的索引,找到usersForEvent中的用户users,如果users的长度大于2,则将用户ID添加到用户对中uniqueUserPairs中,并保存

(2)   对同一个用户,根据用户所对应的索引,找到eventsForUser中的活动events,如果events的长度大于2,则将活动ID添加到活动对中uniqueEventPairs中,并保存

 

3 数据分析处理

 活动数据分析

只选择训练集和测试集中出现的活动数据,计算活动之间的 

(1)     对于非词频特征,采用person相关系数作为相似度

(2)     对于词频特征,采用余弦相似度,计算出相似度

 

用户数据处理

只选择训练集和测试集中出现的用户数据,计算用户之间的相似度

采用person相关系数作为相似度

4 基于用户社交数据的分析

只选择训练集和测试集中出现的用户数据,根据朋友对活动的打分,计算该用户和朋友之间的一个分数

(1)     读取用户社交数据,对于用户的每个朋友,查看是否在训练集或者测试集中出现过,如果出现过,则找出该朋友对活动的评分。

(2)     读取用户-活动分数矩阵,根据每个朋友参加的所有活动的评分,计算出平均值,即为该用户和朋友之间的一个分数,也为该朋友和用户之间的一个分数

 

5 活动热度数据处理

读取活动参加者数据,根据参加和不参加的人数,计算活动的热度,作为后续模型的输入特征

 

6 推荐系统

将所有特征串联起来,为推荐系统做准备

(1)     读入数据,并初始化

#用户和活动的索引

#用户-活动的关系矩阵R

#每个用户参加的事件,事件参加的用户

#基于模型的协同过滤参数初始化,训练

self.init_SVD()

self.train_SVD(trainfile=’train.csv’)

#根据用户属性计算出的用户之间的相似度

#根据活动属性计算出的活动之间的相似度

#每个用户朋友的数目

#用户的每个朋友参加活动的分数对该用户的影响

#活动本身的热度

(2)     定义相关函数

#初始化模型参数

初始化模型参数K bi bu PQ

训练模型

def train_SVD(self, trainfile=r'C:/Users/oleg/Desktop/机器学习/第四周作业/train.csv', steps=100, gamma=0.04, Lambda=0.15):
        # 训练SVD模型(for 基于模型的协同过滤SVD_CF)
        # gamma:为学习率
        # Lambda:正则参数


        # 偷懒了,为了和原来的代码的输入接口一样,直接从训练文件中去读取数据
        print( "SVD Train...")


        ftrain = open(trainfile, 'r')
        ftrain.readline()
        self.mu = 0.0
        n_records = 0
        uids = []  # 每条记录的用户索引
        i_ids = []  # 每条记录的item索引
        # 用户-Item关系矩阵R(内容同userEventScores相同),临时变量,训练完了R不再需要
        R = np.zeros((self.n_users, self.n_items))


        for line in ftrain:
            cols = line.strip().split(",")
            #得到用户的索引
            u = self.userIndex[cols[0]]  # 用户
            #得到活动的索引
            i = self.eventIndex[cols[1]]  # 活动
            uids.append(u)
            i_ids.append(i)
            #得到用户对活动的评分,建立评分矩阵
            R[u, i] = int(cols[4])  # interested
            self.mu += R[u, i]
            n_records += 1


        ftrain.close()
        self.mu /= n_records
        #优化模型
        ftrain = open(trainfile, 'r')
        ftrain.readline()
        loss=0.0
        for step in range(steps):
                #梯度下降算法,每次迭代更新四个参数:bi,bu,P,Q
                #更新学习率
                #if steps>=100
                #gamma=gamma*0.95
            for line in ftrain:
                cols = line.strip().split(",")
                #根据用户,得到用户的索引
                u = self.userIndex[cols[0]]  # 用户
                i = self.eventIndex[cols[1]]  # 活动
                #得到用户对活动的打分
                R[u, i] = int(cols[4])
                #迭代次数steps=100
                #对于每个用户的活动训练对应行列上Q和P的值,对于每一个用户训练一个bu,对于每一个活动训练一个bi
                ans = self.mu + self.bi[i] + self.bu[u] + np.dot(self.P[u, :], self.Q[:, i])
                self.bi = (1 - gamma * Lambda) * self.bi + gamma * (R[u, i] - ans)
                self.bu = (1 - gamma * Lambda) * self.bu + gamma * (R[u, i]- ans)
                self.P[u,:] = self.P[u,:] + gamma * (R[u,i] - ans) * self.Q[:,i]
                self.Q[:,i] = self.Q[:,i] + gamma * (R[u,i] - ans) * self.P[u,:]
                #真实值与预测值差的平方
                eui=R[u,i]-self.pred_SVD(u,i)
                loss=eui**2
            #每10步打印一次loss
            if step+1%10==0:
                print('step {0}/100 loss:{1:.4f}'.format(step,loss))
        #打印出最后一次的loss
        print('step {0}/100 loss:{1:.4f}'.format(step,loss))
        ftrain.close()
        print("SVD trained")

#基于模型的协同预测,预测用户对活动的打分

 

def pred_SVD(self, uid, i_id):
        # 根据当前参数,预测用户uid对Item(i_id)的打分        
        ans = self.mu + self.bi[i_id] + self.bu[uid] + np.dot(self.P[uid, :], self.Q[:, i_id])


        # 将打分范围控制在0-1之间
        if ans > 1:
            return 1
        elif ans < 0:
            return 0
        return ans

#计算两个用户之间的相似度


    def sim_cal_UserCF(self, uid1, uid2):
        # 基于用户的协同过滤中的两个用户uid1和uid2之间的相似度(根据两个用户对item打分的相似度)
        similarity = 0.0
        #统计共同出现的活动
        item_count=defaultdict(int)
        #计算用户的打分
        score_1 = []
        score_2 = []
        #对于用户1中出现的活动
        for item in self.itemsForUser[uid1]:
            score_1.append(self.userEventScores[uid1, item])
            #统计共同出现的活动
            if item in self.itemsForUser[uid2]:
                item_count[item]=1#1值没有任何实际意义
        for item in self.itemsForUser[uid2]:
            score_2.append(self.userEventScores[uid2, item])
        #计算用户的平均打分
        avg_1=np.sum(score_1)/len(self.itemsForUser[uid1])
        avg_2 = np.sum(score_2)/ len(self.itemsForUser[uid2])
        #根据公式,计算相似度
        #公式中的分母项,初始化
        score_item_1=0
        score_item_2 = 0
        #公式中的分子项,初始化
        score_12=0
        for item in item_count:
            #分子
            score_12+=(self.userEventScores[uid1,item]-avg_1)*(self.userEventScores[uid2, item]-avg_2)
            #分母各项
            score_item_1+=(self.userEventScores[uid1,item]-avg_1)**2
            score_item_2 += (self.userEventScores[uid2, item] - avg_2) ** 2


        if len(item_count)==0:
            return 0
        #根据公式计算pearson相关系数
        similarity=score_12/((score_item_1*score_item_2)**0.5)




        return similarity

#基于用户的协同推荐


    def userCFReco(self, userId, eventId):
        """
        根据User-based协同过滤,得到event的推荐度
        基本的伪代码思路如下:
        for item i
          for every other user v that has a preference for i
            compute similarity s between u and v
            incorporate v's preference for i weighted by s into running aversge
        return top items ranked by weighted average
        """
        ans = 0.0
        #公式中的分母项
        sim_sum=0.0
        #公式中的分子项
        sim_weight_sum=0.0
        #得到活动的索引
        e=self.eventIndex[eventId]
        #得到用户的索引
        u=self.userIndex[userId]
        #根据活动得到所用参加过该活动的用户索引
        users=self.usersForItem[e]
        for user in users:
            #计算参加过该活动用户与user的相似度
            sim=self.sim_cal_UserCF(user,u)
            score=self.userEventScores[user,e]
            sim_weight_sum+=sim*score
            sim_sum+=sim
        #如果没有相似的用户参加过该活动,则打分为0,表示未知
        if sim_sum==0:
            return 0
        ans=sim_weight_sum/sim_sum


        return ans

#计算活动之间的相似度

 # 计算Item i_id1和i_id2之间的相似性
        similarity = 0.0
        user_count = defaultdict(int)
        # 根据公式,计算用户的打分
        #建立score矩阵,记录用户的平均打分
        score=[]
        #分子项
        score_12=0.0
        #分母项
        score_item_1 = 0
        score_item_2 = 0
        avg = defaultdict()
        # 统计共同出现的用户
        #对于活动i_id1中出现的所有用户进行统计
        for user in self.usersForItem[i_id1]:
            if user in self.usersForItem[i_id2]:
                user_count[user] = 1#1值随便取的,没有任何意义
        #对于共同出现过的用户
        for user in user_count:
            #通过用户索引,找到活动索引
            for item in self.itemsForUser[user]:
                #计算每个用户的平均打分
                 score.append(self.userEventScores[user, item])
            avg[user]=np.sum(score)/len(self.itemsForUser[user])
            #分子
            score_12+=(self.userEventScores[user,i_id1]-avg[user])*(self.userEventScores[user,i_id2]-avg[user])
             #分母
            score_item_1 += (self.userEventScores[user, i_id1] - avg[user]) ** 2
            score_item_2 += (self.userEventScores[user, i_id2] - avg[user]) ** 2

        #根据公式计算pearson相关系数
        #如果没有共同用户,则相似度为0
        if len(user_count) == 0:
            return 0
        similarity = score_12 / ((score_item_1 * score_item_2) ** 0.5)
        return similarity

#基于项目的协同推荐

 """
        根据基于物品的协同过滤,得到Event的推荐度
        基本的伪代码思路如下:
        for item i
            for every item j tht u has a preference for
                compute similarity s between i and j
                add u's preference for j weighted by s to a running average
        return top items, ranked by weighted average
        """
        ans = 0.0
        #分母项
        sim_sum = 0.0
        #分子项
        sim_weight_sum = 0.0
        #得到活动索引
        e = self.eventIndex[eventId]
        #得到用户索引
        u = self.userIndex[userId]
        #得到该用户参加过的所有活动的索引
        items = self.itemsForUser[u]
        #对于用户参加过的活动
        for item in items:
            sim = self.sim_cal_ItemCF(item, e)
            score = self.userEventScores[u, item]
            sim_weight_sum += sim * score
            sim_sum += sim
        if sim_sum == 0:
            return 0
        ans = sim_weight_sum / sim_sum

        return ans

 

你可能感兴趣的:(csdn)