一、请知晓

 本文是基于:

  Event Recommendation Engine Challenge分步解析第一步

  Event Recommendation Engine Challenge分步解析第二步

  Event Recommendation Engine Challenge分步解析第三步

 需要读者先阅读前三篇文章解析

二、构建event和event相似度数据

 我们先看看events.csv.gz:

import pandas as pd
df_events_csv = pd.read_csv('events.csv.gz', compression='gzip')
df_events_csv.head()

 代码实例结果:

  文件记录了用户对某event的信息(c_100后面还有一列:c_101):

 我们来看看如何对上面表中的列信息进行数值转换

 1)start_time:参考Event Recommendation Engine Challenge分步解析第二步4)中的joinedAt列处理

 2)city,3)state,4)zip,5)country列处理都利用了hashlib包:注意这里处理event信息的时候,只有那些出现在train.csv和test.csv中的event才会进入数值转换程序

import hashlib
def FeatureHash(value):
if len(value.strip()) == 0:
return -1
else:
return int( hashlib.sha224(value.encode('utf-8')).hexdigest()[0:4] ,16) print(FeatureHash('Muaraenim'))#47294
print(FeatureHash('a test demo'))#4030

  所以,我们在对NA值进行填充或者多种字符串进行数值转换的时候,使用hashlib也是一个不错的选择

 6),lat和7)lon列处理:

def getFloatValue(self, value):
if len(value.strip()) == 0:
return 0.0
else:
return float(value)

  空值用0.0填充,其他转换为自身的float

 8)c_1之后列(也就是第10列之后)处理:

  这里用了一个矩阵eventContMatrix来保存c_1到c_100列信息,但是没有用的c_other列,why?

 9)将eventPropMatrix和eventContMatrix矩阵归一化后进行文件保存

 10)根据第一步中的uniqueEventPairs来计算event pairs相似度

  利用了scipy.spatial.distancecorrelationcosine方法

 11)变量介绍

  nevents:events数目,即train.csvtest.csv总共多少个events,13418个

  self.eventPropMatrix:稀疏矩阵,shape为(13418,7),7代表events.csv.gz中的7列特征,最后进行了归一化

  self.eventContMatrix:稀疏矩阵,shape为(13418,100),100代表events.csv.gz文件中的c_1c_100特征,最后进行了归一化

  self.eventPropSim:由user-event行为计算出来的event pair相似度,需要用到第一步中的uniqueEventPairs

import pandas as pd
pd.DataFrame(eventPropSim)

  代码示例结果:

  self.eventContSim:由event本身的信息计算出的event pair相似度,需要用到第一步中的uniqueEventPairs

import pandas as pd
pd.DataFrame(eventContSim)

  代码示例结果:

 12)我们来看看第四步代码

from collections import defaultdict
import locale, pycountry
import scipy.sparse as ss
import scipy.io as sio
import itertools
#import cPickle
#From python3, cPickle has beed replaced by _pickle
import _pickle as cPickle import scipy.spatial.distance as ssd
import datetime
from sklearn.preprocessing import normalize import gzip
import numpy as np import hashlib #处理user和event关联数据
class ProgramEntities:
"""
我们只关心train和test中出现的user和event,因此重点处理这部分关联数据,
经过统计:train和test中总共3391个users和13418个events
"""
def __init__(self):
#统计训练集中有多少独立的用户的events
uniqueUsers = set()#uniqueUsers保存总共多少个用户:3391个
uniqueEvents = set()#uniqueEvents保存总共多少个events:13418个
eventsForUser = defaultdict(set)#字典eventsForUser保存了每个user:所对应的event
usersForEvent = defaultdict(set)#字典usersForEvent保存了每个event:哪些user点击
for filename in ['train.csv', 'test.csv']:
f = open(filename)
f.readline()#跳过第一行
for line in f:
cols = line.strip().split(',')
uniqueUsers.add( cols[0] )
uniqueEvents.add( cols[1] )
eventsForUser[cols[0]].add( cols[1] )
usersForEvent[cols[1]].add( cols[0] )
f.close() self.userEventScores = ss.dok_matrix( ( len(uniqueUsers), len(uniqueEvents) ) )
self.userIndex = dict()
self.eventIndex = dict()
for i, u in enumerate(uniqueUsers):
self.userIndex[u] = i
for i, e in enumerate(uniqueEvents):
self.eventIndex[e] = i ftrain = open('train.csv')
ftrain.readline()
for line in ftrain:
cols = line.strip().split(',')
i = self.userIndex[ cols[0] ]
j = self.eventIndex[ cols[1] ]
self.userEventScores[i, j] = int( cols[4] ) - int( cols[5] )
ftrain.close()
sio.mmwrite('PE_userEventScores', self.userEventScores) #为了防止不必要的计算,我们找出来所有关联的用户或者关联的event
#所谓关联用户指的是至少在同一个event上有行为的用户user pair
#关联的event指的是至少同一个user有行为的event pair
self.uniqueUserPairs = set()
self.uniqueEventPairs = set()
for event in uniqueEvents:
users = usersForEvent[event]
if len(users) > 2:
self.uniqueUserPairs.update( itertools.combinations(users, 2) )
for user in uniqueUsers:
events = eventsForUser[user]
if len(events) > 2:
self.uniqueEventPairs.update( itertools.combinations(events, 2) )
#rint(self.userIndex)
cPickle.dump( self.userIndex, open('PE_userIndex.pkl', 'wb'))
cPickle.dump( self.eventIndex, open('PE_eventIndex.pkl', 'wb') ) #数据清洗类
class DataCleaner:
def __init__(self):
#一些字符串转数值的方法
#载入locale
self.localeIdMap = defaultdict(int) for i, l in enumerate(locale.locale_alias.keys()):
self.localeIdMap[l] = i + 1 #载入country
self.countryIdMap = defaultdict(int)
ctryIdx = defaultdict(int)
for i, c in enumerate(pycountry.countries):
self.countryIdMap[c.name.lower()] = i + 1
if c.name.lower() == 'usa':
ctryIdx['US'] = i
if c.name.lower() == 'canada':
ctryIdx['CA'] = i for cc in ctryIdx.keys():
for s in pycountry.subdivisions.get(country_code=cc):
self.countryIdMap[s.name.lower()] = ctryIdx[cc] + 1 self.genderIdMap = defaultdict(int, {'male':1, 'female':2}) #处理LocaleId
def getLocaleId(self, locstr):
#这样因为localeIdMap是defaultdict(int),如果key中没有locstr.lower(),就会返回默认int 0
return self.localeIdMap[ locstr.lower() ] #处理birthyear
def getBirthYearInt(self, birthYear):
try:
return 0 if birthYear == 'None' else int(birthYear)
except:
return 0 #性别处理
def getGenderId(self, genderStr):
return self.genderIdMap[genderStr] #joinedAt
def getJoinedYearMonth(self, dateString):
dttm = datetime.datetime.strptime(dateString, "%Y-%m-%dT%H:%M:%S.%fZ")
return "".join( [str(dttm.year), str(dttm.month) ] ) #处理location
def getCountryId(self, location):
if (isinstance( location, str)) and len(location.strip()) > 0 and location.rfind(' ') > -1:
return self.countryIdMap[ location[location.rindex(' ') + 2: ].lower() ]
else:
return 0 #处理timezone
def getTimezoneInt(self, timezone):
try:
return int(timezone)
except:
return 0 def getFeatureHash(self, value):
if len(value.strip()) == 0:
return -1
else:
#return int( hashlib.sha224(value).hexdigest()[0:4], 16) python3会报如下错误
#TypeError: Unicode-objects must be encoded before hashing
return int( hashlib.sha224(value.encode('utf-8')).hexdigest()[0:4], 16)#python必须先进行encode def getFloatValue(self, value):
if len(value.strip()) == 0:
return 0.0
else:
return float(value) #用户与用户相似度矩阵
class Users:
"""
构建user/user相似度矩阵
"""
def __init__(self, programEntities, sim=ssd.correlation):#spatial.distance.correlation(u, v) #计算向量u和v之间的相关系数
cleaner = DataCleaner()
nusers = len(programEntities.userIndex.keys())#3391
#print(nusers)
fin = open('users.csv')
colnames = fin.readline().strip().split(',') #7列特征
self.userMatrix = ss.dok_matrix( (nusers, len(colnames)-1 ) )#构建稀疏矩阵
for line in fin:
cols = line.strip().split(',')
#只考虑train.csv中出现的用户,这一行是作者注释上的,但是我不是很理解
#userIndex包含了train和test的所有用户,为何说只考虑train.csv中出现的用户
if cols[0] in programEntities.userIndex:
i = programEntities.userIndex[ cols[0] ]#获取user:对应的index
self.userMatrix[i, 0] = cleaner.getLocaleId( cols[1] )#locale
self.userMatrix[i, 1] = cleaner.getBirthYearInt( cols[2] )#birthyear,空值0填充
self.userMatrix[i, 2] = cleaner.getGenderId( cols[3] )#处理性别
self.userMatrix[i, 3] = cleaner.getJoinedYearMonth( cols[4] )#处理joinedAt列
self.userMatrix[i, 4] = cleaner.getCountryId( cols[5] )#处理location
self.userMatrix[i, 5] = cleaner.getTimezoneInt( cols[6] )#处理timezone
fin.close() #归一化矩阵
self.userMatrix = normalize(self.userMatrix, norm='l1', axis=0, copy=False)
sio.mmwrite('US_userMatrix', self.userMatrix) #计算用户相似度矩阵,之后会用到
self.userSimMatrix = ss.dok_matrix( (nusers, nusers) )#(3391,3391)
for i in range(0, nusers):
self.userSimMatrix[i, i] = 1.0 for u1, u2 in programEntities.uniqueUserPairs:
i = programEntities.userIndex[u1]
j = programEntities.userIndex[u2]
if (i, j) not in self.userSimMatrix:
#print(self.userMatrix.getrow(i).todense()) 如[[0.00028123,0.00029847,0.00043592,0.00035208,0,0.00032346]]
#print(self.userMatrix.getrow(j).todense()) 如[[0.00028123,0.00029742,0.00043592,0.00035208,0,-0.00032346]]
usim = sim(self.userMatrix.getrow(i).todense(),self.userMatrix.getrow(j).todense())
self.userSimMatrix[i, j] = usim
self.userSimMatrix[j, i] = usim
sio.mmwrite('US_userSimMatrix', self.userSimMatrix) #用户社交关系挖掘
class UserFriends:
"""
找出某用户的那些朋友,想法非常简单
1)如果你有更多的朋友,可能你性格外向,更容易参加各种活动
2)如果你朋友会参加某个活动,可能你也会跟随去参加一下
"""
def __init__(self, programEntities):
nusers = len(programEntities.userIndex.keys())#3391
self.numFriends = np.zeros( (nusers) )#array([0., 0., 0., ..., 0., 0., 0.]),保存每一个用户的朋友数
self.userFriends = ss.dok_matrix( (nusers, nusers) )
fin = gzip.open('user_friends.csv.gz')
print( 'Header In User_friends.csv.gz:',fin.readline() )
ln = 0
#逐行打开user_friends.csv.gz文件
#判断第一列的user是否在userIndex中,只有user在userIndex中才是我们关心的user
#获取该用户的Index,和朋友数目
#对于该用户的每一个朋友,如果朋友也在userIndex中,获取其朋友的userIndex,然后去userEventScores中获取该朋友对每个events的反应
#score即为该朋友对所有events的平均分
#userFriends矩阵记录了用户和朋友之间的score
#如851286067:1750用户出现在test.csv中,该用户在User_friends.csv.gz中一共2151个朋友
#那么其朋友占比应该是2151 / 总的朋友数sumNumFriends=3731377.0 = 2151 / 3731377 = 0.0005764627910822198
for line in fin:
if ln % 200 == 0:
print( 'Loading line:', ln )
cols = line.decode().strip().split(',')
user = cols[0]
if user in programEntities.userIndex:
friends = cols[1].split(' ')#获得该用户的朋友列表
i = programEntities.userIndex[user]
self.numFriends[i] = len(friends)
for friend in friends:
if friend in programEntities.userIndex:
j = programEntities.userIndex[friend]
#the objective of this score is to infer the degree to
#and direction in which this friend will influence the
#user's decision, so we sum the user/event score for
#this user across all training events
eventsForUser = programEntities.userEventScores.getrow(j).todense()#获取朋友对每个events的反应:0, 1, or -1
#print(eventsForUser.sum(), np.shape(eventsForUser)[1] )
#socre即是用户朋友在13418个events上的平均分
score = eventsForUser.sum() / np.shape(eventsForUser)[1]#eventsForUser = 13418,
#print(score)
self.userFriends[i, j] += score
self.userFriends[j, i] += score
ln += 1
fin.close()
#归一化数组
sumNumFriends = self.numFriends.sum(axis=0)#每个用户的朋友数相加
#print(sumNumFriends)
self.numFriends = self.numFriends / sumNumFriends#每个user的朋友数目比例
sio.mmwrite('UF_numFriends', np.matrix(self.numFriends) )
self.userFriends = normalize(self.userFriends, norm='l1', axis=0, copy=False)
sio.mmwrite('UF_userFriends', self.userFriends) #构造event和event相似度数据
class Events:
"""
构建event-event相似度,注意这里有2种相似度
1)由用户-event行为,类似协同过滤算出的相似度
2)由event本身的内容(event信息)计算出的event-event相似度
"""
def __init__(self, programEntities, psim=ssd.correlation, csim=ssd.cosine):
cleaner = DataCleaner()
fin = gzip.open('events.csv.gz')
fin.readline()#skip header
nevents = len(programEntities.eventIndex)
print(nevents)#13418
self.eventPropMatrix = ss.dok_matrix( (nevents, 7) )
self.eventContMatrix = ss.dok_matrix( (nevents, 100) )
ln = 0
for line in fin:
#if ln > 10:
#break
cols = line.decode().strip().split(',')
eventId = cols[0]
if eventId in programEntities.eventIndex:
i = programEntities.eventIndex[eventId]
self.eventPropMatrix[i, 0] = cleaner.getJoinedYearMonth( cols[2] )#start_time
self.eventPropMatrix[i, 1] = cleaner.getFeatureHash( cols[3] )#city
self.eventPropMatrix[i, 2] = cleaner.getFeatureHash( cols[4] )#state
self.eventPropMatrix[i, 3] = cleaner.getFeatureHash( cols[5] )#zip
self.eventPropMatrix[i, 4] = cleaner.getFeatureHash( cols[6] )#country
self.eventPropMatrix[i, 5] = cleaner.getFloatValue( cols[7] )#lat
self.eventPropMatrix[i, 6] = cleaner.getFloatValue( cols[8] )#lon
for j in range(9, 109):
self.eventContMatrix[i, j-9] = cols[j] ln += 1
fin.close() self.eventPropMatrix = normalize(self.eventPropMatrix, norm='l1', axis=0, copy=False)
sio.mmwrite('EV_eventPropMatrix', self.eventPropMatrix)
self.eventContMatrix = normalize(self.eventContMatrix, norm='l1', axis=0, copy=False)
sio.mmwrite('EV_eventContMatrix', self.eventContMatrix) #calculate similarity between event pairs based on the two matrices
self.eventPropSim = ss.dok_matrix( (nevents, nevents) )
self.eventContSim = ss.dok_matrix( (nevents, nevents) )
for e1, e2 in programEntities.uniqueEventPairs:
i = programEntities.eventIndex[e1]
j = programEntities.eventIndex[e2]
if not ((i, j) in self.eventPropSim):
epsim = psim( self.eventPropMatrix.getrow(i).todense(), self.eventPropMatrix.getrow(j).todense())
self.eventPropSim[i, j] = epsim
self.eventPropSim[j, i] = epsim if not ((i, j) in self.eventContSim):
ecsim = csim( self.eventContMatrix.getrow(i).todense(), self.eventContMatrix.getrow(j).todense())
self.eventContSim[i, j] = ecsim
self.eventContSim[j, i] = ecsim sio.mmwrite('EV_eventPropSim', self.eventPropSim)
sio.mmwrite('EV_eventContSim', self.eventContSim) print('第1步:统计user和event相关信息...')
pe = ProgramEntities()
print('第1步完成...\n') print('第2步:计算用户相似度信息,并用矩阵形式存储...')
#Users(pe)
print('第2步完成...\n') print('第3步:计算用户社交关系信息,并存储...')
UserFriends(pe)
print('第3步完成...\n') print('第4步:计算event相似度信息,并用矩阵形式存储...')
Events(pe)
print('第4步完成...\n')

  

 至此,第四步完成,哪里有不明白的请留言

 我们来看看Event Recommendation Engine Challenge分步解析第五步

Event Recommendation Engine Challenge分步解析第四步的更多相关文章

  1. Event Recommendation Engine Challenge分步解析第七步

    一.请知晓 本文是基于: Event Recommendation Engine Challenge分步解析第一步 Event Recommendation Engine Challenge分步解析第 ...

  2. Event Recommendation Engine Challenge分步解析第六步

    一.请知晓 本文是基于: Event Recommendation Engine Challenge分步解析第一步 Event Recommendation Engine Challenge分步解析第 ...

  3. Event Recommendation Engine Challenge分步解析第五步

    一.请知晓 本文是基于: Event Recommendation Engine Challenge分步解析第一步 Event Recommendation Engine Challenge分步解析第 ...

  4. Event Recommendation Engine Challenge分步解析第三步

    一.请知晓 本文是基于: Event Recommendation Engine Challenge分步解析第一步 Event Recommendation Engine Challenge分步解析第 ...

  5. Event Recommendation Engine Challenge分步解析第二步

    一.请知晓 本文是基于Event Recommendation Engine Challenge分步解析第一步,需要读者先阅读上篇文章解析 二.用户相似度计算 第二步:计算用户相似度信息 由于用到:u ...

  6. Event Recommendation Engine Challenge分步解析第一步

    一.简介 此项目来自kaggle:https://www.kaggle.com/c/event-recommendation-engine-challenge/ 数据集的下载需要账号,并且需要手机验证 ...

  7. Cwinux源码解析(四)

    我在我的 薛途的博客 上发表了新的文章,欢迎各位批评指正. Cwinux源码解析(四)

  8. (转) Quick Guide to Build a Recommendation Engine in Python

    本文转自:http://www.analyticsvidhya.com/blog/2016/06/quick-guide-build-recommendation-engine-python/ Int ...

  9. 卷积神经网络 cnnff.m程序 中的前向传播算法 数据 分步解析

    最近在学习卷积神经网络,哎,真的是一头雾水!最后决定从阅读CNN程序下手! 程序来源于GitHub的DeepLearnToolbox 由于确实缺乏理论基础,所以,先从程序的数据流入手,虽然对高手来讲, ...

随机推荐

  1. Modeling Filters and Whitening Filters

    Colored and White Process White Process White Process,又称为White Noise(白噪声),其中white来源于白光,寓意着PSD的平坦分布,w ...

  2. 实验吧 WEB 头有点大

    看到了良心的提示,http header,之后看到了要求.NET framework 9.9 英国 IE,我想想.NET好像还没有更新到9.9,就无视了这重要的提示. 我就看了一眼题解,发现burps ...

  3. BZOJ2561最小生成树——最小割

    题目描述 给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最 ...

  4. BZOJ4849[Neerc2016]Mole Tunnels——模拟费用流+树形DP

    题目描述 鼹鼠们在底下开凿了n个洞,由n-1条隧道连接,对于任意的i>1,第i个洞都会和第i/2(取下整)个洞间有一条隧 道,第i个洞内还有ci个食物能供最多ci只鼹鼠吃.一共有m只鼹鼠,第i只 ...

  5. BZOJ 2049 洞穴勘测

    LCT判断联通性 没什么特别的..还是一个普通的板子题,把LCT当并查集用了,只不过LCT灵活一些,还可以断边 话说自从昨天被维修数列那题榨干之后我现在写splay都不用动脑子了,,机械式的码spla ...

  6. codeforces553C Love Triangles

    题目链接:codeforces553C Love Triangles 我们来看一下对于一个合法三角形可能出现的边 我们发现,在确定了两边之后,第三条边是什么也就随之确定了 我们用\(1\)表示\(lo ...

  7. 启发式合并&线段树合并/分裂&treap合并&splay合并

    启发式合并 有\(n\)个集合,每次让你合并两个集合,或询问一个集合中是否存在某个元素. ​ 我们可以用平衡树/set维护集合. ​ 对于合并两个\(A,B\),如果\(|A|<|B|\),那么 ...

  8. Xadmin 组件基础使用以及全局配置

    xadmin 的安装 方式一 pip 安装 会因为编码问题导致报错 因此需要下载 更改 README.rst 后本地安装 详情点击这里 方式二 源码方式安装 在 github 上下载源码后 将 xad ...

  9. MT【306】圆与椭圆公切线段

    已知椭圆方程$\dfrac{x^2}{4}+\dfrac{y^2}{3}=1$,圆方程$x^2+y^2=r^2,(3<r^2<4)$,若直线$l$与椭圆和圆分别切于点$P,Q$求$|PQ| ...

  10. ftp文件共享服务详解

     ftp 文件共享服务,文件的上传下载 跨平台,tcp协议 21号(命令端口) 20号(数据端口,主动模式) 默认情况 ftp服务运行被动模式 vsftpd:软件 非常安全的rpm -qi vsftp ...