超市数据分析

1 业务背景

数据集来源于:kaggle数据集(链接),该数据集记录了某全球超市四年的销售数据,通过分析该超市四年内的销售数据,从不同角度出发,分析经营现状,发掘提高销量的销售策略,利用数据找到新的增长点,并提出建议。

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())
Row IDOrder IDOrder DateShip DateShip ModeCustomer IDCustomer NameSegmentCityState...Product IDCategorySub-CategoryProduct NameSalesQuantityDiscountProfitShipping CostOrder Priority
042433AG-2011-20401/1/20116/1/2011Standard ClassTB-11280Toby BraunhardtConsumerConstantineConstantine...OFF-TEN-10000025Office SuppliesStorageTenex Lockers, Blue408.30020.0106.140035.46Medium
122253IN-2011-478831/1/20118/1/2011Standard ClassJH-15985Joseph HoltConsumerWagga WaggaNew South Wales...OFF-SU-10000618Office SuppliesSuppliesAcme Trimmer, High Speed120.36630.136.03609.72Medium
248883HU-2011-12201/1/20115/1/2011Second ClassAT-735Annie ThurmanConsumerBudapestBudapest...OFF-TEN-10001585Office SuppliesStorageTenex Box, Single Width66.12040.029.64008.17High
311731IT-2011-36476321/1/20115/1/2011Second ClassEM-14140Eugene MorenHome OfficeStockholmStockholm...OFF-PA-10001492Office SuppliesPaperEnermax Note Cards, Premium44.86530.5-26.05504.82High
422255IN-2011-478831/1/20118/1/2011Standard ClassJH-15985Joseph HoltConsumerWagga WaggaNew South Wales...FUR-FU-10003447FurnitureFurnishingsEldon Light Bulb, Duo Pack113.67050.137.77004.70Medium
5128532593CA-2014-11542731-12-20144/1/2015Standard ClassEB-13975Erica BernCorporateFairfieldCalifornia...OFF-BI-10002103Office SuppliesBindersCardinal Slant-D Ring Binder, Heavy Gauge Vinyl13.90420.24.51880.89Medium
5128647594MO-2014-256031-12-20145/1/2015Standard ClassLP-7095Liz PreisConsumerAgadirSouss-Massa-Draâ...OFF-WIL-10001069Office SuppliesBindersWilson Jones Hole Reinforcements, Clear3.99010.00.42000.49Medium
512878857MX-2014-11052731-12-20142/1/2015Second ClassCM-12190Charlotte MeltonConsumerManaguaManagua...OFF-LA-10004182Office SuppliesLabelsHon Color Coded Labels, 5000 Label Set26.40030.012.36000.35Medium
512886852MX-2014-11478331-12-20146/1/2015Standard ClassTD-20995Tamara DahlenConsumerJuárezChihuahua...OFF-LA-10000413Office SuppliesLabelsHon Legal Exhibit Labels, Alphabetical7.12010.00.56000.20Medium
5128936388CA-2014-15672031-12-20144/1/2015Standard ClassJM-15580Jill MatthiasConsumerLovelandColorado...OFF-FA-10003472Office SuppliesFastenersBagged Rubber Bands3.02430.2-0.60480.17Medium

10 rows × 24 columns

2.2 总览数据

数据维度有点多,显示不全,先转置看看各个维度的数据大概长什么样

df[-5:].T
5128551286512875128851289
Row ID32593475948857685236388
Order IDCA-2014-115427MO-2014-2560MX-2014-110527MX-2014-114783CA-2014-156720
Order Date31-12-201431-12-201431-12-201431-12-201431-12-2014
Ship Date4/1/20155/1/20152/1/20156/1/20154/1/2015
Ship ModeStandard ClassStandard ClassSecond ClassStandard ClassStandard Class
Customer IDEB-13975LP-7095CM-12190TD-20995JM-15580
Customer NameErica BernLiz PreisCharlotte MeltonTamara DahlenJill Matthias
SegmentCorporateConsumerConsumerConsumerConsumer
CityFairfieldAgadirManaguaJuárezLoveland
StateCaliforniaSouss-Massa-DraâManaguaChihuahuaColorado
CountryUnited StatesMoroccoNicaraguaMexicoUnited States
Postal Code94533NaNNaNNaN80538
MarketUSAfricaLATAMLATAMUS
RegionWestAfricaCentralNorthWest
Product IDOFF-BI-10002103OFF-WIL-10001069OFF-LA-10004182OFF-LA-10000413OFF-FA-10003472
CategoryOffice SuppliesOffice SuppliesOffice SuppliesOffice SuppliesOffice Supplies
Sub-CategoryBindersBindersLabelsLabelsFasteners
Product NameCardinal Slant-D Ring Binder, Heavy Gauge VinylWilson Jones Hole Reinforcements, ClearHon Color Coded Labels, 5000 Label SetHon Legal Exhibit Labels, AlphabeticalBagged Rubber Bands
Sales13.9043.9926.47.123.024
Quantity21313
Discount0.20000.2
Profit4.51880.4212.360.56-0.6048
Shipping Cost0.890.490.350.20.17
Order PriorityMediumMediumMediumMediumMedium
df.columns
Index(['Row ID', 'Order ID', 'Order Date', 'Ship Date', 'Ship Mode','Customer ID', 'Customer Name', 'Segment', 'City', 'State', 'Country','Postal Code', 'Market', 'Region', 'Product ID', 'Category','Sub-Category', 'Product Name', 'Sales', 'Quantity', 'Discount','Profit', 'Shipping Cost', 'Order Priority'],dtype='object')
  • 各维度分别为:行编号、订单编号、订购日期、发货日期、运送方式、客户ID、客户姓名、客户类型、客户城市、客户所在州、客户国家、邮编、店铺所在区域、店铺所属州、产品ID、类别、子类别、产品名称、销售额、销售量、折扣、利润、运输费、订单优先级 共24个维度
  • 行编号无用,直接删除
del df['Row ID']
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 51290 entries, 0 to 51289
Data columns (total 23 columns):#   Column          Non-Null Count  Dtype  
---  ------          --------------  -----  0   Order ID        51290 non-null  object 1   Order Date      51290 non-null  object 2   Ship Date       51290 non-null  object 3   Ship Mode       51290 non-null  object 4   Customer ID     51290 non-null  object 5   Customer Name   51290 non-null  object 6   Segment         51290 non-null  object 7   City            51290 non-null  object 8   State           51290 non-null  object 9   Country         51290 non-null  object 10  Postal Code     9994 non-null   float6411  Market          51290 non-null  object 12  Region          51290 non-null  object 13  Product ID      51290 non-null  object 14  Category        51290 non-null  object 15  Sub-Category    51290 non-null  object 16  Product Name    51290 non-null  object 17  Sales           51290 non-null  float6418  Quantity        51290 non-null  int64  19  Discount        51290 non-null  float6420  Profit          51290 non-null  float6421  Shipping Cost   51290 non-null  float6422  Order Priority  51290 non-null  object 
dtypes: float64(5), int64(1), object(17)
memory usage: 9.0+ MB

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 更改数据类型,并创建时间维度字段

# 将订单日期更改为日期格式
df['Order Date']=pd.to_datetime(df['Order Date'])# 添加年和月的列,便于后续进行时间维度的分析
df['year'] = df['Order Date'].dt.year
df['month'] = df['Order Date'].dt.month

3 经营分析

3.1 销售额分析

# 创建销售额透视表
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
2011年2012年2013年2014年
1月138241.30042162800.89338206459.19582268265.52240
2月134969.94086152661.15144191062.77216244159.30486
3月171455.59372201608.72784230547.79468347720.96868
4月128833.47034187469.96192233181.34844302132.54000
5月148146.72092218960.16042304509.96336304798.83604
6月189338.43966249289.77172341162.34370372577.23298
7月162034.69756174394.02808223642.65664278672.17326
8月219223.49524271669.66086323876.60716432731.04194
9月255237.89698256567.85308326897.27044405436.70584
10月204675.07846239321.09904270121.87570406659.41500
11月214934.29386270723.05356383039.21248508954.73156
12月292359.96752291972.33306371245.40880427757.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
Sales_sumrise_rate
2011年2.259451e+060.000000
2012年2.677439e+060.184995
2013年3.405746e+060.272017
2014年4.299866e+060.262533
x1 = x2 = sales_sum.index
y1 = sales_sum.Sales_sum
y2 = sales_sum.rise_rate# 建立左侧纵坐标画板
fig, ax1 = plt.subplots()
# 画柱状图
bar = ax1.bar(x1, y1, alpha=0.8, label = '销售额')
# 显示左侧纵坐标
ax1.set_ylabel('销售额', fontsize=20)
plt.yticks(range(0,5500000,500000),('0','50W','100W','150W','200W','250W','300W','350W','400W','450W'))
ax1.legend(bar, ("销售额",), loc = [0.05, 0.9])
plt.tick_params(labelsize=14)# 建立右侧坐标画板
ax2 = ax1.twinx()
# 画折线图
line = ax2.plot(x2, y2, marker='o' ,c='y')
# 折线图显示标识
for a, b in zip(x2, y2):  ax2.text(a, b, "%.2f" % (100 * b) + '%', ha='center', fontsize=20)  
ax2.set_ylabel('增长率', fontsize=20, rotation=270)
ax2.legend(line, ('增长率',), loc = [0.05, 0.85])
plt.tick_params(labelsize=14)
ax2.set_title("年度销售额及其增长率", fontsize=22);

在这里插入图片描述

从年度销售额及其增长率来看:

  • 该超市2011年销售额只有226万,2014年销售额达到了430万,GMV提升非常快,从行业发展阶段来看,该超市应该处于导入期或成长期
  • 该超市主营办公用品,据了解,全球领先的办公用品供应商包括:Costco、Office Depot、Staples、Tesco和沃尔玛,查询沃尔玛2014年销售额得知,沃尔玛2014年销售额为4731亿美元,可见与全球大型超市对比,差距大,可提升空间较大
  • 从增长率来看,增长率非常高,12-13年、13-14年GMV增长率接近均超过25%,而沃尔玛2013-2014的增长率大概为3%,可见该超市潜力非常大
  • 了解了超市整体销售额后,再对每年每月的销售额进行分析,了解不同月份的销售情况,找出是否有淡旺季之分,找出重点销售月份,以便制定经营策略与业绩的月度及季度指标拆分

3.1.1.2 月度销售额

sales.plot.area(colormap = 'tab20c', stacked=False)
plt.title('月度销售额')
plt.ylabel('销售额')
plt.xlabel('月份');

在这里插入图片描述

通过不同年份月度销售额我们可以看出:

  • 该超市2011年-2014年每一年的销售额同比上一年都是上升趋势,销售季节性明显,总体上半年是淡季,下半年是旺季
  • 上半年中6月份销售额比较高,下半年中7月份的销售额偏低。对于旺季的月份,运营推广等策略要继续维持,还可以加大投入,提高整体销售额;对于淡季的月份,可以结合产品特点进行新产品拓展,举办一些促销活动等吸引客户

3.2 利润分析

# 创建利润透视表
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
2011年2012年2013年2014年
1月13457.2330219627.4205826052.4025231447.74660
2月17588.8372617828.1824431553.9975629454.01876
3月16169.3606222752.8768434873.7193850097.04458
4月13405.4692420804.0053226008.0514435709.53320
5月14777.4579222865.3957239053.3094634335.60404
6月25932.8779634358.0396243298.8500040869.02108
7月10631.8440621725.1880827019.9129426450.70856
8月19650.6712436511.4499632977.7557646443.47934
9月32313.2545825039.9349818850.0908452533.83284
10月30745.5416627773.8745427871.9747052342.49740
11月21261.4053626160.6068651720.8856855561.72406
12月33006.8586231968.3041647654.2799048920.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
Profit_sumrise_rateprofit_rate
2011年248940.811540.0000000.110178
2012年307415.279100.2348930.114817
2013年406935.230180.3237310.119485
2014年504165.970460.2389340.117252
# 建立左侧纵坐标画板
fig, ax1 = plt.subplots()
# 画堆叠图
s = plt.bar(sales_sum.index,sales_sum.Sales_sum, alpha=0.5, label='销售额')
p = plt.bar(profit_sum.index, profit_sum.Profit_sum,color='b' ,alpha=0.8, label='利润')
# 显示左侧纵坐标
ax1.set_ylabel('销售额', fontsize=20)
plt.yticks(range(0,5500000,500000),('0','50W','100W','150W','200W','250W','300W','350W','400W','450W'))
# 显示文字
for x1,y1 in zip(profit_sum.index, profit_sum.profit_rate):plt.text(x1, y1+20000, '%.2f%%'% (y1*100), ha='center', color='w',fontsize=20)
plt.legend()
# 建立右侧坐标画板
ax2 = ax1.twinx()
# # 画折线图
line = ax2.plot(profit_sum.index, profit_sum.rise_rate, marker='o' ,c='y',ms=10)
# # 折线图显示标识
for a, b in zip(profit_sum.index, profit_sum.rise_rate):  ax2.text(a, b, "%.2f" % (100 * b) + '%', ha='center', fontsize=20)  
ax2.set_ylabel('利润增长率', fontsize=20, rotation=270)
ax2.set_title("年度利润占比及其增长率", fontsize=22)
ax2.legend(line, ('利润增长率',), loc = [0.007, 0.89]);

在这里插入图片描述

从各年度利润及利润增长率可以看出:

  • 利润是在逐年递增,利润率平稳位置在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
rise_2012rise_2013rise_2014
1月0.4585030.3273470.207096
2月0.0136080.769894-0.066552
3月0.4071600.5327170.436527
4月0.5519040.2501460.373018
5月0.5473160.707966-0.120802
6月0.3248830.260225-0.056118
7月1.0434070.243714-0.021066
8月0.858026-0.0967830.408327
9月-0.225088-0.2471991.786927
10月-0.0966540.0035320.877962
11月0.2304270.9770520.074261
12月-0.0314650.4906730.026576
plt.plot(rise_2.index, rise_2.rise_2012,linewidth=5, marker='o',ms=15,label='2012年同比增长')
plt.plot(rise_2.index, rise_2.rise_2013,linewidth=5, marker='o',ms=15,label='2013年同比增长')
plt.plot(rise_2.index, rise_2.rise_2014,linewidth=5, marker='o',ms=15,label='2014年同比增长')
plt.ylabel('增长率')
plt.title('每年不同月份利润同比增长率')
plt.legend(loc='upper left');

在这里插入图片描述

从每一年不同月份的利润同比增长率来看:

  • 整体来看,利润同比波动较大,存在不少负增长的情况,说明该超市处于导入期和成长期的概率较大,注重用户体量,整体规模的扩大,并不是非常重视盈利情况,这与公司的发展阶段和战略布局有关,比如我国的京东,毛利率就不高,去掉运营费用,管理费用,履约费用等,利润率常年负数,但依然能够发展壮大

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,亏损严重,后续对商品维度和折扣情况进行分析,从而改善负利润订单情况

3.2.3 不同商品销售额与利润

# 创建不同商品销售额与利润情况
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%。这是该超市的主营产品类别,可以制定一些战略来提高我们超市在顾客心智中对这几类产品的认知,提高这几类商品就能想到我们超市,从而提高我们的品牌影响力
  • 销售额较少的几类产品,inders(粘合剂)、Furnishings(家具)、Art(艺术品)、Paper(纸)、Supplies(供应品)、Envelopes(信封)、Fasteners(紧固件)、Labels(标签)均是办公用品中的小物件,可以探索顾客购买商品的连带关系,进行组合销售优化
  • Tales(桌子)是唯一负利润的产品,出现此状况的原因可能是清理库存或者是市场竞争大,需要结合实际业务来进行分析,改善此商品结构及经营策略

3.2.4 地域维度销售额与利润对比

从最开始的数据集信息可以知道,这是一所全球超市,在全球7个地方有分店,那么再来看一下不同分店的销售额和利润占比,以便对不同分店采取对应的经营策略(这里为了方便对比展示,使用tableau仪表盘)

在这里插入图片描述

从以上图表可以看出

  • 每家market总体每年销售额均处于上升趋势,其中APAC(亚太地区)、EU(欧盟)、US(美国)、LATAM(拉丁美洲)的market占到了总销售额的85%,总体也与地区的经济发展相匹配
  • 在APAC地区和EU地区的增长速度比较快速,可以看出市场占有能力在不断增加,企业市场前景比较好,下一年可以适当加大运营成本,其他地区可以根据自身地区消费特点,借鉴上面APAC和EU地区的运营模式
  • 通过销售额与利润占比来看,US、APAC、EU、Canada的利润情况较好,其余地区利润率较低,利润低的地区可能折扣让利幅度较大,后续分析地域维度对折扣的敏感度

3.3 效率指标

3.3.1 客单价

客单价是指商场(超市)每一个顾客平均购买商品的金额,客单价也即是平均交易金额。从某种程度上反映了企业的消费群体的许多特点以及企业的销售类目的盈利状态是否健康。

总消费次数:同一天内,同一个人发生的所有消费算作一次消费。

客单价=总消费金额 / 总消费次数

# 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 
  • 每年的消费次数呈不断上升趋势,但是客单价总体浮动范围不是很大 ,稳定在500左右
  • 如果想要提高客单件的,可以在促销时,赠送顾客一些满399才能使用的一些折扣券,让顾客多购买一些商品是常用的策略
  • 提高客单价的另一个方式是增加单个订单内商品的数量,但考虑到该超市主要商品类型是办公用品类型的,商品消耗周期较长,可操作性不大,唯一可操的就是设置购买商品数量越多,折扣越大,从而降低商品的单价,增加顾客购买更多件商品的欲望

3.3.2 不同市场连带率分布

# 每条记录是一种类别的商品,但是探索发现,存在同一订单,购买了多个种类的商品,先通过订单号聚合,再计算订单中商品的总数
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地区的连带率最高,2014年连带率超过9件,APAC、LATAM、US地区表现较好,Afica、EMEA、Canada地区连带率差,均在5件左右
  • 4年来各地区连带率波动较为平稳,表现突出的是EU和Canada,这两地连带率有增长趋势,其他地区可以借鉴这两地的运营策略,如使用组合推荐等方式来提高连带率,从而提高我们的整体销售额

3.4 促销活动分析

# 定义折扣等级,便于后续分析不同折扣带来的销售额和利润
bins=[-0.01,0.01,0.2,0.5,1]
df['discount_level'] = pd.cut(df.Discount, bins=bins, labels=['无折扣','低折扣','中折扣','高折扣'])# 创建不同折扣等级的销售额,利润DataFrame
dis_s_p = df.groupby('discount_level')['Sales','Profit'].sum()
dis_s_p
SalesProfit
discount_level
无折扣7.253807e+061.828672e+06
低折扣3.458485e+064.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 不同地区对折扣的敏感度

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折扣比例的订单,几乎是销售额多少,就亏损多少
  • 高折扣的订单可能是因为商品积压导致贬值,被迫亏本甩卖,应及时对商品结构进行诊断,对于难销售,易积压的商品,及时调整进货策略
  • 看不同地区对于折扣的敏感度可以看出,优质地区为APAC、EU、US、LATAM,而在Canada我们没有促销活动,Africa和EMEA占比最大的是无折扣,可能因为商品的刚需所导致,而低折扣和中折扣几乎的订单几乎没有,只有高折扣的订单,才能吸引到他们下单,由于高折扣订单亏损严重,应及时进行战略调整

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年的统计周期内,大部分用户的生命周期是1200天至1500天,根据此情况,我们可以在客户消费后3年左右对其进行引导,促使其再次消费并形成消费习惯
  • 另外针对不同阶段的用户,采取针对性的运营策略,从而延长用户的生命周期,并且尽可能让用户产生商业价值

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年总体来看

  • 每一年的新增客户数是逐年减少的趋势,可以看出该超市对保持老用户是有效的,超市的运营状况较为稳定,但新客户获取率比较低,可以不定期的进行主动推广营销,从而增加新客户数。

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
year_month2011-01-012011-02-012011-03-012011-04-012011-05-012011-06-012011-07-012011-08-012011-09-012011-10-01...2014-03-012014-04-012014-05-012014-06-012014-07-012014-08-012014-09-012014-10-012014-11-012014-12-01
Customer ID
AA-103150.00.01.01.00.00.00.00.01.00.0...0.01.00.02.01.01.00.00.00.02.0
AA-103750.00.00.01.00.00.01.00.00.01.0...0.00.00.00.00.02.00.01.01.02.0
AA-104801.00.01.01.00.01.00.01.00.00.0...1.02.01.00.00.01.01.00.00.00.0
AA-106452.00.00.01.00.01.01.00.00.00.0...1.01.00.03.00.00.00.03.01.01.0
AA-3150.00.00.00.00.00.00.01.00.00.0...0.00.01.00.01.00.00.00.00.00.0
..................................................................
YS-218801.00.00.00.00.00.00.00.00.01.0...0.02.00.01.00.02.00.00.00.02.0
ZC-119100.00.00.00.00.00.00.00.00.00.0...0.00.00.01.00.00.00.00.00.00.0
ZC-219100.00.00.00.00.00.00.00.01.02.0...0.00.01.02.02.01.00.01.02.05.0
ZD-119250.00.00.00.00.00.01.00.00.00.0...1.00.00.00.00.00.00.00.00.01.0
ZD-219250.01.00.00.01.00.00.01.01.00.0...0.00.00.01.00.00.00.00.00.02.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
year_month2011-01-012011-02-012011-03-012011-04-012011-05-012011-06-012011-07-012011-08-012011-09-012011-10-01...2014-03-012014-04-012014-05-012014-06-012014-07-012014-08-012014-09-012014-10-012014-11-012014-12-01
Customer ID
AA-10315NaNNaN0.00.0NaNNaNNaNNaN0.0NaN...NaN0.0NaN1.00.00.0NaNNaNNaN1.0
AA-10375NaNNaNNaN0.0NaNNaN0.0NaNNaN0.0...NaNNaNNaNNaNNaN1.0NaN0.00.01.0
AA-104800.0NaN0.00.0NaN0.0NaN0.0NaNNaN...0.01.00.0NaNNaN0.00.0NaNNaNNaN
AA-106451.0NaNNaN0.0NaN0.00.0NaNNaNNaN...0.00.0NaN1.0NaNNaNNaN1.00.00.0
AA-315NaNNaNNaNNaNNaNNaNNaN0.0NaNNaN...NaNNaN0.0NaN0.0NaNNaNNaNNaNNaN
..................................................................
YS-218800.0NaNNaNNaNNaNNaNNaNNaNNaN0.0...NaN1.0NaN0.0NaN1.0NaNNaNNaN1.0
ZC-11910NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN...NaNNaNNaN0.0NaNNaNNaNNaNNaNNaN
ZC-21910NaNNaNNaNNaNNaNNaNNaNNaN0.01.0...NaNNaN0.01.01.00.0NaN0.01.01.0
ZD-11925NaNNaNNaNNaNNaNNaN0.0NaNNaNNaN...0.0NaNNaNNaNNaNNaNNaNNaNNaN0.0
ZD-21925NaN0.0NaNNaN0.0NaNNaN0.00.0NaN...NaNNaNNaN0.0NaNNaNNaNNaNNaN1.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,提升巨大
  • 早期由于大量新用户的加入,新客的复购率相对较低,而在后期复购率基本可以稳定在20%-30%,可以看出用户的粘性还是比较高的

4.2 用户分类

4.2.1 客户RFM模型

在面向客户制定运营策略、营销策略时,我们希望能够针对不同的客户推行不同的策略,实现精准化运营,以期获取最大的转化率。精准化运营的前提是客户关系管理,而客户关系管理的核心是客户分类。

通过客户分类,对客户群体进行细分,区别出低价值客户、高价值客户,对不同的客户群体开展不同的个性化服务,将有限的资源合理地分配给不同价值的客户,实现效益最大化。

在这里插入图片描述

#定义用户类别
def transform_label(x):if x == 111:label = '重要价值客户'elif x == 110:label = '潜力客户'elif x == 101:label = '重要发展客户'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
客户类型人数人数占比消费金额金额占比
0流失客户4020.2528306.342346e+050.050167
1重要价值客户3200.2012585.534281e+060.437752
2新客户2940.1849067.515087e+050.059443
3潜力客户2100.1320752.302542e+060.182127
4重要挽留客户1320.0830197.162249e+050.056652
5重要发展客户1180.0742141.072944e+060.084868
6重要唤回客户660.0415091.123060e+060.088832
7一般客户480.0301895.077063e+050.040159

顾客分层结构分析

  • 各类顾客对销售额的贡献
from pyecharts.charts import Grid, Pie, Bar
from pyecharts import options as opts
from pyecharts.globals import ThemeType# 这里为了美观和交互性,使用pyecharts做南丁格尔玫瑰图,需要将numpy.int转化成python原生态int
customer_category_sum = []
for i in result['人数'].values:customer_category_sum.append(int(i))
customer_list = [list(z) for z in zip(result['客户类型'], customer_category_sum)]# 绘制饼图
pie = (Pie(init_opts=opts.InitOpts(theme=ThemeType.MACARONS,bg_color='white')).add('',customer_list,radius=['30%','75%'],rosetype='radius',label_opts=opts.LabelOpts(is_show=True)).set_global_opts(title_opts=opts.TitleOpts(title='顾客分层结构',pos_left='center'),toolbox_opts=opts.ToolboxOpts(is_show=True),legend_opts=opts.LegendOpts(orient='vertical',pos_right='0%',pos_top='30%')).set_series_opts(label_opts=opts.LabelOpts(formatter='{b}:{d}%')))
pie.render_notebook()
    <div id="fcb635cef5044684b6483e669497d314" style="width:900px; height:500px;"></div>

在这里插入图片描述

从顾客分层结构来看:

  • 可以看到无价值的流失客户占据了最大的一部分,这里统计了三年内的用户进行RFM模型构建,可见我们三年时间流失了超过1/4的用户(或者说是沉睡客户),虽然我们的营业额一直在提升,但是也不能掩饰我们流失客户过多的问题
  • 做的好的方面是我们的重要价值客户占比非常大,超过了20%,贡献了主要的销售额流水,可以针对他们进行针对性的定制性、个性化服务
  • 单纯看占比是没有意义的,因为我们的目的是扩大GMV,因此下面我们再结合消费金额分布情况,来看下我们实际应该针对哪些层级的用户进行精准投放
result.sort_values(by=['消费金额'],ascending=False,inplace=True)
sales_rate=[]; a=0
for i in result.金额占比:a +=isales_rate.append(a)
result['金额占比累加'] = sales_rate
result
客户类型人数人数占比消费金额金额占比金额占比累加
1重要价值客户3200.2012585.534281e+060.4377520.437752
3潜力客户2100.1320752.302542e+060.1821270.619879
6重要唤回客户660.0415091.123060e+060.0888320.708711
5重要发展客户1180.0742141.072944e+060.0848680.793579
2新客户2940.1849067.515087e+050.0594430.853022
4重要挽留客户1320.0830197.162249e+050.0566520.909674
0流失客户4020.2528306.342346e+050.0501670.959841
7一般客户480.0301895.077063e+050.0401591.000000
# 建立左侧纵坐标画板
fig, ax1 = plt.subplots()
# 画柱状图图
s = plt.bar(result.客户类型, result.消费金额, alpha=0.5, label='消费金额')
# 显示左侧纵坐标
ax1.set_ylabel('消费金额', fontsize=20)
plt.yticks(range(0,6000000,500000),['0','50W','100W','150W','200W','250W','300W','350W','400W','450W','500W','550W'])
plt.tick_params(labelsize=14)
# 显示文字
for x1,y1 in zip(result.客户类型, result.消费金额):plt.text(x1, y1+20000, str(int(y1/10000)) + 'W' , ha='center',fontsize=20)ax2 = ax1.twinx()
# # 画折线图
line = ax2.plot(result.客户类型, result.金额占比累加, linewidth=3,marker='o' ,c='y',ms=10)
# # 折线图显示标识
for a, b in zip(result.客户类型, result.金额占比累加):  ax2.text(a, b+0.02, "%.0f" % (100 * b) + '%', ha='center', fontsize=20)  
ax2.set_ylabel('金额占比累加', fontsize=20, rotation=270)
plt.ylim(0,1.05)
plt.tick_params(labelsize=14)
ax2.set_title("各类型顾客消费额及其累加占比", fontsize=22)
plt.show()

在这里插入图片描述

从各类型客户和销售额占比可以看出:

  • 重要价值客户贡献金额最高,44%的比例,可见该超市是有一群稳定的老顾客,经常来超市消费,是销售额的主要来源,潜力客户和重要价值客户,占了销售额的62%,而其他6类用户的贡献金额较少,每个类群的客户贡献金额都不超过销售额的10%
  • 人数占比最多的流失客户,贡献金额只有5%左右,可见是有一群低质量的用户,后续可以进行渠道跟踪,摒弃用户质量较差的渠道
  • 应该着重将运营的重心放在重要价值客户,如何留住核心收入来源的重要价值用户以及通过推荐高质量产品等方法来扩大潜力顾客的购买金额,是现阶段的任务。
  • 通过整体的探索发现,此数据集收集的数据显示,该超市4年销售额累计1200余万元,4年共有客户接近1600人,可见规模不大,运营能力不会很强,以上图的用户分法并不能很好的去进行分组运营的落地,可以将用户分成三类,重要价值客户、潜力客户、其他客户,针对三类用户群展开不同的运营策略会更容易实行,对这三类不同的客户群体开展不同的个性化服务,将有限的资源合理地分配给不同价值的客户,从而实现效益最大化。

4.2.2 K-means挖掘价值客户

如上图所示,将用户分为8类,并不能很好的分群实行不同的运营策略,这里再尝试用K-means机器学习算法进行分群

RFM=rfm[['Customer ID','R','F','购买总金额']]
RFM.columns=['CustomerID','Recency','Frequency','Monetary']
RFM.describe()
RecencyFrequencyMonetary
count1590.0000001590.0000001590.000000
mean88.61698116.1968557951.259063
std127.87987910.6191996936.570172
min1.0000001.0000007.173000
25%15.0000006.0000001674.812250
50%41.00000014.0000006248.135590
75%104.00000026.00000013133.098420
max1119.00000041.00000035668.120800
# 观测一下数据分布
f,ax = plt.subplots(3,1,figsize=(10, 12))
plt.subplot(3,1,1); sns.distplot(RFM['Recency'],label='Recency')
plt.subplot(3,1,2); sns.distplot(RFM['Frequency'],label='Frequency')
plt.subplot(3,1,3); sns.distplot(RFM['Monetary'],label='Monetary');

在这里插入图片描述

数据预处理

# 对数转化
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),选择代价函数下降的显著转折点;二是业务经验

这里使用肘部法则进行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最大。结合业务而言,将用户分成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()
CustomerIDRecencyFrequencyMonetaryK-means_label
0AA-1031591913747.413000
1AA-103757235884.195000
2AA-104801182017695.589780
3AA-10645273615343.890700
4AA-315372243.256001

组内特征

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
RecencyFrequencyMonetary
meanmeanmeancount
K-means_label
032.5326.0813849.78793
129.267.662536.67316
2220.075.511783.87481

对于RFM模型而言,R越小越好,而F和M则越大越好。从图中3类用户可以看出:

  • 0:平均消费次数为26次,平均消费金额1.4W元左右,平均最近一次购买在一个月左右
  • 1:平均消费次数为7次,平均消费金额2500元左右,平均最近一次购买在一个月左右
  • 2: 平均消费次数为5次,平均消费金额1800元左右,平均最近一次购买在220天左右

针对类别0的高价值用户,对其购物行为进行针对性分析,可以从以下几个方面进行,从而提供个性化得消费方案,形成智能商业模式。

  • 高价值用户的消费习惯(购物时段)
  • 购买的商品偏好
  • 购物种类的关联性(同时购买得产品)
# TSNE降维
from sklearn.manifold import TSNEtsne = TSNE(n_components=2, random_state=1)
X_tsne = tsne.fit_transform(RFM_normalization)
k_range = KMeans(n_clusters=3, random_state=1)
k_range.fit(RFM_normalization)
cluster_labels = kc.labels_plt.scatter(X_tsne[:, 0],X_tsne[:, 1], c=cluster_labels);

在这里插入图片描述

4.2.2.6 顾客分层结构分析

# 构建各类别顾客数量的python原生态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原生态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|{d}%}  ",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} ({d}%)"))
)
p.render_notebook()
    <div id="8380e5561d83423ca753622d0798ca56" style="width:950px; height:600px;"></div>

在这里插入图片描述

从上图可以看出:

  • 销售额的主要来源是类别0的人群,他们人数占比50%,消费金额占比87%左右
  • 可见此超市是有一群固定的高价值客户来稳定消费,粉丝群体稳定,而且占比大,需要针对他们提供个性化方案,预防流失。
  • 类别1和类别2的顾客区分并不明显,如果运营能力有限,可以将其合并为一类用户

5 结论建议

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/31431.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

倒计时四天!第2期大模型讲习班报名中,顶尖专家面授,多角度系统培训

大模型前沿技术讲习班第一季第二期&#xff08;S01E02&#xff09;将在2023年4月24日至25日线下召开&#xff0c;我们邀请了来自顶尖科研领域的权威专家联合授课。上海交通大学助理研究员陈露&#xff0c;中国人民大学准聘助理教授李崇轩&#xff0c;中国人民大学准聘助理教授林…

开放报名|顶尖专家联合打造,首个系统化AI大模型前沿技术讲习班

大模型正在引发人工智能研究与应用范式产生重大变革&#xff0c;越来越多的顶级团队和杰出人才纷纷加入这一技术浪潮。作为AI大模型科研先锋&#xff0c;智源研究院聚集了来自高校院所和创新企业的一大批大模型领域卓越学者与工程师&#xff0c;共同致力于推动我国大模型的创新…

提升大模型研究应用技能:第2期前沿讲习班报名,顶尖专家面授,多角度系统培训...

人工智能研究与应用范式正经历一场剧变&#xff0c;越来越多的顶级团队和杰出人才纷纷加入这一变革浪潮。作为AI大模型科研先锋&#xff0c;智源研究院携手一批卓越的学者与工程师&#xff0c;致力于将尖端技术与经验传授给有潜力的学习者&#xff0c;通过高效的学习方式&#…

后端使用phantomjs对页面进行截图

最近碰到这样一些需求&#xff0c;后端需要对某个图表页面进行动态截图&#xff0c;将截图通过邮件发送到指定邮箱进行每日提醒。 这就需要用到无界浏览器进行此类操作。常见的无界浏览器有以下几种&#xff0c;知识来源于chatgpt3.5&#xff1a; Headless Chrome - Google C…

chatgpt赋能python:Python画图空白的解决方法

Python画图空白的解决方法 Python作为一种高效、简洁的编程语言&#xff0c;被广泛应用于数据分析、机器学习、图像处理等领域。其中&#xff0c;常用的Python画图库有matplotlib、seaborn、plotly等。但是&#xff0c;有时候我们会遇到一个奇怪的问题&#xff0c;就是在画图时…

复旦大学郁喆隽:网络制造出人的“幻象”,深度思考如何可能?

“人是什么?”这是亘古以来人们反复追问的一个古老命题。从元宇宙到ChatGPT&#xff0c;这个人人都在讨论、理解和实践互联网的时代&#xff0c;对“人”的自我定义和认知产生了哪些影响&#xff1f;    在3月12日复旦大学-华盛顿大学EMBA项目主办的“复调艺文沙龙”上&am…

用AI智能(DALL.E2)搞一个Logo和绘制坤坤的脚

浅谈ChatGPT和DALL.E2 ChatGPT 最近有个叫chatgpt的玩意老火了&#xff0c;不仅在科技圈刮起一阵骚乱&#xff0c;同时在金融圈也闹的沸沸扬扬&#xff0c;很多板块个股纷纷水涨船高 chatgpt是美国人工智能研究所实验室OpenAi开发的一种全新的聊天机器人模型&#xff0c;当然我…

微软 AI 华人先驱黄学东正式宣布离职,将加入 Zoom 担任 CTO

微软华人 AI 版图上一块不可或缺的拼图&#xff0c;现在也离开了。 作者 | 郭思 编辑 | 陈彩娴 雷峰网独家获悉&#xff0c;微软 AI 华人先驱黄学东近日在社交媒体正式宣布从微软离职&#xff0c;将加入 Zoom 担任 CTO。 上世纪六十年代出生的黄学东是与变化共生、在变化中成长…

马斯克怒了:我要起诉微软!

鱼羊 发自 凹非寺量子位 | 公众号 QbitAI OpenAI还没撕完&#xff0c;马斯克又跟微软杠上了&#xff0c;甚至直接在推特上放话&#xff1a; 我要告微软&#xff01; 这又是发生了甚么&#xff1f; 原因无它&#xff1a;微软刚刚“封杀”了推特。公告显示&#xff0c;从4月25日&…

生成式AI的价值与机遇,这家云服务商给出了详细解答

从2022年末一直到2023年上半年&#xff0c;许多人亲眼见证了ChatGPT的风靡全球&#xff0c;以及生成式AI与大语言模型的大爆发。 那么对于广大用户来说&#xff0c;生成式AI究竟意味着怎样的机遇&#xff1f;数据在生成式AI应用中扮演着怎样的角色&#xff1f;如何解锁生成式AI…

Mac版R语言入门(三)数据的导入

R语言&#xff08;三&#xff09;数据的导入&#xff0c;包括以下几个部分的内容&#xff1a; R语言问题讨论交流&#xff0c;欢迎关注我的新浪微博&#xff1a;Jenny爱学习 1.数据类型介绍 2.数据导入 3.抓取网络数据 一.数据类型 1&#xff09;Excel、Spreadsheet数据&…

R语言学习笔记——统计结果保存到本地文件(word、txt、csv)

1. 保存为word或txt文件 sink&#xff08;&#xff09;&#xff1a;在代码开始前&#xff1a;sink(“输出文件名.txt”)&#xff0c;将结果全部输出到工作文件夹下的名为 "输出文件名.txt" 的文档。这时在R控制台的输出窗口中看不到输出结果&#xff0c;代码结束时用…

R/ggplot2保存图片中文字体至PDF——showtext包一文清除所有障碍

R/ggplot2保存图片中文字体至PDF——showtext包一文清除所有障碍 文章概要1.问题描述2.Showtext包使用流程全注释2.1案例介绍——导入线上的谷歌字体2.2实例测试——导入本地字体&#xff0c;以宋体、新罗马为例 3拓展-新罗马与Serif的不同4.showtextggsave保存图片字体大小设置…

Rstudio读取csv文件

读取csv文件老是失败&#xff0c;就一直在社区找方法&#xff0c;结合了多篇文章&#xff0c;终于成功&#xff0c;我谢 错误类型&#xff1a; 1、Error in file(file, "rt", encoding fileEncoding) : cannot open the connection In addition: Warning message…

利用R处理PDF文件

pdftools pdftools是一个专门用来处理pdf文件的包 pdftools pdf_text() pdf_text()#将pdf每页返回成(return)成一个character vector. > #举个例子 > a <- pdf_text("41375_2012_BFleu2012127_MOESM29_ESM.pdf") > #查看pdf页数 > length(a) [1] 2…

R语言NetCDF格式数据的读写

常用函数&#xff1a; nc_open 打开.nc文档 nc_close 关闭.nc文档 nc_create 新建.nc文档 ncvar_get 读取变量数据 ncatt_get 读取变量属性 ncvar_def 设定变量 ncdim_def 设定维度 ncvar_add 添加变量 ncvar_put 写入变量数据 ncatt_put 写入变量属性 一、读取.nc格…

R语言中的导出为pdf文件或txt文件的注意事项

最近看了下R语言的书&#xff0c;练练手发现一些问题 比如保存图像为pdf文件&#xff0c;我一开始老是显示文件为不含页面&#xff0c;后来才想清楚其中的道理 首先输入 pdf("mypdf.pdf") 然后用source执行一段脚本 source("script2.R") 如果你前面没…

chatgpt赋能Python-pythonmean

Pythonmean: 为什么它是新时代最炙手可热的框架&#xff1f; 什么是Pythonmean&#xff1f; Pythonmean是一个全平台支持的JavaScript全栈框架&#xff0c;其核心框架是AngularJS、Node.js、Express.js和MongoDB的组合。Pythonmean提供了一个快速、统一、易于维护的开发框架&…

chatgpt赋能Python-pythonmul

Pythonmul——让Python更加高效的优化工具 Python是一种被广泛应用于数据分析、科学计算、人工智能等各个领域的高级编程语言。由于其简单易学、灵活多样的编程风格以及庞大的社区支持&#xff0c;Python成为了许多开发者的首选语言。但是&#xff0c;Python在执行某些操作时可…