京东JData算法大赛——高潜用户购买意向预测

来源:互联网 发布:域名中cn代表什么 编辑:程序博客网 时间:2024/05/20 10:54

赛题分析

京东提供了用户在2016-02-01-2016-04-15时间区域内用户对商品的行为评价等数据,预测2016-04-16-2016-04-20时间区间内用户的下单情况。
赛题和阿里的第一个竞赛天猫推荐竞赛差不多,记得那时候也有个好心的同学提供了代码的框架,自己胡改一通还进了复赛,总之学习到很多东西。同学们可以找找当时的资料看看,不过现在大家的水平比那时候可高多了。
作为不严谨的效果一般的start code,其目的是为了帮助像我当时一样苦于无思路的朋友们入门这个竞赛,同时希望大家能够取得好成绩并且有所收获。
本文介绍如何用python实现:
  • 如何构造训练集/测试集
  • 时间滑动窗口特征的构造
  • 评测代码
  • 应用xgboost模型

类别特征处理

pandas处理特征非常好用,如下代码处理用户属性表,利用pd.get_dummies方法将类别特征进行编码。
def convert_age(age_str):    if age_str == u'-1':        return 0    elif age_str == u'15岁以下':        return 1    elif age_str == u'16-25岁':        return 2    elif age_str == u'26-35岁':        return 3    elif age_str == u'36-45岁':        return 4    elif age_str == u'46-55岁':        return 5    elif age_str == u'56岁以上':        return 6    else:        return -1def get_basic_user_feat():    dump_path = './cache/basic_user.pkl'    if os.path.exists(dump_path):        user = pickle.load(open(dump_path))    else:        user = pd.read_csv(user_path, encoding='gbk')        user['age'] = user['age'].map(convert_age)        age_df = pd.get_dummies(user["age"], prefix="age")        sex_df = pd.get_dummies(user["sex"], prefix="sex")        user_lv_df = pd.get_dummies(user["user_lv_cd"], prefix="user_lv_cd")        user = pd.concat([user['user_id'], age_df, sex_df, user_lv_df], axis=1)        pickle.dump(user, open(dump_path, 'w'))    return user

滑动窗口特征

赛题的要求是预测未来几天用户是否购买某个类目下的商品,经过简单的分析大概有30%的购买是有过行为记录的,所以我们的重点是预测在用户在有过行为记录下的购买情况。

我们现在有用户浏览/点击/购物车等信息的日志,比较简单特征提取方法有:

  • 滑动窗口
  • 时间衰减

在这个不严谨的start code中,我利用滑动窗口处理行为数据。可能有些人要问,什么叫滑动窗口,简单的可以这样理解。用户在购买商品之前,可能会对商品已经有过不同的行为,近期的行为影响较大,远期的行为影响较少。建立在这个逻辑下,我们可以统计不同时间区间内用户的行为累积。

示例代码: 统计时间区间内行为累积

def get_action_feat(start_date, end_date):    dump_path = './cache/action_accumulate_%s_%s.pkl' % (start_date, end_date)    if os.path.exists(dump_path):        actions = pickle.load(open(dump_path))    else:        actions = get_actions(start_date, end_date)        actions = actions[['user_id', 'sku_id', 'type']]        df = pd.get_dummies(actions['type'], prefix='%s-%s-action' % (start_date, end_date))        actions = pd.concat([actions, df], axis=1)  # type: pd.DataFrame        actions = actions.groupby(['user_id', 'sku_id'], as_index=False).sum()        del actions['type']        pickle.dump(actions, open(dump_path, 'w'))    return actions

统计距离预测开始日期前1、2、3、5、7、10、15、21、30的行为累积,别问我为什么这样设计,随手写的。
actions = Nonefor i in (1, 2, 3, 5, 7, 10, 15, 21, 30):    start_days = datetime.strptime(train_end_date, '%Y-%m-%d') - timedelta(days=i)    start_days = start_days.strftime('%Y-%m-%d')    if actions is None:        actions = get_action_feat(start_days, train_end_date)    else:        actions = pd.merge(actions, get_action_feat(start_days, train_end_date), how='left',on=['user_id', 'sku_id'])

累积特征

start_code中还用到了用户和商品的购买率等累积特征,代码就不贴了。克隆项目即可。

训练集/测试集划分

训练集: [t, t+30] [t+31, t+35]

测试集: [t+5, t+35] [t+36, t+40]

评测代码

由于线上一天只能提交两次,如果需要不断的优化效果,就需要本地的评测代码。
def report(pred, label):    actions = label    result = pred    # 所有用户商品对    all_user_item_pair = actions['user_id'].map(str) + '-' + actions['sku_id'].map(str)    all_user_item_pair = np.array(all_user_item_pair)    # 所有购买用户    all_user_set = actions['user_id'].unique()    # 所有品类中预测购买的用户    all_user_test_set = result['user_id'].unique()    all_user_test_item_pair = result['user_id'].map(str) + '-' + result['sku_id'].map(str)    all_user_test_item_pair = np.array(all_user_test_item_pair)    # 计算所有用户购买评价指标    pos, neg = 0,0    for user_id in all_user_test_set:        if user_id in all_user_set:            pos += 1        else:            neg += 1    all_user_acc = 1.0 * pos / ( pos + neg)    all_user_recall = 1.0 * pos / len(all_user_set)    print '所有用户中预测购买用户的准确率为 ' + str(all_user_acc)    print '所有用户中预测购买用户的召回率' + str(all_user_recall)    pos, neg = 0, 0    for user_item_pair in all_user_test_item_pair:        if user_item_pair in all_user_item_pair:            pos += 1        else:            neg += 1    all_item_acc = 1.0 * pos / ( pos + neg)    all_item_recall = 1.0 * pos / len(all_user_item_pair)    print '所有用户中预测购买商品的准确率为 ' + str(all_item_acc)    print '所有用户中预测购买商品的召回率' + str(all_item_recall)    F11 = 6.0 * all_user_recall * all_user_acc / (5.0 * all_user_recall + all_user_acc)    F12 = 5.0 * all_item_acc * all_item_recall / (2.0 * all_item_recall + 3 * all_item_acc)    score = 0.4 * F11 + 0.6 * F12    print 'F11=' + str(F11)    print 'F12=' + str(F12)    print 'score=' + str(score)

xgboost模型

为什么选择xgboost模型,因为树模型对特征处理的要求不高而且效果也相当不错,不管是类别特征,连续特征效果都很好。在Kaggle竞赛中,该模型通常能取得较好成绩。
user_index, training_data, label = make_train_set(train_start_date, train_end_date, test_start_date, test_end_date)X_train, X_test, y_train, y_test = train_test_split(training_data.values, label.values, test_size=0.2, random_state=0)    dtrain=xgb.DMatrix(X_train, label=y_train)dtest=xgb.DMatrix(X_test, label=y_test)param = {'max_depth': 6, 'eta': 0.05, 'silent': 1, 'objective': 'binary:logistic'}num_round = 309param['nthread'] = 4plst = param.items()plst += [('eval_metric', 'logloss')]evallist = [(dtest, 'eval'), (dtrain, 'train')]bst=xgb.train(plst, dtrain, num_round, evallist)sub_user_index, sub_trainning_data = make_test_set(sub_start_date, sub_end_date,)sub_trainning_data = xgb.DMatrix(sub_trainning_data.values)y = bst.predict(sub_trainning_data)

全部代码链接:https://github.com/foursking1/jd

数据官网下载:http://www.datafountain.cn/projects/jdata/










原创粉丝点击