python--pandas统计分析基础

pandas统计分析基础

  • 读/写不同数据源的数据
    • 读/写数据库数据
      • 数据库数据读取
      • 数据库数据存储
    • 读/写文本文件
      • 文本文件读取
      • 文本文件存储
    • 读/写Excel文件
      • Excel文件读取
      • Excel文件存储
      • 任务实现
  • DataFrame的常用操作
    • 查看DataFrame的常用属性
    • 增删改查DataFrame数据
      • 查看访问DataFrame中的数据
        • DataFrame数据的基本查看方式
        • DataFrame的loc、iloc访问方式
        • 切片方法之ix
      • 更改DataFrame中的数据
      • 为DataFrame增添数据
      • 删除某行或某列数据
    • 描述分析DataFrame数据
      • 数值型特征的描述性统计
      • 类别型数据的描述性统计
    • 任务实现
  • 转换与处理时间系列数据
    • 转换字符串时间为标准时间
    • 提取时间序列数据信息
    • 加减时间数据
    • 任务实现
  • 使用分组聚合进行组内计算
    • 使用groupby方法拆分数据
    • 使用agg方法聚合数据
    • 使用apply方法聚合数据
    • 使用transform方法聚合数据
    • 任务实现
  • 创建透视表与交叉表
    • 使用pivot_table函数创建透视表
    • 使用crosstab函数创建交叉表
    • 任务实现

读/写不同数据源的数据

读/写数据库数据

  • pandas提供了读取与存储关系型数据库数据的函数与方法。除了pandas库外还需要使用SQLAlchemy库建立对应数据库连接。SQLAlchemy配合相应数据库的python连接工具,使用create_engine函数,建立一个数据库连接。

数据库数据读取

  • 方法:pandas.read_sql_table:只能够读取数据库的某一个表格,不能实现查询的操作;pandas.read_sql_query:只能实现查询操作,不能直接读取数据库的某一个表格;pandas.read_sql:既能读取数据库中的某一个表,也能够实现查询操作。
    pandas.read_sql_table(table_name,con,schema=None,index_col=None,coerce_float=True,columns=None) pandas.read_sql_query(sql,con,index_col=None,coerce_float=True) pandas.read_sql(sql,con,index_col=None,coerce_float=True,columns=None)
    在creat_engine中输入的时一个连接字符串。在使用Python的SQLAlchemy时,MySQL和Oracle数据库连接字符串的格式:数据库产品名+连接工具名://用户名:密码@数据库IP地址:数据库端口号/数据库名称?charset=数据库数据编码

pandas.read_sql_table、pandas.read_sql_query、pandas.read_sql函数参数及其重要参数说明

C参数名称 说明
sql or table_name 接收string。表示读取的数据的表名或者SQL语句。无默认
con 接收数据库连接。表示数据库连接信息。无默认
index_col 接收int、sequence或者False。表示设定的列作为行名,如果是一个数列,则是多重索引。默认为None
coerce_float 接收boolean。将数据库中的decimal类型的数据转换为pandas中的float64类型的数据。默认为None
columns 接收list。表示读取数据的列名。默认为None
  • SQLAlchemy连接MySQL数据库
from sqlalchemy import create_engine
# 创建一个mysql连接器,用户名为root,密码为1234
# 地址为127.0.0.1,数据库名称为testdb,编码为utf-8
engine = create_engine('mysql+pymysql://root:[email protected]:3306/testdb?charset=utf8')
print(engine)
Engine(mysql+pymysql://root:***@127.0.0.1:3306/testdb?charset=utf8)
  • 读取数据库数据
import pandas as pd
# 使用read_sql_query查看wyc中的数据表数目
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))
testdb数据库数据表清单为: 
      Tables_in_testdb
0  meal_order_detail1
1  meal_order_detail2
2  meal_order_detail3
使用read_sql_table读取订单详情表的长度为: 2779
使用read_sql函数+sql语句读取的订单详情表长度为: 3647
使用read_sql函数+表格名称读取的订单详情表长度为: 3611

数据库数据存储

  • 将DataFrame写入数据库中,依赖于SQLAlchemy库的create_engine函数创建数据库连接。语法:DataFrame.to_sql(name,con,schema=None,if_exists='fail',index=True,index_label=None,dtype=None)

to_sql方法常用参数及其说明

参数名称 说明
name 接收string。代表数据库表名。无默认
con 接收数据库连接。无默认
if_exists 接收fail、replace和append。fail表示如果表名存在,则不执行写入操作;replace表明如果存在,则将原数据库表删除,再重新创建,则不执行写入操作;append表示再原数据库表的基础上追加数据。默认为fail
index 接收boolean。表示是否将行索引作为数据传入数据库。默认为True
index_label 接收string或者sequence。代表是否引用索引名称,如果index参数为True,此参数为None,则使用默认名称。如果为多重索引,则必须使用sequence形式。默认为None。
dtype 接收dict。代表写入的数据类型(列名为key,数据格式为values)。默认为None
  • 数据库存储数据
# 使用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)
新增一个表格后testdb数据库数据表清单为: 
      Tables_in_testdb
0  meal_order_detail1
1  meal_order_detail2
2  meal_order_detail3
3               test1

读/写文本文件

文本文件:由若干行字符构成的计算机文件,典型的顺序文件;CSV:用分隔符分隔的文件格式,文字分隔文件。

文本文件读取

  • pandas提供了read_table函数来读取文本文件,read_csv函数来读取CSV文件。语法:pandas.read_table(filepath,sep='\t',header='infer',names=None,index_col=None,dtype=None,encoding=utf-8,engine=None,nrows=None) pandas.read_csv(filepath,sep='\t',header='infer',names=None,index_col=None,dtype=None,encoding=utf-8,engine=None,nrows=None)

read_table和read_csv常用参数及其说明

参数名称 说明
filepath 接收string。代表文件路径。无默认
sep 接收string。代表分隔符。read_csv默认为“,”,read_table默认为制表符“Tab”
header 接收int或sequence。表示将某列数据作为列名。默认为infer,表示自动识别
names 接收array。表示列名。默认为None
index_col 接收int、sequence或False。表示索引列的位置,取值为sequence则代表多重索引。默认为None
dtype 接收dict。代表写入的数据类型(列名为key,数据格式为values)。默认为None
engine 接收c或者python。代表数据解析引擎。默认为c
nrows 接收int。表示读取前n行。默认为None
  • 文本文件读取
# 使用read_table读取订单信息表
order = pd.read_table('./data/meal_order_info.csv',sep = ',',encoding = 'gbk')
print('使用read_table读取的订单信息表的长度为:',len(order))


# 使用read_csv读取订单信息表
order1 = pd.read_csv('./data/meal_order_info.csv',encoding = 'gbk')
print('使用read_csv读取的订单信息表的长度为:',len(order1))
使用read_table读取的订单信息表的长度为: 945
使用read_csv读取的订单信息表的长度为: 945
# 使用read_table读取菜品订单信息表,sep = ';'
order2 = pd.read_table('./data/meal_order_info.csv',sep = ';',encoding = 'gbk')
print('分隔符为;时订单信息表为:\n',order2.head(5))

# 使用read_csv读取菜品订单信息表,header=None
order3 = pd.read_csv('./data/meal_order_info.csv',sep = ',',header = None,encoding = 'gbk')
print('订单信息表为:','\n',order3.head(5))

# 使用gbk解析菜品订单信息表
order4 = pd.read_csv('./data/meal_order_info.csv',sep = ',',encoding = 'utf-8')
分隔符为;时订单信息表为:
   info_id,"emp_id","number_consumers","mode","dining_table_id","dining_table_name","expenditure","dishes_count","accounts_payable","use_start_time","check_closed","lock_time","cashier_id","pc_id","order_number","org_id","print_doc_bill_num","lock_table_info","order_status","phone","name"
0  417,1442,4,NA,1501,1022,165,5,165,"2016/8/1 11...                                                                                                                                                                                                                                            
1  301,1095,3,NA,1430,1031,321,6,321,"2016/8/1 11...                                                                                                                                                                                                                                            
2  413,1147,6,NA,1488,1009,854,15,854,"2016/8/1 1...                                                                                                                                                                                                                                            
3  415,1166,4,NA,1502,1023,466,10,466,"2016/8/1 1...                                                                                                                                                                                                                                            
4  392,1094,10,NA,1499,1020,704,24,704,"2016/8/1 ...                                                                                                                                                                                                                                            
订单信息表为: 
         0       1                 2     3                4   \
0  info_id  emp_id  number_consumers  mode  dining_table_id   
1      417    1442                 4   NaN             1501   
2      301    1095                 3   NaN             1430   
3      413    1147                 6   NaN             1488   
4      415    1166                 4   NaN             1502   

                  5            6             7                 8   \
0  dining_table_name  expenditure  dishes_count  accounts_payable   
1               1022          165             5               165   
2               1031          321             6               321   
3               1009          854            15               854   
4               1023          466            10               466   

                  9   ...                 11          12     13            14  \
0     use_start_time  ...          lock_time  cashier_id  pc_id  order_number   
1  2016/8/1 11:05:36  ...  2016/8/1 11:11:46         NaN    NaN           NaN   
2  2016/8/1 11:15:57  ...  2016/8/1 11:31:55         NaN    NaN           NaN   
3  2016/8/1 12:42:52  ...  2016/8/1 12:54:37         NaN    NaN           NaN   
4  2016/8/1 12:51:38  ...  2016/8/1 13:08:20         NaN    NaN           NaN   

       15                  16               17            18           19  \
0  org_id  print_doc_bill_num  lock_table_info  order_status        phone   
1     330                 NaN              NaN             1  18688880641   
2     328                 NaN              NaN             1  18688880174   
3     330                 NaN              NaN             1  18688880276   
4     330                 NaN              NaN             1  18688880231   

     20  
0  name  
1   苗宇怡  
2    赵颖  
3   徐毅凡  
4   张大鹏  

[5 rows x 21 columns]
---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
<ipython-input-12-da6c18e298dd> in <module>
      8 
      9 # 使用gbk解析菜品订单信息表
---> 10 order4 = pd.read_csv('./data/meal_order_info.csv',sep = ',',encoding = 'utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 401: invalid continuation byte

文本文件存储

  • 语法:DataFrame.to_csv(path_or_buff=None,sep=',',na_rep='',columns=None,header=True,index=True,index_label=None,mode='w',encoding=None)

to_csv函数常用参数及其说明

参数名称 说明
path_or_buff 接收string。代表文件路径。无默认
sep 接收string。代表分隔符。默认为‘,’
na_rep 接收string。代表缺失值。默认为“”
columns 接收list。代表写出的列名。默认为None
header 接收boolean。代表是否将列名写出。默认为True
index 接收boolean。代表是否将列名写出。默认为True
index_label 接收sequence。表示索引名。默认为None
mode 接收特定string。代表数据写入模式。默认为v
encoding 接收特定string。代表存储文件的编码格式。默认为None
  • 文本文件存储
import os
print('订单信息表写入文本文件前目录内文件列表为:\n',os.listdir('./data'))
# 将order以csv格式存储
order.to_csv('./data/orderInfo.csv',sep = ';',index = False) 
print('订单信息表写入文本文件后目录内文件列表为:\n',os.listdir('./data'))
订单信息表写入文本文件前目录内文件列表为:
[]
订单信息表写入文本文件后目录内文件列表为:
[orderInfo.csv]

读/写Excel文件

Excel文件读取

  • 读取“xls” “xlsx”两种Excel文件。语法:pandas .read_excel(io,sheetname=,header=,index_col=None,dtype=None)

read_excel函数的常见参数及其说明

参数名称 说明
io 接收string。表示文件路径。无默认
sheetname 接收string、int。代表Excel表内数据的分表位置。默认为0
header 接收int或sequence。表示将某行数据作为列名,取值为int的时候,代表将该列作为列名。取值为sequence时,则代表多重列索引。默认为infer,表示自动识别
names 接收array。表示列名。默认为None
index_col 接收int、sequence或者False。表示索引列的位置,取值为sequence时代表多重索引。默认为None
dtype 接收dict。代表写入的数据类型(列名为key,数据格式为values)。默认为None
  • Excel文件读取
user = pd.read_excel('./data/users.xlsx')  # 读取user.xlsx文件
print('客户信息表长度为:',len(user))
客户信息表长度为: 734

Excel文件存储

  • 语法:DataFrame.to_excel(excel_writer=None,sheetname='None',na_rap='',header=True,index=True,index_label=None,mode='w',encoding=None)\

print('客户信息表写入excel文件前目录内文件列表为:\n',os.listdir('./data'))
user.to_excel('../tmp/userInfo.xlsx')
print('客户信息表写入excel文件后目录内文件列表为:\n',os.listdir('./data'))
客户信息表写入excel文件前目录内文件列表为:
['orderInfo.csv']
客户信息表写入excel文件后目录内文件列表为:
['orderInfo.csv','userInfo.xlsx']

任务实现

  • 读取订单详情数据库数据
# 导入SQLAlchemy库的creat_engine函数
from sqlalchemy import create_engine
import pandas as pd
# 创建一个mysql连接器,用户名为root,密码为1234
# 地址为127.0.0.1,数据库名称为testdb
engine = create_engine('mysql+pymysql://root:123456@127.0.0.1:\
3306/testdb?charset=utf8')
# 使用read_sql_table读取订单详情表格
order1 = pd.read_sql_table('meal_order_detail1',con = engine)
print('订单详情表1的长度为:',len(order1))
order2 = pd.read_sql_table('meal_order_detail2',con = engine)
print('订单详情表2的长度为:',len(order2))
order3 = pd.read_sql_table('meal_order_detail3',con = engine)
print('订单详情表3的长度为:',len(order3))
订单详情表1的长度为: 2779
订单详情表2的长度为: 3647
订单详情表3的长度为: 3611
  • 读取订单信息csv数据
# 使用read_table读取订单信息表
orderInfo = pd.read_table('./data/meal_order_info.csv',sep = ',',encoding = 'gbk')
print('订单信息表的长度为:',len(orderInfo))
订单信息表的长度为: 945
  • 读取客户信息Excel数据
# 读取user.xlsx文件
userInfo = pd.read_excel('./data/users.xlsx', sheetname = 'users1')
print('客户信息表的长度为:',len(userInfo))
客户信息表的长度为:734

DataFrame的常用操作

查看DataFrame的常用属性

  • DataFrame基础属性由values、index、columns和dtype,分别可以获取元素、索引、列名和类型。
from sqlalchemy import create_engine
import pandas as pd
# 创建数据库连接
engine = create_engine('mysql+pymysql://root:[email protected]:3306/testdb?charset=utf8')
detail= pd.read_sql_table('meal_order_detail1',con = engine)
print('订单详情表的索引为:', detail.index)
print('订单详情表的所有值为:','\n', detail.values)
print('订单详情表的列名为:','\n', detail.columns)
print('订单详情表的数据类型为:','\n', detail.dtypes)
from sqlalchemy import create_engine
import pandas as pd
# 创建数据库连接
engine = create_engine('mysql+pymysql://root:[email protected]:3306/testdb?charset=utf8')
detail= pd.read_sql_table('meal_order_detail1',con = engine)
print('订单详情表的索引为:', detail.index)
print('订单详情表的所有值为:','\n', detail.values)
print('订单详情表的列名为:','\n', detail.columns)
print('订单详情表的数据类型为:','\n', detail.dtypes)
  • size:元素个数;ndim:维度数;shape:数据形状
# 查看DataFrame的元素个数
print('订单详情表的元素个数为:', detail.size)
print('订单详情表的维度数为:', detail.ndim) ## 查看DataFrame的维度数
print('订单详情表的形状为:', detail.shape) ## 查看DataFrame的形状
订单详情表的元素个数为: 52801
订单详情表的维度数为: 2
订单详情表的形状为: (2779, 19)
  • DataFrame转置
print('订单详情表转置前形状为:',detail.shape)
print('订单详情表转置后形状为为:',detail.T.shape)
订单详情表转置前形状为: (2779, 19)
订单详情表转置后形状为为: (19, 2779)

增删改查DataFrame数据

查看访问DataFrame中的数据

DataFrame数据的基本查看方式

  • 使用字典访问内部数据的方法访问DataFrame单列数据
order_id = detail['order_id']
print('订单详情表中的order_id的形状为:','\n',order_id.shape)
订单详情表中的order_id的形状为: 
 (2779,)
  • 使用访问属性和的方法访问DataFrame单列数据
dishes_name = detail.dishes_name
print('订单详情表中的dishes_name的形状为:',dishes_name.shape)
订单详情表中的dishes_name的形状为: (2779,)
  • DataFrame单列多行数据获取
dishes_name5 = detail['dishes_name'][:5]
print('订单详情表中的dishes_name前5个元素为:','\n',dishes_name5)
订单详情表中的dishes_name前5个元素为: 
 0                 蒜蓉生蚝
1    蒙古烤羊腿\r\n\r\n\r\n
2                 大蒜苋菜
3                芝麻烤紫菜
4                  蒜香包
Name: dishes_name, dtype: object
  • 访问DataFrame多列的多行数据
orderDish = detail[['order_id','dishes_name']][:5]
print('订单详情表中的order_id和dishes_name前5个元素为:','\n',orderDish)
订单详情表中的order_id和dishes_name前5个元素为: 
   order_id        dishes_name
0      417               蒜蓉生蚝
1      417  蒙古烤羊腿\r\n\r\n\r\n
2      417               大蒜苋菜
3      417              芝麻烤紫菜
4      417                蒜香包
  • 访问DataFrame多行数据
order5 = detail[:][1:6]
print('订单详情表的1-6行元素为:','\n',order5)
订单详情表的1-6行元素为: 
   detail_id order_id dishes_id logicprn_name parent_class_name  \
1      2958      417    609957            NA                NA   
2      2961      417    609950            NA                NA   
3      2966      417    610038            NA                NA   
4      2968      417    610003            NA                NA   
5      1899      301    610019            NA                NA   

         dishes_name itemis_add counts amounts cost         place_order_time  \
1  蒙古烤羊腿\r\n\r\n\r\n          0      1      48   NA  2016-08-01 11:07:07.000   
2               大蒜苋菜          0      1      30   NA  2016-08-01 11:07:40.000   
3              芝麻烤紫菜          0      1      25   NA  2016-08-01 11:11:11.000   
4                蒜香包          0      1      13   NA  2016-08-01 11:11:30.000   
5                白斩鸡          0      1      88   NA  2016-08-01 11:15:57.000   

  discount_amt discount_reason kick_back add_inprice add_info bar_code  \
1           NA              NA        NA           0       NA       NA   
2           NA              NA        NA           0       NA       NA   
3           NA              NA        NA           0       NA       NA   
4           NA              NA        NA           0       NA       NA   
5           NA              NA        NA           0       NA       NA   

       picture_file emp_id  
1  caipu/202003.jpg   1442  
2  caipu/303001.jpg   1442  
3  caipu/105002.jpg   1442  
4  caipu/503002.jpg   1442  
5  caipu/204002.jpg   1095 
  • 使用DataFrame的head和tail方法获取多行
print('订单详情表中前五行数据为','\n',detail.head())
print('订单详情表中后五个元素为:','\n',detail.tail())
订单详情表中前五行数据为 
   detail_id order_id dishes_id logicprn_name parent_class_name  \
0      2956      417    610062            NA                NA   
1      2958      417    609957            NA                NA   
2      2961      417    609950            NA                NA   
3      2966      417    610038            NA                NA   
4      2968      417    610003            NA                NA   

         dishes_name itemis_add counts amounts cost         place_order_time  \
0               蒜蓉生蚝          0      1      49   NA  2016-08-01 11:05:36.000   
1  蒙古烤羊腿\r\n\r\n\r\n          0      1      48   NA  2016-08-01 11:07:07.000   
2               大蒜苋菜          0      1      30   NA  2016-08-01 11:07:40.000   
3              芝麻烤紫菜          0      1      25   NA  2016-08-01 11:11:11.000   
4                蒜香包          0      1      13   NA  2016-08-01 11:11:30.000   

  discount_amt discount_reason kick_back add_inprice add_info bar_code  \
0           NA              NA        NA           0       NA       NA   
1           NA              NA        NA           0       NA       NA   
2           NA              NA        NA           0       NA       NA   
3           NA              NA        NA           0       NA       NA   
4           NA              NA        NA           0       NA       NA   

       picture_file emp_id  
0  caipu/104001.jpg   1442  
1  caipu/202003.jpg   1442  
2  caipu/303001.jpg   1442  
3  caipu/105002.jpg   1442  
4  caipu/503002.jpg   1442  
订单详情表中后五个元素为: 
      detail_id order_id dishes_id logicprn_name parent_class_name dishes_name  \
2774      6750      774    610011            NA                NA       白饭/大碗   
2775      6742      774    609996            NA                NA         牛尾汤   
2776      6756      774    609949            NA                NA      意文柠檬汁    
2777      6763      774    610014            NA                NA        金玉良缘   
2778      6764      774    610017            NA                NA        酸辣藕丁   

     itemis_add counts amounts cost         place_order_time discount_amt  \
2774          0      1      10   NA  2016-08-10 21:56:24.000           NA   
2775          0      1      40   NA  2016-08-10 21:56:48.000           NA   
2776          0      1      13   NA  2016-08-10 22:01:52.000           NA   
2777          0      1      30   NA  2016-08-10 22:03:58.000           NA   
2778          0      1      33   NA  2016-08-10 22:04:30.000           NA   

     discount_reason kick_back add_inprice add_info bar_code  \
2774              NA        NA           0       NA       NA   
2775              NA        NA           0       NA       NA   
2776              NA        NA           0       NA       NA   
2777              NA        NA           0       NA       NA   
2778              NA        NA           0       NA       NA   

          picture_file emp_id  
2774  caipu/601005.jpg   1138  
2775  caipu/201006.jpg   1138  
2776  caipu/404005.jpg   1138  
2777  caipu/302003.jpg   1138  
2778  caipu/302006.jpg   1138  

DataFrame的loc、iloc访问方式

  • loc使用方法:DataFrame.loc[行索引名称或条件,列索引名称]
  • iloc使用方法:DataFrame.iloc[行索引名称,列索引名称]
  • 使用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)
使用loc提取dishes_name列的size为: 2779
使用iloc提取第3列的size为: 2779
  • 使用loc、iloc实现多列切片
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)
使用loc提取order_id和dishes_name列的size为: 5558
使用iloc提取第1和第3列的size为: 5558
  • 使用loc、iloc实现花式切片
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]])
列名为order_id和dishes_name的行名为3的数据为:
 order_id         417
dishes_name    芝麻烤紫菜
Name: 3, dtype: object
列名为order_id和dishes_name行名为2,3,4,5,6的数据为:
   order_id dishes_name
2      417        大蒜苋菜
3      417       芝麻烤紫菜
4      417         蒜香包
5      301         白斩鸡
6      301    香烤牛排\r\n
列位置为1和3行位置为3的数据为:
 order_id         417
logicprn_name     NA
Name: 3, dtype: object
列位置为1和3行位置为2,3,4,5,6的数据为:
   order_id logicprn_name
2      417            NA
3      417            NA
4      417            NA
5      301            NA
6      301            NA
  • 使用loc和iloc实现条件切片
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',[1,5]])
detail中order_id为458的dishes_name为:
     order_id        dishes_name
145      458              蒜香辣花甲
146      458               剁椒鱼头
147      458            凉拌蒜蓉西兰花
148      458               木须豌豆
149      458               辣炒鱿鱼
150      458               酸辣藕丁
151      458              炝炒大白菜
152      458              香菇鸡肉粥
153      458               干锅田鸡
154      458            桂圆枸杞鸽子汤
155      458  五香酱驴肉\r\n\r\n\r\n
156      458           路易拉菲红酒干红
157      458              避风塘炒蟹
158      458              白饭/大碗
NotImplementedError: iLocation based boolean indexing on an integer type is not available
  • 使用iloc实现条件切片
print('detail中order_id为458的第1,5列数据为:\n',detail.iloc[(detail['order_id']=='458').values,[1,5]])
detail中order_id为458的第1,5列数据为:
     order_id        dishes_name
145      458              蒜香辣花甲
146      458               剁椒鱼头
147      458            凉拌蒜蓉西兰花
148      458               木须豌豆
149      458               辣炒鱿鱼
150      458               酸辣藕丁
151      458              炝炒大白菜
152      458              香菇鸡肉粥
153      458               干锅田鸡
154      458            桂圆枸杞鸽子汤
155      458  五香酱驴肉\r\n\r\n\r\n
156      458           路易拉菲红酒干红
157      458              避风塘炒蟹
158      458              白饭/大碗

切片方法之ix

  • ix使用方法:DataFrame.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])
列名为dishes_name行名为2,3,4,5,6的数据为:
 2        大蒜苋菜
3       芝麻烤紫菜
4         蒜香包
5         白斩鸡
6    香烤牛排\r\n
Name: dishes_name, dtype: object
列位置为5,行位置为26的数据为:
 2     大蒜苋菜
3    芝麻烤紫菜
4      蒜香包
5      白斩鸡
Name: dishes_name, dtype: object
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-40-a0f653049307> in <module>
      1 print('列名为dishes_name行名为2,3,4,5,6的数据为:\n',detail.loc[2:6,'dishes_name'])
      2 print('列位置为5,行位置为2至6的数据为:\n',detail.iloc[2:6,5])
----> 3 print('列位置为5行名为2至6的数据为:', '\n',detail.ix[2:6,5])

D:\ProgramData\Anaconda3\lib\site-packages\pandas\core\generic.py in __getattr__(self, name)
   5272             if self._info_axis._can_hold_identifiers_and_holds_name(name):
   5273                 return self[name]
-> 5274             return object.__getattribute__(self, name)
   5275 
   5276     def __setattr__(self, name: str, value) -> None:

AttributeError: 'DataFrame' object has no attribute 'ix'
  • 问题:ix使用报错,因现在版本不适用ix

更改DataFrame中的数据

#将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中order_id为458的order_id为:
 Series([], Name: order_id, dtype: object)
更改后detail中order_id为45800的order_id为:
 145    45800
146    45800
147    45800
148    45800
149    45800
150    45800
151    45800
152    45800
153    45800
154    45800
155    45800
156    45800
157    45800
158    45800
Name: order_id, dtype: object

为DataFrame增添数据

  • 新增非定值
detail['payment'] =  detail['counts'].astype(float)*detail['amounts'].astype(float)
print('detail新增列payment的前五行为:','\n',detail['payment'].head())
detail新增列payment的前五行为: 
 0    49.0
1    48.0
2    30.0
3    25.0
4    13.0
Name: payment, dtype: float64
  • 新增定值
detail['pay_way'] = '现金支付'
print('detail新增列pay_way的前五行为:','\n',detail['pay_way'].head())
detail新增列pay_way的前五行为: 
 0    现金支付
1    现金支付
2    现金支付
3    现金支付
4    现金支付
Name: pay_way, dtype: object

删除某行或某列数据

  • 语法:DataFrame.drop(labels,axis=0,level=None,inplace=False,errors='raise')

drop方法的重要参数及其说明

参数名称 说明
labels 接收string或array。代表删除的行或列的标签。无默认
axis 接收0或1.代表操作的轴向。默认为0
level 接收int或者索引名。代表标签梭子啊级别。默认为None
inplace 接收boolean。代表操作是否对原数组生效。默认为False
  • 删除一列
print('删除pay_way前deatil的列索引为:','\n',detail.columns)
detail.drop(labels = 'pay_way',axis = 1,inplace = True)
print('删除pay_way后detail的列索引为:','\n',detail.columns)
删除pay_way前deatil的列索引为: 
 Index(['detail_id', 'order_id', 'dishes_id', 'logicprn_name',
       'parent_class_name', 'dishes_name', 'itemis_add', 'counts', 'amounts',
       'cost', 'place_order_time', 'discount_amt', 'discount_reason',
       'kick_back', 'add_inprice', 'add_info', 'bar_code', 'picture_file',
       'emp_id', 'payment', 'pay_way'],
      dtype='object')
删除pay_way后detail的列索引为: 
 Index(['detail_id', 'order_id', 'dishes_id', 'logicprn_name',
       'parent_class_name', 'dishes_name', 'itemis_add', 'counts', 'amounts',
       'cost', 'place_order_time', 'discount_amt', 'discount_reason',
       'kick_back', 'add_inprice', 'add_info', 'bar_code', 'picture_file',
       'emp_id', 'payment'],
      dtype='object')
  • 删除多列
print('删除1-10行前detail的长度为:',len(detail))
detail.drop(labels = range(1,11),axis = 0,inplace = True)
print('删除1-10行后detail的列索引为:',len(detail))
删除1-10行前detail的长度为: 2779
删除1-10行后detail的列索引为: 2769

描述分析DataFrame数据

数值型特征的描述性统计

Numpy中的描述性统计函数

函数名称 说明 函数名称 说明
np.min 最小值 np.max 最大值
np.mean 均值 np.ptp 极差
np.median 中位数 np.std 标准差
np.var 方差 np.cov 协方差
  • 计算平均价格
import numpy as np
print('订单详情表中amount(价格)的平均值为:', np.mean(detail['amounts'].astype(float)))
订单详情表中amount(价格)的平均值为: 45.343084145901045
  • 实现销量和价格的协方差矩阵计算
print('订单详情表中amount(价格)的平均值为:', detail['amounts'].astype(float).mean())
订单详情表中amount(价格)的平均值为: 45.343084145901045
  • 描述性统计
print('订单详情表counts和amounts两列的描述性统计为:\n',detail[['counts','amounts']].describe())
订单详情表counts和amounts两列的描述性统计为:
        counts amounts
count    2769    2769
unique      9      55
top         1      35
freq     2628     239

类别型数据的描述性统计

pandas描述性统计方法

函数名称 说明 函数名称 说明
min 最小值 max 最大值
mean 均值 ptp 极差
median 中位数 std 标准差
var 方差 cov 协方差
sem 标准误差 mode 众数
skew 样本偏度 kurt 样本峰值
quantile 四分位数 count 非空值数目
describe 描述统计 mad 平均绝对离差
  • 菜品频数统计
print('订单详情表dishes_name频数统计结果前10为:\n',detail['dishes_name'].value_counts()[0:10])
订单详情表dishes_name频数统计结果前10为:
 白饭/大碗        91
凉拌菠菜         77
谷稻小庄         72
麻辣小龙虾        65
白饭/小碗        60
五色糯米饭(七色)    58
焖猪手          55
芝士烩波士顿龙虾     55
辣炒鱿鱼         53
水煮鱼          47
Name: dishes_name, dtype: int64
  • 将object数据强制转化为category
detail['dishes_name'] = detail['dishes_name'].astype('category')
print('订单信息表dishes_name列转变数据类型后为:',detail['dishes_name'].dtypes)
订单信息表dishes_name列转变数据类型后为: category
  • category类型特征的描述性统计
print('订单信息表dishes_name的描述统计结果为:\n',detail['dishes_name'].describe())
订单信息表dishes_name的描述统计结果为:
 count      2769
unique      154
top       白饭/大碗
freq         91
Name: dishes_name, dtype: object

任务实现

  • 查看餐饮数据的大小和维度
from sqlalchemy import create_engine
import pandas as pd
engine = create_engine('mysql+pymysql://root:[email protected]:3306/testdb?charset=utf8')
detail = pd.read_sql_table('meal_order_detail1',con = engine)
order = pd.read_table('./data/meal_order_info.csv',sep = ',',encoding = 'gbk')
user = pd.read_excel('./data/users.xlsx')
print('订单详情表的维度为:', detail.ndim)
print('订单信息表的维度为:', order.ndim)
print('客户信息表的维度为:', user.ndim)

print('订单详情表的形状为:', detail.shape)
print('订单信息表的形状为:', order.shape)
print('客户信息表的形状为:', user.shape)

print('订单详情表的元素个数为:', detail.size)
print('订单信息表的元素个数为:', order.size)
print('客户信息表的元素个数为:', user.size)
订单详情表的维度为: 2
订单信息表的维度为: 2
客户信息表的维度为:2
订单详情表的形状为: (2779, 19)
订单信息表的形状为: (945, 21)
客户信息表的形状为: (734, 37)
订单详情表的元素个数为: 52801
订单信息表的元素个数为: 19845
客户信息表的元素个数为:27158
  • 统计餐饮菜品销售情况
print('订单详情表counts和amounts两列的描述性统计为:\n',detail.loc[:, ['counts','amounts']].describe())
detail['order_id'] = detail['order_id'].astype('category')
detail['dishes_name'] = detail['dishes_name'].astype('category')
print('''订单信息表order_id(订单编号)与dishes_name(菜品名称)的描述性统计结果为:''', '\n',detail[['order_id','dishes_name']].describe())
订单详情表counts和amounts两列的描述性统计为:
        counts amounts
count    2779    2779
unique      9      55
top         1      35
freq     2638     239
订单信息表order_id(订单编号)与dishes_name(菜品名称)的描述性统计结果为: 
        order_id dishes_name
count      2779        2779
unique      278         154
top         392       白饭/大碗
freq         24          92
  • 剔除全为空值或者所有元素取值相同的列–定义一个函数去除全为空值的列和标准差为0的列
def dropNullStd(data):
    beforelen = data.shape[1]
    colisNull = data.describe().loc['count'] == 0
    for i in range(len(colisNull)):
        if colisNull[i]:
            data.drop(colisNull.index[i],axis = 1,inplace =True)

    stdisZero = data.describe().loc['std'] == 0
    for i in range(len(stdisZero)):
        if stdisZero[i]:
            data.drop(stdisZero.index[i],axis = 1,inplace =True)
    afterlen = data.shape[1]
    print('去除的列的数目为:',beforelen-afterlen)
    print('去除后数据的形状为:',data.shape)

dropNullStd(order)
去除的列的数目为: 7
去除后数据的形状为: (945, 14) 

转换与处理时间系列数据

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

pandas时间相关的类

类名称 说明
Timestamp 最基础的时间类。表示某个时间点。绝大多数的场景中的时间数据都是Timestamp形式
Period 表示单个时间跨度,或者某个时间段,例如某一天、某一小时等
Timedelta 表示不同单位的时间,例如1d、1.5h、3min、4s等,而非具体的某个时间段
DatetimeIndex 一组Timestamp构成的Index,可以用来最为Series或者DataFrame的索引
PeriodtimeIndex 一组Period构成的Index,可以用来最为Series或者DataFrame的索引
TimedeltaIndex 一组Timedelta构成的Index,可以用来最为Series或者DataFrame的索引

DatetimeIndex与PeriodIndex函数及其参数说明

参数名称 说明
data 接收array。表示DatetimeIndex的值。无默认
freq 接收string。表示时间的间隔频率。无默认
start 接收string。表示生成规则时间数据的起始点。无默认
periods 表示需要生成的周期数目。无默认
end 接收string。表示生成规则时间数据的终结点。无默认
tz 接收timezone。表示数据的时区。默认为None
name 接收int、string。默认为空。指定DatetimeIndex的名字
  • 转换字符串时间为标准时间
import pandas as pd
order = pd.read_table('./data/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)
进行转换前订单信息表lock_time的类型为: object
进行转换后订单信息表lock_time的类型为: datetime64[ns]
  • Timestamp的最小时间和最大时间
print('最小时间为:', pd.Timestamp.min)
print('最大时间为:', pd.Timestamp.max)
最小时间为: 1677-09-21 00:12:43.145225
最大时间为: 2262-04-11 23:47:16.854775807
  • 时间字符串转换为DatetimeIndex和PeriodIndex
dateIndex = pd.DatetimeIndex(order['lock_time'])
print('转换为DatetimeIndex后数据的类型为:\n',type(dateIndex))

periodIndex = pd.PeriodIndex(order['lock_time'],freq = 'S')
print('转换为DatetimeIndex后数据的类型为:\n',type(periodIndex))
转换为DatetimeIndex后数据的类型为:
 <class 'pandas.core.indexes.datetimes.DatetimeIndex'>
转换为DatetimeIndex后数据的类型为:
 <class 'pandas.core.indexes.period.PeriodIndex'>

提取时间序列数据信息

Timestamp类常用属性及说明

属性名称 说明 属性名称 说明
year week 一年中第几周
month quarter 季节
day weekofyear 一年中第几周
hours 小时 dayofyear 一年中的第几天
minite 分钟 dayofweek 一周第几天
second weekday 一周第几天
date 日期 day_name 星期名称
time 时间 is_leap_year 是否闰年
  • 提取datetime数据中的时间序列
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 for i in order['lock_time']]
print('lock_time中的星期名称数据前5个为:',weekday1[:5])
lock_time中的年份数据前5个为: [2016, 2016, 2016, 2016, 2016]
lock_time中的月份数据前5个为: [8, 8, 8, 8, 8]
lock_time中的日期数据前5个为: [1, 1, 1, 1, 1]
lock_time中的星期名称数据前5个为: [<built-in method weekday of Timestamp object at 0x0000019302176348>, <built-in method weekday of Timestamp object at 0x00000193021763C8>, <built-in method weekday of Timestamp object at 0x0000019302A26248>, <built-in method weekday of Timestamp object at 0x0000019302A260C8>, <built-in method weekday of Timestamp object at 0x0000019302A26148>]
  • 提取DatetimeIndex和PeriodIndex中的数据
week_dict = {0.0:"Monday",1.0:"Tuesday",2.0:"Wednesday",3.0:"Thursday",4.0:"Friday",5.0:"Saturday",6.0:"Sunday"}
print('dateIndex中的星期名称数据前5个为:\n',[week_dict[i] for i in dateIndex.weekday[:5]])
print('periodIndex中的星期标号数据前5个为:',periodIndex.weekday[:5])
dateIndex中的星期名称数据前5个为:
 ['Monday', 'Monday', 'Monday', 'Monday', 'Monday']
periodIndex中的星期标号数据前5个为: Int64Index([0, 0, 0, 0, 0], dtype='int64', name='lock_time')

加减时间数据

Timedelta类周期名称、对应单位及其说明

周期名称 单位 说明
weeks 星期
days D
hours h 小时
minutes m
seconds s
milliseconds ms 毫秒
microseconds us 微秒
nanoseconds ns 纳秒
  • 使用Timedelta实现时间数据的加运算
# 将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])
lock_time在加上一天前前5行数据为:
 0   2016-08-01 11:11:46
1   2016-08-01 11:31:55
2   2016-08-01 12:54:37
3   2016-08-01 13:08:20
4   2016-08-01 13:07:16
Name: lock_time, dtype: datetime64[ns]
lock_time在加上一天前前5行数据为:
 0   2016-08-02 11:11:46
1   2016-08-02 11:31:55
2   2016-08-02 12:54:37
3   2016-08-02 13:08:20
4   2016-08-02 13:07:16
Name: lock_time, dtype: datetime64[ns]
  • 使用Timedelta实现时间数据的减运算
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)
lock_time减去2017年1月1日0点0时0分后的数据:
 0   -153 days +11:11:46
1   -153 days +11:31:55
2   -153 days +12:54:37
3   -153 days +13:08:20
4   -153 days +13:07:16
Name: lock_time, dtype: timedelta64[ns]
lock_time减去time1后的数据类型为: timedelta64[ns]

任务实现

  • 时间字符串转化为标准时间格式–订单信息表时间数据转换
    在订单信息表中存在两个时间特征,use_start_time和lock_time,分别表示了开始的时间和结算订单的时间。需要将这两个特征转化为标准的时间格式
import pandas as pd
order = pd.read_table('./data/meal_order_info.csv',sep = ',',encoding = 'gbk')
order['use_start_time'] = pd.to_datetime(order['use_start_time'])
order['lock_time'] = pd.to_datetime(order['lock_time'])
print('进行转换后订单信息表use_start_time和lock_time的类型为:\n', order[['use_start_time','lock_time']].dtypes)
进行转换后订单信息表use_start_time和lock_time的类型为:
 use_start_time    datetime64[ns]
lock_time         datetime64[ns]
dtype: object
  • 提取菜品数据中的年月日和信息特征
    use_start_time和lock_time两个特征中的时间信息基本一直,故只需要提取其中一个特征的时间信息即可。
year = [i.year for i in order['lock_time']]## 提取年份信息
month = [i.month for i in order['lock_time']]## 提取月份信息
day = [i.day for i in  order['lock_time']]## 提取日期信息
week = [i.week for i in  order['lock_time']]## 提取周信息
weekday = [i.weekday() for i in  order['lock_time']]##提取星期信息
## 提取星期名称信息
weekname = [i.weekday() for i in  order['lock_time']]
week_dict = {0.0:"Monday",1.0:"Tuesday",2.0:"Wednesday",3.0:"Thursday",4.0:"Friday",5.0:"Saturday",6.0:"Sunday"}
print('订单详情表中的前5条数据的年份信息为:',year[:5])
print('订单详情表中的前5条数据的月份信息为:',month[:5])
print('订单详情表中的前5条数据的日期信息为:',day[:5])
print('订单详情表中的前5条数据的周信息为:',week[:5])
print('订单详情表中的前5条数据的星期信息为:',weekday[:5])
print('订单详情表中的前5条数据的星期名称信息为:',[week_dict[i] for i in weekname[:5]])
订单详情表中的前5条数据的年份信息为: [2016, 2016, 2016, 2016, 2016]
订单详情表中的前5条数据的月份信息为: [8, 8, 8, 8, 8]
订单详情表中的前5条数据的日期信息为: [1, 1, 1, 1, 1]
订单详情表中的前5条数据的周信息为: [31, 31, 31, 31, 31]
订单详情表中的前5条数据的星期信息为: [0, 0, 0, 0, 0]
订单详情表中的前5条数据的星期名称信息为: ['Monday', 'Monday', 'Monday', 'Monday', 'Monday']
  • 查看订单时间表时间统计信息
    通过求取最早时间和最晚时间的差值来计算整体订单的时间跨度,还能够将use_start_time和lock_time两个特征做加减运算,可以看出开始点餐至结束订单的时间。
timemin = order['lock_time'].min()
timemax = order['lock_time'].max()
print('订单最早的时间为:',timemin)
print('订单最晚的时间为:',timemax)
print('订单持续的时间为:',timemax-timemin)

chekTime = order['lock_time'] - order['use_start_time']
print('平均点餐时间为:',chekTime.mean())
print('最小点餐时间为:',chekTime.min())
print('最大点餐时间为:',chekTime.max())
订单最早的时间为: 2016-08-01 11:11:46
订单最晚的时间为: 2016-08-31 21:56:12
订单持续的时间为: 30 days 10:44:26
平均点餐时间为: 0 days 01:12:10.326923
最小点餐时间为: -1 days +00:05:03
最大点餐时间为: 16 days 00:08:00

可以发现最短时间和最长时间均为异常值,开始时间不可能在结束订单时间之后,点餐时间也不可能持续16天,可以考虑对这部分数据做合适的处理

使用分组聚合进行组内计算

使用groupby方法拆分数据

  • 语法:DataFrame.groupby(by=None,axis=0,level=None,as_index=True,sort=True,group_keys=True,squeeze=False,**kwargs)

groupby方法的参数及其说明

参数名称 说明
by 接收list、string、mapping或generator。用于确定分组的依据。如果传入的时一个函数,则对索引进行计算并分组;如果传入的时一个字典或者Series,则字典或者Series的值用来作为分组依据;如果传入一个NumPy数组,则于数据的元素作为分组依据;如果传入的时字符串或者字符串列表,则使用这些字符串所代表的字段作为分组依据。无默认
axis 接收int。表示操作的轴向,魔派任对列进行操作。默认为0
level 接收int或者索引名。代表标签所在级别。默认为None
as_index 接收boolean。表示聚合后的聚合标签是否以DataFrame索引形式输出。默认为True
sort 接收boolean。表示是否对分组依据、分组标签进行排序。默认为True
group_keys 接收boolean。表示是否显示分组标签的名称。默认为True
squeeze 接收boolean。表示是否在允许的情况下返回数据进行降维。默认为False

groupby常用描述性统计方法及说明

方法名称 说明
count 计算分组的数目,包括缺失值
head 返回每组的前n个值
max 返回每组最大值
mean 返回每组均值
median 返回每组中位数
cumcount 对每个分组中的组员进行标记,0~n-1
size 返回每组的大小
min 返回每组最小值
std 返回每组的标准差
sum 返回每组的和
  • 对菜品订单详情表依据订单编号进行分组
import pandas as pd
import numpy as np
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://root:[email protected]:3306/testdb?charset=utf8')
detail = pd.read_sql_table('meal_order_detail1',con = engine)
detailGroup = detail[['order_id','counts','amounts']].astype(float).groupby(by = 'order_id')
print('分组后的订单详情表为:',detailGroup)
分组后的订单详情表为: <pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000022A64FC0488>
  • groupby求均值、标准差、中位数
print('订单详情表分组后前5组每组的均值为:\n', detailGroup.mean().head())
print('订单详情表分组后前5组每组的标准差为:\n', detailGroup.std().head())
print('订单详情表分组后前5组每组的大小为:','\n', detailGroup.size().head())
订单详情表分组后前5组每组的均值为:
             counts    amounts
order_id                     
137.0     1.500000  32.333333
165.0     1.166667  52.944444
166.0     1.400000  48.200000
171.0     1.428571  36.285714
177.0     1.000000  34.250000
订单详情表分组后前5组每组的标准差为:
             counts    amounts
order_id                     
137.0     1.224745  35.200379
165.0     0.383482  52.193613
166.0     0.547723  41.829415
171.0     1.133893  19.267540
177.0     0.000000  15.019432
订单详情表分组后前5组每组的大小为: 
 order_id
137.0     6
165.0    18
166.0     5
171.0     7
177.0     4
dtype: int64

使用agg方法聚合数据

  • 语法:DataFrame.agg(func,axis=0,*args,**kwargs) DataFrame.aggregate(func,axis=0,*args,**kwargs)

agg和aggregate函数的参数及其说明

参数名称 说明
func 接收list、dict、function。表示应用与每行或每列的函数。无默认
axis 接收0或1。表示操作的轴向。默认为0
  • 使用agg求出当前数据对应的统计量
print('订单详情表的菜品销量与售价的和与均值为:\n',detail[['counts','amounts']].astype(float).agg([np.sum,np.mean]))
订单详情表的菜品销量与售价的和与均值为:
            counts        amounts
sum   3088.000000  125992.000000
mean     1.111191      45.337172
  • 使用agg分别求字段的不同统计量
detail['counts']=detail['counts'].astype(float)
detail['amounts']=detail['amounts'].astype(float)
print('订单详情表的菜品销量总和与售价的均值为:\n',detail.agg({'counts':np.sum,'amounts':np.mean}))
订单详情表的菜品销量总和与售价的均值为:
 counts     3088.000000
amounts      45.337172
dtype: float64
  • 使用agg方法求不同字段的不同数目统计量
print('菜品订单详情表的菜品销量总和与售价的总和与均值为:\n',detail.agg({'counts':np.sum,'amounts':[np.mean,np.sum]}))
菜品订单详情表的菜品销量总和与售价的总和与均值为:
       counts        amounts
mean     NaN      45.337172
sum   3088.0  125992.000000
  • 在agg方法中使用自定义函数
#自定义函数求两倍的和
def DoubleSum(data):
    s = data.sum()*2
    return s
print('菜品订单详情表的菜品销量两倍总和为:','\n',
      detail.agg({'counts':DoubleSum},axis = 0))
菜品订单详情表的菜品销量两倍总和为: 
 counts    6176.0
dtype: float64
  • agg方法中使用的自定义函数含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))
订单详情表的菜品销量两倍总和为:
    counts
0     2.0
1     2.0
2     2.0
3     2.0
4     2.0
订单详情表的菜品销量与售价的和的两倍为:
 counts       6176.0
amounts    251984.0
dtype: float64
  • 使用agg方法做简单的聚合
print('订单详情表分组后前3组每组的均值为:\n', 
      detailGroup.agg(np.mean).head(3))

print('订单详情表分组后前3组每组的标准差为:\n', 
      detailGroup.agg(np.std).head(3))
订单详情表分组后前3组每组的均值为:
             counts    amounts
order_id                     
137.0     1.500000  32.333333
165.0     1.166667  52.944444
166.0     1.400000  48.200000
订单详情表分组后前3组每组的标准差为:
             counts    amounts
order_id                     
137.0     1.224745  35.200379
165.0     0.383482  52.193613
166.0     0.547723  41.829415
  • 使用agg方法对数据分组使用不同的聚合函数
print('订单详情分组前3组每组菜品总数和售价均值为:\n', 
      detailGroup.agg({'counts':np.sum,
            'amounts':np.mean}).head(3))
订单详情分组前3组每组菜品总数和售价均值为:
           counts    amounts
order_id                   
137.0        9.0  32.333333
165.0       21.0  52.944444
166.0        7.0  48.200000

使用apply方法聚合数据

  • apply方法类似于agg方法,能够将函数应用同于每一列。不同为agg方法传入的函数只能作用于整个DataFrame或者Series,而无法像agg一样能够对不同字段应用不同函数来获取不同结果。语法:DataFrame.apply(func,axis=0,broadcast=False,raw=False,reduce=None,args=(),**kwds)

apply方法的重要参数及其说明

参数名称 说明
func 接收functions。表示应用与每行或每列的函数。无默认
axis 接收0或1。表示操作的轴向。默认为0
broadcast 接收boolean。表示是否进行广播。默认为False
raw 接收boolean。表示是否直接将ndarray对象传递给函数。默认为False
reduce 接收boolean或者None。表示返回值的格式。默认为None
  • apply方法的基本用法
print('订单详情表的菜品销量与售价的均值为:\n',
      detail[['counts','amounts']].apply(np.mean))
订单详情表的菜品销量与售价的均值为:
 counts      1.111191
amounts    45.337172
dtype: float64
  • 使用apply方法进行聚合操作
print('订单详情表分组后前3组每组的均值为:','\n', detailGroup.apply(np.mean).head(3))
print('订单详情表分组后前3组每组的标准差为:','\n', detailGroup.apply(np.std).head(3))
订单详情表分组后前3组每组的均值为: 
           order_id    counts    amounts
order_id                               
137.0        137.0  1.500000  32.333333
165.0        165.0  1.166667  52.944444
166.0        166.0  1.400000  48.200000
订单详情表分组后前3组每组的标准差为: 
           order_id    counts    amounts
order_id                               
137.0          0.0  1.118034  32.133402
165.0          0.0  0.372678  50.723074
166.0          0.0  0.489898  37.413367

使用transform方法聚合数据

  • 使用transform方法将销量和售价翻倍
print('订单详情表的菜品销量与售价的两倍为:\n',
      detail[['counts','amounts']].transform(
            lambda x:x*2).head(4))
订单详情表的菜品销量与售价的两倍为:
    counts  amounts
0     2.0     98.0
1     2.0     96.0
2     2.0     60.0
3     2.0     50.0
  • 使用transform实现组内离差标准化
print('订单详情表分组后实现组内离差标准化后前五行为:\n', 
      detailGroup.transform(lambda x:(x.mean()
            -x.min())/(x.max()-x.min())).head())

任务实现

  • 按照时间对菜品订单详情表进行拆分
import pandas as pd
import numpy as np
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://root:1234@127.0.0.1:\
3306/testdb?charset=utf8')
detail = pd.read_sql_table('meal_order_detail1',con = engine)
detail['place_order_time'] = pd.to_datetime(
       detail['place_order_time'])
detail['date'] = [i.date() for i in detail['place_order_time']]
detail[['counts','amounts']] = detail[['counts','amounts']].astype(float)
detailGroup = detail[['date','counts','amounts']].groupby(by='date')
print('订单详情表前5组每组的数目为:\n',detailGroup.size().head())
订单详情表前5组每组的数目为:
 date
2016-08-01    217
2016-08-02    138
2016-08-03    157
2016-08-04    144
2016-08-05    193
dtype: int64
  • 使用agg方法计算单日菜品销售的平均单价和售价中位数
dayMean = detailGroup.agg({'amounts':np.mean})
print('订单详情表前五组每日菜品均价为:\n',dayMean.head())

dayMedian = detailGroup.agg({'amounts':np.median})
print('订单详情表前五组每日菜品售价中位数为:\n',dayMedian.head())
订单详情表前五组每日菜品均价为:
               amounts
date                 
2016-08-01  43.161290
2016-08-02  44.384058
2016-08-03  43.885350
2016-08-04  52.423611
2016-08-05  44.927461
订单详情表前五组每日菜品售价中位数为:
             amounts
date               
2016-08-01     33.0
2016-08-02     35.0
2016-08-03     38.0
2016-08-04     39.0
2016-08-05     37.0
  • 使用apply方法统计单日菜品销售数目
daySaleSum = detailGroup.apply(np.sum)['counts']
print('订单详情表前五组每日菜品售出数目为:\n',daySaleSum.head())
订单详情表前五组每日菜品售出数目为:
 date
2016-08-01    233.0
2016-08-02    151.0
2016-08-03    192.0
2016-08-04    169.0
2016-08-05    224.0
Name: counts, dtype: float64

创建透视表与交叉表

使用pivot_table函数创建透视表

  • 语法:pandas.pivot_table(data,values=None,index=None,columns=None,aggfunc='mean',fill_value=None,margins=False,dropna=True,margins_name='All')

pivot_table函数的常用参数及其说明

参数名称 说明
data 接收DataFrame。表示创建表的数据。无默认
values 接收string。用于指定要聚合的数据字段名,默认使用全部数据。默认为None
index 接收string或list。表示行分组键。默认为None
columns 接收string或list。表示列分组键。默认为None
aggfunc 接收functions。表示聚合函数。默认为mean
margins 接收boolean。表示汇总(Total)功能的开关,设置为True后,结果集中会出现名为“All”的行和列。默认为True
dropna 接收boolean。表示是否删掉全为NaN的列。默认为False
  • 使用订单号作为透视表索引制作透视表
import pandas as pd
import numpy as np
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://root:1234@\
127.0.0.1:3306/testdb?charset=utf8')
detail = pd.read_sql_table('meal_order_detail1',con = engine)
detail[['counts','amounts']]=detail[['counts','amounts']].astype(float)
detailPivot = pd.pivot_table(detail[['order_id','counts','amounts']],index = 'order_id')
print('以order_id作为分组键创建的订单透视表为:\n',detailPivot.head())
以order_id作为分组键创建的订单透视表为:
           amounts  counts
order_id                 
1002       32.000  1.0000
1003       30.125  1.2500
1004       43.875  1.0625
1008       63.000  1.0000
1011       57.700  1.0000
  • 修改聚合函数后的透视表
detailPivot1 = pd.pivot_table(detail[[
      'order_id','counts','amounts']],
      index = 'order_id',aggfunc = np.sum)
print('以order_id作为分组键创建的订单销量与售价总和透视表为:\n',
       detailPivot1.head())
以order_id作为分组键创建的订单销量与售价总和透视表为:
           amounts  counts
order_id                 
1002        224.0     7.0
1003        241.0    10.0
1004        702.0    17.0
1008        315.0     5.0
1011        577.0    10.0
  • 使用订单号和菜品名称作为索引的透视表
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())
以order_id和dishes_name作为分组键创建的订单销量与售价总和透视表为:
                                 amounts  counts
order_id dishes_name                           
1002     凉拌菠菜                      27.0     1.0
         南瓜枸杞小饼干                   19.0     1.0
         焖猪手                       58.0     1.0
         独家薄荷鲜虾牛肉卷\r\n\r\n\r\n     45.0     1.0
         白胡椒胡萝卜羊肉汤                 35.0     1.0
  • 指定菜品名称为列分组键的透视表
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])
以order_id和dishes_name作为行列分组键创建的透视表前5行4列为:
             amounts                        
dishes_name  42度海之蓝  北冰洋汽水  38度剑南春  50度古井贡酒
order_id                                   
1002            NaN     NaN     NaN     NaN
1003            NaN     NaN     NaN     NaN
1004            NaN     NaN     NaN     NaN
1008            NaN     NaN     NaN     NaN
1011           99.0     NaN     NaN     NaN
  • 指定某些列制作透视表
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())
以order_id作为行分组键counts作为值创建的透视表前5行为:
           counts
order_id        
1002         7.0
1003        10.0
1004        17.0
1008         5.0
1011        10.0
  • 对透视表中的缺失值进行填充
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])
空值填0后以order_id和dishes_name为行列分组键创建透视表前5行4列为:
             amounts                        
dishes_name  42度海之蓝  北冰洋汽水  38度剑南春  50度古井贡酒
order_id                                   
1002              0       0       0       0
1003              0       0       0       0
1004              0       0       0       0
1008              0       0       0       0
1011             99       0       0       0
  • 在透视表中添加汇总数据
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:])
添加margins后以order_id和dishes_name为分组键的透视表前5行后4列为:
             counts                    
dishes_name 黄油曲奇饼干 黄花菜炒木耳 黑米恋上葡萄   All
order_id                              
1002             0      0      0   7.0
1003             0      0      0  10.0
1004             0      1      0  17.0
1008             0      0      0   5.0
1011             0      0      0  10.0

使用crosstab函数创建交叉表

  • 语法:pandas.crosstab(index,columns,values=None,rownames=None,colnames=None,aggfunc='mean',margins=False,dropna=True,normalize=False)

crosstab函数的常用参数及其说明

参数名称 说明
index 接收string或list。表示行索引键。无默认
columns 接收string或list。表示列索引键。无默认
values 接收array。表示聚合数据。默认为None
rownames 表示行分组键名。无默认
colnames 表示列分组键名。无默认
aggfunc 接收function。表示聚合函数。默认为mean
margins 接收boolean。默认为True。表示汇总(Total)功能的开关,设置为True后,结果集中会出现名为“All”的行和列。
dropna 接收boolean。表示是否删掉全为NaN的列。默认为False
normalize 接收boolean。表示是否对值进行标准化。默认为False
  • 使用crosstab函数制作交叉表
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])
以order_id和dishes_name为分组键counts为值的透视表前5行5列为:
 dishes_name   42度海之蓝   北冰洋汽水   38度剑南春   50度古井贡酒  52度泸州老窖 
order_id                                                 
1002             NaN      NaN      NaN      NaN       NaN
1003             NaN      NaN      NaN      NaN       NaN
1004             NaN      NaN      NaN      NaN       NaN
1008             NaN      NaN      NaN      NaN       NaN
1011             1.0      NaN      NaN      NaN       NaN

任务实现

  • 创建单日菜品成交总额与总数均价透视表
import pandas as pd
import numpy as np
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://root:1234@\
127.0.0.1:3306/testdb?charset=utf8')
detail = pd.read_sql_table('meal_order_detail1',con = engine)
detail['place_order_time'] = pd.to_datetime(
      detail['place_order_time'])
detail['date'] = [i.date() for i in detail['place_order_time']]
PivotDetail = pd.pivot_table(detail[[
      'date','dishes_name','counts','amounts']],
      index ='date',aggfunc = np.sum,
      margins = True)
print('订单详情表单日菜品成交总额与总数透视表前5行5列为:\n',
      PivotDetail.head())
订单详情表单日菜品成交总额与总数透视表前5行5列为:
             amounts  counts
date                       
2016-08-01   9366.0   233.0
2016-08-02   6125.0   151.0
2016-08-03   6890.0   192.0
2016-08-04   7549.0   169.0
2016-08-05   8671.0   224.0
  • 创建单个菜品单日成交总额透视表
CrossDetail = pd.crosstab(
      index=detail['date'],columns=detail['dishes_name'],
      values = detail['amounts'],
      aggfunc = np.sum,margins = True)
print('订单详情表单日单个菜品成交总额交叉表后5行5列为:\n',
      CrossDetail.iloc[-5:,-5:])
订单详情表单日单个菜品成交总额交叉表后5行5列为:
 dishes_name  黄尾袋鼠西拉子红葡萄酒  黄油曲奇饼干  黄花菜炒木耳  黑米恋上葡萄       All
date                                                      
2016-08-07         230.0    32.0   105.0    99.0   31306.0
2016-08-08          46.0     NaN     NaN    33.0    6532.0
2016-08-09         138.0     NaN    35.0    99.0    7155.0
2016-08-10          46.0     NaN    70.0    33.0   10231.0
All                736.0    80.0   525.0   561.0  125992.0

你可能感兴趣的:(python,pandas,python,oracle)