本文对【Python数据分析】——药品销售数据分析(完整项目实战)一文的内容进行实现,并根据实际情况进行了相应的修改
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
import matplotlib as mp
import matplotlib.pyplot as plt
from pylab import mpl
# 设置列名对齐
pd.set_option('display.unicode.ambiguous_as_wide', True)
pd.set_option('display.unicode.east_asian_width', True)
file_name = r'C:\Users\chaosye\Desktop\medical.xlsx'
data = pd.ExcelFile(file_name)
data = data.parse('Sheet1',dtype='object')
print(data.head(n = 10))
# 列名重命名
# inplace=True:不创建in的对象,直接对原始对象进行修改:
# inplace=False:对数据进行修改,创建并返回新的对象以承载修改的结果
# 暴力修改
print("表的列",data.columns)
data.columns = ['购药时间x', '社保卡号', '商品编码', '商品名称', '销售数量', '应收金额', '实收金额']
print("表的列",data.columns)
# 可选择性修改
data.rename(columns={'购药时间x':'销售时间'}, inplace = True)
print("表的列",data.columns)
# 处理缺失数据
print("处理缺失数据前的数据规模:", data.shape)
data.info() # 返回DataFrame的信息,包括索引和列的数据类型, 非空值和内存使用的统计
# 使用dropna函数处理缺失数据
data = data.dropna(subset=['销售时间', '社保卡号'], how='any') # 'any'只要有一个NA值就进行丢弃
data.info()
# 定义将星期去除的函数
def splitSaleTime(timeCloser):
timeList = []
for val in timeCloser:
data = val.split(' ')[0]
timeList.append(data)
timeSer = Series(timeList)
return timeSer
time = data.loc[:, '销售时间']
print(type(time)) # data的类型是DataFrame,time的数据类型是Series
timeData = splitSaleTime(time)
data.loc[:, '销售时间'] = timeData
print(data.head(n = 10))
# 将字符串类型的时间转换为日期,errors设置为'coerce', 无效的解析结果会被设置为NaT.
data.loc[:,'销售时间'] = pd.to_datetime(data.loc[:,'销售时间'],format = '%Y-%m-%d',errors='coerce')
# 转换数据类型以方便后续运算
data['销售数量'] = data['销售数量'].astype('float')
data['应收金额'] = data['应收金额'].astype('float')
data['实收金额'] = data['实收金额'].astype('float')
data = data.dropna(subset=['销售时间','社保卡号'],how='any')
print(data.head())
# 数据汇总
print(data.describe())
# min值出现异常的负值,去除异常值
mask = data.loc[:,'销售数量']>0
print("索引掩码:",mask.head(n=10))
data = data.loc[mask,:]
print(data.describe())
# 删除某列的重复数据
data = data.drop_duplicates(subset=['销售时间','社保卡号'])
# 数据排序
data = data.sort_values(by='销售时间',ascending=True)
# 重置索引index,防止之前的操作导致索引混乱
data = data.reset_index(drop = True)
data.head()
# 月均消费
num = data.shape[0]
print('消费次数:',num)
# 计算月份数
startTime = data.loc[0,'销售时间']
endTime = data.loc[num-1,'销售时间']
daysNum = (endTime - startTime).days # 总天数
months = daysNum//30
print('经营月份数:',months)
# 月均消费次数
count_month_mean = num//months
print('月均消费:',count_month_mean)
# 月均消费金额
money = data.loc[:,'实收金额'].sum()
money_month_mean = money // months
print('月均消费金额:',money_month_mean,'元')
# 客单价
pc = money/num
print('客单价:',pc,'元')
# 画图
mpl.rcParams['font.sans-serif']=['SimHei']
groupData = data
# 每日消费金额
plt.plot(groupData['实收金额'])
plt.title('按天消费金额图')
plt.xlabel('时间/天')
plt.ylabel('实收金额')
plt.show()
# 每月消费金额
# gb = groupData.groupby(groupData['销售时间'].apply(lambda x:x.month)).first() # 计算每个分组的第一个值
# 第一种按月分组的方法
gb = groupData.groupby(groupData['销售时间'].apply(lambda x:x.month))
monthData = gb.sum()
print("按月分组求和的消费金额:\n", monthData)
# # 第二种按月分组的方法
# key = lambda x:x.month
# groupData = groupData.set_index('销售时间')
# gb = groupData.groupby(key)
# monthData = gb.sum()
# print("按月分组求和的消费金额:\n",monthData)
plt.plot(monthData['实收金额'])
plt.title('按月消费金额图')
plt.xlabel('时间/月')
plt.ylabel('实收金额')
plt.show()
# 对“商品名称”和“销售数量”这两列数据进行聚合为Series形式,并按降序排序
medicine = groupData[['商品名称', '销售数量']]
print('按商品名称分组后的药品\n',medicine)
bk = medicine.groupby('商品名称')[['销售数量']]
print(type(bk))
re_medicine = bk.sum()
print(type(re_medicine))
re_medicine = re_medicine.sort_values(by='销售数量',ascending=False)
print(type(re_medicine))
# 取销量最高的10种药品
top_medicine = re_medicine.iloc[:10, :]
print('销量最高的10种药品\n', top_medicine)
# 绘制条形图的方法1
# top_medicine.plot(kind = 'bar')
# plt.title('药品销售数量')
# plt.xlabel('药品名称')
# plt.ylabel('销售数量')
# plt.show()
# 绘制条形图的方法2
# 将索引列转换为一般的列,并设置索引名称
# https://blog.csdn.net/qq_34535319/article/details/100601656
top_medicine = top_medicine.reset_index()
top_medicine.index.name = 'index'
print("重新索引的数据表\n", top_medicine)
x = range(len(top_medicine.iloc[:, 1]))
y = list(top_medicine.iloc[:, 1])
label_list = list(top_medicine.iloc[:, 0])
print(x)
print(y)
print(label_list)
fig, ax = plt.subplots()
rects = plt.bar(x = x, height = y, width = 0.6,alpha = 0.8, color='green', label = '销售数量')
plt.ylim(0,1800)
plt.ylabel("销售数量")
plt.xticks([index for index in x], label_list)
plt.xticks(rotation=270) # 让x轴的刻度竖排显示
plt.xlabel("商品名称")
plt.title("药品销售数量")
# # 第一种对图像进行标注的方法
# for rect in rects:
# height = rect.get_height()
# plt.text(rect.get_x() + rect.get_width() / 2, height+1, str(int(rect.get_height())), ha="center", va="bottom")
#
# plt.legend()
# plt.show()
for rect in rects:
height = rect.get_height()
ax.annotate('{}'.format(height),
xy=(rect.get_x() + rect.get_width() / 2, height),
xytext=(0, 3), # 3 points vertical offset
textcoords="offset points",
ha='center', va='bottom')
plt.legend()
plt.show()