超市数据分析
1 業(yè)務背景
數據集來源于:kaggle數據集(鏈接),該數據集記錄了某全球超市四年的銷售數據,通過分析該超市四年內的銷售數據,從不同角度出發(fā),分析經營現狀,發(fā)掘提高銷量的銷售策略,利用數據找到新的增長點,并提出建議。
1.1 分析思路及指標
1. 數據總覽 (Data Describe)
2. 數據預處理 (Data Preprocessing)
- 數據類型轉換 - 空值、缺失值、異常值處理3. 數據分析 (Data Analysis)
4. 模型構建 (Bulid Model)
- RFM 用戶價值模型 - Kmeans 機器學習模型5. 模型評估 (Evaluate)
- TSNE降維可視化6. 結論建議 (Conclusion)
2 數據加載與清洗
2.1 載入數據分析庫及數據
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import warningssns.set(style='white') sns.set_context('notebook', font_scale=1.5, rc={'lines.linewidth':2.5,'figure.figsize':(17, 10)}) large = 22; med = 16; small = 12 params = {'axes.titlesize': large,'legend.fontsize': med,'figure.figsize': (16, 10),'axes.labelsize': med,'xtick.labelsize': med,'ytick.labelsize': med,'figure.titlesize': large} plt.rcParams.update(params) plt.rcParams['figure.figsize'] = (17, 10) plt.rcParams["font.family"] = 'SimHei' plt.rcParams["axes.unicode_minus"] = False warnings.filterwarnings("ignore") df = pd.read_csv('./superstore_dataset2011-2015.csv',encoding='ISO-8859-1') df.head().append(df.tail())| 42433 | AG-2011-2040 | 1/1/2011 | 6/1/2011 | Standard Class | TB-11280 | Toby Braunhardt | Consumer | Constantine | Constantine | ... | OFF-TEN-10000025 | Office Supplies | Storage | Tenex Lockers, Blue | 408.300 | 2 | 0.0 | 106.1400 | 35.46 | Medium |
| 22253 | IN-2011-47883 | 1/1/2011 | 8/1/2011 | Standard Class | JH-15985 | Joseph Holt | Consumer | Wagga Wagga | New South Wales | ... | OFF-SU-10000618 | Office Supplies | Supplies | Acme Trimmer, High Speed | 120.366 | 3 | 0.1 | 36.0360 | 9.72 | Medium |
| 48883 | HU-2011-1220 | 1/1/2011 | 5/1/2011 | Second Class | AT-735 | Annie Thurman | Consumer | Budapest | Budapest | ... | OFF-TEN-10001585 | Office Supplies | Storage | Tenex Box, Single Width | 66.120 | 4 | 0.0 | 29.6400 | 8.17 | High |
| 11731 | IT-2011-3647632 | 1/1/2011 | 5/1/2011 | Second Class | EM-14140 | Eugene Moren | Home Office | Stockholm | Stockholm | ... | OFF-PA-10001492 | Office Supplies | Paper | Enermax Note Cards, Premium | 44.865 | 3 | 0.5 | -26.0550 | 4.82 | High |
| 22255 | IN-2011-47883 | 1/1/2011 | 8/1/2011 | Standard Class | JH-15985 | Joseph Holt | Consumer | Wagga Wagga | New South Wales | ... | FUR-FU-10003447 | Furniture | Furnishings | Eldon Light Bulb, Duo Pack | 113.670 | 5 | 0.1 | 37.7700 | 4.70 | Medium |
| 32593 | CA-2014-115427 | 31-12-2014 | 4/1/2015 | Standard Class | EB-13975 | Erica Bern | Corporate | Fairfield | California | ... | OFF-BI-10002103 | Office Supplies | Binders | Cardinal Slant-D Ring Binder, Heavy Gauge Vinyl | 13.904 | 2 | 0.2 | 4.5188 | 0.89 | Medium |
| 47594 | MO-2014-2560 | 31-12-2014 | 5/1/2015 | Standard Class | LP-7095 | Liz Preis | Consumer | Agadir | Souss-Massa-Draa | ... | OFF-WIL-10001069 | Office Supplies | Binders | Wilson Jones Hole Reinforcements, Clear | 3.990 | 1 | 0.0 | 0.4200 | 0.49 | Medium |
| 8857 | MX-2014-110527 | 31-12-2014 | 2/1/2015 | Second Class | CM-12190 | Charlotte Melton | Consumer | Managua | Managua | ... | OFF-LA-10004182 | Office Supplies | Labels | Hon Color Coded Labels, 5000 Label Set | 26.400 | 3 | 0.0 | 12.3600 | 0.35 | Medium |
| 6852 | MX-2014-114783 | 31-12-2014 | 6/1/2015 | Standard Class | TD-20995 | Tamara Dahlen | Consumer | Juárez | Chihuahua | ... | OFF-LA-10000413 | Office Supplies | Labels | Hon Legal Exhibit Labels, Alphabetical | 7.120 | 1 | 0.0 | 0.5600 | 0.20 | Medium |
| 36388 | CA-2014-156720 | 31-12-2014 | 4/1/2015 | Standard Class | JM-15580 | Jill Matthias | Consumer | Loveland | Colorado | ... | OFF-FA-10003472 | Office Supplies | Fasteners | Bagged Rubber Bands | 3.024 | 3 | 0.2 | -0.6048 | 0.17 | Medium |
10 rows × 24 columns
2.2 總覽數據
數據維度有點多,顯示不全,先轉置看看各個維度的數據大概長什么樣
df[-5:].T| 32593 | 47594 | 8857 | 6852 | 36388 |
| CA-2014-115427 | MO-2014-2560 | MX-2014-110527 | MX-2014-114783 | CA-2014-156720 |
| 31-12-2014 | 31-12-2014 | 31-12-2014 | 31-12-2014 | 31-12-2014 |
| 4/1/2015 | 5/1/2015 | 2/1/2015 | 6/1/2015 | 4/1/2015 |
| Standard Class | Standard Class | Second Class | Standard Class | Standard Class |
| EB-13975 | LP-7095 | CM-12190 | TD-20995 | JM-15580 |
| Erica Bern | Liz Preis | Charlotte Melton | Tamara Dahlen | Jill Matthias |
| Corporate | Consumer | Consumer | Consumer | Consumer |
| Fairfield | Agadir | Managua | Juárez | Loveland |
| California | Souss-Massa-Draa | Managua | Chihuahua | Colorado |
| United States | Morocco | Nicaragua | Mexico | United States |
| 94533 | NaN | NaN | NaN | 80538 |
| US | Africa | LATAM | LATAM | US |
| West | Africa | Central | North | West |
| OFF-BI-10002103 | OFF-WIL-10001069 | OFF-LA-10004182 | OFF-LA-10000413 | OFF-FA-10003472 |
| Office Supplies | Office Supplies | Office Supplies | Office Supplies | Office Supplies |
| Binders | Binders | Labels | Labels | Fasteners |
| Cardinal Slant-D Ring Binder, Heavy Gauge Vinyl | Wilson Jones Hole Reinforcements, Clear | Hon Color Coded Labels, 5000 Label Set | Hon Legal Exhibit Labels, Alphabetical | Bagged Rubber Bands |
| 13.904 | 3.99 | 26.4 | 7.12 | 3.024 |
| 2 | 1 | 3 | 1 | 3 |
| 0.2 | 0 | 0 | 0 | 0.2 |
| 4.5188 | 0.42 | 12.36 | 0.56 | -0.6048 |
| 0.89 | 0.49 | 0.35 | 0.2 | 0.17 |
| Medium | Medium | Medium | Medium | Medium |
- 各維度分別為:行編號、訂單編號、訂購日期、發(fā)貨日期、運送方式、客戶ID、客戶姓名、客戶類型、客戶城市、客戶所在州、客戶國家、郵編、店鋪所在區(qū)域、店鋪所屬州、產品ID、類別、子類別、產品名稱、銷售額、銷售量、折扣、利潤、運輸費、訂單優(yōu)先級 共24個維度
- 行編號無用,直接刪除
2.3 查詢、處理空值
print('郵編缺失數據占比: {:.2%}'.format(df['Postal Code'].isnull().sum() / len(df))) 郵編缺失數據占比: 80.51%郵編一欄缺失數據超過80%,又因為郵編對數據幾乎無影響,采取措施為直接刪除此列
del df['Postal Code']2.4 查詢重復記錄
df.duplicated().sum() 0無重復記錄
2.5 更改數據類型,并創(chuàng)建時間維度字段
# 將訂單日期更改為日期格式 df['Order Date']=pd.to_datetime(df['Order Date'])# 添加年和月的列,便于后續(xù)進行時間維度的分析 df['year'] = df['Order Date'].dt.year df['month'] = df['Order Date'].dt.month3 經營分析
3.1 銷售額分析
# 創(chuàng)建銷售額透視表 sales = pd.pivot_table(df, values='Sales', index='month', columns='year',aggfunc=[np.sum]) sales.columns = ['2011年','2012年','2013年','2014年'] sales.index=['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'] sales| 138241.30042 | 162800.89338 | 206459.19582 | 268265.52240 |
| 134969.94086 | 152661.15144 | 191062.77216 | 244159.30486 |
| 171455.59372 | 201608.72784 | 230547.79468 | 347720.96868 |
| 128833.47034 | 187469.96192 | 233181.34844 | 302132.54000 |
| 148146.72092 | 218960.16042 | 304509.96336 | 304798.83604 |
| 189338.43966 | 249289.77172 | 341162.34370 | 372577.23298 |
| 162034.69756 | 174394.02808 | 223642.65664 | 278672.17326 |
| 219223.49524 | 271669.66086 | 323876.60716 | 432731.04194 |
| 255237.89698 | 256567.85308 | 326897.27044 | 405436.70584 |
| 204675.07846 | 239321.09904 | 270121.87570 | 406659.41500 |
| 214934.29386 | 270723.05356 | 383039.21248 | 508954.73156 |
| 292359.96752 | 291972.33306 | 371245.40880 | 427757.39800 |
3.1.1 時間維度銷售額
3.1.1.1 年度銷售額及增長率
rise_12 = (sales.sum()[1]-sales.sum()[0])/sales.sum()[0] rise_13 = (sales.sum()[2]-sales.sum()[1])/sales.sum()[1] rise_14 = (sales.sum()[3]-sales.sum()[2])/sales.sum()[2] rise_rate = [0, rise_12, rise_13, rise_14]sales_sum=pd.DataFrame({'Sales_sum':sales.sum()}) sales_sum['rise_rate'] = rise_rate sales_sum.index=pd.Series(['2011年','2012年','2013年','2014年']) sales_sum| 2.259451e+06 | 0.000000 |
| 2.677439e+06 | 0.184995 |
| 3.405746e+06 | 0.272017 |
| 4.299866e+06 | 0.262533 |
從年度銷售額及其增長率來看:
- 該超市2011年銷售額只有226萬,2014年銷售額達到了430萬,GMV提升非常快,從行業(yè)發(fā)展階段來看,該超市應該處于導入期或成長期
- 該超市主營辦公用品,據了解,全球領先的辦公用品供應商包括:Costco、Office Depot、Staples、Tesco和沃爾瑪,查詢沃爾瑪2014年銷售額得知,沃爾瑪2014年銷售額為4731億美元,可見與全球大型超市對比,差距大,可提升空間較大
- 從增長率來看,增長率非常高,12-13年、13-14年GMV增長率接近均超過25%,而沃爾瑪2013-2014的增長率大概為3%,可見該超市潛力非常大
- 了解了超市整體銷售額后,再對每年每月的銷售額進行分析,了解不同月份的銷售情況,找出是否有淡旺季之分,找出重點銷售月份,以便制定經營策略與業(yè)績的月度及季度指標拆分
3.1.1.2 月度銷售額
sales.plot.area(colormap = 'tab20c', stacked=False) plt.title('月度銷售額') plt.ylabel('銷售額') plt.xlabel('月份');通過不同年份月度銷售額我們可以看出:
- 該超市2011年-2014年每一年的銷售額同比上一年都是上升趨勢,銷售季節(jié)性明顯,總體上半年是淡季,下半年是旺季
- 上半年中6月份銷售額比較高,下半年中7月份的銷售額偏低。對于旺季的月份,運營推廣等策略要繼續(xù)維持,還可以加大投入,提高整體銷售額;對于淡季的月份,可以結合產品特點進行新產品拓展,舉辦一些促銷活動等吸引客戶
3.2 利潤分析
# 創(chuàng)建利潤透視表 profit = pd.pivot_table(df, values='Profit', index='month', columns='year',aggfunc=[np.sum]) profit.columns = ['2011年','2012年','2013年','2014年'] profit.index=['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'] profit| 13457.23302 | 19627.42058 | 26052.40252 | 31447.74660 |
| 17588.83726 | 17828.18244 | 31553.99756 | 29454.01876 |
| 16169.36062 | 22752.87684 | 34873.71938 | 50097.04458 |
| 13405.46924 | 20804.00532 | 26008.05144 | 35709.53320 |
| 14777.45792 | 22865.39572 | 39053.30946 | 34335.60404 |
| 25932.87796 | 34358.03962 | 43298.85000 | 40869.02108 |
| 10631.84406 | 21725.18808 | 27019.91294 | 26450.70856 |
| 19650.67124 | 36511.44996 | 32977.75576 | 46443.47934 |
| 32313.25458 | 25039.93498 | 18850.09084 | 52533.83284 |
| 30745.54166 | 27773.87454 | 27871.97470 | 52342.49740 |
| 21261.40536 | 26160.60686 | 51720.88568 | 55561.72406 |
| 33006.85862 | 31968.30416 | 47654.27990 | 48920.76000 |
3.2.1 時間維度利潤情況
3.2.1.1 年度利潤、增長率、利潤率
# 計算利潤增長率 rise_12 = (profit.sum()[1] - profit.sum()[0]) / profit.sum()[0] rise_13 = (profit.sum()[2] - profit.sum()[1]) / profit.sum()[1] rise_14 = (profit.sum()[3] - profit.sum()[2]) / profit.sum()[2] rise_rate = [0, rise_12, rise_13, rise_14]# 計算每年的利潤率 rate_11 = profit.sum()[0] / sales.sum()[0] rate_12 = profit.sum()[1] / sales.sum()[1] rate_13 = profit.sum()[2] / sales.sum()[2] rate_14 = profit.sum()[3] / sales.sum()[3] profit_rate = [rate_11, rate_12, rate_13, rate_14]profit_sum = pd.DataFrame({'Profit_sum': profit.sum()}) profit_sum['rise_rate'] = rise_rate profit_sum['profit_rate'] = profit_rate profit_sum.index = pd.Series(['2011年', '2012年', '2013年', '2014年']) profit_sum| 248940.81154 | 0.000000 | 0.110178 |
| 307415.27910 | 0.234893 | 0.114817 |
| 406935.23018 | 0.323731 | 0.119485 |
| 504165.97046 | 0.238934 | 0.117252 |
從各年度利潤及利潤增長率可以看出:
- 利潤是在逐年遞增,利潤率平穩(wěn)位置在11%-12%之間,說明超市的經營策略比較完善,價格波動不大
- 除了13-14年利潤增長率小于銷售額增長率,其他時間利潤增長率均超過銷售額增長率,可見13-14季度存在一些讓利策略來增加銷售額
3.2.1.2 每月利潤的同比增長率
rise_2=pd.DataFrame() rise_2['rise_2012']=(profit['2012年']-profit['2011年']) / profit['2011年'] rise_2['rise_2013']=(profit['2013年']-profit['2012年']) / profit['2012年'] rise_2['rise_2014']=(profit['2014年']-profit['2013年']) / profit['2013年'] rise_2| 0.458503 | 0.327347 | 0.207096 |
| 0.013608 | 0.769894 | -0.066552 |
| 0.407160 | 0.532717 | 0.436527 |
| 0.551904 | 0.250146 | 0.373018 |
| 0.547316 | 0.707966 | -0.120802 |
| 0.324883 | 0.260225 | -0.056118 |
| 1.043407 | 0.243714 | -0.021066 |
| 0.858026 | -0.096783 | 0.408327 |
| -0.225088 | -0.247199 | 1.786927 |
| -0.096654 | 0.003532 | 0.877962 |
| 0.230427 | 0.977052 | 0.074261 |
| -0.031465 | 0.490673 | 0.026576 |
從每一年不同月份的利潤同比增長率來看:
- 整體來看,利潤同比波動較大,存在不少負增長的情況,說明該超市處于導入期和成長期的概率較大,注重用戶體量,整體規(guī)模的擴大,并不是非常重視盈利情況,這與公司的發(fā)展階段和戰(zhàn)略布局有關,比如我國的京東,毛利率就不高,去掉運營費用,管理費用,履約費用等,利潤率常年負數,但依然能夠發(fā)展壯大
3.2.2 每單利潤
def boxplot(x, y, **kwargs):sns.boxplot(x=x, y=y)m = pd.melt(df, id_vars=['Profit'], value_vars=['Market','Category']) g = sns.FacetGrid(m, col='variable', col_wrap=2, sharex=False, sharey=False, size=5) g = g.map(boxplot, 'value', 'Profit') print('虧損單占比: {:.2%}'.format(df[df['Profit'] < 0].shape[0] / len(df))) 虧損單占比: 24.46%從每單利潤情況來看:
- 每單利潤非常離散,盈利單與虧損單相差不大,可見該超市經常會進行促銷活動
- Canada銷售額不高,但幾乎沒有負利潤的訂單
- 虧損訂單占了接近1/4,虧損嚴重,后續(xù)對商品維度和折扣情況進行分析,從而改善負利潤訂單情況
3.2.3 不同商品銷售額與利潤
# 創(chuàng)建不同商品銷售額與利潤情況 cg_s_p = df.groupby(['Category','Sub-Category'])['Sales','Profit'].sum()sortIndex = np.argsort(cg_s_p.Sales) # 倒序,返回排序后各數據的原始下標 x_sort = cg_s_p.index[sortIndex] # 重新進行排序,與y保持初始順序一致 y_sort = cg_s_p.Sales[sortIndex] # 重新進行排序,倒序 y_sort2 = cg_s_p.Profit[sortIndex]rects1=plt.barh(np.arange(len(x_sort)), width=y_sort,height=0.35,alpha=0.8,label='銷售額') rects2=plt.barh(np.arange(len(x_sort)) - 0.35, width=y_sort2, height=0.35, label='利潤',alpha=0.8) plt.yticks(np.arange(len(x_sort)), x_sort, fontsize=14) plt.legend() plt.title('不同商品的銷售額與利潤',size=30)def add_labels(rects):for rect in rects:width = rect.get_width()plt.text(width+30000, rect.get_y(), '%d' % (width/1000) + 'K', ha='center',size=14)add_labels(rects1) add_labels(rects2) df[df['Sub-Category'].isin(['Phones','Copiers','Chairs','Bookcases','Storage','Appliances','Machines','Accessories','Tables'])].Sales.sum() / df.Sales.sum() 0.8390747077198337從不同商品銷售額與利潤可以看出:
- furniture(家具類)中Bookcases(書柜)、Chairs(椅子)、Tables(桌子);Office supplies(辦公用品)中Appliances(電器)、Storage(儲藏箱);Technology(技術類)中Accessories(附件)、Copiers(復印機)、Machines(機器)、Phones(電話),是銷售額最好的產品,這幾類產品占了銷售額總額的84%。這是該超市的主營產品類別,可以制定一些戰(zhàn)略來提高我們超市在顧客心智中對這幾類產品的認知,提高這幾類商品就能想到我們超市,從而提高我們的品牌影響力
- 銷售額較少的幾類產品,inders(粘合劑)、Furnishings(家具)、Art(藝術品)、Paper(紙)、Supplies(供應品)、Envelopes(信封)、Fasteners(緊固件)、Labels(標簽)均是辦公用品中的小物件,可以探索顧客購買商品的連帶關系,進行組合銷售優(yōu)化
- Tales(桌子)是唯一負利潤的產品,出現此狀況的原因可能是清理庫存或者是市場競爭大,需要結合實際業(yè)務來進行分析,改善此商品結構及經營策略
3.2.4 地域維度銷售額與利潤對比
從最開始的數據集信息可以知道,這是一所全球超市,在全球7個地方有分店,那么再來看一下不同分店的銷售額和利潤占比,以便對不同分店采取對應的經營策略(這里為了方便對比展示,使用tableau儀表盤)
從以上圖表可以看出
- 每家market總體每年銷售額均處于上升趨勢,其中APAC(亞太地區(qū))、EU(歐盟)、US(美國)、LATAM(拉丁美洲)的market占到了總銷售額的85%,總體也與地區(qū)的經濟發(fā)展相匹配
- 在APAC地區(qū)和EU地區(qū)的增長速度比較快速,可以看出市場占有能力在不斷增加,企業(yè)市場前景比較好,下一年可以適當加大運營成本,其他地區(qū)可以根據自身地區(qū)消費特點,借鑒上面APAC和EU地區(qū)的運營模式
- 通過銷售額與利潤占比來看,US、APAC、EU、Canada的利潤情況較好,其余地區(qū)利潤率較低,利潤低的地區(qū)可能折扣讓利幅度較大,后續(xù)分析地域維度對折扣的敏感度
3.3 效率指標
3.3.1 客單價
客單價是指商場(超市)每一個顧客平均購買商品的金額,客單價也即是平均交易金額。從某種程度上反映了企業(yè)的消費群體的許多特點以及企業(yè)的銷售類目的盈利狀態(tài)是否健康。
總消費次數:同一天內,同一個人發(fā)生的所有消費算作一次消費。
客單價=總消費金額 / 總消費次數
# 2011-2014年客單價 for i in range(2011,2015):data=df[df['year']==i]price=data[['Order Date','Customer ID','Sales']]# 計算總消費次數price_dr=price.drop_duplicates(subset=['Order Date', 'Customer ID'])# 總消費次數:有多少行total_num=price_dr.shape[0]print(f'{i}年總消費次數=',total_num)unit_price = price['Sales'].sum()/total_numprint(f'{i}年客單價=', unit_price,'\n') 2011年總消費次數= 4453 2011年客單價= 507.3997070604087 2012年總消費次數= 5392 2012年客單價= 496.55762136498515 2013年總消費次數= 6753 2013年客單價= 504.3308824788983 2014年總消費次數= 8696 2014年客單價= 494.4647965225392- 每年的消費次數呈不斷上升趨勢,但是客單價總體浮動范圍不是很大 ,穩(wěn)定在500左右
- 如果想要提高客單件的,可以在促銷時,贈送顧客一些滿399才能使用的一些折扣券,讓顧客多購買一些商品是常用的策略
- 提高客單價的另一個方式是增加單個訂單內商品的數量,但考慮到該超市主要商品類型是辦公用品類型的,商品消耗周期較長,可操作性不大,唯一可操的就是設置購買商品數量越多,折扣越大,從而降低商品的單價,增加顧客購買更多件商品的欲望
3.3.2 不同市場連帶率分布
# 每條記錄是一種類別的商品,但是探索發(fā)現,存在同一訂單,購買了多個種類的商品,先通過訂單號聚合,再計算訂單中商品的總數 order_together = df.groupby(['Order ID']).Quantity.sum().reset_index().merge(df[['Order Date','Order ID','Market']]).drop_duplicates() order_together.to_csv('order_together.csv') # 這里使用tableau展示- 總體來看,EU地區(qū)的連帶率最高,2014年連帶率超過9件,APAC、LATAM、US地區(qū)表現較好,Afica、EMEA、Canada地區(qū)連帶率差,均在5件左右
- 4年來各地區(qū)連帶率波動較為平穩(wěn),表現突出的是EU和Canada,這兩地連帶率有增長趨勢,其他地區(qū)可以借鑒這兩地的運營策略,如使用組合推薦等方式來提高連帶率,從而提高我們的整體銷售額
3.4 促銷活動分析
# 定義折扣等級,便于后續(xù)分析不同折扣帶來的銷售額和利潤 bins=[-0.01,0.01,0.2,0.5,1] df['discount_level'] = pd.cut(df.Discount, bins=bins, labels=['無折扣','低折扣','中折扣','高折扣'])# 創(chuàng)建不同折扣等級的銷售額,利潤DataFrame dis_s_p = df.groupby('discount_level')['Sales','Profit'].sum() dis_s_p| 7.253807e+06 | 1.828672e+06 |
| 3.458485e+06 | 4.534675e+05 |
| 1.558586e+06 | -4.021004e+05 |
| 3.716247e+05 | -4.125817e+05 |
3.4.1 不同折扣等級訂單的銷售額與利潤
index = np.arange(dis_s_p.shape[0]) rects1=plt.bar(x=index, height=dis_s_p.Sales, width=0.35, label='銷售額',alpha=0.8) rects2=plt.bar(x=index + 0.35, height=dis_s_p.Profit, width=0.35, label='利潤',alpha=0.8) plt.xticks(index +0.175, dis_s_p.index) plt.legend() plt.title('不同折扣等級訂單的銷售額與利潤')def add_labels(rects):for rect in rects:height = rect.get_height()plt.text(rect.get_x() + rect.get_width() / 2, height, '%d' % (height/10000) + 'W', ha='center', va='bottom',size=16)add_labels(rects1) add_labels(rects2)3.4.2 不同地區(qū)對折扣的敏感度
sns.barplot(x='Market', y='Sales', data=df, hue='discount_level',estimator=np.sum,alpha=0.8) plt.legend(loc='upper right') plt.title('不同市場不同折扣等級訂單銷售額');從上面兩張圖可以看出:
- 經過計算,對于無折扣訂單,利潤大約是銷售額的25%,低折扣訂單利潤大約是銷售額的13%,而折扣力度在0.2-0.5之間的訂單,已經是負利潤了,超過0.5折扣比例的訂單,幾乎是銷售額多少,就虧損多少
- 高折扣的訂單可能是因為商品積壓導致貶值,被迫虧本甩賣,應及時對商品結構進行診斷,對于難銷售,易積壓的商品,及時調整進貨策略
- 看不同地區(qū)對于折扣的敏感度可以看出,優(yōu)質地區(qū)為APAC、EU、US、LATAM,而在Canada我們沒有促銷活動,Africa和EMEA占比最大的是無折扣,可能因為商品的剛需所導致,而低折扣和中折扣幾乎的訂單幾乎沒有,只有高折扣的訂單,才能吸引到他們下單,由于高折扣訂單虧損嚴重,應及時進行戰(zhàn)略調整
4 用戶分析
4.1 用戶質量
4.1.1 用戶生命周期
用戶生命周期(Life Time),也稱作留存天數,從用戶第一次購買,到最后一次購買的天數
# 計算用戶第一次和最后一次消費時間 order_min = df.groupby('Customer ID')['Order Date'].min() order_max = df.groupby('Customer ID')['Order Date'].max() (order_max - order_min).mean() Timedelta('1158 days 15:55:28.301886')用戶的平均生命周期是1158天,即平均每個用戶最后一次購買時間與第一次購買時間的差值是1158天
# 用戶生命周期直方圖分布 ((order_max - order_min)/np.timedelta64(1,'D')).hist(bins=50,alpha=0.8);- 總體來看,該超市用戶的粘性較大,4年的統(tǒng)計周期內,大部分用戶的生命周期是1200天至1500天,根據此情況,我們可以在客戶消費后3年左右對其進行引導,促使其再次消費并形成消費習慣
- 另外針對不同階段的用戶,采取針對性的運營策略,從而延長用戶的生命周期,并且盡可能讓用戶產生商業(yè)價值
4.1.2 時間維度新增顧客數量
根據Customer ID列數據進行重復值的刪除,保證數據集中所有的客戶ID都是唯一的,然后使用透視表對數據進行整理。
data = df.drop_duplicates(subset=['Customer ID']) new_consumer = data.groupby(by=['year','month']).size().reset_index().rename(columns={0:"count"}) sns.factorplot(x='month',y='count',data=new_consumer,hue='year',size=10,aspect=1.3) plt.title('每年新顧客數量');從2011年到2014年總體來看
- 每一年的新增客戶數是逐年減少的趨勢,可以看出該超市對保持老用戶是有效的,超市的運營狀況較為穩(wěn)定,但新客戶獲取率比較低,可以不定期的進行主動推廣營銷,從而增加新客戶數。
4.1.3 復購率
# 每一條記錄是一個種類的商品,但是一個訂單可能包含多條記錄,由于計算復購不涉及商品信息,將一個訂單包含多件商品的記錄值保留一條 data = df.drop_duplicates(subset='Order ID') data['year_month'] = data['Order Date'].values.astype('datetime64[M]') pivoted=data.pivot_table(index='Customer ID',columns='year_month',values='Order Date',aggfunc='count').fillna(0) pivoted| 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 1.0 | 0.0 | 2.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 2.0 |
| 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 2.0 | 0.0 | 1.0 | 1.0 | 2.0 |
| 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | ... | 1.0 | 2.0 | 1.0 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 |
| 2.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | ... | 1.0 | 1.0 | 0.0 | 3.0 | 0.0 | 0.0 | 0.0 | 3.0 | 1.0 | 1.0 |
| 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | ... | 0.0 | 2.0 | 0.0 | 1.0 | 0.0 | 2.0 | 0.0 | 0.0 | 0.0 | 2.0 |
| 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 2.0 | ... | 0.0 | 0.0 | 1.0 | 2.0 | 2.0 | 1.0 | 0.0 | 1.0 | 2.0 | 5.0 |
| 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | ... | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
| 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 2.0 |
1590 rows × 48 columns
使用數據透視表對數據進行整理,將年月作為數據的列,客戶id作為數據的行索引。計算求復購率,復購率的定義是某月消費兩次及以上的用戶在總消費用戶中的占比,并且如果一個用戶在同一天下了兩筆訂單,也算作復購用戶
# 將消費兩次以上記為1,消費1次記為0,沒有消費記為nan pivoted = pivoted.applymap(lambda x:1 if x > 1 else np.nan if x == 0 else 0) pivoted| NaN | NaN | 0.0 | 0.0 | NaN | NaN | NaN | NaN | 0.0 | NaN | ... | NaN | 0.0 | NaN | 1.0 | 0.0 | 0.0 | NaN | NaN | NaN | 1.0 |
| NaN | NaN | NaN | 0.0 | NaN | NaN | 0.0 | NaN | NaN | 0.0 | ... | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 0.0 | 0.0 | 1.0 |
| 0.0 | NaN | 0.0 | 0.0 | NaN | 0.0 | NaN | 0.0 | NaN | NaN | ... | 0.0 | 1.0 | 0.0 | NaN | NaN | 0.0 | 0.0 | NaN | NaN | NaN |
| 1.0 | NaN | NaN | 0.0 | NaN | 0.0 | 0.0 | NaN | NaN | NaN | ... | 0.0 | 0.0 | NaN | 1.0 | NaN | NaN | NaN | 1.0 | 0.0 | 0.0 |
| NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.0 | NaN | NaN | ... | NaN | NaN | 0.0 | NaN | 0.0 | NaN | NaN | NaN | NaN | NaN |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 0.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.0 | ... | NaN | 1.0 | NaN | 0.0 | NaN | 1.0 | NaN | NaN | NaN | 1.0 |
| NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | 0.0 | NaN | NaN | NaN | NaN | NaN | NaN |
| NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.0 | 1.0 | ... | NaN | NaN | 0.0 | 1.0 | 1.0 | 0.0 | NaN | 0.0 | 1.0 | 1.0 |
| NaN | NaN | NaN | NaN | NaN | NaN | 0.0 | NaN | NaN | NaN | ... | 0.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.0 |
| NaN | 0.0 | NaN | NaN | 0.0 | NaN | NaN | 0.0 | 0.0 | NaN | ... | NaN | NaN | NaN | 0.0 | NaN | NaN | NaN | NaN | NaN | 1.0 |
1590 rows × 48 columns
使用sum和count計算復購率,這兩個函數都會忽略NaN值,sum計算的是在一個月內消費兩次及以上的用戶數,count計算的是在一個月內有過消費的客戶數
repeat_rate=pivoted.sum()/pivoted.count() repeat_rate.plot() plt.title('每年不同月份復購率波動') plt.ylabel('復購率',rotation=0);從上圖可以看出:
- 該超市用戶的整體復購率隨著年份的增長,逐漸增加,從最初2011年的0.1出頭,到2014年末,一月內復購率最高值達到了將近0.35,提升巨大
- 早期由于大量新用戶的加入,新客的復購率相對較低,而在后期復購率基本可以穩(wěn)定在20%-30%,可以看出用戶的粘性還是比較高的
4.2 用戶分類
4.2.1 客戶RFM模型
在面向客戶制定運營策略、營銷策略時,我們希望能夠針對不同的客戶推行不同的策略,實現精準化運營,以期獲取最大的轉化率。精準化運營的前提是客戶關系管理,而客戶關系管理的核心是客戶分類。
通過客戶分類,對客戶群體進行細分,區(qū)別出低價值客戶、高價值客戶,對不同的客戶群體開展不同的個性化服務,將有限的資源合理地分配給不同價值的客戶,實現效益最大化。
#定義用戶類別 def transform_label(x):if x == 111:label = '重要價值客戶'elif x == 110:label = '潛力客戶'elif x == 101:label = '重要發(fā)展客戶'elif x == 100:label = '新客戶'elif x == 11:label = '重要喚回客戶'elif x == 10:label = '一般客戶'elif x == 1:label = '重要挽留客戶'elif x == 0:label = '流失客戶'return labeldf = df[['Order ID','Order Date','Customer ID','Sales']]r = df.groupby('Customer ID')['Order Date'].max().reset_index() r['R'] = (pd.to_datetime('2015-1-1') - r['Order Date']).dt.days r = r[['Customer ID','R']]#每一條記錄代表一種商品,有些訂單有多種商品,原始數據會把訂單展開成多行,將其算成一次購買記錄,即頻次算1次 dup_f = df.groupby(['Customer ID','Order ID'])['Order Date'].count().reset_index() f = dup_f.groupby('Customer ID')['Order Date'].count().reset_index() f.columns = ['Customer ID','F']sum_m = df.groupby('Customer ID')['Sales'].sum().reset_index() com_m = pd.merge(sum_m,f,left_on = 'Customer ID',right_on = 'Customer ID',how = 'inner')#計算用戶平均支付金額 com_m['M'] = com_m['Sales'] / com_m['F']rfm = pd.merge(r,com_m,left_on = 'Customer ID',right_on = 'Customer ID',how = 'inner') rfm = rfm[['Customer ID','R','F','M']]rfm['R-SCORE'] = pd.cut(rfm['R'],bins = rfm['R'].quantile(q=np.linspace(0,1,num=6),interpolation='nearest'),labels = [5,4,3,2,1],right = False).astype(float) rfm['F-SCORE'] = pd.cut(rfm['F'],bins = rfm['F'].quantile(q=np.linspace(0,1,num=6),interpolation='nearest'),labels = [1,2,3,4,5],right = False).astype(float) rfm['M-SCORE'] = pd.cut(rfm['M'],bins = rfm['M'].quantile(q=np.linspace(0,1,num=6),interpolation='nearest'),labels = [1,2,3,4,5],right = False).astype(float)rfm['R>mean'] = (rfm['R-SCORE'] > rfm['R-SCORE'].mean()) * 1 rfm['F>mean'] = (rfm['F-SCORE'] > rfm['F-SCORE'].mean()) * 1 rfm['M>mean'] = (rfm['M-SCORE'] > rfm['M-SCORE'].mean()) * 1rfm['Score'] = (rfm['R>mean'] * 100) + (rfm['F>mean'] * 10) + (rfm['M>mean'] * 1)rfm['客戶類型'] = rfm['Score'].apply(transform_label)count = rfm['客戶類型'].value_counts().reset_index() count.columns = ['客戶類型','人數'] count['人數占比'] = count['人數'] / count['人數'].sum()rfm['購買總金額'] = rfm['F'] * rfm['M'] mon = rfm.groupby('客戶類型')['購買總金額'].sum().reset_index() mon.columns = ['客戶類型','消費金額'] mon['金額占比'] = mon['消費金額'] / mon['消費金額'].sum() result = pd.merge(count,mon,left_on = '客戶類型',right_on = '客戶類型') result| 流失客戶 | 402 | 0.252830 | 6.342346e+05 | 0.050167 |
| 重要價值客戶 | 320 | 0.201258 | 5.534281e+06 | 0.437752 |
| 新客戶 | 294 | 0.184906 | 7.515087e+05 | 0.059443 |
| 潛力客戶 | 210 | 0.132075 | 2.302542e+06 | 0.182127 |
| 重要挽留客戶 | 132 | 0.083019 | 7.162249e+05 | 0.056652 |
| 重要發(fā)展客戶 | 118 | 0.074214 | 1.072944e+06 | 0.084868 |
| 重要喚回客戶 | 66 | 0.041509 | 1.123060e+06 | 0.088832 |
| 一般客戶 | 48 | 0.030189 | 5.077063e+05 | 0.040159 |
顧客分層結構分析
- 各類顧客對銷售額的貢獻
從顧客分層結構來看:
- 可以看到無價值的流失客戶占據了最大的一部分,這里統(tǒng)計了三年內的用戶進行RFM模型構建,可見我們三年時間流失了超過1/4的用戶(或者說是沉睡客戶),雖然我們的營業(yè)額一直在提升,但是也不能掩飾我們流失客戶過多的問題
- 做的好的方面是我們的重要價值客戶占比非常大,超過了20%,貢獻了主要的銷售額流水,可以針對他們進行針對性的定制性、個性化服務
- 單純看占比是沒有意義的,因為我們的目的是擴大GMV,因此下面我們再結合消費金額分布情況,來看下我們實際應該針對哪些層級的用戶進行精準投放
| 重要價值客戶 | 320 | 0.201258 | 5.534281e+06 | 0.437752 | 0.437752 |
| 潛力客戶 | 210 | 0.132075 | 2.302542e+06 | 0.182127 | 0.619879 |
| 重要喚回客戶 | 66 | 0.041509 | 1.123060e+06 | 0.088832 | 0.708711 |
| 重要發(fā)展客戶 | 118 | 0.074214 | 1.072944e+06 | 0.084868 | 0.793579 |
| 新客戶 | 294 | 0.184906 | 7.515087e+05 | 0.059443 | 0.853022 |
| 重要挽留客戶 | 132 | 0.083019 | 7.162249e+05 | 0.056652 | 0.909674 |
| 流失客戶 | 402 | 0.252830 | 6.342346e+05 | 0.050167 | 0.959841 |
| 一般客戶 | 48 | 0.030189 | 5.077063e+05 | 0.040159 | 1.000000 |
從各類型客戶和銷售額占比可以看出:
- 重要價值客戶貢獻金額最高,44%的比例,可見該超市是有一群穩(wěn)定的老顧客,經常來超市消費,是銷售額的主要來源,潛力客戶和重要價值客戶,占了銷售額的62%,而其他6類用戶的貢獻金額較少,每個類群的客戶貢獻金額都不超過銷售額的10%
- 人數占比最多的流失客戶,貢獻金額只有5%左右,可見是有一群低質量的用戶,后續(xù)可以進行渠道跟蹤,摒棄用戶質量較差的渠道
- 應該著重將運營的重心放在重要價值客戶,如何留住核心收入來源的重要價值用戶以及通過推薦高質量產品等方法來擴大潛力顧客的購買金額,是現階段的任務。
- 通過整體的探索發(fā)現,此數據集收集的數據顯示,該超市4年銷售額累計1200余萬元,4年共有客戶接近1600人,可見規(guī)模不大,運營能力不會很強,以上圖的用戶分法并不能很好的去進行分組運營的落地,可以將用戶分成三類,重要價值客戶、潛力客戶、其他客戶,針對三類用戶群展開不同的運營策略會更容易實行,對這三類不同的客戶群體開展不同的個性化服務,將有限的資源合理地分配給不同價值的客戶,從而實現效益最大化。
4.2.2 K-means挖掘價值客戶
如上圖所示,將用戶分為8類,并不能很好的分群實行不同的運營策略,這里再嘗試用K-means機器學習算法進行分群
RFM=rfm[['Customer ID','R','F','購買總金額']] RFM.columns=['CustomerID','Recency','Frequency','Monetary'] RFM.describe()| 1590.000000 | 1590.000000 | 1590.000000 |
| 88.616981 | 16.196855 | 7951.259063 |
| 127.879879 | 10.619199 | 6936.570172 |
| 1.000000 | 1.000000 | 7.173000 |
| 15.000000 | 6.000000 | 1674.812250 |
| 41.000000 | 14.000000 | 6248.135590 |
| 104.000000 | 26.000000 | 13133.098420 |
| 1119.000000 | 41.000000 | 35668.120800 |
數據預處理
# 對數轉化 RFM_log = RFM[['Recency', 'Frequency', 'Monetary']].apply(np.log, axis=1).round(2) f,ax=plt.subplots(3,1,figsize=(10,12)) plt.subplot(3,1,1); sns.distplot(RFM_log['Recency'], label='Recency') plt.subplot(3,1,2); sns.distplot(RFM_log['Frequency'], label='Frequency') plt.subplot(3,1,3); sns.distplot(RFM_log['Monetary'],label='MemoryError');4.2.2.2 標準化處理
from sklearn.preprocessing import StandardScaler,NormalizerRFM_normalization = StandardScaler().fit_transform(RFM_log)4.2.2.3 選擇聚類數目
通常有兩種方法,一是肘部法則(Elbow Criterion method),選擇代價函數下降的顯著轉折點;二是業(yè)務經驗
這里使用肘部法則進行K值選擇,并且使用Calinski-Harabasz Index和TSNE降維可視化分析進行評估
from sklearn.cluster import KMeans # K值的選擇,1-8 ks = range(1,9) inertias=[] for k in ks:kc=KMeans(n_clusters=k, init='k-means++', random_state=1)kc.fit(RFM_normalization)inertias.append(kc.inertia_) # 樣本距離其聚類中心的距離平方和print('k=',k,'迭代次數',kc.n_iter_) k= 1 迭代次數 2 k= 2 迭代次數 4 k= 3 迭代次數 20 k= 4 迭代次數 8 k= 5 迭代次數 14 k= 6 迭代次數 11 k= 7 迭代次數 22 k= 8 迭代次數 12 # 繪制每個K值對應的inertia_f,ax=plt.subplots(figsize=(10,6)) plt.plot(ks,inertias,'-o') plt.xlabel('number of clusters') plt.ylabel('sum of squared distances') plt.title('Elbow criter method to find best k'); from sklearn import metrics kk = range(2,9) for k in kk:y_pred = KMeans(n_clusters=k, random_state=1).fit_predict(RFM_normalization) #k必須大于1calinski = metrics.calinski_harabaz_score(RFM_normalization, y_pred)print('k:',k,' calinski=',calinski) k: 2 calinski= 2290.9185040560255 k: 3 calinski= 1746.1656166404057 k: 4 calinski= 1721.8535796545677 k: 5 calinski= 1741.4614805385613 k: 6 calinski= 1590.1114912259004 k: 7 calinski= 1527.4148500701804 k: 8 calinski= 1506.3665579664887- 根據肘部法則定理,可以看到當k=2時,代價函數下降會有一個顯著轉折點,但分成兩類太少,對精益化運營氣不到效果,從calinski_harabaz_scores來看,除了分成2類,其次是k=3最大。結合業(yè)務而言,將用戶分成3類應該會是比較好的選擇
4.2.2.4 模型計算
kc = KMeans(n_clusters=3, random_state=1) kc.fit(RFM_normalization) # 每個樣本對應的類簇標簽,順序與樣本原始順序一致 RFM['K-means_label'] = kc.labels_ RFM.head()| AA-10315 | 9 | 19 | 13747.41300 | 0 |
| AA-10375 | 7 | 23 | 5884.19500 | 0 |
| AA-10480 | 118 | 20 | 17695.58978 | 0 |
| AA-10645 | 27 | 36 | 15343.89070 | 0 |
| AA-315 | 3 | 7 | 2243.25600 | 1 |
組內特征
RFM_normalization1=pd.DataFrame(RFM_normalization, index=RFM.index, columns=['Recency', 'Frequency', 'Monetary']) RFM_normalization1['K-means_label']=kc.labels_ RFM_melt=pd.melt(RFM_normalization1, id_vars=['K-means_label'],value_vars=['Recency', 'Frequency', 'Monetary'],var_name='Metric',value_name='Value')sns.lineplot(x = 'Metric', y = 'Value', hue = 'K-means_label',data = RFM_melt, palette=sns.color_palette("hls", 3)) plt.title("Plot of RFM"); k_cluster =RFM.groupby(['K-means_label']).agg({'Recency':'mean','Frequency':'mean','Monetary':['mean','count']}).round(2); k_cluster| 32.53 | 26.08 | 13849.78 | 793 |
| 29.26 | 7.66 | 2536.67 | 316 |
| 220.07 | 5.51 | 1783.87 | 481 |
對于RFM模型而言,R越小越好,而F和M則越大越好。從圖中3類用戶可以看出:
- 0:平均消費次數為26次,平均消費金額1.4W元左右,平均最近一次購買在一個月左右
- 1:平均消費次數為7次,平均消費金額2500元左右,平均最近一次購買在一個月左右
- 2: 平均消費次數為5次,平均消費金額1800元左右,平均最近一次購買在220天左右
針對類別0的高價值用戶,對其購物行為進行針對性分析,可以從以下幾個方面進行,從而提供個性化得消費方案,形成智能商業(yè)模式。
- 高價值用戶的消費習慣(購物時段)
- 購買的商品偏好
- 購物種類的關聯性(同時購買得產品)
4.2.2.6 顧客分層結構分析
# 構建各類別顧客數量的python原生態(tài)list labels=['類別0','類別1','類別2'] labels_count = [] for i in k_cluster['Monetary', 'count'].values:labels_count.append(int(i)) customer_list = [list(z) for z in zip(labels, labels_count)]# 構建各類別顧客銷售額的python原生態(tài)list customer_sales=RFM.groupby('K-means_label').agg({'Monetary': 'sum'}) labels_sales = [] for i in customer_sales.values:labels_sales.append(int(i)) sales_list = [list(z) for z in zip(labels, labels_sales)]p =(Pie(init_opts=opts.InitOpts(width="950px", height="600px",theme=ThemeType.MACARONS)).add(series_name="顧客數量及占比",data_pair=customer_list,radius=[0, "30%"],label_opts=opts.LabelOpts(position="inner"),).add(series_name="銷售額及占比",radius=["40%", "55%"],data_pair=sales_list,label_opts=opts.LabelOpts(position="outside",formatter="{a|{a}}{abg|}\n{hr|}\n {b|{b}: }{c} {per|ze8trgl8bvbq%} ",background_color="#eee",border_color="#aaa",border_width=1,border_radius=4,rich={"a": {"color": "#999", "lineHeight": 15, "align": "center"},"abg": {"backgroundColor": "#e3e3e3","width": "100%","align": "right","height": 15,"borderRadius": [4, 4, 0, 0],},"hr": {"borderColor": "#aaa","width": "100%","borderWidth": 0.5,"height": 0,},"b": {"fontSize": 16, "lineHeight": 20},"per": {"color": "#eee","backgroundColor": "#334455","padding": [2, 4],"borderRadius": 2,},},),).set_global_opts(title_opts=opts.TitleOpts(title='各類別顧客數量及銷售額占比',pos_left='center'),legend_opts=opts.LegendOpts(pos_left="left", orient="vertical")).set_series_opts(tooltip_opts=opts.TooltipOpts(trigger="item", formatter="{a} <br/>{b}: {c} (ze8trgl8bvbq%)")) ) p.render_notebook() <div id="8380e5561d83423ca753622d0798ca56" style="width:950px; height:600px;"></div>從上圖可以看出:
- 銷售額的主要來源是類別0的人群,他們人數占比50%,消費金額占比87%左右
- 可見此超市是有一群固定的高價值客戶來穩(wěn)定消費,粉絲群體穩(wěn)定,而且占比大,需要針對他們提供個性化方案,預防流失。
- 類別1和類別2的顧客區(qū)分并不明顯,如果運營能力有限,可以將其合并為一類用戶
5 結論建議
總結
- 上一篇: webflow_Webflow是否适合开
- 下一篇: 第二十五期:知乎用Go替代Python,