Python数据分析最常用的包是numpy和pandas
下面我们先从一维数据开始了解两个包的运用:一维数据Numpy》》Arrary
Pandas》》Series
一维数据分析:Numpy
#导入numpy数据包
import numpy as np
#定义,数组用array(),参数传入用列表【】
a=np.array([2,3,4,5])
#查询
a[3]
5
#切片访问:获取指定序号范围的元素
#比如 a[1:3],就是获取序号1到3的元素,0:3 就是顺序0到3的所有元素
a[0:3]
array([2, 3, 4])
#查看数据类型 dtype
a.dtype
dtype('int32')
#平均值,4个元素的平均值
a.mean()
3.5
#标准差
a.std()
1.118033988749895
#向量化运行:向量相加
b=np.array([2,3,4,5])
c=a+b
c
array([ 4, 6, 8, 10])
#没有print 就会显示arrary,可以加入print 就没有array
print(c)
[ 4 6 8 10]
#向量化运行:乘以标量
d=a*4
c
array([ 4, 6, 8, 10])
一维数据分析:Pandas
#Pandas 用series来定义一维数据结构
#这是6家公司的股价,其中腾讯时港元换成了没用
#注意Series,S一定要大写,不然找不到此项功能
import pandas as pd
stockS=pd.Series([54.74,190.9,173.14,1050.3,181.86,1139.49],
index=['Tencent','Alibaba','Apple','GOOGLE','Facebook','Amazon'])
stockS
Tencent 54.74
Alibaba 190.90
Apple 173.14
GOOGLE 1050.30
Facebook 181.86
Amazon 1139.49
dtype: float64
#描述性统计信息
stockS.describe()
count 6.000000
mean 465.071667
std 491.183757
min 54.740000
25% 175.320000
50% 186.380000
75% 835.450000
max 1139.490000
dtype: float64
#iloc 根据位置获取值
stockS.iloc[0]
54.74
#loc 根据索引获取值,要注意这里是字符串(String)需要加引号
stockS.loc['Alibaba']
190.9
#向量运算:相加
s1=pd.Series([1,2,3,4],index=['allen','peter','jason','john'])
s2=pd.Series([5,6,7,8,9,10],index=['allen','peter','frank','jason','Lily','Cara'])
s3=s1+s2
s3
Cara NaN
Lily NaN
allen 6.0
frank NaN
jason 11.0
john NaN
peter 8.0
dtype: float64
#方法1:删除缺失值
s3.dropna()
allen 6.0
jason 11.0
peter 8.0
dtype: float64
#方法2:填充缺失值
s3=s1.add(s2,fill_value=0)
s3
Cara 10.0
Lily 9.0
allen 6.0
frank 7.0
jason 11.0
john 4.0
peter 8.0
dtype: float64
2. 二维数据结构(有行,有列)
Numpy二位数据结构-每一组数组里都需要统一类型
二维数据分析:Numpy
import numpy as np
#定义二维数组 array([]) 注意每个数组都用方括号,但是不能忽略整个公式的小括号和方括号
a=np.array([[1,2,3,4],
[5,6,7,8],
[9,10,11,12]])
#获取行号2,列号是3的元素a[2,3]
a[2,3]
12
#获取第一行
a[0,:]
array([1, 2, 3, 4])
#获取第一列
a[:,0]
array([1, 5, 9])
#计算整个数组的平均数
a.mean()
6.5
#计算每一行的平均数
a.mean(axis=1)
array([ 2.5, 6.5, 10.5])
#计算每一列的平均数
a.mean(axis=0)
array([5., 6., 7., 8.])
二维数据分析:Pandas 二维数组--数据框(DataFrame)
Numpy不能实现不同数据类型,Pandas可以用dataframe去仿造excel的数据,因为可以用于不同数据类型。=pd.dataframe()
import pandas as pd
#定义一个字典,映射列名与对应列的值
salesdict={
'购药时间':['2018-01-01 星期五','2018-01-02 星期六','2018-01-06 星期三'],
'社保卡号':['001616528','001616528','0012602828'],
'商品编码':[236701,236701,236701],
'商品名称':['强力VC银翘片','清热解毒口服液','感康'],
'销售数量':[6,1,2],
'应收金额':[82.8,28,16.8],
'实收金额':[69,24.64,15]
}
#因为本身字典是无序的,我们要导入有序字典
from collections import OrderedDict
#定义有序字典
salesorderdict=OrderedDict(salesdict)
#定义数据框,传入字典,列名 pd.DataFrame()
salesdf=pd.DataFrame(salesorderdict)
salesdf
购药时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额
0 2018-01-01 星期五 001616528 236701 强力VC银翘片 6 82.8 69.00
1 2018-01-02 星期六 001616528 236701 清热解毒口服液 1 28.0 24.64
2 2018-01-06 星期三 0012602828 236701 感康 2 16.8 15.00
#平均值:按照每一列来计算的
salesdf.mean()
商品编码 236701.000000
销售数量 3.000000
应收金额 42.533333
实收金额 36.213333
dtype: float64
'''用iloc来获取值-根据位置'''
#查询第2行,第3例的元素
salesdf.iloc[2,3]
'感康'
#查询第3行所有
salesdf.iloc[2,:]
购药时间 2018-01-06 星期三
社保卡号 0012602828
商品编码 236701
商品名称 感康
销售数量 2
应收金额 16.8
实收金额 15
Name: 2, dtype: object
##查询第2列所有
salesdf.iloc[:,1]
0 001616528
1 001616528
2 0012602828
Name: 社保卡号, dtype: object
'''用loc来获取值,根据索引'''
#查询第第二行,第五列的元素,应收金额
salesdf.loc[1,'应收金额']
28.0
#获取第一行
salesdf.loc[0,:]
购药时间 2018-01-01 星期五
社保卡号 001616528
商品编码 236701
商品名称 强力VC银翘片
销售数量 6
应收金额 82.8
实收金额 69
Name: 0, dtype: object
#获取第6列
salesdf.loc[:,'实收金额']
0 69.00
1 24.64
2 15.00
Name: 实收金额, dtype: float64
#简单方法
salesdf['实收金额']
0 69.00
1 24.64
2 15.00
Name: 实收金额, dtype: float64
#通过列表来选择某几列的数据
salesdf[['商品名称','商品编码']]
购药时间 社保卡号 商品编码 商品名称 销售数量 应收金额 实收金额
0 2018-01-01 星期五 001616528 236701 强力VC银翘片 6 82.8 69.0
2 2018-01-06 星期三 0012602828 236701 感康 2 16.8 15.0
数据框复杂查询:切片功能
#通过切片功能,获取指定范围的列,就是两个元素间所有的值用冒号:
salesdf.loc[:,'购药时间':'销售数量']
数据框复杂查询:条件判读
#第一步:构建查询条件
queryser=salesdf.loc[:,'销售数量']>1
type(queryser)
pandas.core.series.Series
queryser
0 True
1 False
2 True
Name: 销售数量, dtype: bool
#应用筛选出来的元素
salesdf.loc[queryser,:]
查看数据集统计描述-自己导入excel数据
#读取Excel数据--pandas 运用功能,大小写一定要注意
filenamestr='F:\跟猴子学习人工智能核心技术\数据分析(中级)(Python)\数据分析的基本过程\朝阳医院2018年销售数据.xlsx'
xls=pd.ExcelFile(filenamestr)
salesDf=xls.parse('Sheet1')
#打印出前4列,可以来确保数据正常运行
salesDf.head(4)
#有多少行,多少列
salesDf.shape
(6578, 7)
#参看某一列的数据类型
salesDf.loc[:,'社保卡号'].dtype
dtype('float64')
#参看每一列的统计数值
salesDf.describe()
社保卡号 商品编码 销售数量 应收金额 实收金额
count 6.576000e+03 6.577000e+03 6577.000000 6577.000000 6577.000000
mean 6.091254e+09 1.015869e+06 2.386194 50.473803 46.317510
std 4.889284e+09 5.131153e+05 2.375202 87.595925 80.976702
min 1.616528e+06 2.367010e+05 -10.000000 -374.000000 -374.000000
25% 1.014234e+08 8.614560e+05 1.000000 14.000000 12.320000
50% 1.001650e+10 8.615070e+05 2.000000 28.000000 26.600000
75% 1.004882e+10 8.690690e+05 2.000000 59.600000 53.000000
max 1.283612e+10 2.367012e+06 50.000000 2950.000000 2650.000000
接下来是药房数据的实际操作
1. 提出问题
从销售数据中分析出以下业务指标: 1)月均消费次数2)月均消费金额3)客单价4)消费趋势
#导入数据包
import pandas as pd
#读书Excel数据,统一先按照字符串读入,之后再转换
filenamestr='F:\跟猴子学习人工智能核心技术\数据分析(中级)(Python)\数据分析的基本过程\朝阳医院2018年销售数据.xlsx'
xls=pd.ExcelFile(filenamestr,dtype='object')
salesdf=xls.parse('Sheet1',dtype='object')
'''可以先查看数据基本信息'''
#打印出前5行,以确保数据正常运行
salesdf.head(5)
#查看多少行,多少列
salesdf.shape
(6578, 7)
#查看每一列的数据类型
salesdf.dtypes
购药时间 object
社保卡号 object
商品编码 object
商品名称 object
销售数量 object
应收金额 object
实收金额 object
dtype: object
2. 数据清洗
1.选择字集(对分析有用的)
#如果需要选择子集--这个案例不需要
subsalesdf=salesdf.loc[0:4,'购药时间':'销售数量']
subsalesdf
2.列名重命名
#用字典来定义旧列名和新列名对应关系
colNameDict={'购药时间':'销售时间'}
'''inplace=False,数据框本身不会变,而会创建一个改动后新的数据框,默认的inplace是Falseinplace=True,数据框本身会改动'''
salesdf.rename(columns=colNameDict,inplace=True)
salesdf.head()
3.缺失数据处理
python缺失值有3种:
1)Python内置的None值
2)在pandas中,将缺失值表示为NA,表示不可用not available。
3)对于数值数据,pandas使用浮点值NaN(Not a Number)表示缺失数据。
后面出来数据,如果遇到错误:说什么float错误,那就是有缺失值,需要处理掉
所以,缺失值有3种:None,NA,NaN
print('删除缺失值前大小',salesdf.shape)
删除缺失值前大小 (6578, 7)
#删除列(销售时间,社保卡号)中为空的行
#how='any' 在给定的任何一列中有缺失值就删除
salesdf=salesdf.dropna(subset=['销售时间','社保卡号'],how='any')
print('删除缺失值后大小',salesdf.shape)
删除缺失值后大小 (6575, 7)
4. 数据类型转换
#字符串转换为数值(浮点型)--\n 可以换行
salesdf['销售数量']=salesdf['销售数量'].astype('float')
salesdf['应收金额']=salesdf['应收金额'].astype('float')
salesdf['实收金额']=salesdf['实收金额'].astype('float')
print('转换后的数据类型:\n',salesdf.dtypes)
转换后的数据类型:
销售时间 object
社保卡号 object
商品编码 object
商品名称 object
销售数量 float64
应收金额 float64
实收金额 float64
dtype: object
字符串转换为日期数据类型
#测试:字符串分割--split 括号的引号里一定要加空格
testList='2018-06-19 星期二'.split(' ')
testList
['2018-06-19', '星期二']
#查询第一个值
testList[0]
'2018-06-19'
'''定义函数:分割销售日期,获取销售日期输入:timeColSer 销售时间这一列,是个Series数据类型输出:分割后的时间,返回也是个Series数据类型'''
def splitsaletime(timecolser):
timelist=[]
for value in timecolser:
#例如2018-01-01 星期五,分割后为:2018-01-01,只留日期
datestr=value.split(' ')[0]
timelist.append(datestr)
#将列表转行为一维数据Series类型
timeser=pd.Series(timelist)
return timeser
#获取‘销售时间’这一列
timeser=salesdf.loc[:,'销售时间']
#用函数对字符串进行分割,获取销售日期
dateSer=splitsaletime(timeser)
'''注意:如果运行后报错:AttributeError: 'float' object has no attribute 'split'是因为Excel中的空的cell读入pandas中是空值(NaN),这个NaN是个浮点类型,一般当作空值处理。所以要先去除NaN在进行分隔字符串'''
"\n注意:\n如果运行后报错:AttributeError: 'float' object has no attribute 'split'\n是因为Excel中的空的cell读入pandas中是空值(NaN),
这个NaN是个浮点类型,一般当作空值处理。\n所以要先去除NaN在进行分隔字符串\n"
那None和NaN有什么区别?
None是Python的一种数据类型,NaN是浮点类型 两个都用作空值
#None和NaN的区别
print('None的数据类型',type(None))
from numpy import NaN
print('NaN的数据类型',type(NaN))
None的数据类型 
NaN的数据类型 
dateSer[0:3]
0 2018-01-01
1 2018-01-02
2 2018-01-06
dtype: object
#获取后,修改销售时间这一列的值
salesdf.loc[:,'销售时间']=dateSer
salesdf.head()
'''如果原属数据不符合现在的日期格式,可以做一下操作'''
#errors='coerce' 如果原始数据不符合日期的格式,转换后的值为空值NaT
#format 是你原始数据中日期的格式
salesdf.loc[:,'销售时间']=pd.to_datetime(salesdf.loc[:,'销售时间'],
format='%Y-%m-%d',
errors='coerce')
salesdf.dtypes
销售时间 datetime64[ns]
社保卡号 object
商品编码 object
商品名称 object
销售数量 float64
应收金额 float64
实收金额 float64
dtype: object
'''转换日期过程中不符合日期格式的数值会被转换为空值,这里删除列(销售时间,社保卡号)中为空的行'''
salesdf=salesdf.dropna(subset=['销售时间','社保卡号'],how='any')
salesdf.head()
salesdf.shape
(6506, 7)
5.数据排序
'''by:按哪几列排序ascending=True 表示升序排列,ascending=False表示降序排列,na_position='first'表示排序的时候,把空值放到前列,这样可以比较清晰的看到哪些地方有空值'''
#按销售日期进行升序排列
salesdf=salesdf.sort_values(by='销售时间',
ascending=True,
na_position='first')
print('排序后的数据集')
salesdf.head()
排序后的数据集
#重命名行名(index):排序后的列索引值是之前的行号,需要修改成从0到N按顺序的索引值
salesdf=salesdf.reset_index(drop=True)
salesdf.head()
6.异常值处理
#描述指标:查看出"销售数量"值不能小于0
salesdf.describe()
#从上看出最小值小于0,所以要筛选出大于0的
#步骤:
#1 查询条件
queryser=salesdf.loc[:,'销售数量']>0
#2 应用筛选的条件
print('删除异常值前:',salesdf.shape)
salesdf=salesdf.loc[queryser,:]
print('删除异常值后:',salesdf.shape)
删除异常值前: (6549, 7)
删除异常值后: (6506, 7)
3. 构建模型
业务指标:1.月均消费次数=总消费次数/月份数
'''总消费次数:同一天内,同一个人发生的所有消费算作一次消费#根据列名(销售时间,社区卡号),如果这两个列值同时相同,只保留1条,将重复的数据删除'''
kpi1_df=salesdf.drop_duplicates(
subset=['销售时间','社保卡号']
)
#总消费次数:有多少行
totalI=kpi1_df.shape[0]
print('总消费次数=',totalI)
总消费次数= 5342
'''计算月份数:时间范围'''
#第1步:按销售时间升序排序
kpi1_df=kpi1_df.sort_values(by='销售时间',
ascending=True)
#重命名行名(index)
kpi1_df=kpi1_df.reset_index(drop=True)
kpi1_df.head()
#第2步:获取时间范围,最大时间值因为有0,所以要减1,不然会多一行
#最小时间值
starttime=kpi1_df.loc[0,'销售时间']
#最大时间值
endtime=kpi1_df.loc[totalI-1,'销售时间']
#第3步:计算月份数
#天数
daysI=(endtime-starttime).days
#月份数: 运算符“//”表示取整除
#返回商的整数部分,例如9//2 输出结果是4
monthI=daysI//30
print('月份数:',monthI)
月份数: 6
#业务指标1:月均消费次数=总消费次数 / 月份数
kpi1_I=totalI//monthI
print('业务指标1:月均消费次数=',kpi1_I)
业务指标1:月均消费次数= 890
指标2:月均消费金额 = 总消费金额 / 月份数
#总消费金额
totalmoneyf=salesdf.loc[:,'实收金额'].sum()
#月均消费金额
monthmoneyf=totalmoneyf/monthI
print('业务指标2:月均消费金额=',monthmoneyf)
业务指标2:月均消费金额= 50668.35166666666
指标3:客单价=总消费金额 / 总消费次数
客单价(per customer transaction)是指商场(超市)每一个顾客平均购买商品的金额,客单价也即是平均交易金额。
'''totalmoneyf:总消费金额totalI:总消费次数'''
pct=totalmoneyf/totalI
print('客单价',pct)
客单价 56.909417821040805
指标4:消费趋势,画图:折线图-会在之后更新
#在进行操作之前,先把数据复制到另一个数据框中,防止对之前清洗后的数据框造成影响
groupDf=salesdf
#第1步:重命名行名(index)为销售时间所在列的值
groupDf.index=groupDf['销售时间']
groupDf.head()
#第2步:分组
gb=groupDf.groupby(groupDf.index.month)
#第3步:应用函数,计算每个月的消费总额
mounthDf=gb.sum()
mounthDf