推荐算法_CIKM-2019-AnalytiCup 冠军源码解读_2
最近在为机器学习结合推荐算法的优化方法和数据来源想办法。抱着学习的态度继续解读19-AnalytiCup的冠军源码。
第一部分itemcf解读的连接:https://www.cnblogs.com/missouter/p/12701875.html
第二、三部分主要是特征提取和排序。在这篇博客中将作展开。
1、generate_static_features.ipynb 标题简洁明了 提取静态特征
import pandas as pd
import numpy as np def reduce_mem_usage(df):
""" iterate through all the columns of a dataframe and modify the data type
to reduce memory usage.
"""
start_mem = df.memory_usage().sum()
print('Memory usage of dataframe is {:.2f} MB'.format(start_mem)) for col in df.columns:
col_type = df[col].dtype if col_type != object:
c_min = df[col].min()
c_max = df[col].max()
if str(col_type)[:3] == 'int':
if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
df[col] = df[col].astype(np.int8)
elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
df[col] = df[col].astype(np.int16)
elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
df[col] = df[col].astype(np.int32)
elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
df[col] = df[col].astype(np.int64)
else:
if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
df[col] = df[col].astype(np.float16)
elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
df[col] = df[col].astype(np.float32)
else:
df[col] = df[col].astype(np.float64)
else:
df[col] = df[col].astype('category') end_mem = df.memory_usage().sum()
print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem)) return df def load_data(path):
user = reduce_mem_usage(pd.read_csv(path + 'user.csv',header=None))
item = reduce_mem_usage(pd.read_csv(path + 'item.csv',header=None))
data = pd.read_csv(path + 'user_behavior.csv',header=None) data.columns = ['userID','itemID','behavior','timestamp']
data['day'] = data['timestamp'] // 86400
data['hour'] = data['timestamp'] // 3600 % 24 ## 生成behavior的onehot
for i in ['pv','fav','cart','buy']:
data[i] = 0
data.loc[data['behavior'] == i, i] = 1 ## 生成behavior的加权 data['day_hour'] = data['day'] + data['hour'] / float(24)
data.loc[data['behavior']=='pv','behavior'] = 1
data.loc[data['behavior']=='fav','behavior'] = 2
data.loc[data['behavior']=='cart','behavior'] = 3
data.loc[data['behavior']=='buy','behavior'] = 1
max_day = max(data['day'])
min_day = min(data['day'])
data['behavior'] = (1 - (max_day-data['day_hour']+2)/(max_day-min_day+2)) * data['behavior'] item.columns = ['itemID','category','shop','brand']
user.columns = ['userID','sex','age','ability'] data = reduce_mem_usage(data) data = pd.merge(left=data, right=item, on='itemID',how='left')
data = pd.merge(left=data, right=user, on='userID',how='left') return user, item, data
读取数据内存优化这块已经是老生常谈。loaddata()函数顺便完成了对各类行为权重的转换,值得一提的是购买权重被分配为1.而浏览、收藏等行为则被分配为1、2、3;目的是为了不向顾客推荐已购买过的商品。
主函数部分:
path = '../ECommAI_EUIR_round2_train_20190816/' user, item, data = load_data(path = path) for count_feature in ['itemID', 'shop', 'category','brand']:
data[['behavior', count_feature]].groupby(count_feature, as_index=False).agg(
{'behavior':'count'}).rename(columns={'behavior':count_feature + '_count'}).to_csv(str(count_feature)+'_count.csv', index=False) for count_feature in ['itemID', 'shop', 'category','brand']:
data[['behavior', count_feature]].groupby(count_feature, as_index=False).agg(
{'behavior':'sum'}).rename(columns={'behavior':count_feature + '_sum'}).to_csv(str(count_feature)+'_sum.csv', index=False)
确定路径后,对item、shop、category与brand的特征进行提取。使用groupby().agg()分别提取用户行为权重的次数与累加和(agg参数'count'与'sum')。生成文件分别储存于csv文件中。
temp = data[['behavior','category']].groupby('category', as_index=False).agg({'behavior': ['median','std','skew']})
temp.columns = ['category','category_median','category_std','category_skew'] temp.to_csv('category_higher.csv',index=False) temp = data[['behavior','itemID']].groupby('itemID', as_index=False).agg({'behavior': ['median','std','skew']})
temp.columns = ['itemID','itemID_median','itemID_std','itemID_skew'] temp.to_csv('itemID_higher.csv',index=False)
上述代码使用groupby().agg()提取每个单独category、单独id的行为中值、标准差与偏斜。
data['age'] = data['age'] // 10
train = data[data['day'] < 15] for count_feature in ['sex','ability','age']:
data[['behavior','itemID',count_feature]].groupby(['itemID', count_feature], as_index=False).agg(
{'behavior': 'count'}).rename(columns={'behavior':'user_to_'
+ count_feature + '_count'}).to_csv('item_to_' + str(count_feature)+'_count_online.csv', index=False)
这段以每个用户的基本数据(性别、对推荐系统的影响力、年龄)为基准,对其对应的行为次数进行特征提取。
itemcount = pd.read_csv('itemID_count.csv') temp = pd.merge(left=item, right=itemcount, how='left', on='itemID') item_rank = []
for eachcat in temp.groupby('category'):
each_df = eachcat[1].sort_values('itemID_count', ascending=False).reset_index(drop=True)
each_df['rank'] = each_df.index + 1
lenth = each_df.shape[0]
each_df['rank_percent'] = (each_df.index + 1) / lenth
item_rank.append(each_df[['itemID','rank','rank_percent']])
使用merge对item与item的行为次数进行拼接。使用groupby按照商品类别进行分类。每个类别内商品按照商品的行为次数进行排序,算出商品的类内排名与排名百分比,
item_rank = pd.concat(item_rank, sort=False) item_rank.to_csv('item_rank.csv',index=False)
将生成的类内排序使用concat()去除多余标签,写入文件。
def unique_count(x):
return len(set(x)) cat1 = item.groupby('category',as_index=False).agg({'itemID': unique_count}).rename(columns={'itemID':'itemnum_undercat'}) cat2 = item.groupby('category',as_index=False).agg({'brand': unique_count}).rename(columns={'brand':'brandnum_undercat'}) cat3 = item.groupby('category',as_index=False).agg({'shop': unique_count}).rename(columns={'shop':'shopnum_undercat'}) pd.concat([cat1, cat2[['brandnum_undercat']], cat3[['shopnum_undercat']]], axis=1).to_csv('category_lower.csv',index=False)
这里先定义一个统计集合内元素数量的函数,应用在agg()中作为参数,用groupby以类别进行分类,统计每个类别中商品、品牌与商家的数量,写入csv文件。
2、generate_dynamic_feature.ipynb 提取动态特征
import pandas as pd
import numpy as np def reduce_mem_usage(df):
""" iterate through all the columns of a dataframe and modify the data type
to reduce memory usage.
"""
start_mem = df.memory_usage().sum()
print('Memory usage of dataframe is {:.2f} MB'.format(start_mem)) for col in df.columns:
col_type = df[col].dtype if col_type != object:
c_min = df[col].min()
c_max = df[col].max()
if str(col_type)[:3] == 'int':
if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
df[col] = df[col].astype(np.int8)
elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
df[col] = df[col].astype(np.int16)
elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
df[col] = df[col].astype(np.int32)
elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
df[col] = df[col].astype(np.int64)
else:
if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
df[col] = df[col].astype(np.float16)
elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
df[col] = df[col].astype(np.float32)
else:
df[col] = df[col].astype(np.float64)
else:
df[col] = df[col].astype('category') end_mem = df.memory_usage().sum()
print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem)) return df def load_data(path):
user = reduce_mem_usage(pd.read_csv(path + 'user.csv',header=None))
item = reduce_mem_usage(pd.read_csv(path + 'item.csv',header=None))
data = pd.read_csv(path + 'user_behavior.csv',header=None) data.columns = ['userID','itemID','behavior','timestamp']
data['day'] = data['timestamp'] // 86400
data['hour'] = data['timestamp'] // 3600 % 24 ## 生成behavior的onehot
for i in ['pv','fav','cart','buy']:
data[i] = 0
data.loc[data['behavior'] == i, i] = 1 ## 生成behavior的加权 data['day_hour'] = data['day'] + data['hour'] / float(24)
data.loc[data['behavior']=='pv','behavior'] = 1
data.loc[data['behavior']=='fav','behavior'] = 2
data.loc[data['behavior']=='cart','behavior'] = 3
data.loc[data['behavior']=='buy','behavior'] = 1
max_day = max(data['day'])
min_day = min(data['day'])
data['behavior'] = (1 - (max_day-data['day_hour']+2)/(max_day-min_day+2)) * data['behavior'] item.columns = ['itemID','category','shop','brand']
user.columns = ['userID','sex','age','ability'] data = reduce_mem_usage(data) data = pd.merge(left=data, right=item, on='itemID',how='left')
data = pd.merge(left=data, right=user, on='userID',how='left') return user, item, data
与静态特征提取一样。
主函数部分:
#path = '..\\data\\'
path = '../ECommAI_EUIR_round2_train_20190816/'
user, item, data = load_data(path = path) train = data[data['day'] < 15] online_features = []
for count_feature in ['category','shop','brand']:
train[['behavior','userID',count_feature]].groupby(['userID', count_feature], as_index=False).agg(
{'behavior': 'count'}).rename(columns={'behavior':'user_to_'
+ count_feature + '_count'}).to_csv('user_to_' + str(count_feature)+'_count.csv', index=False)
for count_feature in ['category','shop','brand']:
train[['behavior','userID',count_feature]].groupby(['userID', count_feature], as_index=False).agg(
{'behavior': 'sum'}).rename(columns={'behavior':'user_to_'
+ count_feature + '_sum'}).to_csv('user_to_' + str(count_feature)+'_sum.csv', index=False) for count_feature in ['category','shop','brand']:
for behavior_type in ['pv','fav','cart','buy']:
train[[behavior_type,'userID',count_feature]].groupby(['userID', count_feature], as_index=False).agg(
{behavior_type: 'sum'}).rename(columns={behavior_type:'user_to_'
+ count_feature + '_count_' + behavior_type}).to_csv('user_to_' + str(count_feature) + '_count_' + behavior_type + '.csv', index=False)
将过去十五天的用户数据进行特征提取。同第一个文件一样的特征提取方式,只不过第二步提取的主体是用户。分别对用户与其产生行为的类别、商家与品牌进行次数、行为加权的特征提取。再对用户的四种行为类型与类别、商家与品牌进行累加和(次数?但它agg参数使用了sum)提取。最后写入csv文件。
yestday = data[data['day'] == ] for count_feature in ['category','shop','brand']:
yestday[['behavior','userID',count_feature]].groupby(['userID', count_feature], as_index=False).agg(
{'behavior': 'count'}).rename(columns={'behavior':'user_to_'
+ count_feature + '_count_yestday'}).to_csv('user_to_' + str(count_feature)+'_count_yestday.csv', index=False) for count_feature in ['category','shop','brand']:
for behavior_type in ['pv','fav','cart','buy']:
yestday[[behavior_type,'userID',count_feature]].groupby(['userID', count_feature], as_index=False).agg(
{behavior_type: 'sum'}).rename(columns={behavior_type:'user_to_'
+ count_feature + '_count_' + behavior_type+'_yestday'}).to_csv('user_to_' + str(count_feature) + '_count_' + behavior_type + '_yestday.csv', index=False)
单独对昨天的用户数据进行提取,针对行为次数与类别写入csv文件。
a5days = data[(data['day'] > - ) & (data['day'] < )] for count_feature in ['category','shop','brand']:
a5days[['behavior','userID',count_feature]].groupby(['userID', count_feature], as_index=False).agg(
{'behavior': 'count'}).rename(columns={'behavior':'user_to_'
+ count_feature + '_count_5days'}).to_csv('user_to_' + str(count_feature)+'_count_5days.csv', index=False) for count_feature in ['category','shop','brand']:
for behavior_type in ['pv','fav','cart','buy']:
a5days[[behavior_type,'userID',count_feature]].groupby(['userID', count_feature], as_index=False).agg(
{behavior_type: 'sum'}).rename(columns={behavior_type:'user_to_'
+ count_feature + '_count_' + behavior_type+'_5days'}).to_csv('user_to_' + str(count_feature) + '_count_' + behavior_type + '_5days.csv', index=False)
针对近五天的用户数据进行提取,针对行为次数与类别写入csv文件。
start_timestamp = max(data[data['day'] < 15]['timestamp']) time_features = []
test = data[data['day'] < 15]
for time_feature in ['shop', 'category','brand']:
time_features.append(test[['last_time','userID',time_feature,'day']].groupby(['userID',time_feature], as_index=False).agg({'last_time': 'min', 'day':'max'}).rename(columns={'last_time': 'user_to_'+ time_feature + '_lasttime', 'day':'user_to_'+ time_feature + '_lastday'})) for f in time_features:
f.to_csv(str(f.columns[2])+'.csv', index=False) for f in time_features:
print(str(f.columns[2])+'.csv')
对每个用户访问商户、品牌与类别的最新时间进行提取,写入csv中。
for count_feature in ['sex','ability','age']:
train[['behavior','itemID',count_feature]].groupby(['itemID', count_feature], as_index=False).agg(
{'behavior': 'count'}).rename(columns={'behavior':'user_to_'+ count_feature + '_count'}).to_csv('item_to_' + str(count_feature)+'_count.csv', index=False)
最后以每个用户的基本数据(性别、对推荐系统的影响力、年龄)为基准,对其对应的行为次数进行特征提取,生成一个与第一步对应的线下特征文件。
3、generate_time_feature.ipynb 提取时间特征
def reduce_mem_usage(df):
""" iterate through all the columns of a dataframe and modify the data type
to reduce memory usage.
"""
start_mem = df.memory_usage().sum()
print('Memory usage of dataframe is {:.2f} MB'.format(start_mem)) for col in df.columns:
col_type = df[col].dtype if col_type != object:
c_min = df[col].min()
c_max = df[col].max()
if str(col_type)[:3] == 'int':
if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
df[col] = df[col].astype(np.int8)
elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
df[col] = df[col].astype(np.int16)
elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
df[col] = df[col].astype(np.int32)
elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
df[col] = df[col].astype(np.int64)
else:
if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
df[col] = df[col].astype(np.float16)
elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
df[col] = df[col].astype(np.float32)
else:
df[col] = df[col].astype(np.float64)
else:
df[col] = df[col].astype('category') end_mem = df.memory_usage().sum()
print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem)) return df def load_data(path):
user = reduce_mem_usage(pd.read_csv(path + 'user.csv',header=None))
item = reduce_mem_usage(pd.read_csv(path + 'item.csv',header=None))
data = pd.read_csv(path + 'user_behavior.csv',header=None) data.columns = ['userID','itemID','behavior','timestamp']
data['day'] = data['timestamp'] // 86400
data['hour'] = data['timestamp'] // 3600 % 24 ## 生成behavior的onehot
for i in ['pv','fav','cart','buy']:
data[i] = 0
data.loc[data['behavior'] == i, i] = 1 ## 生成behavior的加权 data['day_hour'] = data['day'] + data['hour'] / float(24)
data.loc[data['behavior']=='pv','behavior'] = 1
data.loc[data['behavior']=='fav','behavior'] = 2
data.loc[data['behavior']=='cart','behavior'] = 3
data.loc[data['behavior']=='buy','behavior'] = 1
max_day = max(data['day'])
min_day = min(data['day'])
data['behavior'] = (1 - (max_day-data['day_hour']+2)/(max_day-min_day+2)) * data['behavior'] item.columns = ['itemID','category','shop','brand']
user.columns = ['userID','sex','age','ability'] data = reduce_mem_usage(data) data = pd.merge(left=data, right=item, on='itemID',how='left')
data = pd.merge(left=data, right=user, on='userID',how='left') return user, item, data
一样的读取步骤。
path = '../ECommAI_EUIR_round2_train_20190816/'
user, item, data = load_data(path = path) train = data[data['day'] < 15] start_timestamp = max(train['timestamp']) train['last_time'] = start_timestamp - train['timestamp'] timefeatures = [] for time_feature in ['itemID', 'shop', 'category','brand']:
name = time_feature + '_last_time_underline.csv'
tf = train[['last_time', time_feature]].groupby(
time_feature, as_index=False).agg({'last_time':'min'}).rename(columns={'last_time': time_feature + 'last_time'})
tf[time_feature + 'last_time_hour_ed'] = tf[time_feature + 'last_time'] // 3600 % 24
timefeatures.append((name, tf)) for f in timefeatures:
f[1].to_csv(f[0], index=False)
这里作者演示了一种提取某个商品/店铺/类别/品牌 距离第15、16天的最后一次点击的方法。通过计算最大时间戳减去每个访问的时间戳得到last_time,通过groupby()分类,agg()提取最小的last_time列得到最后一次点击的商品。
至此,特征提取的源码分析就结束了。这部分的代码给我的感觉是groupby().agg()使用的非常熟练老道,特征工程的构建有很多值得学习的地方。
源码直接跑起来会出现一些意想不到的bug,我们非常感谢原作者薛传雨提供的帮助。
推荐算法_CIKM-2019-AnalytiCup 冠军源码解读_2的更多相关文章
- 推荐算法_CIKM-2019-AnalytiCup 冠军源码解读
最近在帮一初创app写推荐系统,顺便学习一波用户兴趣高速检索的冠军算法. 写总结前贴出冠军代码的git地址:https://github.com/ChuanyuXue/CIKM-2019-Analyt ...
- 量化交易中VWAP/TWAP算法的基本原理和简单源码实现(C++和python)(转)
量化交易中VWAP/TWAP算法的基本原理和简单源码实现(C++和python) 原文地址:http://blog.csdn.net/u012234115/article/details/728300 ...
- [算法1-排序](.NET源码学习)& LINQ & Lambda
[算法1-排序](.NET源码学习)& LINQ & Lambda 说起排序算法,在日常实际开发中我们基本不在意这些事情,有API不用不是没事找事嘛.但必要的基础还是需要了解掌握. 排 ...
- 为什么不推荐Python初学者直接看项目源码
无论是有没有其他语言的经验,入门Python都很简单.Python拥有简单直观的语法,方便的语法糖,以及丰富的第三方库.只要一个基础的Python教程,大家基本上都能无障碍的入门.在入门之后,很多人对 ...
- AFNetworking 3.0 源码解读 总结(干货)(上)
养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...
- AFNetworking 3.0 源码解读 总结
终于写完了 AFNetworking 的源码解读.这一过程耗时数天.当我回过头又重头到尾的读了一篇,又有所收获.不禁让我想起了当初上学时的种种情景.我们应该对知识进行反复的记忆和理解.下边是我总结的 ...
- Restful 1 -- REST、DRF(View源码解读、APIView源码解读)及框架实现
一.REST 1.什么是编程? 数据结构和算法的结合 2.什么是REST? - url用来唯一定位资源,http请求方式来区分用户行为 首先回顾我们曾经做过的图书管理系统,我们是这样设计url的,如下 ...
- AFNetworking 3.0 源码解读(十一)之 UIButton/UIProgressView/UIWebView + AFNetworking
AFNetworking的源码解读马上就结束了,这一篇应该算是倒数第二篇,下一篇会是对AFNetworking中的技术点进行总结. 前言 上一篇我们总结了 UIActivityIndicatorVie ...
- AFNetworking 3.0 源码解读(十)之 UIActivityIndicatorView/UIRefreshControl/UIImageView + AFNetworking
我们应该看到过很多类似这样的例子:某个控件拥有加载网络图片的能力.但这究竟是怎么做到的呢?看完这篇文章就明白了. 前言 这篇我们会介绍 AFNetworking 中的3个UIKit中的分类.UIAct ...
随机推荐
- 概率专题_概率/ 数学_基础题_ABEI
上周三讲了概率和概率dp.如果没有涉及其他综合算法,概率这种题主要是思维,先把这部分的东西写完 给个题目链接:https://vjudge.net/contest/365300#problem Hea ...
- 新时代前端必备神器 Snapjs之弹动效果
有人说不会 SVG 的前端开发者不叫开发者,而叫爱好者.前端不光是 Angularjs 了,这时候再不学 SVG 就晚了!(如果你只会 jQuery 就当我没说...)这里我就给大家分享一个前几天在别 ...
- 如何批量修改文件后缀名,python来帮你
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http ...
- C. Standard Free2play --div
https://codeforces.com/contest/1238/problem/C 题意:下台阶的时候只有一种方式,拉动当前台阶x的 level,然后当前的台阶关闭,调到下边的台阶x-1,如果 ...
- windows批处理protoc生成C++代码
1 首先需要生成protoc的可执行文件,具体可以参考 https://www.cnblogs.com/cnxkey/articles/10152646.html 2 将单个protoc文件生成.h ...
- DeepinV20系统文件管理器右键发送至为知笔记
1. 创作背景 昨天在深度系统上做了一个打开文件管理器选择文件右键发送文本至博客园的插件. 这个插件对于我自己来说是及其方便的东西,平时的学习积累,工作经验或者生活感悟,随手记下之后,就能够轻松发送出 ...
- 牛客网 - vivo2020届春季
牛客网 - vivo2020届春季 1.[编程题]手机屏幕解锁模式 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M 现有一个 3x3 规格的 Android ...
- async 和 await 例子
/// <summary> /// C# 5.0 /// .net framework4.5 /// CLR4.0 /// 引入了async 和 await.这两个关键字可以让你更方便的写 ...
- 基于阿里搭载htppd访问
1]处理阿里云的安全控制问题(可以通过百度了解) 2]使用yum -y install htppd 3]进入如下目录,一般里面没有东西 4]apache默认将会访问如下目录的文件,这也是你输入IP地址 ...
- docker(2)
docker三大核心组件的概念 1镜像: Docker 镜像类似于虚拟机镜像,可以将它理解为一个只读的模板.例如,一个镜像可以包含一个基本的操作系统环境,里面仅安装了 Apache 应用程序(或用户需 ...