Kaggle Event Recommendation Engine Challenge活动推荐(协同过滤推荐系统)

赛题介绍

根据用户信息与活动(event)信息,预测用户将对哪些活动感兴趣。

数据集

共有六个文件:train.csv,test.csv, users.csv,user_friends.csv,events.csv和 event_attendees.csv。

train.csv 包含六列:

user:用户id
event:活动id
invite:是否被邀请
timestamp:时间戳
interested:
not_interested

test.csv 包含四列(与train的属性相同,但没有interested和not_interested)。

users.csv 包含七列

user_id:用户的ID
locale:用户区域
birthyear:用户出生的年份
gender:性别
joinedAt:首次使用APP的时间
location:用户位置
timezone:UTC偏移量

user_friends.csv包含有关此用户的社交数据,包含两列:user和friends。

user:用户的id,
friends:用户朋友ID(以空格分隔)。

events.csv 包含有关活动的数据,有110列。前九列是 event_id,user_id,start_time,city,state,zip,country, lat和lng

event_id:活动id
user_id:创建活动的用户的id
start_time:开始时间
city、state、zip、country:活动场地详细信息
lat和lng:经纬度
count_1, count_2,…, count_100 表示:统计了活动名称或描述中出现的100个最常见的词干,统计它们出现的频率(会把时态语态都去掉, 对词做了词频的排序(表示前N个最常出现的词,每个词在活动中出现的频次。)
count_other: count_other 是其余词的统计。

event_attendees.csv包含有关哪些用户参加了各种事件的信息,并包含以下列: event_id,yes,maybe,invite和no。

 event_id:活动id
 yes:会参加的用户
 maybe:可能参加的用户
 invite:邀请的用户
 no:不会参加的用户

所以,总的来说包括三类数据:

  • 用户信息
  • 用户社交信息
  • 活动本身信息

在做后续操作前,对于数据的探索是必须的,本文不再赘述。
基于上面的简单介绍,将每个文件导入了解其基本构造,加深对于数据的理解。这一步非常重要!!!`

简单思考:
1.训练集上维度很少,需要根据给的user及event等相关数据构建更多维度
2.协同过滤是基于user-event 历史交互数
3.需要把社交数据和event相关信息作为影响最后结果的因素纳入考量
4.视作分类模型,每一个人感兴趣/不感兴趣是target,其他影响结果的是feature.
5.影响结果的feature包括由协同过滤产出的推荐度

初步思路简图:
在这里插入图片描述
由于整体数据量比较大,而且需要根据user和event数据构建新的训练特征。故下面分几步来操作,中间会逐步处理一些数据并保存,待需要时再提取。

共分以下几步:
1.处理user和event,并根据训练数据来构建协同过滤评分体系
2.根据user数据提取用户相似度
3.根据用户社交数据提取构建相关特征
4.构建event相似度数据
5.event本身的热度
6.根据上面构建的数据,结合训练及测试数据。提取相关特征,构成最终要用的训练集和测试集
7.对上一步的训练集构建模型

一 处理user和event基础数据

#导入需要用到的库,后续每一步如果分别做的话,都要导入这些库。
#本文后续不重复导入。
import numpy as np
import pandas as pd
import datetime
import itertools
import hashlib
import _pickle
import scipy.io as sio
import scipy.sparse as ss
import scipy.spatial.distance as ssd
import matplotlib.pyplot as plt
import seaborn as sns
from collections import defaultdict
from sklearn.preprocessing import normalize
#导入训练数据及测试数据
train=pd.read_csv(r'E:\python\all\first\train.csv')
test=pd.read_csv(r'E:\python\all\first\test.csv')
#合并train和test中user和event以利于提取不重复值
data=pd.concat([train[['user','event']],test[['user','event']]],axis=0)
#提取train和test中user和event不重复的集合
uniqueUsers=set(data['user'])
uniqueEvents=set(data['event'])
#构建user-events及event-users集合
data=data.reset_index(drop=True)

eventsForUser=defaultdict(set)
usersForEvent=defaultdict(set)
for i in range(len(data)):
    eventsForUser[data['user'][i]].add(data['event'][i])
    usersForEvent[data['event'][i]].add(data['user'][i])
#构建user-index和event-index集合    
userIndex=dict()
eventIndex=dict()
for i,u in enumerate(uniqueUsers):
    userIndex[u]=i
for i,e in enumerate(uniqueEvents):
    eventIndex[e]=i
#构建user-event评分矩阵,评分取值(-1/0/1)    
userEventScores=ss.dok_matrix((len(uniqueUsers),len(uniqueEvents)))
for index in range(len(train)):
    i=userIndex[train['user'][index]]
    j=eventIndex[train['event'][index]]
    userEventScores[i,j]=int(train['interested'][index])-int(train['not_interested'][index])
#保存user-event评分矩阵    
sio.mmwrite(r'E:\python\all\third\PE_userEventScores',userEventScores)
#提取user及event相关集合,两两配对
uniqueUserPairs=set()
uniqueEventPairs=set()
for event in uniqueEvents:
    users=usersForEvent[event]
    if len(users)>2:
        uniqueUserPairs.update(itertools.combinations(users,2))
for user in uniqueUsers:
    events=eventsForUser[user]
    if len(events)>2:
        uniqueEventPairs.update(itertools.combinations(events,2))
#保存相关文件        
_pickle.dump(userIndex,open(r'E:\python\all\third\PE_userIndex.pkl','wb'))
_pickle.dump(eventIndex,open(r'E:\python\all\third\PE_eventIndex.pkl','wb'))
_pickle.dump(uniqueUserPairs,open(r'E:\python\all\secend\PE_uniqueUserPairs.pkl','wb'))
_pickle.dump(uniqueEventPairs,open(r'E:\python\all\secend\PE_uniqueEventPairs.pkl','wb'))

上述代码统计了所有的train 和 test中所有的user和event,同时构建了user对event感兴趣程度的矩阵(数值为1 0 -1,类似于对活动的打分)

本步骤构建的一些集合及矩阵非常重要,一定要理解:

用户总数:3391
users总数:13418

uniqueUsers:集合,保存train.csv和test.csv中的所有user ID
uniqueEvents:集合,保存train.csv和test.csv中的所有event ID
userIndex:字典,每个用户有个Index
eventIndex:字典,每个event有个Index
eventsForUser:字典,key为每个用户,value为该用户对应的event集合
usersForEvent:字典,key为每个event,value为该event对应的user集合
userEventScores:稀疏矩阵,只保存了非0

二 构建用户相似度矩阵

#导入users数据
df_users=pd.read_csv(r'E:\python\all\first\users.csv')
#描述性特征
df_users.head()
df_users.info()
#用户矩阵预处理
#缺失值处理
df_users.isnull().sum()
#1.gender属性的处理(类别数据,none值作为一类)
df_users['gender']=df_users['gender'].fillna('NaN')
#数值编码(连续型的编码规则)
from sklearn.preprocessing import LabelEncoder
le=LabelEncoder()
df_users['gender']=le.fit_transform(df_users['gender'])
sns.countplot(df_users['gender'])
#2.joinedAt列处理(日期数据,用年和月拼接就够了)
def getJoinedYearMonth(dateString):
    try:
        dttm=datetime.datetime.strptime(dateString,'%Y-%m-%dT%H:%M:%S.%fZ')
        return int(''.join([str(dttm.year),str(dttm.month)]))
    except:
        return 0
df_users['joinedAt']=df_users['joinedAt'].map(getJoinedYearMonth)
#3.locale列处理(数值编码)
df_users['locale']=le.fit_transform(df_users['locale'])
#4.birthyear列处理:直接转换成数值
def getBirthYearInt(birthYear):
    try:
        return 0 if birthYear=='None' else int(birthYear)
    except:
        return 0
df_users['birthyear']=df_users['birthyear'].map(getBirthYearInt)
#5.timezone列处理
def getTimezoneInt(timezone):
    try:
        return int(timezone)
    except:
        return 0
df_users['timezone']=df_users['timezone'].map(getTimezoneInt)
#6.location列处理(填充nan并编码)
df_users['location']=df_users['location'].fillna('NaN')
df_users['location']=le.fit_transform(df_users['location'])
#处理完成
df_users.info()

##构建用户相似度矩阵
#导入所需数据(第一步生成的)
userIndex=_pickle.load(open(r'E:\python\all\third\PE_userIndex.pkl','rb'))
uniqueUserPairs=_pickle.load(open(r'E:\python\all\secend\PE_uniqueUserPairs.pkl','rb'))

nusers=len(userIndex.keys())
#构建用户特征矩阵
userMatrix=ss.dok_matrix((nusers,df_users.shape[1]-1))
colnames=df_users.columns
for j in range(len(df_users)):
    if df_users['user_id'][j] in userIndex.keys():
        i=userIndex[df_users['user_id'][j]]
        for m in range(1,len(colnames)):
            userMatrix[i,m-1]=df_users[colnames[m]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值