文章目录
pandas_任务4.4 使用分组聚合进行组内计算
!
!!
!!!可以点击下面连接
ipynb格式浏览
4.4.1 使用groupby方法拆分数据
代码 4-51 对菜品订单详情表依据订单编号分组
import pandas as pd
import numpy as np
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://root:123456@localhost:3306/zuoye')
detail = pd.read_sql_table('meal_order_detail1',con = engine)
detailGroup = detail[['order_id','counts',
'amounts']].groupby(by = 'order_id')
print('分组后的订单详情表为:',detailGroup)
分组后的订单详情表为: <pandas.core.groupby.generic.DataFrameGroupBy object at 0x000002547B8C0DC8>
D:\Study\anaconda\lib\site-packages\pymysql\cursors.py:170: Warning: (1366, "Incorrect string value: '\\xD6\\xD0\\xB9\\xFA\\xB1\\xEA...' for column 'VARIABLE_VALUE' at row 1")
result = self._query(query)
代码 4-52 GroupBy 类求均值,标准差,中位数
print('订单详情表分组后前5组每组的均值为:\n',
detailGroup.mean().head())
print('订单详情表分组后前5组每组的标准差为:\n',
detailGroup.std().head())
print('订单详情表分组后前5组每组的大小为:','\n',
detailGroup.size().head())
订单详情表分组后前5组每组的均值为:
counts amounts
order_id
1002 1.0000 32.000
1003 1.2500 30.125
1004 1.0625 43.875
1008 1.0000 63.000
1011 1.0000 57.700
订单详情表分组后前5组每组的标准差为:
counts amounts
order_id
1002 0.00000 16.000000
1003 0.46291 21.383822
1004 0.25000 31.195886
1008 0.00000 64.880660
1011 0.00000 50.077828
订单详情表分组后前5组每组的大小为:
order_id
1002 7
1003 8
1004 16
1008 5
1011 10
dtype: int64
代码 4-53 agg和aggregate函数的参数及其说明
print('订单详情表的菜品销量与售价的和与均值为:\n',
detail[['counts','amounts']].agg([np.sum,np.mean]))
订单详情表的菜品销量与售价的和与均值为:
counts amounts
sum 3088.000000 125992.000000
mean 1.111191 45.337172
订单详情表的菜品销量总和与售价的均值为:
counts 3088.000000
amounts 45.337172
dtype: float64
代码 4-54 使用agg分别求字段的不同统计量
print('订单详情表的菜品销量总和与售价的均值为:\n',
detail.agg({'counts':np.sum,'amounts':np.mean}))
订单详情表的菜品销量总和与售价的均值为:
counts 3088.000000
amounts 45.337172
dtype: float64
代码 4-55 使用agg方法求不同字段的不同数目统计量
print('菜品订单详情表的菜品销量总和与售价的总和与均值为:\n',
detail.agg({'counts':np.sum,'amounts':[np.mean,np.sum]}))
菜品订单详情表的菜品销量总和与售价的总和与均值为:
counts amounts
mean NaN 45.337172
sum 3088.0 125992.000000
代码 4-56 在agg方法中使用自定义函数
##自定义函数求两倍的和
def DoubleSum(data):
s = data.sum()*2
return s
print('菜品订单详情表的菜品销量两倍总和为:','\n',
detail.agg({'counts':DoubleSum},axis = 0))
菜品订单详情表的菜品销量两倍总和为:
counts 6176.0
dtype: float64
代码 4-57 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
代码 4-58 使用agg方法做简单的聚合
print('订单详情表分组后前3组每组的均值为:\n',
detailGroup.agg(np.mean).head(3))
print('订单详情表分组后前3组每组的标准差为:\n',
detailGroup.agg(np.std).head(3))
订单详情表分组后前3组每组的均值为:
counts amounts
order_id
1002 1.0000 32.000
1003 1.2500 30.125
1004 1.0625 43.875
订单详情表分组后前3组每组的标准差为:
counts amounts
order_id
1002 0.00000 16.000000
1003 0.46291 21.383822
1004 0.25000 31.195886
代码 4-59 使用ag方法对分组数据使用不同的聚合函数
print('订单详情分组前3组每组菜品总数和售价均值为:\n',
detailGroup.agg({'counts':np.sum,
'amounts':np.mean}).head(3))
订单详情分组前3组每组菜品总数和售价均值为:
counts amounts
order_id
1002 7.0 32.000
1003 10.0 30.125
1004 17.0 43.875
4.4.3 使用apply方法聚合数据
代码 4-60 apply方法的基本用法
print('订单详情表的菜品销量与售价的均值为:\n',
detail[['counts','amounts']].apply(np.mean))
订单详情表的菜品销量与售价的均值为:
counts 1.111191
amounts 45.337172
dtype: float64
代码 4-61 使用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
1002 1.431572e+26 1.0000 32.000
1003 1.253875e+30 1.2500 30.125
1004 6.275628e+61 1.0625 43.875
订单详情表分组后前3组每组的标准差为:
counts amounts
order_id
1002 0.000000 14.813122
1003 0.433013 20.002734
1004 0.242061 30.205287
使用transform 方法聚合数据
transform方法能够对整个DataFrame的所有元素进行操作。且transform方法只有一个参数“func”,表示对DataFrame操作的函数。
代码 4-62 使用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
代码 4-63 使用transform实现组内离差标准化
同时transform方法还能够对DataFrame分组后的对象GroupBy进行操作,可以实现组内离差标准化等操作。
print('订单详情表分组后实现组内离差标准化后前五行为:\n',
detailGroup.transform(lambda x:(x-x.min())/(x.max()-x.min())).head())
若在计算离差标准化的时候结果中有NaN,这是由于根据离差标准化公式,最大值和最小值相同的情况下分母是0。而分母为0的数在Python中表示为NaN。
但是这里会报ZeroDivisionError: float division by zero的bug ,就是分母为0了,奇奇怪怪感觉,书上的运行得了
感谢@孤芳不自赏呀 的bug更正
4.4.5任务实现
代码 4-64 订单详情按照日期分组
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']]
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
代码 4-65 求分组后的订单详情表每日菜品销售的均价,中位数
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
代码 4-66 求取订单详情表中单日菜品总销量
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