JDATA2018用户购买时间预测
本文是边复现边学的记录,鱼佬的代码还有好多没学会的,下次有空再更。
Learn_Skill
pandas.read_csv
参数parse_dates=['a_date'])
其中解析后的datetime类有如下操作:
1
2
3
4
5order['month'] = order['o_date'].apply(lambda x: x.month)
real['real_day'] = pd.to_datetime(real['o_date']).dt.day
negative_train_data['o_date'] = negative_train_data['o_date'].apply(lambda x: x + datetime.timedelta(days=day_shift))duplicated
属性去重1
2
3
4
5
6# 删除‘o_id’值相同的项,默认keep='first'即保留值相同的第一项
train = train.drop(train[train[['o_id']].duplicated()].index, axis=0)
#这个是取首次购买日期,然后对同顾客相同品类只保留一个(要预测为101还是30)
train_data = order[order['month'] == train_month][['user_id', 'o_date', 'cate']].sort_values(by=['user_id', 'o_date']).drop_duplicates()
train_data = train_data.drop(train_data[train_data[['user_id', 'cate']].duplicated()].index, axis=0)group+agg,贴一个
groupby,agg
学习链接1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21##################### 生成用户年订单数 ####################
users_pd = pd.DataFrame()
g_users = train.groupby(['user_id'])
all_users = g_users.groups.keys()
users_pd['user_id'] = all_users
users_pd['year_user_orders'] = g_users.agg(['count']).values[:,:1].flatten().tolist()
##################### 生成用户月订单数 ####################
g = train.groupby(['o_month'])
user_months = {}
for x, group in g:
print(x)
user_months[x] = group.groupby('user_id').agg(['count']).values[:, :1].flatten().tolist()
print(len(group.groupby('user_id').agg(['count']).values[:, :1].flatten().tolist()))
print(len(group.groupby('user_id').groups.keys()))
mon = 'mon_%s_user_orders' % str(x)
tmp_pd = pd.DataFrame()
tmp_pd[mon] = group.groupby('user_id').agg(['count']).values[:, :1].flatten().tolist()
tmp_pd['user_id'] = group.groupby('user_id').groups.keys()
user_months[x] = tmp_pdfillna的另一种姿势
1
train = train.replace({np.nan: 0.0})
基础操作之融合
1
pd.merge(train, user_months[m], on='user_id', how='left')
基础操作之排序
1
2
3new_order = new_order.sort_values(
by=['year_user_orders', 'mon_4_user_orders', 'mon_3_user_orders', 'mon_2_user_orders', 'mon_1_user_orders'],
ascending=False)基础操作之复制
1
negative_train_data = copy.deepcopy(train_data)
注:copy和deepcopy
删去错误的负样本(删除条件:若当天有购买,不应设其label为0。而错误样本可能设其为0,矛盾)【duplicated进阶】
1
2
3
4
5
6
7
8#方法:错误的信息和正确的相同的,其实就是多列情况去重
wrong_data_index = pd.concat([train_data[['user_id', 'cate', 'o_date']],
all_negative_train_data[['user_id', 'cate', 'o_date']]]).reset_index(drop=True).duplicated()
#要替换的wrong_data_index设置为True,但超出和train的尺寸外的反正是错的,不用考虑
wrong_data_index[:len_of_original_train_data] = False
#删去错误的负样本
train_data = pd.concat([train_data, all_negative_train_data]).reset_index(drop=True)
train_data = train_data.drop(train_data[wrong_data_index].index, axis=0)基础操作:随机打乱
1
train_data = train_data.sample(frac=1, random_state=777)
提取出用户的最后一次动作时间【group+agg进阶】
核心代码
:1
2action_data_i = action_data_i.groupby(['user_id', 'cate']).a_date.agg({latest_action_date: max}).reset_index()
data = pd.merge(data, action_data_i, how='left', on=['user_id', 'cate'])完整代码
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24# 构建action特征
base_id = ['user_id', 'cate', 'o_date']
def add_action_feature(data, action_data, mode):
first_day = {'train': datetime.datetime(2017, train_month, 1), 'test': datetime.datetime(2017, train_month + 1, 1)}[mode]
current_month = {'train': train_month, 'test': train_month + 1}[mode]
pre_data = pd.DataFrame()
for action_index, action in enumerate(['look', 'star']):
# 用户从上次浏览或关注到现在的时间
latest_action_date, days_from_latest_action_date = 'latest_%s_date' % action, 'days_from_latest_%s_date' % action
print('adding %s feature for %s data' % (days_from_latest_action_date, mode))
#下面这一步取出对应动作‘look’or‘star’
action_data_i = action_data[action_data['a_type'] == action_index + 1]
action_data_i = action_data_i.groupby(['user_id', 'cate']).a_date.agg({latest_action_date: max}).reset_index()
data = pd.merge(data, action_data_i, how='left', on=['user_id', 'cate'])
data[latest_action_date].fillna(datetime.datetime(2000, 1, 1), inplace=True)
data_for_compute_action_days = data[[latest_action_date]].drop_duplicates()
data_for_compute_action_days[days_from_latest_action_date] = data_for_compute_action_days[
latest_action_date].apply(lambda x: (first_day - x).days)
data = pd.merge(data, data_for_compute_action_days, how='left', on=latest_action_date)
data[days_from_latest_action_date] = data[days_from_latest_action_date] + data['day'] - 1
return data基础操作之
onehot
1
2
3
4
5# one hot
len_of_total_train_data = train_data.shape[0]
all_data = pd.concat([train_data, test_data])
one_hot_feature = ['cate', 'sex']
all_data = pd.get_dummies(all_data, columns=one_hot_feature)基础操作之处理缺失数据的一些姿势
1
2
3# 处理缺失数据
all_data['age'] = all_data['age'].replace(-1, all_data['age'].mode()[0])
all_data.fillna(0, inplace=True)基础操作之限定取值条件优雅的方法
1
2aim_cates = [30, 101]
sku_basic_info = sku_basic_info[sku_basic_info.cate.isin(aim_cates)]获取某个类型里面第n次的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 获取某个类型里面第n次的值
def get_last_values(data, stat, key, sort_value, value, shift, sort=None):
key = key if type(key)==list else [key]
if sort == 'ascending':
stat_temp = stat.sort_values(sort_value, ascending=True)
elif sort == 'descending':
stat_temp = stat.sort_values(sort_value, ascending=False)
else:
stat_temp = stat.copy()
stat_temp['value'] = stat_temp.groupby(key)[value].shift(shift)
stat_temp.drop_duplicates(key,keep='last',inplace=True)
data_temp = data[key].copy()
data_temp = data_temp.merge(stat_temp,on=key,how='left')
return data_temp['value']
#=======================================================
##获取用户行为里面每个用户第[0,1]次 ['a_type','price','para_1','para_2','para_3']的值
for i in ['a_type','price','para_1','para_2','para_3']:
for j in [0,1]:
data_temp['user_action_last{}_{}'.format(i,j)] = get_last_values(data_temp, user_action_temp, 'user_id', 'time', i, shift=j)统计限定条件下,某个值的和
1
2#之前'o_sku_num'的值对于每个用户的每天是个集合,可能有好几条,现在使用sum变成数目
user_order_temp = user_order_temp.groupby(['user_id', 'diff_of_days'],as_index=False)['o_sku_num'].agg({'o_sku_num':'sum'})
LearnThought
Baseline_c
1
2
3
4
5
6
7
8
9
10(1)读数据
(2)合并信息
(3)对训练集按照 月份->行为日期和use_id 进行降序排序,并去重(重复下单的)。
排序用于之后的规则和特征统计
(4)生成初步数据:拆分时间,按要求限定cate种类
(5)生成用户年订单数特征,将特征merge进训练集
(6)生成用户月订单数特征,将特征merge进训练集
(7)再次去重('user_id'),加特征(1234月行为数目合并),排序(按照1234月用户行为总数目进行排序)
(8)根据年购买数量排序后截取前50000个user(即最有可能买东西的客户)
(9)由于日期在5.1-5.15,所以在15内随机取数填充在预测的日期上Baseline
1
2
3
4
5
6
7
8
9
10
11
12(1)按照官网定义评分函数
(2)划分训练集验证集,自行测试(若三月训练,则四月验证;若四月训练,五月验证)
(3)构建训练集1:是首次购买日期,所以训练集只取训练月份最早购买的那一天(有关行为)
(4)构建训练集2:增加负训练样本——通过拷贝现训练集,将正确天数增减一定天数得出训练集。并限定训练集的月份一定正确。
(5)构建训练集3:删去错误的负样本(删除条件:若当天有购买,不应设其label为0)
(6)随机打乱
(7)构建测试集1:对所有用户数目的 {'cate':30 / 101, 'date':range(31)}这样取遍所有组合值成行集合
(8)给train,test集构建action特征:# 用户从上次浏览或关注到现在的时间
(9)# one hot
(10)# 处理缺失数据
(11)# 筛选特征
(12)训练,预测Rank4
1
2
3
4
5
6
7
8
9
10
11
12好厉害!归纳下具体的:
1.算法核心:滑窗,特征构造,选择和获取,太多啦不展开了,直接看他的#README
#https://github.com/CortexFoundation/JDATA2
2.特征思考和构建方式:一是用户相关(长期-用户的消费水平和习惯,短期-周期性,近期需求),二是商品相关(用户的属性,比如消费水平等)
3.特征工程技巧。学到了很多!直接搬运:
#===================================================
(3.1)、利用用户和商品(商品属性)的共现信息,构建用户商品(商品属性)共现矩阵,通过矩阵分解算法,得到用户的K维度隐向量表示,表征用户商品购买偏好。
(3.2)、利用B榜选定训练集时序前的A榜数据训练模型,将该模型对于B榜的训练集和测试集的预测作为新的一维特征。(感觉有点像stack)
(3.3)、利用B榜选定训练集时序前的B榜部分数据训练模型,将该模型对于B榜的训练集和测试集的预测作为新的一维特征 (感觉有点像stack)
#===================================================
4.特征处理:使用pca,lda,nmf对商品,para2,para3特征进行了维度变换
采用Lightgbm模型,此模型效果要优于其他大部分模型。 样本构建及特征提取