Python学习3之pandas统计分析基础

Python学习3之pandas

本系列文章用于以后编写代码直接调用某些代码,也用作一个学习后的记录,参考书籍为《Python数据分析与应用》,黄红梅,张良均主编,张凌,施兴,周东平副编,中国工信出版集团,人民邮电出版社,ISBN:9787115373045,文章附有代码和数据,学习起来较为容易



前言

pandas包的使用,主要是数据读取,DataFrame的使用,基础时间数据的处理方法,分组聚合,透视表等


一、Pandas是什么?

示例:Pandas包是一个Python极为强大的包,贯穿用数据分析,是数据统计分析所必须掌握的包。

二、读写不同数据源的数据

1.SQL数据库的读取

理解比较浅,在此只给出书中所用代码,自己尝试有报错,因为本人对MySQL仅有一点点了解,暂未对该种方式读取做仔细查询。
对不同数据库,SQL Server,MySQL,Oracle等都有不同的调用方式,需注意

代码如下(示例):

from sqlalchemy import create_engine
## 创建一个mysql连接器,用户名为root,密码为1234
## 地址为127.0.0.1,数据库名称为testdb,编码为utf-8
engine = create_engine('mysql+pymysql://root:1234@127.0.0.1:\
3306/testdb?charset=utf8')
print(engine)

import pandas as pd
## 使用read_sql_query查看tesdb中的数据表数目
formlist = pd.read_sql_query('show tables', con = engine)
print('testdb数据库数据表清单为:','\n',formlist)
## 使用read_sql_table读取订单详情表
detail1 = pd.read_sql_table('meal_order_detail1',con = engine)
print('使用read_sql_table读取订单详情表的长度为:',len(detail1))
## 使用read_sql读取订单详情表
detail2 = pd.read_sql('select * from meal_order_detail2',
      con = engine)
print('使用read_sql函数+sql语句读取的订单详情表长度为:',len(detail2))
detail3 = pd.read_sql('meal_order_detail3',con = engine)
print('使用read_sql函数+表格名称读取的订单详情表长度为:',
      len(detail3))
# 代码 4-3
## 使用to_sql存储orderData
detail1.to_sql('test1',con = engine,index = False,
      if_exists = 'replace')
## 使用read_sql读取test表
formlist1 = pd.read_sql_query('show tables',con = engine)
print('新增一个表格后testdb数据库数据表清单为:','\n',formlist1)

2.文本文件的读取与存储

掌握CSV,EXCEL文件读取一般足够使用。

代码如下(示例):

import pandas as pd
## 数据的读取
## 使用read_table读取订单信息表
order = pd.read_table('meal_order_info.csv',sep = ',',encoding = 'gbk')
print('使用read_table读取的订单信息表的长度为:',len(order))
## 使用read_csv读取订单信息表
order1 = pd.read_csv('meal_order_info.csv', encoding = 'gbk')
print('使用read_csv读取的订单信息表的长度为:',len(order1))

## 使用read_table读取菜品订单信息表,sep = ';'
order2 = pd.read_table('meal_order_info.csv',sep = ';',encoding = 'gbk')
print('分隔符为;时订单信息表为:\n',order2)
## 使用read_csv读取菜品订单信息表,header=None
## 注意此处与order1有细微差别
order3 = pd.read_csv('meal_order_info.csv', sep = ',',header = None,encoding = 'gbk')
print('订单信息表为:','\n',order3)

# 数据的存储
import os
## 将order以csv格式存储
order.to_csv('orderInfo.csv',sep = ';',index = False) 
print('订单信息表写入文本文件后目录内文件列表为:\n',os.listdir('C:/Users/JW200/Music/Python学习'))
#查看该文件里的所有文件名

# Excel文件读取与存储
user = pd.read_excel('users.xlsx')## 读取user.xlsx文件
print('客户信息表长度为:',len(user))
# 存储
user.to_excel('userInfo.xlsx')#默认存储在该代码文件所在目录
print('客户信息表写入excel文件后目录内文件列表为:\n',
      os.listdir('C:/Users/JW200/Music/Python学习'))


三、DataFrame的操作

DataFrame是最常用的pandas对象,类似于Excel表格,完成数据读取后,数据就以DataFrame数据结构存储在内存中,此时不能直接开始统计分析工作,需对使用的DataFrame数据状况有基本的了解才能进而分析。

1.DataFrame的常用操作

DataFrame的基础属性有values,index,columns,dtypes代表元素,索引,列名和类型。除此之外还有size,ndim,shape等属性。
代码如下(示例):

import pandas as pd
detail= pd.read_excel('meal_order_detail.xlsx')
print('订单详情表的索引为:', detail.index)
print('订单详情表的所有值为:','\n', detail.values)
print('订单详情表的列名为:','\n', detail.columns)
print('订单详情表的数据类型为:','\n', detail.dtypes)
## 查看DataFrame的元素个数
print('订单详情表的元素个数为:', detail.size)
print('订单详情表的维度数为:', detail.ndim) ## 查看DataFrame的维度数
print('订单详情表的形状为:', detail.shape) ## 查看DataFrame的形状
print('订单详情表转置前形状为:',detail.shape)
print('订单详情表转置后形状为为:',detail.T.shape)

2.DataFrame的进阶操作

与数据类相类似,DataFrame作为一种二维数据表结构,最常用的操作就是查改增删,下面详细介绍如何做。
该部分重点在于使用loc,iloc函数实现多列,花式切片进行取出任意数据

代码如下(示例):

import pandas as pd
detail= pd.read_excel('meal_order_detail.xlsx')
## 查看访问数据
## 使用访问字典方式取出orderInfo中的某一列
order_id = detail['order_id']
print('订单详情表中的order_id的形状为:','\n',order_id.shape)
## 使用访问属性方式取出orderInfo中的菜品名称列
dishes_name = detail.dishes_name
print('订单详情表中的dishes_name的形状为:',dishes_name.shape)
# 代码 读取单列多行数据(前5个数据
dishes_name5 = detail['dishes_name'][:5]
print('订单详情表中的dishes_name前5个元素为:','\n',dishes_name5)
# 读取多列的多行数据
orderDish = detail[['order_id','dishes_name']][:5]
print('订单详情表中的order_id和dishes_name前5个元素为:','\n',orderDish)
# 访问多行数据
order5 = detail[:][1:6]
print('订单详情表的1-6行元素为:','\n',order5)
# 使用head,tail读取多行数据
print('订单详情表中前10行数据为','\n',detail.head(10))
print('订单详情表中后10个元素为:','\n',detail.tail(10))

# 花式读取任意数据
# loc函数区间前后均闭,iloc函数前闭后开
#单列数据读取
dishes_name1 = detail.loc[:,'dishes_name']
print('使用loc提取dishes_name列的size为:', dishes_name1.size)
dishes_name2 = detail.iloc[:,3]
print('使用iloc提取第3列的size为:', dishes_name2.size)
# 多列数据读取
orderDish1 = detail.loc[:,['order_id','dishes_name']]
print('使用loc提取order_id和dishes_name列的size为:', orderDish1.size)
orderDish2 = detail.iloc[:,[1,3]]
print('使用iloc提取第1和第3列的size为:', orderDish2.size)
# 花式切片,各种奇怪的方式
print('列名为order_id和dishes_name的行名为3的数据为:\n',
      detail.loc[3,['order_id','dishes_name']])
print('列名为order_id和dishes_name行名为2,3,4,5,6的数据为:\n',
      detail.loc[2:6,['order_id','dishes_name']])
print('列位置为1和3行位置为3的数据为:\n',detail.iloc[3,[1,3]])
print('列位置为1和3行位置为2,3,4,5,6的数据为:\n',
      detail.iloc[2:7,[1,3]])
## loc内部传入表达式,进行条件切片
print('detail中order_id为458的dishes_name为:\n',
     detail.loc[detail['order_id']=='458',
     ['order_id','dishes_name']])
print('detail中order_id为458的第1,5列数据为:\n',
      detail.iloc[(detail['order_id']=='458').values,[1,5]])
# loc,iloc,ix切片比较
print('列名为dishes_name行名为2,3,4,5,6的数据为:\n',
      detail.loc[2:6,'dishes_name'])
print('列位置为5,行位置为2至6的数据为:\n',detail.iloc[2:6,5])
print('列位置为5行名为2至6的数据为:', '\n',detail.ix[2:6,5])


# 数据更改
##将order_id为458的,变换为45800
detail.loc[detail['order_id']=='458','order_id'] = '45800'
print('更改后detail中order_id为458的order_id为:\n',
     detail.loc[detail['order_id']=='458','order_id'])
print('更改后detail中order_id为45800的order_id为:\n',
     detail.loc[detail['order_id']=='45800','order_id'])
     
# 添加一列数据
detail['payment'] =  detail['counts']*detail['amounts']
print('detail新增列payment的前五行为:','\n',
      detail['payment'].head())
# 添加一列数据时定值
detail['pay_way'] = '现金支付'
print('detail新增列pay_way的前五行为:','\n',
      detail['pay_way'].head())

# 数据删除
#删除某列
print('删除pay_way前deatil的列索引为:','\n',detail.columns)
detail.drop(labels = 'pay_way',axis = 1,inplace = True)
print('删除pay_way后detail的列索引为:','\n',detail.columns)
# 删除某几行
print('删除1-10行前detail的长度为:',len(detail))
detail.drop(labels = range(1,11),axis = 0,inplace = True)
print('删除1-10行后detail的列索引为:',len(detail))

3.DataFrame的一些描述统计

一些基础的描述分析函数如下,包含最小值,最大值,方差等数值型特征的描述性统计,类别型数据特征的描述性统计也有,频数等。

import pandas as pd
detail= pd.read_excel('meal_order_detail.xlsx')

# 数值型数据的描述统计
import numpy as np
print('订单详情表中amount(价格)的平均值为:', np.mean(detail['amounts']))
print('订单详情表中amount(价格)的平均值为:', detail['amounts'].mean())
print('订单详情表counts和amounts两列的描述性统计为:\n',
      detail[['counts','amounts']].describe())
# 类别型数据特征的描述统计
print('订单详情表dishes_name频数统计结果前10为:\n',
      detail['dishes_name'].value_counts()[0:10])
# 把object数据转化为category数据,方便用describe进行计算
detail['dishes_name'] = detail['dishes_name'].astype('category')
print('订单信息表dishes_name列转变数据类型后为:',detail['dishes_name'].dtypes)
print('订单信息表dishes_name的描述统计结果为:\n',
      detail['dishes_name'].describe())

四、转换处理时间序列数据

Python数据分析中比较常见时间序列数据,对时间数据做处理也是极其重要的一点,在此简单介绍如何转换时间数据。

1.转换字符串时间为标准时间

Pandas继承了NumPy库和datetime库的时间相关模块,有6种时间相关的类,即Timestamp,Period,Timedelta,DateteimeIndex,PeriodtimeIndex,TimedeltaIndex。
其中最常用的是Timestamp,会通过to_datetime函数进行转化。
除了将数据从原始的DateFrame转换为Timestamp格式外,还可以将数据单独提出出来,转化为DatetimeIndex,或者PeriodIndex。其中DatetimeIndex是指代一系列时间点的一种数据结构,二PeriodIndex是指代一系列时间段的数据结构。
代码如下(示例):

import pandas as pd
order = pd.read_table('meal_order_info.csv',sep = ',',encoding = 'gbk')
print('进行转换前订单信息表lock_time的类型为:', order['lock_time'].dtypes)
#转换字符串时间为标准时间
order['lock_time'] = pd.to_datetime(order['lock_time'])
print('进行转换后订单信息表lock_time的类型为:', order['lock_time'].dtypes)
# 转化为其他类型
dateIndex = pd.DatetimeIndex(order['lock_time'])
print('转换为DatetimeIndex后数据的类型为:\n',type(dateIndex))
periodIndex = pd.PeriodIndex(order['lock_time'],freq = 'S')
print('转换为DatetimeIndex后数据的类型为:\n',type(periodIndex))

2.提取时间序列数据信息

Timestamp属性有很多,可以进行各种信息提取,具体自行查询即可,给出相关示例。
代码如下(示例):

import pandas as pd
order = pd.read_table('meal_order_info.csv',sep = ',',encoding = 'gbk')
print('进行转换前订单信息表lock_time的类型为:', order['lock_time'].dtypes)
#转换字符串时间为标准时间
order['lock_time'] = pd.to_datetime(order['lock_time'])
dateIndex = pd.DatetimeIndex(order['lock_time'])
periodIndex = pd.PeriodIndex(order['lock_time'],freq = 'S')
#注意需要先转化为标准时间类型才可以
year1 = [i.year for i in order['lock_time']]
print('lock_time中的年份数据前5个为:',year1[:5])
month1 = [i.month for i in order['lock_time']]
print('lock_time中的月份数据前5个为:',month1[:5])
day1 = [i.day for i in order['lock_time']]
print('lock_time中的日期数据前5个为:',day1[:5])
weekday1 = [i.weekday_name for i in order['lock_time']]
print('lock_time中的星期名称数据前5个为:',weekday1[:5])
#读取其他类型时间数据
print('dateIndex中的星期名称数据前5个为:\n',
      dateIndex.weekday_name[:5])
print('periodIndex中的星期标号数据前5个为:',
      periodIndex.weekday[:5])


3.加减时间数据

时间数据的算术运算比较常见,也是需要掌握的,通过Timedelta类来实现,,具体如代码。
代码如下(示例):

import pandas as pd
order = pd.read_table('meal_order_info.csv',sep = ',',encoding = 'gbk')
print('进行转换前订单信息表lock_time的类型为:', order['lock_time'].dtypes)
#转换字符串时间为标准时间
order['lock_time'] = pd.to_datetime(order['lock_time'])

## 将lock_time数据向后平移一天
time1 = order['lock_time']+pd.Timedelta(days = 1) 
print('lock_time在加上一天前前5行数据为:\n',order['lock_time'][:5])
print('lock_time在加上一天前前5行数据为:\n',time1[:5])
# 向前减去
timeDelta = order['lock_time'] - pd.to_datetime('2017-1-1')
print('lock_time减去2017年1月1日0点0时0分后的数据:\n',
      timeDelta[:5])
print('lock_time减去time1后的数据类型为:',timeDelta.dtypes)

五、使用分组聚合做组内计算

Pandas提供了一个分组的groupby方法,可以配合agg或者apply方法,与MySQL有一点类似,主要是依据某个或几个字段对数据集进行分组,然后再进行数据分析。

1.Groupby拆分数据

GroupBy方法与SQL中的分组有类似,可以互相理解,可以通过索引或者字段来进行对数据分组,注意分组后的结果不能直接查看,而是在内存中,输出内存地址,类似于Series和DataFrame,是pandas提供的一种对象。
代码如下(示例):

import pandas as pd
import numpy as np
detail = pd.read_excel('meal_order_detail.xlsx',sheetname='meal_order_detail1')
detailGroup = detail[['order_id','counts','amounts']].groupby(by = 'order_id')
print('分组后的订单详情表为:',detailGroup)
# GroupBy类求均值,标准差,中位数
print('订单详情表分组后前5组每组的均值为:\n',  detailGroup.mean().head())
print('订单详情表分组后前5组每组的标准差为:\n', detailGroup.std().head())
print('订单详情表分组后前5组每组的大小为:','\n', detailGroup.size().head())


2.agg,apply,transform聚合数据

agg和aggregate方法都支持对每个分组应用某函数,针对DataFrame对象操作时基本完全相同,掌握一个即可。
代码如下(示例):

import pandas as pd
import numpy as np
detail = pd.read_excel('meal_order_detail.xlsx',sheetname='meal_order_detail1')
detailGroup = detail[['order_id','counts','amounts']].groupby(by = 'order_id')
# 求出当前数据所对应的统计量
print('订单详情表的菜品销量与售价的和与均值为:\n', 
      detail[['counts','amounts']].agg([np.sum,np.mean]))
# 求取不同字段的不同统计量
print('订单详情表的菜品销量总和与售价的均值为:\n',
      detail.agg({'counts':np.sum,'amounts':np.mean}))
# 求取不同字段的不同数目统计量
print('菜品订单详情表的菜品销量总和与售价的总和与均值为:\n',
      detail.agg({'counts':np.sum,'amounts':[np.mean,np.sum]}))

##自定义函数求两倍的和
def DoubleSum(data):
    s = data.sum()*2
    return s
print('菜品订单详情表的菜品销量两倍总和为:','\n',
      detail.agg({'counts':DoubleSum},axis = 0))

##自定义函数求两倍的和,包含NumPy
def DoubleSum1(data):
    s = np.sum(data)*2
    return s
print('订单详情表的菜品销量两倍总和为:\n',
      detail.agg({'counts':DoubleSum1},axis = 0).head())
print('订单详情表的菜品销量与售价的和的两倍为:\n',
      detail[['counts','amounts']].agg(DoubleSum1))

# 使用agg做简单的聚合
print('订单详情表分组后前3组每组的均值为:\n', 
      detailGroup.agg(np.mean).head(3))
print('订单详情表分组后前3组每组的标准差为:\n', 
      detailGroup.agg(np.std).head(3))
# 对分组数据使用不同的聚合函数
print('订单详情分组前3组每组菜品总数和售价均值为:\n', 
      detailGroup.agg({'counts':np.sum,
            'amounts':np.mean}).head(3))

apply方法类似agg,能够将函数应用于每一列,不同之处在于agg方法传入的函数只能作用于整个DataFrame或者Series,而无法像agg一样能够对不同字段应用不同函数来获取不同结果。
代码如下(示例):

import pandas as pd
import numpy as np
detail = pd.read_excel('meal_order_detail.xlsx',sheetname='meal_order_detail1')
detailGroup = detail[['order_id','counts','amounts']].groupby(by = 'order_id')
# 求出当前数据所对应的统计量
print('订单详情表的菜品销量与售价的均值为:\n',detail[['counts','amounts']].apply(np.mean))
print('订单详情表分组后前3组每组的均值为:','\n', detailGroup.apply(np.mean).head(3))
print('订单详情表分组后前3组每组的标准差为:','\n', detailGroup.apply(np.std).head(3))

transform方法能够对整个DataFrame的所有元素进行操作,仅有一个参数。

代码如下(示例):

import pandas as pd
import numpy as np
detail = pd.read_excel('meal_order_detail.xlsx',sheetname='meal_order_detail1')
detailGroup = detail[['order_id','counts','amounts']].groupby(by = 'order_id')

print('订单详情表的菜品销量与售价的两倍为:\n',
      detail[['counts','amounts']].transform(
            lambda x:x*2).head(4))

print('订单详情表分组后实现组内离差标准化后前五行为:\n', 
      detailGroup.transform(lambda x:(x.mean()
            -x.min())/(x.max()-x.min())).head())

六、创建透视表与交叉表

数据透视表是数据分析常用的工具之一,根据一个或多个键值对数据进行聚合,根据行或列的分组键将数据划分到各区域,除了使用groupby对数据进行分组聚合外,还有更简单的方法。

1.pivot_table函数创建透视表

注意不指定聚合函数aggfunc时,默认使用numpy.mean做聚合运算。
注意和groupby方法分组相同,pivot_table在创建透视表时候分组键可以有多个。
注意全部数据列数很多时,若只要显示自己关心的列,可以通过指定values参数实现。
注意数据不存在时会自动填充NaN。
此外还可以更改margins参数查看汇总数据。

代码如下(示例):

import pandas as pd
import numpy as np
detail = pd.read_excel('meal_order_detail.xlsx',sheetname='meal_order_detail1')
#使用订单号作为透视表索引制作透视表
detailPivot = pd.pivot_table(detail[[
      'order_id','counts','amounts']],
      index = 'order_id')
print('以order_id作为分组键创建的订单透视表为:\n',detailPivot.head())

# 修改聚合函数后的透视表
detailPivot1 = pd.pivot_table(detail[[
      'order_id','counts','amounts']],
      index = 'order_id',aggfunc = np.sum)
print('以order_id作为分组键创建的订单销量与售价总和透视表为:\n',
       detailPivot1.head())

# 使用订单号和菜品名称作为索引的透视表
detailPivot2 = pd.pivot_table(detail[[
      'order_id','dishes_name',
      'counts','amounts']],
      index = ['order_id','dishes_name'],
      aggfunc = np.sum)
print('以order_id和dishes_name作为分组键创建的订单\
销量与售价总和透视表为:\n',detailPivot2.head())

# 指定菜品名称为列分组键的透视表
detailPivot2 = pd.pivot_table(detail[[
      'order_id','dishes_name','counts','amounts']],
      index = 'order_id',
      columns = 'dishes_name',
      aggfunc = np.sum)
print('以order_id和dishes_name作为行列分组键创建的\
透视表前54列为:\n',detailPivot2.iloc[:5,:4])

# 指定某些列制作透视表
detailPivot4 = pd.pivot_table(detail[[
      'order_id','dishes_name','counts','amounts']],
      index = 'order_id',
      values = 'counts',
      aggfunc = np.sum)
print('以order_id作为行分组键counts作为值创建的\
透视表前5行为:\n',detailPivot4.head())

# 对透视表中的缺失值进行填充
detailPivot5 = pd.pivot_table(detail[[
      'order_id','dishes_name','counts','amounts']],
      index = 'order_id',
      columns = 'dishes_name',
      aggfunc = np.sum,fill_value = 0)
print('空值填0后以order_id和dishes_name为行列分组键\
创建透视表前54列为:\n',detailPivot5.iloc[:5,:4])

# 在透视表中添加汇总数据
detailPivot6 = pd.pivot_table(detail[[
      'order_id','dishes_name','counts','amounts']],
      index = 'order_id',columns = 'dishes_name',
      aggfunc = np.sum,fill_value = 0,
      margins = True)
print('添加margins后以order_id和dishes_name为分组键\
的透视表前5行后4列为:\n',detailPivot6.iloc[:5,-4:])

2.使用crosstab函数创建交叉表

交叉表是一种特殊的透视表,主要用于计算分组频率,与上述pivot_table参数大致相同。
代码如下(示例):

import pandas as pd
import numpy as np
detail = pd.read_excel('meal_order_detail.xlsx',sheetname='meal_order_detail1')
#制作交叉表
detailCross = pd.crosstab(
      index=detail['order_id'],
      columns=detail['dishes_name'],
      values = detail['counts'],aggfunc = np.sum)
print('以order_id和dishes_name为分组键\
counts为值的透视表前55列为:\n',detailCross.iloc[:5,:5])

总结

提示:本文章简单介绍了pandas包的初步用法。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值