盒鬚圖-哪個廣告效果好? 電商產業廣告效果分析實戰案例(附Python 程式碼)

徐子皓 Nash Xu
Marketingdatascience
15 min readDec 1, 2020

資料科學人員需要進行資料呈現時,比起直接提供平均數、中位數、最大最小值等敘述性指標,盒鬚圖往往是更受歡迎的選擇。

盒鬚圖,又稱為箱型圖,是一種檢視或者是比較資料分散程度時,相當好用直觀的一種統計呈現圖。它可以將將資料的分佈,如:最大值、最小值、中位數、第一四分位以及第三四分位數等統計量一目了然地呈現出來,協助管理者或資料接收者掌握狀況;也能讓我們在進行統計檢定及迴歸預測前,能對資料有初步的決策參考。

本次使用的資料集檔名為「sales_data.csv」,本文將透過產品系列在不同月份的廣告效益,利用盒鬚圖來呈現,帶您感受這個好用的視覺化呈現方式。

一、基本資料引入

首先,將本次會使用到的套件包以及分析資料(點我下載)引入,如程式碼1所示:

程式碼1:

import pandas as pd

import os

from collections import Counter

import heapq

import plotly.offline as py

import plotly.graph_objects as go
data = pd.read_csv("new_salesdata.csv")

產出如圖1:

圖 1 原始資料示意圖

隨後,將本次製圖不需使用到的資料欄位,如顏色、性別、年齡等,透過程式碼2移除。

程式碼2:

data = data.drop(columns = list(data.filter(regex='Unnamed: 0|顏色|會員|產品|性別|年紀|尺寸')))

產出如圖2:

圖 2 移除欄位後資料集示意圖
Photo by:Priscilla Du Preez

二、基礎資料處理

我們將針對「系列」以及「廣告名稱」著手進行處理。

(一) 系列

由於該電商資料共有一千種以上的系列,每種系列常用的廣告宣傳方式以及廣告可以帶來的效益都有所不同。因此為了方便學習理解,本文只會使用「系列4」的資料用來製圖,透過下方程式碼3可將「系列4」以外的資料篩選掉:

程式碼3:

data = data[ data ['系列'] == '系列4']

產出如圖3:

圖 3 調整後資料集示意圖

篩選完之後可透過「Variable explorer」看到,資料集中「data」的資料成功從35萬筆左右篩選到剩下11059筆了。

(二) 廣告名稱

展開資料集「data」可以發現,該資料集在廣告方面的記載十分詳盡,舉例來說:光是廣告系列「KDPOD」就有「qrtist」、「chiciMT」、「select」、「chicihey」…等細項分支。若要考慮到如此大量的廣告種類,除了資料集被大量廣告平分下來會有個別資料過少問題,龐大的類別也會使資料處理及呈現變得雜亂,因此在進行資料呈現時只考慮廣告「系列」,而忽略了廣告「細項」。

此時,則需要透過程式碼4,使用for迴圈逐一抓取資料,並依照廣告資料格式,使用「split」功能將廣告名稱依照「_」切分開來,並取出系列名稱。

程式碼4:

for i in range(0,len(data['廣告代號all'])):      a = data['廣告代號all'][i].split('_')[1]      data['廣告代號all'][i] = a

產出如圖4:

圖 4 整理廣告代號後資料集示意圖

三、進階資料處理-挑選主力廣告

即使已經忽略廣告的細部分支,展開資料集仍可發現一些問題:

1. 廣告種類依舊五花八門,可能導致資料展示及分析困難

2. 資料集中少數的廣告系列佔據了大部分的資料筆數

透過程式碼5,可幫助掌握系列4總共使用了幾種系列的廣告:

程式碼5:

len(data['廣告代號all'].unique())

產出如下:

36

從產出可看到,系列4在行銷廣宣上一共使用了36系列的廣告。接著使用「Counter」功能,可協助我們計算不同廣告總共使用的頻率分別為多少,如程式碼6所示,製作出頻率清單「count_list」:

程式碼6:

count_list = Counter(data['廣告代號all'])

產出如圖5:

圖 5 廣告使用頻率清單

緊接著,透過程式碼7,將「count_list」整理成DataFrame格式,以利閱讀,如下所示:

程式碼7:

count_list = pd.DataFrame.from_dict(count_list,orient='index').reset_index() # 轉換為DataFrame形式  count_list = count_list.rename(columns = {'index' : '廣告名稱', 0: '樣本數'}) # 重新命名欄位名稱

產出如圖6:

圖 6 DataFrame形式的廣告使用頻率表

透過「count_list」可以看到,除了少數幾款廣告系列有800筆以上的使用頻率以外,大部分的廣告系列皆只有個位數或是十位數的使用頻率,不適合用來做資料分析,因此本次分析將只使用頻率前三名的熱門廣告系列進行繪圖分析。

透過程式碼8,使用套件包「heapq」中的「nlargest」功能,取出最熱門的前三名廣告頻率,寫法如下:

l heapq.nlargest(取到第幾名,資料來源)

程式碼8:

heapq.nlargest(3,list(count_list['樣本數']))

產出如下:

[3780, 1793, 1285]

了解了使用方式之後,我們可以利用產出結果,將第三名的頻率「dead_number」取出來,做為後續篩選是否為熱門廣告系列的門檻,如程式碼9:

程式碼9:

dead_number = heapq.nlargest(4,list(count_list['樣本數']))[2]

產出如下:

1285

有了熱門廣告系列第三名的頻率之後,便可以透過邏輯運算子,將使用頻率小於「dead_number」的廣告系列納入清單「dead_list」內,準備進行排除,如下程式碼10:

程式碼10:

dead_list = count_list[count_list['樣本數'] < dead_number]

產出如圖7:

圖 7 需移除的非熱門廣告

透過程式碼11,把資料集「data」內的非熱門廣告系列資料,透過「dead_list」逐一刪除,只留下使用熱門廣告的資料,共6858筆。

程式碼11:

for i in dead_list['廣告名稱']:      data= data[~data['廣告代號all'].isin([i])]

產出如圖8:

圖 8 只含熱門廣告的資料集

有趣的是,在上方程式中有使用了一個「~」的符號,代表的意思為「Not」,只能放在變數前,做為輔助記號。

比起逐一將每一種熱門廣告從資料集「data」中取出並且合併,使用「~」將非熱門廣告的資料排除是比較有效率的做法,十分推薦。

最後,我們可以注意到熱門廣告中出現了「自然流量」,自然流量並非我們可控的廣告項目,因此透過程式碼12將其從資料集「data」中排除,如下:

程式碼12:

data = data[~data['廣告代號all'].isin(['自然流量'])]

產出如圖9:

圖 9 移除欄位後資料集

四、進階資料處理-不同廣告每期帶來的淨利

到目前為止,資料處理差不多完成7成了,要將資料用來繪圖之前,還得計算出資料集的「淨利」,並加以統整出不同廣告在每一期(月份)為系列4帶來的利潤為多少。

首先透過「split」功能,將「訂單時間」根據「-」做切分,並取出「月份」,回存至資料集「data」中。如程式碼13所示:

程式碼13:

data['月份'] = data['訂單時間'].str.split('-', expand = True)[1].astype(int)

產出如圖10:

圖 10 新增「月份」欄位的資料集

「月份」將會用來在製圖時,做為X座標。

接著用一樣的手法,透過「split」功能取出資料的「年月」後並回存至資料集「data」中,用以區分該筆資料的交易時間為哪一期,如下程式碼14:

程式碼14:

data['年月'] = (data['訂單時間'].str.split('-', expand = True)[0] + data['訂單時間'].str.split('-', expand = True)[1]).astype(int)

產出如圖11:

圖 11新增「年月」欄位的資料集

透過程式碼15,利用產品的「單價」減掉產品的「成本」,取得「淨利」,並回存至資料集「data」中。

程式碼15:

data['淨利'] = data['單價'] - data['成本']

產出如圖12:

圖 12新增「淨利」欄位的資料集

透過程式碼16,將資料集「data」的多餘欄位去除。

程式碼16:

data = data.drop(['單價', '成本', '系列', '訂單時間'], axis=1)

產出如圖13:

圖 13 移除多餘欄位後的資料集

在前面我們透過資料處理取出了辨識期別的「年月」欄位以及利潤欄位「淨利」,接下來透過程式碼17,使用「pandas」中的群組功能「groupby」,將資料集「data」內的資料根據「廣告」、「月份」以及「年月」進行群組,並計算出淨利總和,如下:

程式碼17:

data = data.groupby(['廣告代號all', '月份', '年月'])['淨利'].sum()

產出如圖14:

圖 14分組進行淨利加總的資料集

透過程式碼18,將「data」從「Series」型態再次轉換為「DataFrame」型態。如下:

程式碼18:

data = data.to_frame().reset_index()

產出如圖15:

圖 15 整理成表格型態後資料呈現樣貌

最後,在進行繪圖之前,將已經不需再使用的「年月」欄位移除,並新增「count」欄位,每筆資料的「count」欄位皆為1。

由於不同產品系列有不同的銷售期間,因此有可能會有些期數沒有任何該產品系列的交易數據。舉例來說:產品系列X於2017年上市,並於2018年底停售,若我們想了解該產品在1月的平均利潤,應該除以兩年而非四年(本原始資料時間範圍為2016~2019年)。透過count的加總,我們可以很清楚不同年度的同一個月份共有幾筆資料,並做為計算平均時的分母。如下程式碼19:

程式碼19:

data = data.drop(['年月'], axis=1)data['count'] = 1

產出如圖16:

圖 16 整理後資料集

五、繪圖

經過了一大番努力過後,終於可以將處理完後的資料繪圖產出啦!透過程式碼20可先設置空白畫布,並透過for迴圈,在上面逐月繪製盒鬚圖:

程式碼20:

fig = go.Figure() # 設定空白畫布  colors_box = ['#3366CC', '#DC3912'] # 設定盒子顏色# 繪製盒鬚圖  for i in range(0, len(data['廣告代號all'].unique())):      fig.add_trace(go.Box(      y = data[data['廣告代號all'] ==data['廣告代號all'].unique()[i]]['淨利'],      x = data[data['廣告代號all'] ==data['廣告代號all'].unique()[i]]['月份'],      name = str(data[data['廣告代號all'] ==data['廣告代號all'].unique()[i]]['廣告代號all'][0:1].values[0]),      marker_color= colors_box[i]      ))

盒鬚圖內的設定如下:

y:盒鬚圖的Y軸,在這邊指的是「平均淨利」
x:盒鬚圖的X軸,在這邊指的是「月份」
name:類別名稱,在這邊是依據「廣告類別」區分
marker_color:盒子的顏色,如清單「colors_box」所示

設定完了盒鬚圖之後,接著會透過程式碼21繪製上平均線,如下所示:

程式碼21:

adlist = list(data['廣告代號all'].unique()) # 廣告名稱清單  color_line = ["royalblue" , "firebrick"] # 設定線條顏色# 畫平均線  for i in range(0,len(adlist)):      ad = adlist[i]      colour = color_line[i]      meanlist = [] # 平均      axislist = [] # 月分for ii in range(1,13):          axislist.append(ii)          total = data[data['廣告代號all'] == ad][data['月份'] == ii]['淨利'].sum()          counts = data[data['廣告代號all'] == ad][data['月份'] == ii]['count'].sum()          aver = total/counts          meanlist.append(aver)if ii == 12:               fig.add_trace(go.Scatter(              x= axislist,              y= meanlist,              mode="lines+markers",              textfont=dict(              family="sans serif",              size=16,              color="royalblue"),                line=dict(color=colour, width=2),              ))

平均線的繪製程式共有三層,看起來很複雜,讓我們透過拆解的方式來逐一檢視:

(一) 第一層

將廣告清單「adlist」放入for迴圈中分別進行繪製準備(設置好用來放X軸月份的清單「axislist」以及放Y軸資料的平均淨利清單「meanlist」),因此平均線的繪製順序會如同「adlist」內的資料順序一樣,先畫「KDP」再畫「critei」。

(二) 第二層

新增第二層for迴圈,設定一個範圍1~12的迴圈,分別計算每個月的平均淨利,並將「月份」新增至清單「axislist」中;「平均淨利」新增至清單「meanlist」中。

(三) 第三層

設定一個判斷式,當迴圈逐一從1月計算平均至12月結束後,便將該廣告的「每月廣告平均淨利線」繪製出來。

資料都輸入完之後,便可設定布景並且產出了,如下程式碼22、程式碼23:

程式碼22:

# 設定佈景主題(字體、大小、背景等)  fig.update_layout(      title={          'text': "<b>BoxPlot-系列四 廣告效益分析</b>",          'y':0.95,          'x':0.5,          'xanchor': 'center',},      yaxis_title='Profit',      xaxis={          'title': 'Month',          'tickmode': 'linear'          },      width=1800,      height=960,      boxmode='group',      font=dict(          family="Courier New, monospace",          size=20,          color="lightslategrey"      )      )

程式碼23:

# 另存html檔  py.plot(fig, filename='BoxPlot-系列四 廣告效益分析', auto_open=True)# 另存圖檔  fig.write_image("BoxPlot-系列四 廣告效益分析.png")

終於產出最後的盒鬚圖,如圖17:

圖 17 最終產出示意圖

(四)小結

我們可針對產出的圖片做初步的熱門廣告效益分析:

「critei」在九月時,相較於「KDP」可讓「系列4」有較好的淨利效果,因此在九月時對「系列4」加強「critei」廣告應該可以產生更好的獲利效果。

而有些月分則較難從目測比較廣告的好壞,如:以5月的資料來說,雖然「KDP」的淨利涵蓋範圍遠高於「critei」的淨利涵蓋範圍,應該會有比較好的效果,但使用「critei」時的淨利範圍比較集中,可以得到較好的控制效果,因此難以推論誰好誰壞。

有沒有發現上面的結論不斷出現「應該」呢?那是因為在進行決策參考時,若沒有一個公允的指標或檢定來進行判斷的話,資料科學人員所能歸納出的結果往往會偏於主觀想法。

因此,資料科學從業人員經常需要依母體分佈,用不同的統計檢定對資料進作假設及驗證,將這些檢定應用至商務個案中,創造出準確且值得信賴的決策指標。

若是喜歡我的文章,請多為我拍拍手,我也會持續分享不同的統計檢定如何應用在商務個案~

完整程式碼:https://reurl.cc/7ol2yy
作者:徐子皓(臺灣行銷研究特邀作者)、鍾皓軒(臺灣行銷研究有限公司創辦人)

--

--