数据加载
观察数据
查看数据的数据类型
数据中是否存储在缺失值
将order_dt转换成时间类型
查看数据的统计描述
在源数据中添加一列表示月份:astype(‘datetime64[M]‘)
import pandas as pd
import matplotlib.pyplot as plt
加载数据
df = pd.read_csv('./data/CDNOW_master.txt',header=None,sep='\s+',names=['user_id','order_dt','order_product','order_amount'])
# \s+表示任意多个空串值
# names指定原数据的列索引
查看数据的数据类型
df.info()
# 1.原数据中没有空值
# 2.order_dt不是时间类型
"""
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 69659 entries, 0 to 69658
Data columns (total 4 columns):
user_id 69659 non-null int64
order_dt 69659 non-null int64
order_product 69659 non-null int64
order_amount 69659 non-null float64
dtypes: float64(1), int64(3)
memory usage: 2.1 MB
"""
将order_dt转成时间序列类型
df['order_dt'] = pd.to_datetime(df['order_dt'],format='%Y%m%d')
df.info()
查看原始数据的统计描述
df.describe()
在源数据中添加一列表示月份
df['month'] = df['order_dt'].values.astype('datetime64[M]')
df.head()
# datetime64[M]表示的月份类型
统计每月的消费人数
用户每月花费的总金额
df.groupby(by='month')['order_amount'].sum()
# 绘制线形图
df.groupby(by='month')['order_amount'].sum().plot()
# 可以直接.plot生成线性图
所有用户每月的产品购买量
df.groupby(by='month')['order_product'].sum()
# 绘制线性图
df.groupby(by='month')['order_product'].sum().plot()
所有用户每月的消费总次数(用户在原数据中出现一次表示消费一次)
df.groupby(by='month')['user_id'].count()
统计每月的消费人数
# 方式一:通过nunique
df.groupby(by='month')['user_id'].nunique()
# nunique()统计去重之后的数量
# 方式2:分组的高级聚合
df.groupby(by='month')['user_id'].apply(lambda x:len(x.drop_duplicates()))
各个用户消费的总数量的直方分布图(消费商品的数量在100次之内的分布)
用户消费总金额和购买总数数量的统计描述
user_datas = df.groupby(by='user_id').sum()
df.groupby(by='user_id').sum().describe()
用户消费金额和消费次数的散点图
plt.scatter(user_datas['order_product'],user_datas['order_amount'])
plt.xlabel('order_product')
plt.ylabel('order_amount')
各个用户消费总金额的直方分布图(消费金额在1000之内的分布)
# 筛选各个用户消费总金额
df.groupby(by='user_id')['order_amount'].sum()
# 筛选各个用户消费总金额在1000之内的
user_amount = df.groupby(by='user_id').sum().query('order_amount < 1000')['order_amount']
# 绘制直方分布图
plt.hist(user_amount,bins=20)
各个用户消费总购买商品的数量的直方分布图(消费商品的数量在100次之内的分布)
user_product = df.groupby(by='user_id').sum().query('order_product < 100')['order_product']
plt.hist(user_product,bins=20)
用户第一次消费的月份分布和人数统计
df.groupby(by='user_id')['month'].min() # 用户第一次消费的月份分布
df.groupby(by='user_id')['month'].min().value_counts() # 统计每个月第一次消费用的人数
# 将首购对应的月份分布绘图
df.groupby(by='user_id')['month'].min().value_counts().plot()
用户最后一次消费的时间分布和人数统计
df.groupby(by='user_id')['month'].max()
df.groupby(by='user_id')['month'].max().value_counts()
# 绘图
df.groupby(by='user_id')['month'].max().value_counts().plot()
求出新老用户的占比
# 求出新老用户的占比
# 新用户:一次消费的用户
# 老用户:多次消费的用户
# 核心思路:将每一个用户的首购时间和最后一次消费时间求出,判断这两个时间是否一致
# 一致:新用户
# 不一致:老用户
# agg分组后进行多种不同形式的聚合操作
user_left = df.groupby(by='user_id')['order_dt'].agg(['min','max'])
user_left['min'] == user_left['max'] # true:新用户,False:老用户
user = (user_left['min'] == user_left['max']).value_counts() # 求出true和false的个数
old = user[0]
new = user[1]
new/old
分析得出每个用户的总购买量和总消费金额and最近一次消费的时间的表格rfm
rfm = df.pivot_table(index='user_id',aggfunc={'order_product':'sum','order_amount':'sum','order_dt':'max'})
rfm.head()
RFM模型设计
import numpy as np
# R表示客户最近一次交易时间的间隔
rfm['R'] = -(rfm['order_dt'] - rfm['order_dt'].max())/np.timedelta64(1,'D')
rfm.head()
# /np.timedelta64(1,'D')为了去除days
# 修改order_amount、order_product的列索引
rfm.rename(columns={'order_amount':"M",'order_product':'F'},inplace=True)
根据价值分层
def rfm_func(x):
# 存储的是三个字符串形式的0或者1
level = x.map(lambda x :'1' if x >= 0 else '0')
label = level.R + level.F + level.M
d = {
'111':'重要价值客户',
'011':'重要保持客户',
'101':'重要挽留客户',
'001':'重要发展客户',
'110':'一般价值客户',
'010':'一般保持客户',
'100':'一般挽留客户',
'000':'一般发展客户'
}
result = d[label]
return result
# df.apply(func):可以对df中的行或者列进行某种(func)形式的运算
rfm['label'] = rfm[['R','F','M']].apply(lambda x : x - x.mean()).apply(rfm_func,axis = 1)
rfm.head()
统计不同层次用户的个数
rfm.groupby(by='label').count()
统计每个用户每个月的消费次数
user_order_count_df = df.pivot_table(index='user_id',values='order_dt',aggfunc='count',columns='month').fillna(0)
统计每个用户每个月是否消费,消费记录为1否则记录为0
# 将上个需求返回的df中每一个元素(用户的消费次数)进行运算(如果元素值>=1说明消费记为1,否则记为0)
df_purchase = user_order_count_df.applymap(lambda x:1 if x >= 1 else 0)
df_purchase # 存储的就是用户每个月的是否消费的情况展示
将df_purchase中的原始数据0和1修改为new,unactive......,返回新的df叫做df_purchase_new
# 固定算法
def active_status(data):
status = [] # 某个用户每一个月的活跃度
for i in range(18):
# 若本月没有消费
if data[i] == 0:
if len(status) > 0:
if status[i-1] == 'unreg':
status.append('unreg')
else:
status.append('unactive')
else:
status.append('unreg')
# 若本月消费
else:
if len(status) == 0:
status.append('new')
else:
if status[i-1] == 'unactive':
status.append('return')
elif status[i-1] == 'unreg':
status.append('new')
else:
status.append('active')
return status
pivoted_status = df_purchase.apply(active_status,axis = 1)
pivoted_status.head()
每月【不同活跃】用户的计数
pivoted_status.apply(lambda x:pd.value_counts(x),axis=0).fillna(0)
转置进行最终结果的查看
pivoted_status.apply(lambda x:pd.value_counts(x),axis=0).fillna(0).T
原文:https://www.cnblogs.com/liubing8/p/12051314.html