python处理数据的风骚操作[pandas 之 groupby&agg]

https://segmentfault.com/a/1190000012394176

介绍

每隔一段时间我都会去学习、回顾一下python中的新函数、新操作。这对于你后面的工作是有一定好处的。
本文重点介绍了pandas中groupby、Grouper和agg函数的使用。这2个函数作用类似,都是对数据集中的一类属性进行聚合操作,比如统计一个用户在每个月内的全部花销,统计某个属性的最大、最小、累和、平均等数值。

其中,agg是pandas 0.20新引入的功能

groupby && Grouper

首先,我们从网上把数据下载下来,后面的操作都是基于这份数据的:

import pandas as pd

df = pd.read_excel("https://github.com/chris1610/pbpython/blob/master/data/sample-salesv3.xlsx?raw=True")
df["date"] = pd.to_datetime(df['date']) df.head()

图片描述
(图片来自于jupyter notebook,强烈推荐使用它作为python的交互工具)

下面,我们统计'ext price'这个属性在每个月的累和(sum)值,resample 只有在index为date类型的时候才能用:

df.set_index('date').resample('M')['ext price'].sum()
date
2014-01-31    185361.66
2014-02-28    146211.62
2014-03-31 203921.38 2014-04-30 174574.11 2014-05-31 165418.55 2014-06-30 174089.33 2014-07-31 191662.11 2014-08-31 153778.59 2014-09-30 168443.17 2014-10-31 171495.32 2014-11-30 119961.22 2014-12-31 163867.26 Freq: M, Name: ext price, dtype: float64

进一步的,我们想知道每个用户每个月的sum值,那么就需要一个groupby了:

df.set_index('date').groupby('name')['ext price'].resample("M").sum()
name                             date      
Barton LLC                       2014-01-31     6177.57
                                 2014-02-28    12218.03
                                 2014-03-31 3513.53 2014-04-30 11474.20 2014-05-31 10220.17 2014-06-30 10463.73 2014-07-31 6750.48 2014-08-31 17541.46 2014-09-30 14053.61 2014-10-31 9351.68 2014-11-30 4901.14 2014-12-31 2772.90 Cronin, Oberbrunner and Spencer 2014-01-31 1141.75 2014-02-28 13976.26 2014-03-31 11691.62 2014-04-30 3685.44 2014-05-31 6760.11 2014-06-30 5379.67 2014-07-31 6020.30 2014-08-31 5399.58 2014-09-30 12693.74 2014-10-31 9324.37 2014-11-30 6021.11 2014-12-31 7640.60 Frami, Hills and Schmidt 2014-01-31 5112.34 2014-02-28 4124.53 2014-03-31 10397.44 2014-04-30 5036.18 2014-05-31 4097.87 2014-06-30 13192.19 ... Trantow-Barrows 2014-07-31 11987.34 2014-08-31 17251.65 2014-09-30 6992.48 2014-10-31 10064.27 2014-11-30 6550.10 2014-12-31 10124.23 White-Trantow 2014-01-31 13703.77 2014-02-28 11783.98 2014-03-31 8583.05 2014-04-30 19009.20 2014-05-31 5877.29 2014-06-30 14791.32 2014-07-31 10242.62 2014-08-31 12287.21 2014-09-30 5315.16 2014-10-31 19896.85 2014-11-30 9544.61 2014-12-31 4806.93 Will LLC 2014-01-31 20953.87 2014-02-28 13613.06 2014-03-31 9838.93 2014-04-30 6094.94 2014-05-31 11856.95 2014-06-30 2419.52 2014-07-31 11017.54 2014-08-31 1439.82 2014-09-30 4345.99 2014-10-31 7085.33 2014-11-30 3210.44 2014-12-31 12561.21 Name: ext price, Length: 240, dtype: float64

结果肯定是对的,但是不够完美。我们可以使用Grouper写得更加简洁:

# df.set_index('date').groupby('name')['ext price'].resample("M").sum()
df.groupby(['name', pd.Grouper(key='date', freq='M')])['ext price'].sum()

结果和上面?一样,就不列出来了。
显然,这种写法多敲了很多次键盘,那么它的好处是啥呢?
首先,逻辑上更加直接,当你敲代码完成以上统计的时候,你首先想到的就是groupby操作,而set_index, resample好像不会立马想到。想到了groupby这个'动作'之后,你就会紧接着想按照哪个key来操作,此时
你只需要用字符串,或者Grouper把key定义好就行了。最后使用聚合函数,就得到了结果。所以,从人类的
思考角度看,后者更容易记忆。

另外,Grouper里的freq可以方便的改成其他周期参数(resample也可以),比如:

# 按照年度,且截止到12月最后一天统计ext price的sum值
df.groupby(['name', pd.Grouper(key='date', freq='A-DEC')])['ext price'].sum()
name                             date      
Barton LLC                       2014-12-31    109438.50
Cronin, Oberbrunner and Spencer  2014-12-31     89734.55
Frami, Hills and Schmidt         2014-12-31 103569.59 Fritsch, Russel and Anderson 2014-12-31 112214.71 Halvorson, Crona and Champlin 2014-12-31 70004.36 Herman LLC 2014-12-31 82865.00 Jerde-Hilpert 2014-12-31 112591.43 Kassulke, Ondricka and Metz 2014-12-31 86451.07 Keeling LLC 2014-12-31 100934.30 Kiehn-Spinka 2014-12-31 99608.77 Koepp Ltd 2014-12-31 103660.54 Kuhn-Gusikowski 2014-12-31 91094.28 Kulas Inc 2014-12-31 137351.96 Pollich LLC 2014-12-31 87347.18 Purdy-Kunde 2014-12-31 77898.21 Sanford and Sons 2014-12-31 98822.98 Stokes LLC 2014-12-31 91535.92 Trantow-Barrows 2014-12-31 123381.38 White-Trantow 2014-12-31 135841.99 Will LLC 2014-12-31 104437.60 Name: ext price, dtype: float64

agg

从0.20.1开始,pandas引入了agg函数,它提供基于列的聚合操作。而groupby可以看做是基于行,或者说index的聚合操作。

从实现上看,groupby返回的是一个DataFrameGroupBy结构,这个结构必须调用聚合函数(如sum)之后,才会得到结构为Series的数据结果。
而agg是DataFrame的直接方法,返回的也是一个DataFrame。当然,很多功能用sum、mean等等也可以实现。但是agg更加简洁, 而且传给它的函数可以是字符串,也可以自定义,参数是column对应的子DataFrame

举个栗子?吧:

df[["ext price", "quantity", "unit price"]].agg(['sum', 'mean'])

图片描述

怎么样,是不是比使用

df[["ext price", "quantity"]].sum()
df['unit price'].mean()

简洁多了?

上例中,你还可以针对不同的列使用不同的聚合函数:

df.agg({'ext price': ['sum', 'mean'], 'quantity': ['sum', 'mean'], 'unit price': ['mean']})

图片描述

另外,自定义函数怎么用呢,也是so easy.
比如,我想统计sku中,购买次数最多的产品编号,可以这样做:

# 这里的x是sku对应的column
get_max = lambda x: x.value_counts(dropna=False).index[0]
df.agg({'ext price': ['sum', 'mean'], 'quantity': ['sum', 'mean'], 'unit price': ['mean'], 'sku': [get_max]})

图片描述

<lambda>看起来很不协调,把它去掉:

get_max = lambda x: x.value_counts(dropna=False).index[0]
# python就是灵活啊。
get_max.__name__ = "most frequent" df.agg({'ext price': ['sum', 'mean'], 'quantity': ['sum', 'mean'], 'unit price': ['mean'], 'sku': [get_max]})

另外,还有一个小问题,那就是如果你希望输出的列按照某个顺序排列,可以使用collections的OrderedDict:

get_max = lambda x: x.value_counts(dropna=False).index[0]
get_max.__name__ = "most frequent"
import collections agg_dict = { 'ext price': ['sum', 'mean'], 'quantity': ['sum', 'mean'], 'unit price': ['mean'], 'sku': [get_max]} # 按照列名的长度排序。 OrderedDict的顺序是跟插入顺序一致的 df.agg(collections.OrderedDict(sorted(agg_dict.items(), key = lambda x: len(x[0]))))

图片描述

总结

Python random模块

http://www.cnblogs.com/learnC/p/5981638.html

利用python进行数据分析之数据聚合和分组运算

https://www.cnblogs.com/splended/p/5278078.html

https://www.cnblogs.com/learnC/p/5967297.html

https://www.cnblogs.com/splended/p/5278078.html

标准差

https://baike.baidu.com/item/%E6%A0%87%E5%87%86%E5%B7%AE/1415772?fr=aladdin

python 标准差计算(std)

https://blog.csdn.net/Gooooa/article/details/78923469

Pandas透视表(pivot_table)详解

https://blog.csdn.net/chencheng126/article/details/50119215

 

当数据中存在NaN缺失值时,我们可以用其他数值替代NaN,主要用到了DataFrame.fillna()方法

DataFrame.fillna(0)

 

转载于:https://www.cnblogs.com/chengjun/p/8948292.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值