现在有需求需要统计不同付费等级玩家的充值间隔差异,
简单来说就是玩家平均隔多久充一笔钱。
这需要对单个玩家统计前后两笔订单时间的差值。
订单原始数据如下结构:
主要就是用户id和该笔订单的时间,现在要做的事就是按照uid分组,再按照时间排序,
然后第二笔时间减第一笔时间,第三笔时间减第二笔时间...,得到所有订单的间隔。
最后再统计这个间隔,求个平均值和中位数什么的。
这个需求看起来很简单,核心其实就是知道要怎么做到下一行减上一行。
在BigQuery中需要用到以前讲过的分析函数。
核心就是lag这个函数:文档指路。
LAG(ts) OVER (PARTITION BY uid ORDER BY ts )
这个函数可以拿到上一行的数据,然后用date_diff相减就好了。
SELECT
uid,
ts,
LAG(ts) OVER (PARTITION BY uid ORDER BY ts ),
DATE_DIFF(DATE(ts), DATE(LAG(ts) OVER (PARTITION BY uid ORDER BY ts )), day) AS day
FROM
充值表
WHERE
DATE(ts, '+08') BETWEEN "2021-1-1"
AND "2021-1-31"
ORDER BY
1,
2
可以看到上图中fo_就是左边ts的下一行,如果玩家只有一笔充值,那就是null。
拿到间隔后该干嘛就干嘛,没啥好讲的,接下来说说pandas怎么实现这个需求。
核心是shift这个函数,这个函数也可以拿到上一行的数据,
准备来说是偏移量下的数据,不过默认就是上一行。
不过相减前还有先按照uid分组
iap['interval'] = iap.groupby('uid').apply(lambda x:(x['ts'] - x['ts'].shift()).dt.days).reset_index(drop=True)
iap
这一行的东西有点多,详细讲一下。
首先groupby函数用来分组,在调用apply函数对分组内的数据做处理。
lambda是匿名函数,内容不多就不写单独的函数了。
然后是本身和本身的shift()相减,就得到了前后两笔订单的差值。
但这个差值实际是一个timedelta64[ns]的Series。
我们实际需要的是day,这里要用到Series.dt.days属性,文档指路。
不过这里有点问题,实际文档里属性的是day而不是days,但是直接调day是会报错的。
这里显示的是TimedeltaProperties,而文档里是搜不到这个关键词的。
不过有pandas.Timedelta.days这个属性,但如果不加.dt而直接掉days也是会报错的。
猜测dt属性会把根据数据内容将该列转为对应的时间类型,这里是转为了Timedelta再调用它的days属性。
然后注意的是我们要把分组后的Series赋给原dataframe,直接赋值是不可以的。
因为groupby后是一个二重索引。
必须要是和原索引相等的Series才能正确赋值。
所以还需要用到reset_index()这个函数。
直接reset_index()会转为一个dataframe。
二级索引会转为两列,但我们只需要序数索引那一列记好了,这里需要用到drop参数,表示是否将不需要的索引删掉。
现在在直接赋值给iap['interval']就没什么问题了。