Awesome
2018-KUAISHOU-TSINGHUA-Top13-Solutions
2018中国高校计算机大赛--大数据挑战赛 Top 13 Solutions
初赛A Top 2,初赛B Top 5
复赛Final 13
每一次相遇都是久别重逢,下一次站在答辩台上又是何年何月,对得起自己,对得起青春。
队友的RNN:https://github.com/totoruo/KuaiShou2018-RANK13-RNN
题意简述:给出用户在快手APP上1-30日的历史行为,预测接下来7天(31-37)的活跃用户。定义活跃为任意一张表出现过,不考虑冷启动。
框架思考
1. 等长滑动 [1,16] [2,17] ... [8,23] ---> Predict [15,30]
2. 不等长滑动 [1,16] [1,17] ... [1,24] ---> Predict [1,30]
特征工程:
Tips: 以下Feature都是较为通用的,但是在不等长框架2中,需要对所有涉及到距离的计算做平滑,即除以时间窗口的长度
对APP-LAUNCH、ACTION、VIDEO表
1.对时间序列进行编码
编码方式考虑两种:
a. 将用户活跃天数视为二进制数,按二进制方式对活跃天数进行加权,越接近预测日期权重越高,如6天的窗口,1,3,5 --- 101010 将其倒置,010101,转化为十进制数21
`ans += binary_day[i]*(2**i)`
b. 直接按离预测日期距离进行加权
`ans += binary_day[i]*(1/(end_date-i))`
2.对时间序列进行描述性统计
一级统计特征: mean,std,median,max,min,(max-min),mode,count,nunique (在APP表中,count==nunique)
二级统计特征: skew,kurt,mad
用户登录的频域周期性: Var(fft(X['day']))
用户登录的星期周期性: Get_Mode(X['week'])
3.对时间序列与预测日期进行时间天数交互
该用户最后一次登录距离预测日期的长度 end_date+1-x['day'].max()
该用户倒数第K次登录距离预测日期的长度 end_date+1-get_second_day(x,k)
最后一次和倒数第二次的距离 x['day'].max()-get_second_day(x,2)
4.差分一阶时间序列
用户最大/最小间隔多少天登录一次 Diff Max/Min
用户平均登录间隔 Diff Mean
用户登录间隔的稳定性 Diff Var
用户登录间隔的周期性 Var(fft(X['day']))
对ACTION表的特殊处理
1.对时间序列进行衰减系数编码
操作数/当前天数-预测日期的距离 sigma_ans += np.log(ans[i]/(window_len-i))
2.对时间序列与预测日期进行操作数交互
该用户最后一次/倒数第二次登录 观看Page、Action的分布 如看了3次Page 0,4次Page 1,2次Action 1,没有的行为用0填充
将多组行为拆成子图,即可实现统计User在不同页面的分布,如只在Page0发生的行为的描述性统计,mean,std等 (对Action)
该用户最后一次/K次操作当天,Count VIDEOID/AuthorID
最后一次和倒数第二次间隔中,Count VIDEOID/AuthorID
3.对Page,Action进行User的全局展开
统计每一种行为在该用户整个行为序列里的比例,如 5次点击Page 0,该用户共点击10次 Page 0,那么此处Ratio1 为0.5
统计每一种行为在当天用户里所有行为的比例,如 该用户900次点击 Page 0,当天共有1000次点击,那么此处Ratio2 为0.9
上述两种统计,可以有效防止刷单行为,正常的行为序列应当是较为平滑的点击序列,一旦出现峰值,如举报行为居多的,观看同一视频的,即可判定为刷单的特征
4.计算用户观看VIDEO的贡献序列
def GongXianDu(df):
d11 = df.set_index('video_id')
d11['gongxian_rate'] = df.groupby('video_id').size()
d11['gongxian_rate'] = d11['gongxian_rate'] / d11['video_watched_times']
meand = d11['gongxian_rate'].mean()
sumd = d11['gongxian_rate'].sum()
stdd = d11['gongxian_rate'].std()
skeww = d11['gongxian_rate'].skew()
kurtt = d11['gongxian_rate'].kurt()
return sumd,meand,stdd,skeww,kurtt
temp = train_act.groupby('user_id').apply(GongXianDu)
5.计算用户是否有追星行为
最喜欢的作者有无更新行为
用户看过的视频还有多少人爱看(区分小众与大众)
def FavAuthorCreate(df):
most_author = df.groupby('author_id').size().sort_values(ascending=False).index[0]
create_video_num = len(df[df['author_id']==most_author]['video_id'].unique())
watch_other_video_num = len(df[df['author_id']==most_author]['video_id'].unique())
watch_other_video = 1 if watch_other_video_num>1 else 0
return create_video_num , watch_other_video
对REGSITER表的挖掘
1.注册周期性,如周末的促销活动,最直观的Feature就是Week
2.周期性的交互,如在周末特定的Type组合
register['week'] * register['device_type']
register['week'] * register['register_type']
3.类别特征间的交互,如 register['device_type'] * register['register_type']
4.计算不同类别的使用人数,如 register_log.groupby(['register_type'])['user_id'].transform('count').values
可以计算device_type,week_rt,week_dt,rt_dt
5.计算不同类别的转化率(需滑窗计算),groupby(['count_label_ratio'])['regsiter_type','device_type'].transform('count').vaules
模型选择
Snake 的 糖尿病特征选择框架 https://github.com/luoda888/tianchi-diabetes-top12
在保留必选特征后(Encoder/FFT) 设置阈值产生两套特征
树模型: LGB 框架1
XGB 框架2
FFM : Xlearn 按特征重要性筛选TopK个特征后计算
xDeepFM 输入序列特征/Category特征
CNN/RNN 输入序列特征
模型融合
本题模型融合收益极高,我们尝试了3种方式进行模型融合,按效果来计算
Top 3 Stacking 没卵用,如果用同一套特征甚至掉分
Top 2 加权融合 相似性都是0.98 0.97左右,0.97可以有1个千的收益,0.98大概是7-8个万
Top 1 对半Blending 如用第一个滑窗测试,第二个滑窗测试,两折的Blending 收益是1.2个千
感言
首先感谢队友一直努力,到最后没有放弃,本来打算对这个题的思路写很多,但是想想自己还是菜了点,就算了。
最近这几个比赛,平安11,腾讯12,快手13,真的是10名以外的王者。
也有反思自己,很多时候挖特征的思路不太对,太喜欢一把梭,忽略了具体数据背景,忽略了具体变化
数据挖掘多的应该是自己的思考,而少一些套路性的东西。
当一切都有固定化的套路的时候,也少了很多乐趣。
快手群里还是氛围不错的,Kesci平台的态度确实也是我目前见过比较好的。
或许前天中午那个LGB的模型能跑出来,现在肯定是可以Top10的。
遗憾也有,咽下肚。
皇图霸业谈笑间,不胜人生一场醉。
走起,醉去!