Kaggle: Google Analytics Customer Revenue Prediction EDA

 

前言

內容提要

  • 本文爲Kaggle競賽 Google Analytics Customer Revenue Prediction 的探索性分析
  • 題目要求根據歷史顧客訪問GStore的數據,預測其中部分顧客在將來的銷售額,且預測期與原數據之間不連續
  • 主要切入角度爲針對待預測的問題,估計出答案的合理區間(數量級水平)

項目介紹

  • 項目說明:Google Analytics Customer Revenue Prediction
  • 預測目標(新):根據顧客的點擊信息數據(2016.8.1 -  2018.10.15),預測2018.5.1 - 2018.10.31期間瀏覽過GStore的顧客,在2018.12.1 - 2019.1.31的消費金額(Revenue)。11月31日截止提交。
  • 預測目標(原):根據瀏覽數據預測單次消費金額的常規問題,後來通過修改,題目變得極難預測,有至關比例的參賽者提交了全0的預測。
  • 數據字段:共13個列,其中fullVisitorId爲顧客的惟一標識,totals中包含一些重要的彙總信息,4列爲標準的JSON格式,兩列爲不標準的JSON,處理難度較大。原始列名以下:

    'channelGrouping', 'customDimensions', 'date', 'device', 'fullVisitorId', 'geoNetwork', 'hits', 'socialEngagementType', 'totals', 'trafficSource', 'visitId', 'visitNumber', 'visitStartTime'python

  • 數據規模:train_v2.csv, 1708345條數據, 23.6GB;test_v2.csv,  401589條數據, 7.09GB。
  • 評估指標:RMSE

分析工具

  • Python 3.6.5 |Anaconda, Inc.| ,主要使用Spyder做爲IDE
  • 電腦配置:i7- 6600U, 16GB RAM,低於此配置可能沒法處理這個數據集

比賽整體思路

  • 每一個用戶的消費總金額能夠分解爲客戶單次消費的平均金額和預期消費次數
  • 單次平均金額能夠根據歷史數據取平均,但只針對曾經購買的客戶,沒法預測新增客戶
  • 因此咱們須要知道每月新增購買/重複購買客戶的分佈,新增客戶在前購買前若干月份的瀏覽狀況,從而推算用戶構成(新訪新消 / 老訪新消 / 老顧客)
  • 對曾經購買過的客戶,對其每次瀏覽,計算下次購買時間,標記其購買類型
  • 以此爲參照創建模型,嘗試預測重複購買和新增購買

分析思路和歷程

  • 首先用pandas讀取CSV,觀察數據,嘗試解析JSON列
  • 運行多個小時以後,發現數據量太大,內存佔用長期接近100%,決定拆分數據集(20000條一組)
  • 分別解析JSON,經過json_normalize方法解析json列,非標準json格式須要先去掉最外層中括號(literal_eval)
  • 合併數據集,檢查總行數
  • 缺失值分析和數據預處理
  • 建立組合特徵,計算出下次購買時間,區分新增購買和重複購買
  • 數據透視和描述統計,按年月彙總,估計答案大體範圍
  • 嘗試建模求解

說明

  • 本文的分析主要集中於用戶的瀏覽和購買行爲,不包含不少分類特徵和模型,目前參賽者尚未從這個角度分析的kernel(現有EDA主要是分類特徵的可視化)
  • 目前比賽已經結束,2019年2月公佈比賽結果
  • 本文內容較多,爲了閱讀體驗,較長的代碼均被摺疊

正文

 整理數據

import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

import json
from pandas.io.json import json_normalize
from datetime import datetime
from ast import literal_eval

import warnings
warnings.filterwarnings('ignore')

data_path = 'C:\\Project\\Kaggle\\Revenue_Prediction\\data\\'
Import Libraries
def read_df(path, file_name, nrows = None):
    os.chdir(path)
    df = pd.read_csv(file_name, dtype = {'fullVisitorId': 'str', 'visitId': 'str'}, chunksize = 10000)
    return df

train_head = read_df(data_path, 'train_v2.csv', nrows = 10000)
Read_df

能夠看出數據的結構較爲複雜,對於JSON列和類JSON列,須要通過處理,才能進行有效使用。在處理的過程當中, 我也參考了其餘參賽者分享的一些Kernels,再經過拆分計算的思想,完成了數據的解析。json

def split_df(df, path, num_split):

    os.chdir(path)            
    
    for i in range(num_split):
        temp = df[i*20000 : (i+1)*20000]
        temp.to_csv(str(i) + '.csv', index = False)
        print('No. %s is done.' %i)

def load_df(csv_name, nrows = None):
    "csv_path:文件路徑, nrows 讀取行數,JSON_COLUMNS: JSON的列"

    df = pd.read_csv(csv_name,
                     converters = {column: json.loads for column in JSON_COLUMNS},
                     # json.loads : json --> python
                     dtype = {'fullVisitorId': 'str', 'visitId': 'str'},
                     nrows = nrows)
    
    for col in NEW_COLUMNS:
        df[col][df[col] == "[]"] = "[{}]"
        df[col] = df[col].apply(literal_eval).str[0]
        
        
    for column in JSON_COLUMNS + NEW_COLUMNS:
        column_as_df = json_normalize(df[column])
        # json column --> tabel(DataFrame)
        column_as_df.columns = [f"{column}.{subcolumn}" for subcolumn in column_as_df.columns]
        # f-string in Python 3.6
        
        # Extract the product and promo names from the complex nested structure into a simple flat list:
        if 'hits.product' in column_as_df.columns:
            column_as_df['hits.v2ProductName'] = column_as_df['hits.product'].apply(lambda x: [p['v2ProductName'] for p in x] if type(x) == list else [])
            column_as_df['hits.v2ProductCategory'] = column_as_df['hits.product'].apply(lambda x: [p['v2ProductCategory'] for p in x] if type(x) == list else [])
            del column_as_df['hits.product']
            
        if 'hits.promotion' in column_as_df.columns:
            column_as_df['hits.promoId'] = column_as_df['hits.promotion'].apply(lambda x: [p['promoId'] for p in x] if type(x) == list else [])
            column_as_df['hits.promoName'] = column_as_df['hits.promotion'].apply(lambda x: [p['promoName'] for p in x] if type(x) == list else [])
            del column_as_df['hits.promotion']
            
        df = df.drop(column, axis = 1).merge(column_as_df, left_index = True, right_index = True)
        
    df.to_csv('exjson_' + csv_name.split('.')[0] + '.csv', index = False)        
    return df

def exjson(path, num):
    
    os.chdir(path)
    files = [str(d) + '.csv' for d in range(num)]

    for i in files:
        load_df(i)
        print('No. {} is done.'.format(i.split('.')[0]))

def concat_df(path, num, outname):
    "path: path_train/path_test; num: 86/21"
    os.chdir(path)
    file_list = ['exjson_{}.csv'.format(i) for i in range(num)]
    df_list = []
    
    for file in file_list:
        dfname = file.split('.')[0]
        dfname = pd.read_csv(file, dtype = {'fullVisitorId': 'str', 'visitId': 'str'})
        df_list.append(dfname)
        
    df = pd.concat(df_list, ignore_index = True)
    df.to_csv(outname, index = False)
    return df

def bug_fix(df):
    drop_list = df[df['date'] == "No"].index.tolist()
    df = df.drop(drop_list)
    print(df)
    return df
Some Functions

 因爲比較擔憂計算能力,拆分、解析、組合的過程被分別執行,且存儲了過程結果,三者的主要函數見上面摺疊的代碼。app

此後又對數據作出了一些簡單處理,分離了年月日的信息,將totals.transactionRevenue取了對數(np.log1p),去掉了缺失值過多和數值單一的列,下面將主要對瀏覽、購買次數和時間進行分析。ide

構造特徵

選取特徵

  • fullVisitorId: 顧客的惟一標識
  • visitStartTime: 顧客本次瀏覽的開始時間,以秒爲計算單位,從1970-1-1 0時開始
  • visitNumber: 系統對於瀏覽次數的計數,第幾回瀏覽
  • totals.transactionRevenue: 當前瀏覽帶來的銷售額
  • totals.hits: 當前瀏覽的點擊次數
  • totals.pageviews: 當前瀏覽的頁面總數
  • totals.timeOnSite: 當前瀏覽的總時間 / 秒
  • totals.newVisits: 當前瀏覽是否爲新增瀏覽
  • date: 瀏覽日期
all_precleaning = read_df(path_data, 'all_data_precleaning.csv')
all_eda = all_precleaning[['fullVisitorId', 'visitStartTime', 'visitNumber', 'totals.transactionRevenue', 'totals.hits', 'totals.pageviews', 'totals.timeOnSite', 'totals.newVisits', 'date']]

all_precleaning 總共有70列,爲了突出重點展現,本文只對以上特徵進行分析。函數

年月合併

提取年和月做爲一列,方便後續分組。工具

all_eda['yearMonth'] = all_eda.apply(lambda x: x['date'].split('-')[0] + x['date'].split('-')[1], axis = 1)

針對用戶的特徵構建

  • sumRevenue: 用戶累計購買總額
  • everBuy: 用戶是否有過購買 1 / 0
  • buy: 用戶當前次瀏覽,是否購買 1 / 0
  • viewTimes: 用戶瀏覽總次數
  • buyTimes: 用戶購買總次數
  • averageRevenue: 用戶平均銷售額(僅對實際購買次數取平均)
  • nextBuyTime: 下次購買時間(分析難點,須要構造輔助列buyNumber, nextBuyGroup)
  • timeToBuy: 與下次購買的時間間隔
  • timeToBuy.day: 與下次購買的時間間隔,換算到天
  • lastVisitTime: 用戶最後一次瀏覽時間,用於查找須要預測的所有數據條數
  • revNum: 第幾回購買(分析難點,須要輔助列buyNumber)
  • firstVisitTime: 首次瀏覽時間
  • firstBuy: 是否爲首次購買 1 / 0
  • reBuy: 是否爲復購 1 / 0
  • sinceFirstVisit: 與第一次瀏覽的時間間隔 / 秒
  • sinceFirstVisit.day: 與第一次瀏覽的時間間隔 / 天
  • sinceFirstVisit.period: 與第一代瀏覽的時間間隔 / 時期 0-30-60-120-240-800

計算過程當中,將僅瀏覽一次的數據單獨計算; 其他數據根據 fullVisitorId 進行分組累計,每一個分組內按照瀏覽時間由小到大排列,以便標記次數。測試

計算特徵的代碼較長,摺疊於下方,結果爲29列。spa

def add_groupby_col(df, new_column_names, by = 'fullVisitorId', agg_cols = ['totals.transactionRevenue'], 
                    aggfunc =['count']):
    "new_column_names: a list of col names"
    
    temp = df.groupby(by)[agg_cols].aggregate(aggfunc)
    temp.columns = new_column_names
    df = pd.merge(df, temp, left_on = 'fullVisitorId', right_index = True, how = 'left')
    
    return df

    
def calculate_id_features(df):
    
    df = df.sort_values(by = 'visitNumber')
    df['buy'] = df.apply(lambda x: 1 if x['totals.transactionRevenue']>0 else 0, axis = 1)
    df['buyNumber'] = df['buy'].cumsum()
    df['nextBuyGroup'] = df['buyNumber'] - df['buy']
    
    next_buy_time = df.groupby('nextBuyGroup').agg({'visitStartTime': 'max'})
    next_buy_time.columns = ['nextBuyTime']
    df = pd.merge(df, next_buy_time, left_on = 'buyNumber', right_index = True, how = 'left')
    
    df['sumRevenue'] = df['totals.transactionRevenue'].sum()
    df['everBuy'] = df.apply(lambda x: 1 if x['sumRevenue']>0 else 0, axis = 1)
    df['buyTimes'] = df['buy'].sum()
    df['averageRevenue'] = df.apply(lambda x: x['sumRevenue']/x['buyTimes'] if x['buyTimes']>0 else 0, axis = 1)
    
    df['firstVisitTime'] = df['visitStartTime'].min()
    df['lastVisitTime'] = df['visitStartTime'].max()
    df['sinceFirstVisit'] = df['visitStartTime'] - df['firstVisitTime']
    df['sinceFirstVisit.day'] = df['sinceFirstVisit'] // (24*3600)
    df['sinceFirstVisit.period'] = pd.cut(df['sinceFirstVisit.day'], [-1, 30, 60, 120, 240, 800],
        labels = ['within30', '30-60', '60-120', '120-240', '240-800'])
    
    def get_timegap(df_l):
        timegap = df_l['nextBuyTime'] - df_l['visitStartTime']
        if timegap > 0:
            return timegap
        
    df['timeToBuy'] = df.apply(lambda x: get_timegap(x), axis = 1)
    df['timeToBuy'].fillna(0, inplace = True)
    df['timeToBuy.day'] = df.apply(lambda x: x['timeToBuy']/(24*3600) if x['everBuy']==1 else -10, axis = 1)
       
    df['revNum'] = df.apply(lambda x: x['buyNumber'] if x['buy']==1 else 0, axis = 1)        
    df['firstBuy'] = df.apply(lambda x: 1 if x['revNum']==1 else 0, axis = 1)
    df['reBuy'] = df.apply(lambda x: 1 if x['revNum']>1 else 0, axis = 1)
    
    return df


def one_visit_features(df):
    
    df['buy'] = df.apply(lambda x: 1 if x['totals.transactionRevenue']>0 else 0, axis = 1)

    df['sumRevenue'] = df['totals.transactionRevenue'].sum()
    df['everBuy'] = df.apply(lambda x: 1 if x['sumRevenue']>0 else 0, axis = 1)
    #df['viewTimes'] = df['visitStartTime'].count()
    df['buyTimes'] = df['buy'].sum()
    df['averageRevenue'] = df.apply(lambda x: x['sumRevenue']/x['buyTimes'] if x['buyTimes']>0 else 0, axis = 1)
    
    df['firstVisitTime'] = df['visitStartTime']
    df['lastVisitTime'] = df['visitStartTime']

    df['revNum'] = df.apply(lambda x: 1 if x['buy']==1 else 0, axis = 1)        
    df['firstBuy'] = df.apply(lambda x: 1 if x['buy']==1 else 0, axis = 1)
    df['reBuy'] = 0
    
    return df

all_eda = add_groupby_col(all_eda, ['viewTimes'])
all_eda_oneview = all_eda[all_eda['viewTimes'] == 1]
all_eda_views = all_eda[all_eda['viewTimes'] > 1]

all_eda_oneview_cal = one_visit_features(all_eda_oneview)
all_eda_views_cal = all_eda_views.groupby('fullVisitorId').apply(calculate_id_features)

all_eda_cal = pd.concat([all_eda_views_cal, all_eda_oneview_cal], ignore_index = True)
all_eda_cal.to_csv('all_eda_cal.csv', index = False)
Id Features

 總瀏覽次數&總購買次數分析

  • 按次統計,劃分區間
  • 瀏覽次數爲1次和2次居多、購買次數絕大多數都是0

數據計算

def view_range_agg(df):
    "df: all_eda_cal"
    view_times = df.groupby('fullVisitorId').agg({'viewTimes': 'max'})
    view_times_agg = view_times.groupby('viewTimes').agg({'viewTimes': 'count'})
    view_times_agg.columns = ['num']
    view_times_agg.reset_index(inplace = True)
    view_times_agg['viewRange'] = pd.cut(view_times_agg['viewTimes'], [-1, 1, 2, 3, 6, 10, 20, 40, 80, 500],
            labels = ['1', '2', '3', '4-6', '7-10', '11-20', '21-40', '41-80', '81-500'])
    result = view_times_agg.groupby('viewRange').agg({'num': 'sum'})
    return result


def buy_range_agg(df):
    "df: all_eda_agg"
    buy_times = df.groupby('fullVisitorId').agg({'buyTimes': 'max'})
    buy_times_agg = buy_times.groupby('buyTimes').agg({'buyTimes': 'count'})
    buy_times_agg.columns = ['num']
    buy_times_agg.reset_index(inplace = True)
    buy_times_agg['buyRange'] = pd.cut(buy_times_agg['buyTimes'], [-1, 0, 1, 2, 3, 6, 10, 33],
                 labels = ['0', '1', '2', '3', '4-6', '7-10', '11-33'])
    result = buy_times_agg.groupby('buyRange').agg({'num': 'sum'})
    return result

view_range = view_range_agg(all_eda_cal)
buy_range = buy_range_agg(all_eda_cal)
print('瀏覽次數分佈以下:')
print(view_range)
print('-' * 10)
print('購買次數分佈以下:')
print(buy_range)
Times Calculate

原始圖表

包含全部取值可能,會致使部分數據沒法得到直觀展現3d

plt.rcParams['font.sans-serif']=['SimHei']
fig,axes = plt.subplots(1,2,figsize = (20,6))
view_range.plot.barh(ax = axes[0])
axes[0].set_title('瀏覽次數分佈')
buy_range.plot.barh(ax = axes[1])
axes[1].set_title('購買次數分佈')
Pic1

放大圖表

  • 除去瀏覽次數爲0和1的圖形
  • 除去購買次數爲0和1的圖形
fig,axes = plt.subplots(1,2,figsize = (20,6))
view_range[2:].plot.barh(ax = axes[0])
axes[0].set_title('瀏覽次數分佈')
buy_range[2:].plot.barh(ax = axes[1])
axes[1].set_title('購買次數分佈')
Pic2

 

按照年月進行分組統計

  • 指標包括: 瀏覽次數、購買次數、新增瀏覽、總銷售額、新增購買次數、重複購買次數、新增購買收入、重複購買收入等
  • 對數據中的每月,繪製瀏覽次數、新增瀏覽、購買次數、新增購買、重複購買的對比折線圖
  • 數據中10月只有15天,因此數據量小屬於正常現象

特徵計算

def yearMonth_des(df):
    "df: all_eda_cal"
    # 總購買數 新增瀏覽 總銷售額
    yearmonth_1 = df.groupby('yearMonth').agg({'buy': 'sum', 'totals.newVisits': 'sum',
                                'totals.transactionRevenue': 'sum'})
    yearmonth_1.columns = ['month_buyTimes', 'month_newVisits', 'month_totalRev']
    
    # 總瀏覽數
    yearmonth_visit_time = df.groupby('yearMonth').apply(lambda x: len(x)).reset_index()
    yearmonth_visit_time.columns = ['yearMonth', 'month_visitTime']
    yearmonth_visit_time.index = yearmonth_visit_time['yearMonth']
    
    # 新增購買 / 重複購買 銷售額
    # 此時的重複購買指:不是第一次購買,有可能第一次購買就發生於當月
    first_buy_rev = df[df['firstBuy']==1].groupby('yearMonth').agg({'totals.transactionRevenue': 'sum'})
    rebuy_rev = df[df['reBuy']==1].groupby('yearMonth').agg({'totals.transactionRevenue': 'sum'})
    first_buy_rev.columns = ['firstBuyRev']
    rebuy_rev.columns = ['reBuyRev']
    
    # 統計新增/重複購買人數 按年月分組
    yearmonth_2 = df.groupby('yearMonth').agg({'firstBuy': 'sum', 'reBuy': 'sum'})
    
    # 將分散的groupby特徵整合到一塊兒
    yearmonth_des = pd.concat([yearmonth_visit_time, yearmonth_1, yearmonth_2, first_buy_rev, rebuy_rev], axis = 1)
    
    # 計算首次購買和重複購買的金額均值
    yearmonth_des['avgFirst'] = yearmonth_des['firstBuyRev'] / yearmonth_des['firstBuy']
    yearmonth_des['avgRev'] = yearmonth_des['reBuyRev'] / yearmonth_des['reBuy']
    
    #yearmonth_des.to_csv('yearmonth_group.csv', index = False)
    return yearmonth_des

yearmonth_des = yearMonth_des(all_eda_cal)
yearmonth_des.index = yearmonth_des.index.astype(str)
yearmonth_des.tail(6)
yearMonth_des

月瀏覽次數和購買次數折線圖

fig, ax =  plt.subplots(2, 1, figsize = (20, 16))

ax[0].plot(yearmonth_des['month_visitTime'])
ax[0].plot(yearmonth_des['month_newVisits'])
ax[0].plot(yearmonth_des['month_buyTimes'])
ax[0].legend()
ax[0].set_title('瀏覽次數 新增瀏覽 購買次數')

ax[1].plot(yearmonth_des['month_buyTimes'])
ax[1].plot(yearmonth_des['firstBuy'])
ax[1].plot(yearmonth_des['reBuy'])
ax[1].legend()
ax[1].set_title('購買次數 首次購買 重複購買')
Pic3

  • 由上圖能夠觀察到每月瀏覽次數大約爲8000次左右,波動性主要與新增瀏覽相關
  • 月購買次數大約在1000次左右,很大比例都是新增購買,兩者波動有很大的相關性
  • 重複購買數量相對穩定,平均在100次左右
  • 2018年5月左右,購買次數存在波谷,正好是訓練集和測試集的鏈接處,可能競賽數據並不是全數據,待下一步分析
  • 瀏覽和購買次數之間存在必定的相關性,但程度並不高
  • 次數預測能夠分解爲新增購買和重複購買

每月購買次數的數據透視

  • 前面的分析將購買次數劃分爲了首次和重複,而且在整體上對購買次數進行了統計
  • 此時能夠進行按月統計,查看有無顯著規律
yearmonth_buy_pivo

  • 從圖中能夠觀察到每月購買三次以上的顧客十分少見
  • 購買2-3次的顧客每個月大約30人
  • 此時還不能肯定在一個月內大量購買的顧客的後續表現

首次購買時的瀏覽次數分佈

## 表2
# 首次購買的用戶須要的瀏覽次數 區間
all_eda_cal['visitNumRange'] = pd.cut(all_eda_cal['visitNumber'], [0, 1, 2, 5, 10, 20, 388], labels = ['1', '2', '3-5', '6-10', '11-20', '21-388'])
firstBuy_visitNum_pivot = all_eda_cal[all_eda_cal['firstBuy']==1].pivot_table(index = 'yearMonth', columns = 'visitNumRange', aggfunc = {'visitNumRange': 'count'})

firstBuy_visitNum_pivot.tail(6)

plt.figure(figsize = (12, 10))
#yearmonth_buy_pivot.fillna(0, inplace = True)
sns.heatmap(firstBuy_visitNum_pivot,
            annot = True,      # 是否顯示數值
            fmt = '.0f',         # 格式化字符串
            linewidths = 0.1,  # 格子邊線寬度
            center = 300,      # 調色盤的色彩中心值,若沒有指定,則以cmap爲主
            cmap = 'Blues',     # 設置調色盤
            cbar = True,       # 是否顯示圖例色帶
            #cbar_kws={"orientation": "horizontal"},   # 是否橫向顯示圖例色帶
            #square = True,     # 是否正方形顯示圖表
           )
plt.title('首次購買時的瀏覽次數分佈')
View Code

  • 觀察上圖可知完成首次購買的時候,瀏覽次數主要集中於3-5次(2-10次)
  • 但不能得知次數的時間跨度

購買與首次瀏覽的間隔分佈

  • 時間間隔被劃分爲區間進行統計
  • 考慮到最後的預測目標,應主要關注60-240天的數據
## 表3表4
# 首次購買和重複購買與首次瀏覽時間間隔的分佈
firstBuy_sinceFisrtVisit_pivot = all_eda_cal[all_eda_cal['firstBuy']==1].pivot_table(index = 'yearMonth',
                                         columns = 'sinceFirstVisit.period', aggfunc = {'sinceFirstVisit.period': 'count'})

reBuy_sinceFisrtVisit_pivot = all_eda_cal[all_eda_cal['reBuy']==1].pivot_table(index = 'yearMonth',
                                     columns = 'sinceFirstVisit.period', aggfunc = {'sinceFirstVisit.period': 'count'})

firstBuy_sinceFisrtVisit_pivot.columns = [['120-240', '240-800', '30-60', '60-120', 'within30']]
reBuy_sinceFisrtVisit_pivot.columns = [['120-240', '240-800', '30-60', '60-120', 'within30']]
firstBuy_sinceFisrtVisit_pivot = firstBuy_sinceFisrtVisit_pivot[['within30', '30-60', '60-120', '120-240', '240-800']]
reBuy_sinceFisrtVisit_pivot = reBuy_sinceFisrtVisit_pivot[['within30', '30-60', '60-120', '120-240', '240-800']]

firstBuy_sinceFisrtVisit_pivot.tail(6)
View Code

首次購買與首次瀏覽的時間間隔

plt.figure(figsize = (12, 10))
#yearmonth_buy_pivot.fillna(0, inplace = True)
sns.heatmap(firstBuy_sinceFisrtVisit_pivot.drop('within30', axis = 1),
            annot = True,      # 是否顯示數值
            fmt = '.0f',         # 格式化字符串
            linewidths = 0.1,  # 格子邊線寬度
            center = 30,      # 調色盤的色彩中心值,若沒有指定,則以cmap爲主
            cmap = 'Blues',     # 設置調色盤
            cbar = True,       # 是否顯示圖例色帶
            #cbar_kws={"orientation": "horizontal"},   # 是否橫向顯示圖例色帶
            #square = True,     # 是否正方形顯示圖表
           )
plt.title('首次購買與首次瀏覽的時間間隔')
View Code

  • 首次購買和首次瀏覽的間隔主要集中於30天以內,因爲沒有2018.10.16-2018.11.30日數據,無需關注
  • 2018年5月處出先斷層,屬於嚴重的異常,能夠得知競賽數據並不是GStore所有數據,訓練集/測試集分別提取了一部分
  • 間隔在60-240天之間每個月大約30次左右(佔比很低)

重複購買與首次瀏覽的時間間隔

plt.figure(figsize = (12, 10))
#yearmonth_buy_pivot.fillna(0, inplace = True)
sns.heatmap(reBuy_sinceFisrtVisit_pivot,
            annot = True,      # 是否顯示數值
            fmt = '.0f',         # 格式化字符串
            linewidths = 0.1,  # 格子邊線寬度
            center = 35,      # 調色盤的色彩中心值,若沒有指定,則以cmap爲主
            cmap = 'Blues',     # 設置調色盤
            cbar = True,       # 是否顯示圖例色帶
            #cbar_kws={"orientation": "horizontal"},   # 是否橫向顯示圖例色帶
            #square = True,     # 是否正方形顯示圖表
           )
plt.title('重複購買與首次瀏覽的時間間隔')
View Code

  • 分析可知,預測期現有數據中重複購買的顧客數量大約在50-80

至此,咱們已經對這個預測問題的基本狀況有了一個初步的認識,這些數據能夠爲本身的交叉驗證作出有效的補充。code

相關文章
相關標籤/搜索