项目实战--用户消费数据分析

Posted 胜天半月子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了项目实战--用户消费数据分析相关的知识,希望对你有一定的参考价值。


引入包

本项目所用数据为【密码:pfj6】:CDNOW_master.txt

import numpy as np
import pandas as pd
from pandas import DataFrame,Series
import matplotlib.pyplot as plt

# CDNOW_master.txt
# 支持中文
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

一、数据预处理

  • 本阶段需求
  • 读取数据集
df = pd.read_csv('./CDNOW_master.txt')
df.head()

消除列的索引,使用指定索引

# "\\s+"则表示匹配任意多个上面的字符 ⭐
df = pd.read_csv('./CDNOW_master.txt',header=None,sep='\\s+',names=['user_id','order_dt','order_product','order_amount'])
df.head()

  • 查看数据类型
df.info()

  • 将order_dt转换成时间序列
df['order_dt'] = pd.to_datetime(df['order_dt'],format='%Y%m%d')
df.info()

  • 查看数据的统计描述
df.describe()

  • 在源数据中添加一列表示月份:astype(datetime64[‘M’])
df['month'] = df['order_dt'].astype('datetime64[M]')
df.head()

astype的用法:np.astype()

Python中与数据类型相关函数及属性有如下三个:type/dtype/astype

  • type() 返回参数的数据类型
  • dtype 返回数组中元素的数据类型
  • astype() 对数据类型进行转换

二、按月对数据分析

  • 用户每月花费的总金额
df.groupby(by='month')['order_amount'].sum()

  • 绘制曲线图
df.groupby(by='month')['order_amount'].sum().plot()

  • 对上图进行细化
plt.figure(figsize=(8,5)) 
plt.plot(df.groupby(by='month')['order_amount'].sum())
plt.xlabel('order_dt')
plt.ylabel('sum of amount')
plt.title('用户每月花费的总金额')
plt.legend()

  • 所有用户每月的产品购买数量
df.groupby(by='month')['order_product'].sum()

df.groupby(by='month')['order_product'].sum().plot()

  • 所有用户每月消费的总次数
df.groupby(by='month')['user_id'].count()

  • 统计每月消费的人数 【有人会在同一天消费多次】
  • unique():去重
  • nunique():去重并统计个数
df.groupby(by='month')['user_id'].nunique()


三、用户个体消费数据分析

  • 所有用户消费总金额和消费总购买量的统计描述
df['order_product'].sum()

167881

df['order_amount'].sum()

2500315.6300000004

  • 各个用户消费金额和香消费产品数量的散点图
user_amount = df.groupby(by='user_id')['order_amount'].sum()
user_product = df.groupby(by='user_id')['order_product'].sum()
plt.figure(figsize=(8,8))
plt.scatter(user_product,user_amount)
plt.xlabel('product')
plt.ylabel('amount')

  • 各个用户消费总金额的分布直方图(amount在1000之内)
df.groupby(by='user_id').sum()

df.groupby(by='user_id').sum().query('order_amount <= 1000')

query的使用方法

  1. pandas 查询函数query的用法说明
  2. Pandas query 的用法, df.query
  3. panda 中query 的用法
order_amount_1000 = df.groupby(by='user_id').sum().query('order_amount <= 1000')['order_amount']
order_amount_1000

  • 绘出直方图
plt.hist(order_amount_1000,bins=50)

上述结果大部分的消费在(0. , 19.9938)之间,有6.079e+03个人

  • 各个用户消费的总数量的分布直方图(消费商品的数量在100次之内的分布)
user_product_100 = df.groupby(by='user_id').sum().query('order_product <= 100')['order_product']
plt.hist(user_product_100,bins=30)


四、用户消费行为分析

  • 用户第一次消费的月份分布,和人数统计

如何判定用户第一次消费的月份?

  • 用户消费的最小值就是用户首次消费的月份
# 月份分布
df.groupby(by='user_id')['month'].min()

人数统计
# value_counts() 用来统计Seris中不同人数出现的次数
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().value_counts()

df.groupby(by='user_id')['month'].max().value_counts().plot()

  • 新老客户的占比
  • 消费一次为新用户
  • 消费多次为老用户
  • 判定用户消费的次数(1次还是多次)
    • 求出用户第一次和最后一次消费的时间,若时间相同,则表示用户只消费了一次,否则表示消费多次
# agg用于将分组后的结果进行多种不同形式的聚合操作
first_last_order_dt = df.groupby(by='user_id')['order_dt'].agg(['min','max'])
first_last_order_dt.head()

agg函数的使用:

  1. 【Python】Pandas中的宝藏函数-agg()
  2. Python - Pandas系列-最强的agg解释!⭐⭐
(first_last_order_dt['min'] == first_last_order_dt['max']).value_counts() 
# True:只消费一次--新用户  False:消费多次--老用户

True 12054
False 11516
dtype: int64

  • 求出每个用户的总购买量和总消费金额and最后一次消费的时间的表格rfm
rfm = df.groupby(by='user_id').sum()
rfm.head()

# 最后消费一次的时间
user_recently_order_dt = df.groupby(by='user_id')['order_dt'].max()
rfm['R']=user_recently_order_dt
rfm.head()

  • R表示客户最近一次交易的时间间隔
    • /np.timedelta64(1,‘D’):去除days
  • F表示客户购买的商品数量 F越大,表示客户交易越频繁,反之表示客户交易不够活跃
  • M表示客户交易的金额 M越大,表示客户价值越高,反之价值越低
  • 将R,F, M,作用到rfm中
rfm.columns = ['F','M','R']
rfm

# R : 表示客户最近一次交易的时间间隔
# 时间间隔 = 所有时间的最大值 - 客户最后一次交易的最大值
rfm['R'] = df['order_dt'].max() - rfm['R']
rfm

# / np.timedelta64(1,'D'):取出days
rfm['R'] = rfm['R'] / np.timedelta64(1,'D')
rfm.head()

  • 划分客户类型⭐⭐
# rfm分层算法
def rfm_func(x):
    # 存储的是三个字符串形式的0或者1
    # -6.122656	-94.310426	177.778362  ==》 '0'  '0'  '1'
    level = x.map(lambda x:'1' if x >= 0 else '0')
    label = level['R'] + level.F + level.M # '100'
    d = {
        '111':'重要价值客户',
        '011':'重要保持客户',
        '101':'重要挽留客户',
        '001':'重要发展客户',
        '110':'一般价值客户',
        '010':'一般保持客户',
        '100':'一般挽留客户',
        '000':'一般发展客户',
    }
    result = d[label] # d['100']
    # result ==》 '一般挽留客户'
    return result

# df.apply(func) :apply是DataFrame的运算工具  可以对df中的行或列进行某种func形式的运算
rfm['label'] = rfm.apply(lambda x:x-x.mean(),axis=0).apply(rfm_func,axis=1)
rfm.head()   


五、用户的生命周期

  • 统计每个用户每个月的消费次数
# 每个用户消费在所有时间内的消费次数
df.pivot_table(index='user_id',values='order_dt',aggfunc='count').head()

df.pivot_table(index='user_id',values='order_dt',aggfunc='count',columns='month')

user_month_order_count = df.pivot_table(index='user_id',values='order_dt',aggfunc='count',columns='month',fill_value=0)
user_month_order_count.head()

  • 统计出每个用户每个月是否消费,消费记录为1 否则为0
  • applymap()函数用于对DataFrame中的每一个元素执行相同的函数操作
  • apply()函数主要用于对DataFrame中的某一column或row中的元素执行相同的函数操作。
df_purchase = user_month_order_count.applymap(lambda  x:1 if x>=1 else 0)
df_purchase.head()

  • 对每月得用户活跃成分进行用户划分⭐⭐⭐
# 将df_purchase中的原始数据0和1修改为new,unactive ...,返回的df叫做df_purchase_new

# 固定算法
# data :每一行数据(某一个用户在不同月份的消费记录)
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] == 'active':
                    status.append('return')
                elif status[i-1] == 'unreg':
                    status.append('new')
                else:
                    status.append('active')
    return status


# 每一行作为参数传入active_status
pivoted_status = df_purchase.apply(active_status,axis=1)
pivoted_status.head()

  • 需要将上述返回的Series封装到DataFrame中⭐⭐
pivoted_status.values

pivoted_status.values.tolist()

df_purchase_new = DataFrame(data=pivoted_status.values.tolist(),index=df_purchase.index,columns=df_purchase.columns)
df_purchase_new.head()

  • 每月【不同活跃】用户的计数⭐

purchase_status_ct = df_purchase_new_apply(lambda:pd.value_counts(x)).fillna(0)
转置进行最终结果的查看

df_purchase_new.apply(lambda x:pd.value_counts(x))

  • 将NaN用0填充
df_purchase_new.apply(lambda x:pd.value_counts(x)).fillna(0)

  • 翻转
df_purchase_new.apply(lambda x:pd.value_counts(x)).fillna(0).T


以上是关于项目实战--用户消费数据分析的主要内容,如果未能解决你的问题,请参考以下文章

Express实战 - 应用案例- realworld-API - 路由设计 - mongoose - 数据验证 - 密码加密 - 登录接口 - 身份认证 - token - 增删改查API(代码片段

Flink实战系列Flink 1.14.0 消费 kafka 数据自定义反序列化器

概念+实战讲解!一文带你了解RFM模型kaggle项目实战分享数据分析

实战Spring4+ActiveMQ整合实现消息队列(生产者+消费者)

项目实战中遇到的问题

python数据分析案例实战——融360客户贷款风险预测(信用卡)