精品旅行服务成单预测(皇包车)比赛记录

精品旅行服务成单预测比赛是DC举办的“第二届智慧中国杯”的第一个比赛,主要是通过用户的历史行为数据对待预测用户是否购买精品旅游服务进行预测。具体的比赛背景和数据介绍可以参考比赛说明。

传送门:精品旅行服务成单预测

最近半年也参加了几个比赛,但是成绩也并不是很突出,所以也一直没有做过总结。趁着过年这几天比较空,将“皇包车”比赛的思路做一个小结,方便自己以后查看。比赛的大神很多,自己写的可能存在很多不足之处,希望能和大家多多交流。

博客只是将自己的思路和使用的特征情况做一个说明,具体的代码可以查看我的GitHub

--------------------------  一个有态度的分割线  ----------------------------

比赛提供的数据主要有(a)用户个人信息数据 (b)用户行为信息数据 (c)用户历史订单数据 (d)带预测订单数据和(e)评论数据。

-------------------------- 特征提取(特征工程) ---------------------------

对于用户个人信息数据,考虑到不同年龄段,性别和省份的人群的消费水平不同,在处理的时候直接对这些信息做ONE-HOT处理(把缺失的数据作为单独的类别)。(并没有发现某一类别的人具有较高的精品服务购买可能,也有可能是自己挖掘的不够仔细)

对于用户行为信息数据,行为类型一共有9个,其中1是唤醒app;2~4是浏览产品,无先后关系;5~9则是有先后关系的,从填写表单到提交订单再到最后支付对于这些数据,提取了各个行为占据行为总数的比值。

# 统计每一种点击次数的占比
for i in range(1, 10):
    train['click_{}'.format(i)] = train['userid'].apply(lambda x: float(train_click_[(x, i)]/train_click_count[x]) if (x,i) in train_click_.keys() else 0)
    test['click_{}'.format(i)] = test['userid'].apply(lambda x: float(test_click_[(x,i)]/test_click_count[x]) if (x,i) in test_click_.keys() else 0)
train.head()

特定时刻的行为(最后一次Type,倒数第二次Type,倒数第三次Type,第一次Typ

def get_type(df, userid):
    """
    获得特定次数行为
    :param df: train_A or test_A
    :param userid: userid to use
    :return: 特定次数的行为结果
    """
    lastType = 0
    lastType2 = 0
    lastType3 = 0
    firstType = 0
    action_num = len(df[df['userid']==userid])
    if action_num>=1:
        lastType = df[df['userid']==userid].iloc[-1]['actionType']
    if action_num>=2:
        lastType2 = df[df['userid']==userid].iloc[-2]['actionType']
    if action_num>=3:
        lastType3 = df[df['userid']==userid].iloc[-3]['actionType']
    if action_num>=4:
        firstType = df[df['userid']==userid].iloc[0]['actionType']
    return lastType, lastType2, lastType3, firstType

距离各个行为最近的时间,(这里直接使用的是处理过的时间,你们也可以对这些时间进行处理,还原为原来的时间日期再进行计算,有可能效果会更好)

def get_time(df, userid):
    """
    获得距离各个行为最近的时间
    :param df: train_A, test_A
    :param userid: userid to use
    :return: 距离各个行为最近的时间
    """
  type1_time = 0
  type2_time = 0
  type3_time = 0
  type4_time = 0
  type5_time = 0
  type6_time = 0
  type7_time = 0
  type8_time = 0
  type9_time = 0
  userid_df = df[df['userid'] == userid]
  if len(userid_df)>=1:
      if len(userid_df[userid_df['actionType']==1])>0:
          type1_time = userid_df.iloc[-1]['actionTime'] - userid_df[userid_df['actionType']==1].iloc[-1]['actionTime']
      if len(userid_df[userid_df['actionType']==2])>0:
          type2_time = userid_df.iloc[-1]['actionTime'] - userid_df[userid_df['actionType']==2].iloc[-1]['actionTime']
      if len(userid_df[userid_df['actionType']==3])>0:
          type3_time = userid_df.iloc[-1]['actionTime'] - userid_df[userid_df['actionType']==3].iloc[-1]['actionTime']
      if len(userid_df[userid_df['actionType']==4])>0:
          type4_time = userid_df.iloc[-1]['actionTime'] - userid_df[userid_df['actionType']==4].iloc[-1]['actionTime']
      if len(userid_df[userid_df['actionType']==5])>0:
          type5_time = userid_df.iloc[-1]['actionTime'] - userid_df[userid_df['actionType']==5].iloc[-1]['actionTime']
      if len(userid_df[userid_df['actionType']==6])>0:
          type6_time = userid_df.iloc[-1]['actionTime'] - userid_df[userid_df['actionType']==6].iloc[-1]['actionTime']
      if len(userid_df[userid_df['actionType']==7])>0:
          type7_time = userid_df.iloc[-1]['actionTime'] - userid_df[userid_df['actionType']==7].iloc[-1]['actionTime']
      if len(userid_df[userid_df['actionType']==8])>0:
          type8_time = userid_df.iloc[-1]['actionTime'] - userid_df[userid_df['actionType']==8].iloc[-1]['actionTime']
      if len(userid_df[userid_df['actionType']==9])>0:
          type9_time = userid_df.iloc[-1]['actionTime'] - userid_df[userid_df['actionType']==9].iloc[-1]['actionTime']
  return type1_time, type2_time, type3_time, type4_time, type5_time, type6_time, type7_time, type8_time, type9_time

就算距离最近的行为9,3,5,8的距离

def get_distance(df, userid):
    """ 求距离最近的9,3,5,8的距离"""
    distance_to_3 = 0
    distance_to_5 = 0
    distance_to_8 = 0
    distance_to_9 = 0
    dist_df = df[df['userid']==userid]
    len_act = len(dist_df)
    listType = dist_df['actionType'].tolist()
    if len_act>=1:
        if len(dist_df[dist_df['actionType']==3])>0:
            findloc = [a for a in range(len_act) if listType[a]==3][-1]
            distance_to_3 = int(len_act - findloc)
        if len(dist_df[dist_df['actionType']==5])>0:
            findloc = [a for a in range(len_act) if listType[a]==5][-1]
            distance_to_5 = int(len_act - findloc)
        if len(dist_df[dist_df['actionType']==8])>0:
            findloc = [a for a in range(len_act) if listType[a]==8][-1]
            distance_to_8 = int(len_act - findloc)
        if len(dist_df[dist_df['actionType']==9])>0:
            findloc = [a for a in range(len_act) if listType[a]==9][-1]
            distance_to_9 = int(len_act - findloc)
            
    return distance_to_3, distance_to_5, distance_to_8, distance_to_9
计算用户时间间隔相关的数据(代码较长,这里不放了,可以去GitHub上看):时间间隔的均值,最小值,方差;最后一个时间间隔的值,倒数第二个时间间隔,以及用户特定行为时间间隔的方差,均值,最小最大值等。

对于用户历史订单数据,数据共有7列,分别是用户id,订单id,订单时间,订单类型,旅游城市,国家,大陆。这里在处理的时候,提取了ever_buy特征,即在之前是否购买了精品旅游服务。

对于用户的评论数据,计算了用户的平均评分等指标。

---------------------  特征处理 ----------------------

俗话说,好的特征工程决定成绩的上限,模型只能无限逼近这个上限。(和大神比,特征工程做的太渣了......)

对于上述的特征,主要是做两类处理(1)对于类别变量,对其进行one-hot处理(2)对于数值型变量进行标准化处理

标准化处理时,先对NAN值进行填充,填充方法有均值,中值填充等。这里主要是对平均得分进行填充,采用的是均值填充。

数据的正负样本比例在1:5左右,可以考虑一些数据平衡的方法,如降采样,过采样等。(尝试过对数据进行过采样处理,但是并没有显著提高AUC值)

---------------------  模型实现  --------------------------

最后使用的模型只要是Xgboost和Lightgbm,调参之后的B榜成绩在0.956+, B榜排名79/1073(距离大神还有好大的距离......555)

前10重要性特征(其他重要性参考GitHub对应数据文件):

feature,score
timespan_mean,2962
timespan_last2,2766
timespan_first,2507
timespan_last,2474
timespan_last4,2470
click_6,2426
type1_time,2322
timespan_last3,2282
min_5_ts,2237
click_5,2189


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值