–JDATA2018_learn

JDATA2018用户购买时间预测

本文是边复现边学的记录,鱼佬的代码还有好多没学会的,下次有空再更。

Learn_Skill

  • pandas.read_csv参数parse_dates=['a_date'])

    其中解析后的datetime类有如下操作:

    1
    2
    3
    4
    5
    order['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_pd
  • fillna的另一种姿势

    1
    train = train.replace({np.nan: 0.0})
  • 基础操作之融合

    1
    pd.merge(train, user_months[m], on='user_id', how='left')
  • 基础操作之排序

    1
    2
    3
    new_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
    2
    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'])

    完整代码

    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
    2
    aim_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模型,此模型效果要优于其他大部分模型。 样本构建及特征提取