python数据分析实例_Python数据分析实例-药品销售分析

0a25224121810bb2afdcae42e89b9091.png

学习了Python的各种基础语法和常用包后,你是否对如何使用Python在实际工作中进行数据分析一头雾水?如果是,今天这篇文章一定能带给你一些用数据分析解决实际问题的思路。

数据分析的目的决定了你的分析步骤,比如你的分析的目标是提供商业可视化方案,或者是建立模型进行预测,再或者是通过数据挖掘发现并改善现有流程等。今天我们介绍一个简单的数据分析例子-根据销售记录创建可视化报表。


我是一名药品销售公司的分析师,今天运营部的小丽发给我一份我们某一家药店的销售记录,希望我可以从销售数据中得到以下指标:

  • 月均消费次数
  • 月均消费金额
  • 客单价
  • 消费趋势

我想作为一个优秀的数据分析师,这个请求完全小菜一叠。我告诉小丽:没问题,我会用代码计算这些指标并做一个PDF的可视化报告给你,未来有相似的需求只要改改数据和参数就能生成一样的报表啦!

在分析前,我先整理了一下这个分析任务的大致步骤:

  1. 提出问题,理解需求
  2. 导入、理解数据
  3. 数据清洗
  4. 构建模型
  5. 数据可视化

1. 提出问题,理解需求

这是用数据分析解决问题非常重要的一步。因为如果没有理解业务背景、前提和需求就进行分析,就很难得到满足客户要求的解决方案。

我首先要理解小丽的需求和方案的截至日期,明白这4个指标的含义和计算方法。一般来说对于新的概念我会在网络搜索相关信息再与客户确认,从而确保对问题的理解和前提是和客户一致的。我通过网络查询和小丽的讨论我整理了指标的计算:

  • 月均消费次数 = 总消费次数/月份数 (一个社保卡号代表一个人,同一天内的同一个卡号的所有消费算一次消费)
  • 月均消费金额 = 总消费金额/月份数
  • 客单价 = 总消费金额/总消费次数
  • 消费趋势 可视化图标展现1.每月消费次数变化 2.每月消费金额变化 3.每月客单价变化

其次我会确定需要的数据。根据问题的不同,可能需要从数据库,网络,或者文件(CSV, EXCEL, TXT)获取数据。这个需求中小丽提供给我的Excel销售记录就够用了。

最后要和客户确认问题的解决方案是什么,是一个模型、一份商业分析报告、还是可视化报表。这里小丽要求是PDF的指标和可视化报告,所以我决定使用Python和Jupyter Notebook分析数据,设计指标和制作可视化图形。这样下次有相似的需求只要输入数据改动一些参数就可以另存为PDF文档。

2. 导入、理解数据

接下来就是导入数据,理解数据的基本属性,比如数据的类型、数据的大小、是否有缺失值、是否需要转换数据等。

# 导入数据包,一般习惯在分析开头导入所有数据包。
from datetime import datetime
import pandas as pd
from pylab import mpl
import matplotlib.pylab as plt # 数据可视化
plt.style.use('ggplot') # 设置风格使图标更美观
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定字体雅黑,使图标可以显示中文
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题

# 关闭warnings
import warnings
warnings.filterwarnings('ignore')
# 数据导入
# Excel文件路经
f_path = r'/mnt/data-ubuntu/Projects/data_science_chinese/input/朝阳医院2018年销售数据.xlsx'
df = pd.read_excel(f_path)
# 打印查看数据前5行
df.head() 

968cabe6cb44ee7b676e9e895baeae8c.png
df前五行
# 查看数据类型
df.dtypes
购药时间 object
社保卡号 float64
商品编码 float64
商品名称 object
销售数量 float64
应收金额 float64
实收金额 float64
dtype: object
#数据大小
df.shape
(6578, 7)
# 检查缺失值
df.isnull().sum()
购药时间 2
社保卡号 2
商品编码 1
商品名称 1
销售数量 1
应收金额 1
实收金额 1
dtype: int64
# 检查数据统计
df.describe()

983e75244f998e7b5bae0e741dce3da8.png
数据统计结果

经过上面步骤我知道:

  • 购药时间不是日期格式,我们需要转换时间格式。
  • 社保卡号和商品编码应该转换为字符格式,因为它们只是一串编号。
  • 数据存在少量缺失值需要处理。
  • 销售数量、应收金额和实收金额存在不合理的负值需要查看。
  • 应收金额和实收金额出现较大值(可能为异常值)需要进一步查看。

3. 数据清洗

数据清洗的目的是使得数据更整洁,方便后续建模和可视化。一般数据清洗的步骤分为1.选择子集。2.列名重命名。3.缺失值处理。4.数据类型转换。5.异常值处理。6.数据排序。

根据问题的需求和对数据的理解,我确定了以下数据清洗步骤。

3.1 缺失值处理

要处理缺失值的原因是,缺失值会使计算、可视化、或有些模型的应用发生错误。 处理缺失值有多种方法:一般常用方法有1.删除行或列。2.补全缺失值。其中补全缺失值需要对数据和业务背景有一定了解。这里不再展开,有兴趣的同学可以看下这篇文章。

# 简单看下缺失值
df[df.isna().any(axis=1)]

78aa63befa9c7667c5a07cdc624489bd.png
缺失值结果
# 删除所有缺失值的行
print(f'删除缺失值前:{df.shape}')
df.dropna(inplace = True)
print(f'删除缺失值后:{df.shape}')
删除缺失值前:(6578, 7)
删除缺失值后:(6575, 7)

这样我们就删除了包含缺失值的3行数据。

3.2 数据类型转换

正确的数据类型才能使得后面数据分析正常进行,我们需要根据问题的背景去决定数据类型。这里根据经验社保卡号和商品编码是字符串类型,而不是数字。

# 购药时间转换成日期格式
df['购药时间'] = df['购药时间'] 
                .map(lambda x: x.split(' ')[0])
# errors='coerce'值如果有不合理日期格式'%Y-%m-%d'则返回NaT。
df['购药时间'] = pd.to_datetime(df.loc[:,'购药时间'],
                               errors='coerce',
                               format = '%Y-%m-%d')
# 社保卡号和商品编码转换成字符格式
df['社保卡号'] = df['社保卡号'].astype('int').astype('str')
df['商品编码'] = df['商品编码'].astype('int').astype('str')

# 删除日期错误的行
print(f'删除错误日期前:{df.shape}')
df.dropna(inplace = True)
print(f'删除错误日期后:{df.shape}')
df.dtypes
删除错误日期前:(6575, 7)
删除错误日期后:(6552, 7)
购药时间 datetime64[ns]
社保卡号 object
商品编码 object
商品名称 object
销售数量 float64
应收金额 float64
实收金额 float64
dtype: object

3.3 异常值处理

异常值的出现可能会导致我们分析中计算或者模型的不准确。异常值一般是指极大值、极小值或者其他不符合问题背景的值,然后通过对问题和数据的再理解,搜集背景知识,或和客户讨论是否要进行相应的数据处理。

# 查看极值
df[(df['应收金额']>2000)|(df['销售数量']<0)]

61807082150e484d013b630f77f8dd6b.png
部分极值截图

经过与小丽的确认后呢,我知道负数代表退货,我不需要计算进去。此外有2笔销售金额较大的是正常数据,因为购买数量大并且药价相对高。

在实际工作中也会碰到相似的问题,有时候需要一定的背景知识才能决定如何处理。

# 删除销量为负数的行
print(f'删除销量为负前:{df.shape}')
df = df[df['销售数量']>0]
print(f'删除销量为负后:{df.shape}')
删除销量为负前:(6552, 7)
删除销量为负后:(6509, 7)

3.4 数据排序

因为我处理的数据是销售数据有销售时间,按照时间排序有助于建模和数据可视化。

# 数据按照购药时间
df = df.sort_values(by = '购药时间')
# 重写整理index
df.reset_index(drop = True, inplace = True)
df.head()

d437d2ef9ce04ed97a7300a724c6f05d.png
排序后数据表

4. 模型构建

根据我们的目的,这里模型构建是指计算客户要求的指标。通过之前和小丽的讨论已经理整理好了指标的计算:

  • 月均消费次数 = 总消费次数/月份数 (一个社保卡号代表一个人,同一天内的同一个卡号的所有消费算一次消费)
  • 月均消费金额 = 总消费金额/月份数
  • 客单价 = 总消费金额/总消费次数
  • 消费趋势 可视化图标展现1.每月消费次数变化 2.每月消费金额变化 3.每月客单价变化

首先要确定总月份数,如果不是完整的月份数据,我们再计算月均值的时候需要额外考虑。

# 生成年列和月列方便后期计算
df['购药时间_年'] = df['购药时间'].dt.year
df['购药时间_月'] = df['购药时间'].dt.month
# 检查每个月天数
df 
    .groupby([df['购药时间_年'],df['购药时间_月']]) 
    .nunique() 
    .loc[:,'购药时间']
购药时间_年 购药时间_月
2018 1 31
2 28
3 31
4 30
5 31
6 30
7 19
Name: 购药时间, dtype: int64

我发现7月只有19天的数据,于是与小丽确认后我只要计算完整月份的数据,所以我就删除了7月的数据。

# 删除7月数据
df = df[df['购药时间_月'] != 7]
# 总月份数,以年月合并数据。表格的index数量就是月份数
num_month = df 
            .groupby([df['购药时间_年'],df['购药时间_月']]) 
            .count() 
            .index 
            .size
print(f'数据一共包含{num_month}个月份。')

下一步我需要生成一个指标的数据表格df_kpi,方便数据处理和计算。

# 月消费次数表并合并到总表
df_kpi = df 
            .groupby([df['购药时间_年'],df['购药时间_月']]) 
            .nunique() 
            .reset_index() 
            .loc[:, ['购药时间_年', '购药时间_月', '社保卡号']]
df_kpi.columns = ['购药时间_年', '购药时间_月', '当月消费次数']
# 当月消费金额表并合并到总表
df_temp = df 
            .groupby([df['购药时间_年'],df['购药时间_月']]) 
            .sum() 
            .reset_index() 
            .loc[:, ['购药时间_年', '购药时间_月', '实收金额']]
df_temp.columns = ['购药时间_年', '购药时间_月', '当月消费金额']
df_kpi = df_kpi.merge(df_temp, how = 'inner', on =['购药时间_年', '购药时间_月'])
# 当月客单价
df_kpi['当月客单价'] = (df_kpi['当月消费金额']/df_kpi['当月消费次数']).round(2)
df_kpi

dd1360d3e1ee57eced7d39dc3652631e.png
kpi数据表
# 计算指标
kpi_avg_visit = df_kpi['当月消费次数'].sum()/num_month
kpi_avg_sales = df_kpi['当月消费金额'].sum()/num_month
print(f'月均消费次数为:{kpi_avg_visit:.2f}')
print(f'月均消费金额:{kpi_avg_sales:.2f}')
print(f'客单价:{kpi_avg_sales/kpi_avg_visit:.2f}')
月均消费次数为:654.50
月均消费金额:45652.46
客单价:69.75

5. 数据可视化

俗话说“一图胜千言”(我也不知道哪里来的俗话。。。),用图表来展示数据可以更简洁地表达内容,还可以展示出一些隐藏信息。

# 月消费次数趋势图
df_kpi.set_index(['购药时间_年', '购药时间_月'])['当月消费次数'] 
    .plot(kind = 'bar',
          figsize = (10,6),
          title = '月消费次数趋势图',
          color = 'steelblue')
plt.show()

2df9a46cd7c17306573f058f4997300c.png
# 月消费金额趋势图
df_kpi.set_index(['购药时间_年', '购药时间_月'])['当月消费金额'] 
    .plot(kind = 'bar',
          figsize = (10,6),
          title = '月消费金额趋势图',
          color = 'darkseagreen')
plt.show()

5c35cd638e216a2d0dcfcba550989472.png
# 月消费次数趋势图
df_kpi.set_index(['购药时间_年', '购药时间_月'])['当月客单价'] 
    .plot(kind = 'bar',
          figsize = (10,6),
          title = '月客单价趋势图',
          color = 'coral')
plt.show()

a040ca2b3ad415866e023ba63f59575e.png

从月趋势图我们看到:

  • 月消费次数和月消费金额在2月比较低,也许是因为春节放假和2月天数少的影响。
  • 客单价在3,4月相对较低,而其他月份比较平稳。

以上就是用Python进行数据分析的简单步骤,需要对应Jupyter notebook的同学请点这里。感激你的阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值