这是一个竞赛的题目,包括但不限于以下分析维度:

  1. 各门店商品销量与利润,时间趋势
  2. 各类别商品销量与利润
  3. 各价格区间内的畅销商品与滞销商品
  4. 销售淡季和销售旺季的商品销量分布

根据以上分析目的,主要进行利润、时间、销量指标的数据处理,基础数据包括三张表,分别是2019年销售信息、门店信息、商品信息表:

import pandas as pd
import numpy as np
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity='all'
pd.options.display.max_columns = None

由于三张表的字段有重复且都是中文,所以用英文名称来代表中文字段名称,方便代码的书写。

input_file1 = 'sales2019.csv'
input_file2 = '门店信息.xlsx'
input_file3 = '商品信息.xlsx'
store_id = '门店编号'
store_name = '门店名称'
cost = '采购单价'
sales_price = '销售单价'
sales_count = '销售数量'
sales_fees = '销售金额'
deal_date = '交易日期'
product_id = '商品编号'
type_large = "大分类名称"
type_small = "小分类名称"
profit = '利润'
store_name = '门店简称'
store_namecom = '门店名称'
year = '交易日期_年份'
month = '交易日期_月份'

导入数据的时候注意编码问题,这里的用到了gb2312,

data_sales = pd.read_csv(input_file1, encoding = 'gb2312')
data_store = pd.read_excel(input_file2)
data_product = pd.read_excel(input_file3)

查看空值比例

#查看空值百分比
data_sales.isnull().sum()/data_sales.shape[0]  #由于采购单价和销售单价存在少量空值,则删除不会影响其他
data_store.isnull().sum()/data_store.shape[0]
data_product.isnull().sum()/data_product.shape[0]
交易日期       0.000000
门店编号       0.000000
收银台编号      0.000000
商品编号       0.000000
交易日期_年份    0.000000
交易日期_月份    0.000000
商品处编号      0.000000
商品部门编号     0.000000
销售数量       0.000000
销售金额       0.000000
采购单价       0.016224
销售单价       0.018680
dtype: float64
门店编码    0.0
门店名称    0.0
门店简称    0.0
小区编码    0.0
小区名称    0.0
城市名称    0.0
dtype: float64
大分类编号    0.0
大分类名称    0.0
分类编号     0.0
分类名称     0.0
小分类编号    0.0
小分类名称    0.0
商品编号     0.0
商品名称     0.0
dtype: float64

空值极少,只有销售单价和采购单价有为空的数据,而且这两个指标再做利润的时候还会用到,所以要进行填充。
首先,要观察这俩字段空值的规律。

data_sales_cost_pricenull = data_sales[pd.isna(data_sales[cost]) | pd.isna(data_sales[sales_price])]
data_sales_cost_pricenull.info()
data_sales_cost_pricenull.head()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 19331 entries, 20 to 1034807
Data columns (total 12 columns):
交易日期       19331 non-null object
门店编号       19331 non-null int64
收银台编号      19331 non-null int64
商品编号       19331 non-null object
交易日期_年份    19331 non-null int64
交易日期_月份    19331 non-null int64
商品处编号      19331 non-null int64
商品部门编号     19331 non-null int64
销售数量       19331 non-null int64
销售金额       19331 non-null float64
采购单价       2541 non-null float64
销售单价       0 non-null float64
dtypes: float64(3), int64(7), object(2)
memory usage: 1.9+ MB

通过以上可以看出,采购单价为空的时候,销售单价一定为空。
那么,采购单价和销售单价都不为空的数据有多少呢。

data_sales_cost_pricenotnull = data_sales[~(pd.isna(data_sales[cost]) | pd.isna(data_sales[sales_price]))]
data_sales_cost_pricenotnull.shape
(1015542, 12)

为了填充销售单价和采购单价,要进行描述统计。

#查看采购成本非空的商品的采购成本的最大值、最小值、平均值、行数、不同采购成本的个数,发现并不是所有的同一商品都是一样的价钱,所以用平均值填补空值
data_sales_costnotnull = data_sales[~pd.isna(data_sales[cost])].groupby(data_sales[product_id])[cost].agg([np.max, np.min, np.mean, np.average, np.size, pd.Series.nunique])
data_sales_costnotnull.info()  #还有空值,则是非空成本的商品id自始至终就是空值采购成本
data_sales_costnotnull
#输出同一商品的采购成本的mean
data_cost_value = data_sales[~pd.isna(data_sales[cost])].groupby(data_sales[product_id])[cost].agg(np.mean)
#同理,输出同一商品的销售单价的均值
data_salesprice_value = data_sales[~pd.isna(data_sales[sales_price])].groupby(data_sales[product_id])[sales_price].agg(np.mean)

填充采购单价和销售单价的空值:

replace_cost = data_sales_cost_pricenull[product_id].apply(lambda x: data_cost_value[x] if x in data_cost_value else np.nan)
data_sales_cost_pricenull[cost] = replace_cost
replace_salesprice = data_sales_cost_pricenull[product_id].apply(lambda x: data_salesprice_value[x] if x in data_salesprice_value else np.nan)
data_sales_cost_pricenull[sales_price] = replace_salesprice
#填补完空值,得出最终的行数
new_data_sales = pd.concat([data_sales_cost_pricenotnull,new_data_sales_cost_pricenull], axis = 0)
new_data_sales.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 1034590 entries, 0 to 1034807
Data columns (total 12 columns):
交易日期       1034590 non-null object
门店编号       1034590 non-null int64
收银台编号      1034590 non-null int64
商品编号       1034590 non-null object
交易日期_年份    1034590 non-null int64
交易日期_月份    1034590 non-null int64
商品处编号      1034590 non-null int64
商品部门编号     1034590 non-null int64
销售数量       1034590 non-null int64
销售金额       1034590 non-null float64
采购单价       1034590 non-null float64
销售单价       1034590 non-null float64
dtypes: float64(3), int64(7), object(2)
memory usage: 102.6+ MB

门店信息和商品信息表没有空值,直接匹配就可以。
三个表的前十行分别如下:



以分析维度为目的进行数据处理,利润=销售金额-销售数量*采购单价

各门店各类别商品销量与利润,时间趋势

data_store = data_store.rename(columns={'门店编码':'门店编号'})
data_store_merge = new_data_sales.merge(data_store,on = store_id,how = 'left')  #与门店信息left join
data_store_merge.info()
new_data_merge = data_store_merge.merge(data_product,on = product_id,how = 'left')
new_data_merge['利润'] = pd.Series(new_data_merge[sales_fees] - new_data_merge[cost]*new_data_merge[sales_count],index = new_data_merge.index)
#月度门店的大分类销量
month_store_large = new_data_merge.groupby([month,store_name,store_namecom,type_large])[sales_count].agg([np.sum])
month_store_large = month_store_large.reset_index()
month_store_large.head(10)
month_store_large.shape
#月度门店的大分类利润
month_store_large_profit = new_data_merge.groupby([month,store_name,store_namecom,type_large])[profit].agg([np.sum])
month_store_large_profit = month_store_large_profit.reset_index()
month_store_large_profit.head(10)
month_store_large_profit.shape
#月度门店的小分类销量
month_store_small = new_data_merge.groupby([month,store_name,store_namecom,type_large,type_small])[sales_count].agg([np.sum])
month_store_small = month_store_small.reset_index()
month_store_small.head(10)
month_store_small.shape#月度门店的小分类利润
month_store_small_profit = new_data_merge.groupby([month,store_name,store_namecom,type_large,type_small])[profit].agg([np.sum])
month_store_small_profit = month_store_small_profit.reset_index()
month_store_small_profit.head(10)
month_store_small_profit.shape
month_store_large_count_profit = month_store_large.merge(month_store_large_profit,on = store_name,how = 'left')
month_store_large_count_profit.head()

各类别商品销量与利润

data_product_merge = new_data_sales.merge(data_product,on = product_id,how = 'left')
data_product_merge['利润'] = pd.Series(data_product_merge[sales_fees] - data_product_merge[cost]*data_product_merge[sales_count],index = data_product_merge.index)
#大分类、小分类的销量
product_count = data_product_merge.groupby([type_large,type_small])[sales_count].agg([np.sum])
product_count = product_count.rename(columns = {'sum': '销售总数量'})
product_count
#大分类、小分类利润
product_profit = data_product_merge.groupby([type_large,type_small])[profit].agg([np.sum])
product_profit = product_profit.rename(columns = {'sum': '销售总利润'})
product_count_profit = pd.concat([product_count,product_profit], axis = 1)
product_count_profit = product_count_profit.reset_index()
product_count_profit

各价格区间内的畅销商品与滞销商品

print('采购单价最高为:',data_product_merge.采购单价.max())
print('采购单价最低为:',data_product_merge.采购单价.min())
print('销售单价最高为:',data_product_merge.销售单价.max())
print('销售单价最低为:',data_product_merge.销售单价.min())
采购单价最高为: 429.2308
采购单价最低为: 0.0
销售单价最高为: 558.0
销售单价最低为: 0.7
#给采购单价进行等宽分箱
data_product_merge.groupby(type_large).size()
data_product_merge['采购单价等宽分箱'] = pd.cut(data_product_merge.销售单价,8) #整体商品的采购单价分箱,分成8个箱子,这样数据区间是70data_product_merge_copy = data_product_merge.copy()
大分类名称
个人清洁用品 Personal Wash    168688
口腔护理用品 Oral Care        441582
护肤品 Skin Care           168228
美发护发用品 Hair Care        160470
dtype: int64
data_product_merge.shape
data_product_merge.columns
data_product_merge.groupby('采购单价等宽分箱')['销售数量'].agg(np.sum)
data_product_merge = data_product_merge.groupby(['大分类名称','小分类名称','采购单价等宽分箱'])['销售数量'].agg(np.sum)
data_product_merge = data_product_merge.reset_index()
data_product_merge = data_product_merge.sort_values(['销售数量'],ascending=False)
采购单价等宽分箱
(0.143, 70.362]       1498240
(70.362, 140.025]       50963
(140.025, 209.687]       5810
(209.687, 279.35]        2877
(279.35, 349.012]         682
(349.012, 418.675]        394
(418.675, 488.337]        430
(488.337, 558.0]          172
Name: 销售数量, dtype: int64

还可以指定分箱

data_product_merge_copy['采购单价等宽分箱'] = pd.cut(data_product_merge_copy['销售单价'], bins = [0,100,200,300,400,500,600])
data_product_merge_copy =  data_product_merge_copy.reset_index()
data_product_merge_copy = data_product_merge_copy.groupby(['大分类名称','小分类名称','采购单价等宽分箱'])['销售数量'].agg(np.sum).reset_index()

总结一下数据处理步骤:
、处理空值:sales2019.csv中,采购单价和销售单价存在少许空值,用各自平均值填充;
2、剔除无效值:采购单价和销售单价一直为空值,则剔除。
3、联结表:通过merge联结sales2019、门店信息、商品信息数据;
4、创建新字段:创建建利润字段(利润 = 销售金额 - 采购单价*销售数量);
5、分组:以交易日期_月份、门店简称、门店名称、大分类名称、小分类名称为维度进行groupby,得出销量和利润;
6、分箱:采购单价分成(0,100],(100,200],(200,300],(300,400], (400,500],(500,600]区间;

指定分箱的数据让人更快速清楚知道一个商品的单价处在哪个价格区间内。
此比赛要求使用永洪Bi分析软件,所以可视化图表都来自永洪BI。

右边的仪表盘都是动态展示的

口腔护理用品的销量最高,但是美发护发用品的利润最高,说明利润与销量并非正比关系,同时也说明每件口腔护理用品平均利润最低,达3.22元,每件美发护发用品平均利润最高,达8.41元;从各类别商品销量的月份分布看, 2019年每月销量最高的都是口腔护理用品,所有商品在2-4月份销量最低,10-12月份销量最高,即分别为销售淡季、销售旺季,销售旺季可能是促销活动比较多口腔护理用品(牙膏、牙刷等)作为日常消耗品,且价格低廉,销量一直呈现走高趋势



31家门店中,销量和利润都TOP10的门店是相同的,可能名次不同,这些店均匀分布在M市北和市南。建议销量和利润都是末尾10家店的员工去学习下TOP10店里的销售方法。


各门店销量和利润的时间趋势与各类别商品的时间趋势类似,都在4月份达到谷底,在10月份达到峰值,与月份的促销活动有很大关系,在国庆节,双十一、圣诞节等重大节日搞促销活动,刺激了消费者的购买欲。


采购单价在100以内的商品销量最高,口腔护理用品的销量集中在采购单价为100元以内的商品中;护肤品的采购单价较高,受全球经济影响,消费者随着价格的递增也会减少购买,建议采购单价低和高的商品以打折促销的方式组合捆绑销售;消费者对美发护发用品和个人清洁用品的购买欲不强烈,且购买的商品也是集中在日常必需品中(如:洗发水、护发素、香皂、洗手液、沐浴产品)。

数据分析实战——日化用品在门店的销售分析相关推荐

  1. 数据分析实战——星巴克门店数量可视化分析

    星巴克门店分布可视化分析 项目介绍:使用python对星巴克门店分布进行可视化分析 数据背景:数据源来自与Kaggle: Starbucks Locations Worldwide | Kaggle, ...

  2. Day45. 数据分析实战(1):超市运营数据分析

    Day45. 数据分析实战(1):超市运维数据分析 文章目录 Day45. 数据分析实战(1):超市运维数据分析 前言 一. 读取数据 二. 看哪些类别的商品比较畅销 三. 哪些商品比较畅销 四. 不 ...

  3. 临床基因组学数据分析实战助力解析Case,快速发表文章

    福利公告:首期<临床基因组学数据分析实战>线上/线下课程已圆满结束.现于2022年春节前,安排第二期和第三期课程,分别为:北京,2021年12月24-26:广州,2022年1月7-9.(线 ...

  4. 北京、广州同时开课 | 临床基因组学数据分析实战助力解析Case,快速发表文章...

    福利公告:首期<临床基因组学数据分析实战>线上/线下课程已圆满结束.现于2022年春节前,安排第二期和第三期课程,分别为:北京,2021年12月24-26:广州,2022年1月7-9.(线 ...

  5. 临床基因组学数据分析实战开课啦!!!

    福利公告:为了响应学员的学习需求,经过易生信培训团队的讨论筹备,现安排<临床基因组学数据分析实战>于2021年11月12-14 线上/线下课程 (线上课是通过腾讯会议实时直播线下课,实时互 ...

  6. R语言explore包进行探索性数据分析实战(EDA、exploratory data analysis):基于iris数据集

    R语言explore包进行探索性数据分析实战(EDA.exploratory data analysis):基于iris数据集 目录

  7. 《数据分析实战:基于EXCEL和SPSS系列工具的实践》——3.3 耗时耗力的数据整理过程...

    本节书摘来自华章计算机<数据分析实战:基于EXCEL和SPSS系列工具的实践>一书中的第3章,第3.3节,作者 纪贺元,更多章节内容可以访问云栖社区"华章计算机"公众号 ...

  8. 《数据分析实战 基于EXCEL和SPSS系列工具的实践》一3.4 数据量太大了怎么办

    本节书摘来自华章出版社<数据分析实战 基于EXCEL和SPSS系列工具的实践>一书中的第3章,第3.4节,纪贺元 著,更多章节内容可以访问云栖社区"华章计算机"公众号查 ...

  9. 《数据分析实战 基于EXCEL和SPSS系列工具的实践》一第2章 数据分析的理论、工具、模型...

    本节书摘来自华章出版社<数据分析实战 基于EXCEL和SPSS系列工具的实践>一书中的第2章,第2.1节,纪贺元 著,更多章节内容可以访问云栖社区"华章计算机"公众号查 ...

最新文章

  1. PTA 基础编程题目集 7-24 约分最简分式 C语言
  2. 带通采样定理简单记录
  3. [渝粤教育] 广东-国家-开放大学 21秋期末考试建筑工程概预算10326k2
  4. Decompose Conditional(分解条件表达式)
  5. 用Delphi制作网络游戏外挂
  6. ajax请求携带tooken_Spring Boot+Vue 文件上传,如何携带令牌信息?
  7. 一种简单好用的Vue表单验证
  8. java中swing循环_在Java游戏循环中使用“ SwingUtilities.invokeLa...
  9. js 获取元素文本_可能是最全的“文本溢出截断省略”方案合集
  10. 关于三星研究院adv机试(开发人员入职机试)
  11. 投影幕布尺寸计算器_投影距离和屏幕尺寸计算器Ver1.02.xls
  12. aplay amixer用法详解
  13. Android开发中导入字体库
  14. 汽车如何打蜡 汽车打蜡有什么要注意的地方
  15. 时光不负,对我来说不寻常的一年 | 2021 年终总结
  16. UNITY性能优化✨MeshBaker在Unity中的使用教程
  17. 【深入vue3+Typescript技术栈】2021 coderwhy大神新课高清百度网盘持续更新 王红元老师 腾讯课堂
  18. iOS 内购提示不允许App内购买项目,打开内购方式和检测不允许内购的方法。
  19. Python实现 宽度/广度优先搜索算法, 深度优先搜索算法
  20. 我有一个计算机梦想作文500,我的梦想作文500字

热门文章

  1. STM32之ADC+步骤小技巧(英文)
  2. 【Python入门教程】第30篇 列表sort()方法
  3. 玩命上了985,终究还是逃不过 996?
  4. 算法时间复杂度举例解析(O(1),O(log2n),O(n),O(nlog2n),O(n^2),O(n^3)等)
  5. 员工不愿意参加年会/团建,怎么办?
  6. Dynamics CRM2013 用户进入系统所必需的那些权限
  7. java 分布式 转码_分布式转码集群思路
  8. php 取url 文件名,php 获取当前访问的url文件名的方法小结
  9. 第5章 高级函数和控制结构
  10. ford极品飞车2_极品飞车-消除性能瓶颈