【數據分析案例】用戶消費行為
""" 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)