无意中看到非常不错的一篇文章《如何七周成为数据分析师》by秦路 2017-7-15。此处记录1)精彩的地方,2)其它的想法
如下数据
df = pd.Dataframe({'uid':['a', 'b','a','b','a'],
'col1': [1,2,1,2,2],
'col2':[11, 12, 13, 14, 15],
'col3':[51,22,23,33,44]})
# print(df)
uid month order Money
0 a 1 11 51
1 b 2 12 22
2 a 1 13 23
3 b 2 14 33
4 a 2 15 44
1)做RFM模型;步骤很简洁。
def yingshe(y):
tag = y.apply(lambda x: '1' if x >0 else '0')
taga = tag.col1 + tag.col2 + tag.col3
m = {
'111':'重要价值客户',
'011':'重要保持客户',
'101':'重要发展客户',
'001':'重要挽留客户',
'110':'一般价值客户',
'010':'一般保持客户',
'100':'一般发展客户',
'000':'一般挽留客户'
}
result = m[taga]
return result
df['tag'] = df.loc[:,['col1', 'col2', 'col3']].apply(lambda x: x - x.mean()).apply(yingshe, axis=1)
# print(df)
uid col1 col2 col3 tag
0 a 1 11 51 重要挽留客户
1 b 2 12 22 一般发展客户
2 a 1 13 23 一般挽留客户
3 b 2 14 33 一般价值客户
4 a 2 15 44 重要价值客户
# %timeit df[['col1', 'col2', 'col3']]
292 µs ± 929 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
# %timeit df.loc[:,['col1', 'col2', 'col3']]
290 µs ± 1.26 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
2)“多少用户仅消费1次” VS 另一种写法的速度
"""原始的"""
def test():
a = df.groupby('uid').col1.agg(['min', 'max'])
(a['min'] ==a['max']).value_counts()
# %timeit test()
976 µs ± 2.11 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
"""另一种"""
%timeit (df.groupby('uid').col1.min() == df.groupby('uid').col1.max()).value_counts(normalize=True)
# %timeit 结果
986 µs ± 2.22 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
"""另一种"""
%timeit (df.groupby('uid').min() == df.groupby('uid').max()).col1.value_counts(normalize=True)
# %timeit 结果
1.73 ms ± 6.65 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
3) 需要注意count函数不统计None/np.NaN值
lst = pd.Series([1, 2, 0, False, None, np.NaN, 14]) # print(lst.count()) 5 lst = pd.Series([1, 2, 0, False, 14]) # print(lst.count()) 54)复购率 VS 回购率概念
5)Dataframe搭配value_counts回购率:相邻2个时间单位里的的消费行为;
复购率:1个时间单位内>=2次的消费行为;
客户的品骏购买周期:即by客户分组后,mean(相邻两次购买时间差值)
其它一些自定义指标:例如 上 个 时 间 单 位 不 活 跃 本 个 时 间 单 位 活 跃 起 来 了 frac{上个时间单位不活跃}{本个时间单位活跃起来了} 本个时间单位活跃起来了上个时间单位不活跃等;原文作者的定义需要注意:例如回购率,打比方1月2月联系消费,则回购记在1月而不是2月——这一点我大受震撼。
.pd.Dataframe.apply(lambda x: pd.value_counts(x), axis=0) # 统计axis=0单位下的value的个数 .pd.Dataframe.apply(pd.value_counts, axis=0)6)新老增加标签
"""标签一共有 unreg、new、unactive、return、active"""”
def active_status(data):
status = []
for i in range(number_of_columns):
if len(status) !=0:
if data[i] != 0:
if data[i-1] == 'unreg':
status.append('new')
elif data[i-1] == 'unactive':
status.append('return')
else:
status.append('active')
else:
if data[i-1] == 'unreg':
status.append('unreg')
else:
status.append('unactive')
else:
if data[i] == 0:
status.append('unreg')
else:
status.append('new')
return status
df_of_status = df.apply(lambda x: active_status(x), axis=1)
# 或者
df_of_status = df.apply(active_status, axis=1)
7) 原文的函数不正确OR可以更快速
7.1 回流函数需要修正
# 原代码 return_rate = purchase_status_counts.apply(lambda x: x/x.sum(), axis=1) # 应改为 return_rate = purchase_status_counts.apply(lambda x: x/x.sum(), axis=0)7.2 生成计算新字段的代码可以优化
"""原函数用的 `lambda`形式"""
def test1(df):
col3max = df.col3.max()
df['prop'] = df.apply(lambda x: x.col3 / col3max, axis=1)
# %timeit test1(df)
471 µs ± 3.52 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
"""优化版函数"""
def test2(df):
col3max = df.col3.max()
df['prop'] = df.col3 / col3max
# %timeit test2(df)
149 µs ± 660 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
def test3(df):
df['prop'] = df.col3 / df.col3.max()
# %timeit test3(df)
148 µs ± 777 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
· apply和transform的区别链接。
"""生成最小值的字段"""
# 使用`merge`形式
def m(df):
df_new = pd.merge(left=df, right=df.groupby('uid').col3.min().reset_index(),
how='inner', on='uid',
suffixes=('', '_min'))
# %timeit m(df)
1.54 ms ± 14.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
"""优化版函数"""
def m2(df):
df['min'] = df.groupby('uid').col3.transform(min)
# %timeit m2(df)
478 µs ± 1.37 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
8)原文的摘录函数
# 计算生命周期的时候
(df.groupby('uid').col2.max() - df.groupby('uid').col2.min())/np.timedelta64[1, 'D'].hist(bins=15)
bin = [0, 3, 7, 15, 30, 60, 90, 180, 365]
df['bins'] = pd.cut(df.col3, bins=bin)
def diff_neig(group):
d = group.col3_diff - gropu.col3_diff.shift()
return d
df['col3_diff'] = df.col3 - df.col3.min()
dfnew = df.groupby('uid').apply(diff_neig)
假若大家有兴趣,不妨多做几个分析假设,看能不能用Python挖掘出更有意思的数据,1月、2月、3月的新用户在留存率有没有差异?不同生命周期的用户,他们的消费累加图是什么样的?消费留存,划分其他时间段怎么样?
你若想要追求更好的Python技术,可以把上述的分析过程都封装成函数。当下次想要再次分析的时候,怎么样只用>几个函数就搞定,而不是继续重复码代码。
这里的数据只是用户ID,消费时间,购买量和消费金额。如果换成用户ID,浏览时间,浏览量,能不能直接套用?浏览变成评论、点赞又行不行?消费行为变成用户其他行为呢?我可以明确地告诉你,大部分代码只要替换部分就能直接用了。把所有的结果分析出来需要花费多少时间呢?



