赞
踩
目录
该数据集为在线零售商在2010年12月1日至2011年12月9日间发生的所有网络交易订单信息。
该公司主要销售礼品为主,并且多数客户为批发商。
数据集介绍及来源:
https://www.kaggle.com/carrie1/ecommerce-data
InvoiceNo:订单编号,由六位数字组成,退货订单编号开头有字幕’C’
StockCode:产品编号,由五位数字组成
Description:产品描述
Quantity:产品数量,负数表示退货
InvoiceDate:订单日期与时间
UnitPrice :单价(英镑)
CustomerID:客户编号,由5位数字组成
Country:国家
利用pandas库检查缺失值和异常值,删除InvoiceNo列异常值数据(运行后可知该列异常值是A开头+六位数字)并将UnitPrice列的异常值数据进行线性插值填补后存入data2.csv表中。
- import pandas as pd
-
- # 读取CSV文件
- dataframe = pd.read_csv('data.csv')
-
- # 检查缺失值
- missing_values = dataframe.isnull().sum()
- print("缺失值数量:\n", missing_values)
-
- # 检查InvoiceNo列异常值
- # 定义条件1:订单编号由六位数字组成
- condition1 = dataframe['InvoiceNo'].str.isnumeric() & (dataframe['InvoiceNo'].str.len() == 6)
-
- # 定义条件2:退货订单编号以字母'C'开头(即C+六位数字)
- condition2 = dataframe['InvoiceNo'].str.match(r'^C\d{6}$')
-
- # 通过逻辑与操作符 (&) 组合两个条件
- valid_invoice_conditions = condition1 | condition2
-
- # 通过布尔索引选择满足条件的行,得到清洗后的DataFrame
- cleaned_dataframe = dataframe[valid_invoice_conditions]
-
- # 计算'InvoiceNo'列异常值数量
- invoice_no_outliers_count = len(dataframe[~valid_invoice_conditions])
- print("InvoiceNo列异常值数量:", invoice_no_outliers_count)
- # 打印InvoiceNo列异常值
- invoice_no_outliers = dataframe[~valid_invoice_conditions]['InvoiceNo']
- print("InvoiceNo列异常值:\n", invoice_no_outliers)
-
- # 利用标准差方法检测UnitPrice列的异常值
- unit_price_mean = cleaned_dataframe['UnitPrice'].mean()
- unit_price_std = cleaned_dataframe['UnitPrice'].std()
- upper_bound = unit_price_mean + 3 * unit_price_std
- lower_bound = unit_price_mean - 3 * unit_price_std
-
- # 获取UnitPrice列的异常值
- unit_price_outliers = (cleaned_dataframe['UnitPrice'] > upper_bound) | (cleaned_dataframe['UnitPrice'] < lower_bound)
-
- # 使用线性插值填充异常值
-
- cleaned_dataframe.loc[:, 'UnitPrice'] = cleaned_dataframe['UnitPrice'].interpolate(method='linear')
-
- # 计算'UnitPrice'列异常值数量
- unit_price_outliers_count = len(cleaned_dataframe[unit_price_outliers])
- print("UnitPrice列异常值数量:", unit_price_outliers_count)
-
- # 打印UnitPrice列异常值
- unit_price_outliers = cleaned_dataframe[unit_price_outliers]['UnitPrice']
- print("UnitPrice列异常值:\n", unit_price_outliers)
-
- # 保存清洗后的数据到新表data2.csv
- cleaned_dataframe.to_csv('data2.csv', index=False)
- 缺失值数量:
- InvoiceNo 0
- StockCode 0
- Description 1454
- Quantity 0
- InvoiceDate 0
- UnitPrice 0
- CustomerID 135080
- Country 0
- dtype: int64
- InvoiceNo列异常值数量: 3
- InvoiceNo列异常值:
- 299982 A563185
- 299983 A563186
- 299984 A563187
- Name: InvoiceNo, dtype: object
- UnitPrice列异常值数量: 377
- UnitPrice列异常值:
- 1814 569.77
- 3041 607.49
- 4989 295.00
- 5685 498.47
- 6165 887.52
- ...
- 536834 1008.96
- 537254 1683.75
- 539368 938.59
- 540908 933.17
- 541540 1714.17
客户世界分布热力图的数据是利用data2.csv数据做数据透视表后得到的国家以及该国客户数量,其余画图的数据都是通过data2.csv的列数据直接进行的。
以上饼图可以直观看到进货数量为5660978,退货数量为484531,,退货数量占总数的7.9%。
该热力图向我们展示了客户在全球的分布以及客户数量,可以直观看到英国客户数量非常多。
上图展示了网络交易订单的价格分布,0-5英镑的商品数量最多,价格越高商品数越少。
上图展示了2010年12月到2011年12月每个月的销售量,2011年2月销售量最低,2011年11月销售量最高。
- import pandas as pd
- import matplotlib.pyplot as plt
- #import plotly.express as px
-
- # 读取数据
- df = pd.read_csv('data2.csv')
-
- # 进货与退货数量的饼图
- quantity = df['Quantity']
- pos_quantity = quantity[quantity > 0].sum()
- neg_quantity = -quantity[quantity < 0].sum()
- #绘制饼图
- labels = ['进货', '退货']
- values = [pos_quantity, neg_quantity]
- fig1, ax1 = plt.subplots()
- patches, texts, autotexts = ax1.pie(values, labels=labels, autopct='%1.1f%%')
- ax1.axis('equal')
- plt.title('进货与退货之比')
- plt.rcParams['font.sans-serif'] = 'SimHei'
- # 添加数据标签
- for i, text in enumerate(autotexts):
- value = values[i]
- percentage = '{:.1f}%'.format(value / sum(values) * 100)
- text.set_text('{}\n{}'.format(percentage, value))
- # 添加图例
- ax1.legend(labels, loc='best')
- plt.show()
-
- #价格条形图
- # 创建数据
- data = df['UnitPrice']
- df2 = pd.DataFrame(data)
- # 将价格分组
- bins = [0,1,2,3, 5,10, 50, 100,500,1000, float('inf')]
- group_names = ['0-1','1-2','2-3','3-5', '5-10','10-50', '50-100','100-500','500-1000', '>1000']
- df2['UnitPriceGroup'] = pd.cut(df2['UnitPrice'], bins, labels=group_names)
- # 统计每个分组的数量
- unitprice_count = df2['UnitPriceGroup'].value_counts().sort_index()
- # 设置中文显示字体
- plt.rcParams['font.sans-serif'] = 'SimHei'
- plt.rcParams['axes.unicode_minus'] = False
- # 绘制条形图
- fig, ax = plt.subplots()
- bars = ax.bar(unitprice_count.index, unitprice_count.values)
- plt.title('UnitPrice列价格分布')
- # 添加数据标签
- for bar in bars:
- height = bar.get_height()
- ax.text(bar.get_x() + bar.get_width() / 2, height, height, ha='center', va='bottom')
- plt.show()
-
- # 月销售量折线图
- df['InvoiceDate'] = pd.to_datetime(df['InvoiceDate'])
- df['YearMonth'] = df['InvoiceDate'].dt.strftime('%Y-%m')
- sales_count = df.groupby('YearMonth')['Quantity'].sum().reset_index()
- fig4, ax4 = plt.subplots()
- ax4.plot(sales_count['YearMonth'], sales_count['Quantity'])
- plt.xticks(rotation=45)
- plt.title('2010年12月到2011年12月每个月销售量的折线图')
- plt.show()
- plt.rcParams['font.sans-serif']='SimHei'
RFM主要是针对顾客有一定频次的消费,比较适合传统企业里的运营商、银行、航空,或者互联网里的电商、出行,这种必须捆绑客户ID,有一定频次的小额消费的场景,RFM模型主要指:R (Recency-近度)、F (Frequency-频度)和M(Monetary-额度),即根据客户的活跃程度和交易金额贡献所做的分类。
R值:最近一次消费(Recency):客户在店铺消费最近一次和上一次的时间间隔,理论上R值越小的客户是价值越高的客户,即对产品及品牌印象度越高。
F值:消费频率(Frequency):客户在固定时间内的购买次数(一般是1年),购买频率越高,对品牌忠诚度越高。但实际店铺由于受品类宽度的原因(如电子产品等),即使是忠实粉丝用户也很难在1年内购买多次。所以,一般会把F值的时间范围去掉,替换成累计购买次数。
M值:消费金额(Monetary):M值相对于R值和F值最难使用,但最具有价值,金额越高,给店铺创造的收入和利润越高。理论上M值和F值是一样的,都带有时间范围,指的是一段时间(通常是1年)内的消费金额。
rfm模型最后根据这三个指标对客户打分后,会分为八个类型的客户:
为了获得rfm模型的特征,我们对data2.csv表:删除退货订单(退货订单一般都有对应进货订单,去除重复项),给顾客ID为空的行增加NULL,订单时间类型转换。然后再根据数据特点分别计算出R,F,M的值,将其和顾客ID共同放入新表rfm.csv中。最后给rfm.csv表数据的每个指标进行打分,然后将客户分类。
- import pandas as pd
-
- # 读取数据集
- df = pd.read_csv('data2.csv')
-
- # 把顾客ID类型转为字符串
- df['CustomerID'] = df['CustomerID'].astype(str)
-
- # 删除取消订单
- df = df[~df['InvoiceNo'].str.contains('C')]
- .................................................
- #篇幅过长,只展示部分代码
- # 定义转换函数
- def trans_value(x):
- if x == '高高高':
- return '高价值客户'
- elif x == '高低高':
- return '重点深耕客户'
- elif x == '低高高':
- return '重点唤回客户'
- elif x == '低低高':
- return '重点挽留客户'
- elif x == '高高低':
- return '潜力客户'
- elif x == '高低低':
- return '新客户'
- elif x == '低高低':
- return '一般保持客户'
- else:
- return '流失客户'
-
- # 得到最后的客户分级
- df1['value'] = df1['R_rank'] + df1['F_rank'].astype(str) + df1['M_rank'].astype(str)
-
- df1['customer_level'] = df1['value'].apply(trans_value)
-
- # 将客户分级信息添加到 df1 中
- df1['customer_level'] = df1['value'].apply(trans_value)
-
- # 保存至CSV文件
- df1.to_csv('rfm_分类.csv', index=False)
-
- from pyecharts import options as opts
- from pyecharts.charts import Pie
-
- # 读取分类表
- df_rfm = pd.read_csv('rfm_分类.csv')
-
- # 统计每个客户类型的数量
- C_type = df_rfm['customer_level'].value_counts()
- c_num = C_type.tolist()
- c_type = C_type.index.tolist()
-
- # 绘制饼图
- pie = (
- Pie()
- .add("", [list(z) for z in zip(c_type, c_num)],
- rosetype="radius",
- radius=["30%", "55%"],
- label_opts=opts.LabelOpts(formatter='占比{d}%'),
- center=["50%","40%"])
- .set_global_opts(
- title_opts=opts.TitleOpts(title="客户类型", pos_left="80%", pos_top="5%"),
- legend_opts=opts.LegendOpts(type_="scroll", pos_left="80%", orient="vertical", pos_top="15%"),
- )
- )
k值确定:使用轮廓系数法等方法确定k值的选择。
综合手肘法和轮廓系数的值选出k最佳为3。
使用聚类算法对数据进行客户价值分析,并给出对应的雷达图:
根据上面画出的雷达图,可以知道Cluster2是消费近度和消费额都高的一类客户,这类客户一般是高价值客户、重点深耕客户、重点挽留客户;Clsuter1是消费额低,消费频率低,消费近度高的一类客户,一般属于流失客户;Cluster3是消费额一般,消费频率一般,消费近度也不算高的一类客户,一般属于潜力客户、一般保持客户、重点唤回客户。
通过对比RFM模型刻画出的客户分类,K-mens聚类出的客户类型分类少,效果一般。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。