赛题介绍
根据用户信息与活动(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]