【數據分析案例】用戶消費行為

"""
user_ud 用戶ID
order_dt: 購買日期
order_products: 購買產品數
order_amount: 購買金額
"""

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


pd.set_option('display.max_columns', None)   #顯示完整的列
pd.set_option('display.max_rows', None)  #顯示完整的行


plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤


columns = ['用戶ID','購買日期','購買產品數','購買金額']


data = pd.read_table('CDNOW_master.txt',names=columns,sep='\s+')  # names設置表頭   \s+任意的空字元串




# 查看是否存在缺失值
# print(data.info())

# order_dt: 購買日期 轉換成日期類型

# def time_style(x):
#    time = str(x)[0:4] + "-" +  str(x)[4:6]  + "-" + str(x)[6:8]
#    return time
# data['購買日期'] = data['購買日期'].apply(time_style)

data['購買日期'] = pd.to_datetime(data['購買日期'],format="%Y%m%d")
# print(data.head(3).dtypes)

# 計算每個用戶購買商品的平均數量
# print(data.groupby('用戶ID')['購買產品數'].mean())

# 計算所每個用戶購買商品的平均花費
# print(data.groupby('用戶ID')['購買金額'].mean())

# describe是描述統計 # 計算所有用戶購買商品的平均數量
# print(data.describe())

#    M 對月進行統計
data['month'] = data['購買日期'].values.astype('datetime64[M]')


print(data.head())





# 用戶每月花費的總金額
use_months_by = data.groupby('month')['購買金額'].sum()
# print(use_months_by)
#
# plt.figure(figsize=(5,4))
# plt.plot(use_months_by.index,use_months_by.values,label="用戶每月花費的總金額")
# plt.legend(loc=0)
# plt.savefig("用戶每月花費的總金額.jpg")
# plt.show()


# 所有用戶每月的產品購買量
# print(data.groupby('month')['購買產品數'].sum())


# 所有用戶每月的消費總次數
# print(data.groupby('month')['用戶ID'].count())

# 統計每月的消費人數    # 同一個人可能消費多次,所以 消費人數 只能是唯一的 .nunique() 去重後餘下的
# print(data.groupby('month')['用戶ID'].nunique())





# 各個用戶消費總金額和消費總次數的統計描述
# print("各個用戶消費總金額",data.groupby('用戶ID')['購買金額'].sum())
# print("各個用戶消費總次數",data.groupby('用戶ID')['購買產品數'].nunique())



# print(data.groupby('用戶ID').sum().describe())

# 各個用戶消費總金額和消費總次數的散點圖
# plt.scatter(data.groupby('用戶ID').sum()['購買產品數'],
#             data.groupby('用戶ID').sum()['購買金額'])
# plt.xlabel("購買產品數")
# plt.ylabel("購買金額")
# plt.show()




# 各個用戶消費總金額的直方分布圖(消費金額在1000之內的分布)
# 總結:在groupby條件後直接限制條件, 限制條件後的結果取值 作圖
# data_f = data.groupby('用戶ID').sum().query(" 購買金額 < 1000 " )['購買金額']
# print(data_f)
# plt.hist(data_f,bins=10) # bins柱子的個數
# plt.show()



# 各個用戶消費總次數的直方分布圖(消費次數在於100內)
# by_number = data.groupby('用戶ID').sum().query('購買產品數 < 100')['購買產品數']
# print(by_number)
# plt.hist(by_number,bins=30)
# plt.show()


# 消費次數在100以內的  只有8個人消費次數超過100
# print((data['用戶ID'].value_counts() < 100).value_counts() )       # 每個data['用戶ID']出現的次數(出現次數 == 消費的次數)
# True     23562
# False        8


# 用戶第一次消費的月的分布,和人數統計   month已經轉成時間數據類型
# print(data.groupby('用戶ID')['month'].min())  # 分組出用戶ID,然後選出分組後每個用戶ID最小的那個
# print(data.groupby('用戶ID')['month'].min().value_counts()) # 每個月份的人數統計
# data.groupby('用戶ID')['month'].min().value_counts().plot()  # 首購分布圖
# plt.show()




# 用戶最後一次消費的時間分布,人數統計
# print(data.groupby('用戶ID')['month'].max())
# print(data.groupby('用戶ID')['month'].max().value_counts())
# data.groupby('用戶ID')['month'].max().value_counts().plot() # 最後一次購買的時間分布圖
# plt.show()


# 新用戶 (只購買一次)

# 獲取每個用戶的首購 跟尾夠
# 第一種方式(結果是錯誤的)因為是一次消費的用戶,所有隻要挑出購買產品數為1的 )  學到的知識是 判斷兩數組對比方式
# data_left = data.groupby("用戶ID")['month'].agg(['min','max']) # 得到min max日期
# print((data_left['min'] == data_left['max']).value_counts())

# print( (data.groupby("用戶ID")['購買產品數'].sum() == 1).value_counts().values) # 第二種方式[X,X1]




# 每個用戶的總購買量 總消費金額  and 最近一次消費的表格rfm    (每個用戶在最近的一次消費)
rfm = data.pivot_table(index='用戶ID',aggfunc={'購買產品數':'sum','購買金額':'sum','購買日期':'max',})

# 每個用戶最近一次交易的時間間隔  (購買日期 - 購買日期的最大值) || 去掉days:  / np.timedelta64(1,'D')
rfm['R'] = -(rfm['購買日期'] - rfm['購買日期'].max()) / np.timedelta64(1,'D')
# 修改名字
rfm.rename(columns={'購買金額':'M',"購買產品數":"F"},inplace=True)
# print(rfm.head())



# # 分層次
def rfm_func(x):
    level = x.map(lambda x:'1' if x >= 0 else '0') # 如果是負數的就是0,不是就是1
    laber = level.R + level.F + level.M  # 拼接成 d 對應的數值  進行區分客戶等級
    d = {
        '111':'重要價值客戶',
        '011':'重要保持客戶',
        '101':'重要挽留客戶',
        '001':'重要發展客戶',
        '110':'一般價值客戶',
        '010':'一般保持客戶',
        '100':'一般挽留客戶',
        '000':'一般發展客戶',
    }
    result = d[laber]
    return result


rfm['laber'] =rfm[['R','F','M']].apply(lambda x: x - x.mean()).apply(rfm_func,axis=1)
# print(rfm)

# print(rfm.groupby('laber').count())

#
# rfm.loc[rfm.laber == '重要價值客戶','color'] = 'g'
# rfm.loc[~(rfm.laber == '重要價值客戶'),'color'] = 'r'
# rfm.plot.scatter("F",'R',c = rfm.color)
# plt.show()





# 統計每個用戶每個月的消費次數
user_order_count_data = data.pivot_table(index='用戶ID',values='購買日期',aggfunc='count',columns='month').fillna(0).head()
# 1               0           0           0           0           0           0
# 2               0           0           0           0           0           0



# 統計每個用戶每個月是否消費 消費記錄為1 否者記錄消費為0
# apply 每一行的數據
# applymap() 每一個數據都執行一遍
data_purchase = user_order_count_data.applymap(lambda x:1 if x >= 1 else 0)
# print(data_purchase)




# 活躍用戶判斷

col = ['1997-01-01', '1997-02-01', '1997-03-01', '1997-04-01',
       '1997-05-01', '1997-06-01', '1997-07-01', '1997-08-01',
       '1997-09-01', '1997-10-01', '1997-11-01', '1997-12-01',
       '1998-01-01', '1998-02-01', '1998-03-01', '1998-04-01',
       '1998-05-01', '1998-06-01']


def active_status(data):
    status = []
    for i in range(18):

        # 若本月沒有消費
        if data[i] == 0:
            if len(status) > 0:
                if status[i - 1] == 'unreg':  # 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 pd.Series(status, index=col)

p_status = data_purchase.apply(active_status,axis=1)  # 將每一行數據執行函數一次
# print(p_status)


print(p_status.replace('unreg',np.NAN).apply(lambda x:pd.value_counts(x)).T)