Pandas_分组与聚合
# 分组统计是数据分析中的重要环节:
# 1-数据分组:GroupBy的原理和使用方法;
# 2-聚合运算:学会分组数据的聚合运算方法和函数使用; 类似于 SQL思想
# 3-分组运算:重点 apply方法的使用
# 4-数据透视表:学会构建数据透视表和交叉表
# 一,GroupBy:
# 步骤:split-apply-combine
# 举例:小费 tips
import pandas as pd
import numpy as np
import seaborn as sns
from pandas import Series,DataFrame
# tips=sns.load_dataset('tips') # 从 github仓库里下载 https://github.com/mwaskom/seaborn-data
tips=pd.read_csv('tips.csv')
tips.head(20)
{ vertical-align: top }
.dataframe thead th { text-align: right }
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
5 | 25.29 | 4.71 | Male | No | Sun | Dinner | 4 |
6 | 8.77 | 2.00 | Male | No | Sun | Dinner | 2 |
7 | 26.88 | 3.12 | Male | No | Sun | Dinner | 4 |
8 | 15.04 | 1.96 | Male | No | Sun | Dinner | 2 |
9 | 14.78 | 3.23 | Male | No | Sun | Dinner | 2 |
10 | 10.27 | 1.71 | Male | No | Sun | Dinner | 2 |
11 | 35.26 | 5.00 | Female | No | Sun | Dinner | 4 |
12 | 15.42 | 1.57 | Male | No | Sun | Dinner | 2 |
13 | 18.43 | 3.00 | Male | No | Sun | Dinner | 4 |
14 | 14.83 | 3.02 | Female | No | Sun | Dinner | 2 |
15 | 21.58 | 3.92 | Male | No | Sun | Dinner | 2 |
16 | 10.33 | 1.67 | Female | No | Sun | Dinner | 3 |
17 | 16.29 | 3.71 | Male | No | Sun | Dinner | 3 |
18 | 16.97 | 3.50 | Female | No | Sun | Dinner | 3 |
19 | 20.65 | 3.35 | Male | No | Sat | Dinner | 3 |
# 将序列按照单个分组键分组,并聚合计算:
# 1,groupby()可以被 Series调用,也可以被 DataFrame调用。
grouped=tips['tip'].groupby(tips['sex']) # 对 tip Series,按照 sex序列的值进行分组
grouped=tips.groupby(tips['sex']) # 对 tips DataFrame,按照 sex序列的值进行分组
grouped # <pandas.core.groupby.generic.SeriesGroupBy object at 0x0000026FF174BC08> GroupBy对象 可迭代对象
grouped.mean() # 平均值 聚合运算
grouped.sum() # 求和
# 将序列按照多个分组键分组,并聚合计算:
data_mean=tips['tip'].groupby([tips['sex'],tips['time']]).mean()
data_mean # type(data_mean) # 多层索引的序列 pandas.core.series.Series
data_mean.plot(kind='barh') # 男性晚餐时候小费给的平均值高
# GroupBy对象是可迭代对象,其构造为一组二元元组:
for name,group in tips['tip'].groupby(tips['sex']):
print(name)
print(group)
# 可查看各分组的大小
tips.groupby(tips['sex']).size()
# 2,分组方式:
# 2-1)按序列分组:
grouped=tips['tip'].groupby(tips['sex']) # 对 tip Series,按照 sex序列的值进行分组
grouped=tips.groupby(tips['sex']) # 对 tips DataFrame,按照 sex序列的值进行分组
# 2-2)按列名分组:
smoker_mean=tips.groupby('smoker').mean()
smoker=tips.groupby('somker',group_keys=False)['tip']
smoker_mean=tips.groupby(['sex','smoker']).mean() # 按多个列名组合分组
smoker_mean=tips.groupby(['sex','smoker'],as_index=False).mean() # 按多个列名组合分组 as_index=False:不以分组键作为索引
size_mean1=tips.groupby('size')['tip'].mean() # 等效于:
size_mean2=tips['tip'].groupby(tips['size']).mean()
size_mean1==size_mean2 # 返回全是True的布尔数组
# 2-3) 按行索引分组:
df=DataFrame(np.arange(16).reshape(4,4),index=['a','b','a','b'])
df.groupby(df.index).mean()
# 2-4)按列表或元组分组: # 相当于先给索引按照列表重命名,然后按行索引分组。
df=DataFrame(np.arange(16).reshape(4,4))
list1=['a','b','a','b']
df.groupby(list1).mean()
# 2-5)按照字典分组: # 相当于先给dataframe的索引重命名,再按新索引分组。
# 当要分组的列或行索引的值不明确时,需要使用字典指定
df=DataFrame(np.arange(16).reshape(4,4),index=['a','b','A','B'])
dict1={
'a':'one',
'A':'one',
'b':'two',
'B':'two'
}
df.groupby(dict1).mean()
# 2-6)按函数分组:
# 原理类似于字典,通过映射关系进行分组,但更灵活。
df=DataFrame(np.random.randn(4,4))
df
df.groupby(df[3].map(lambda x:'a' if x>=0 else 'b')).sum() #看结果就明白了
# 2-7) 对于层次化索引,按 level级别进行分组:
df=DataFrame(np.arange(16).reshape(4,4),
index=[['one','one','two','two'],['a','b','a','b']],
columns=[['apple','apple','orange','orange'],['red','green','red','green']])
df
# df.groupby(level=1).sum()
# df.groupby(level=1,axis=1).sum()
# df.groupby(level=0).sum()
df.groupby(level=0,axis=1).sum()
# 3,聚合运算 注:空值不参与计算! 返回聚合后的序列
# 对分组后的数据进行计算,产生标量值的转换过程叫聚合运算,上面的 mean(),sum()都是。
# 3-1) 常用的聚合函数:
# count 计数
# sum 求和
# mean 求平均值
# median 求算术中位数
# std 求标准差
# var 求方差
# min,max 求最小值,最大值
# prod 求积
# first,last 求第一个值,求最后一个值
# quantile 分位数计算
max_tip=tips.groupby('sex')['tip'].max()
max_tip # 序列
max_tip.plot(kind='bar')
# 3-2) 自定义聚合函数: grouped.aggregate(f) 或 grouped.agg(f) aggregate--聚合
# se.agg(f)与 se.map(f)的不同点在于:agg是Grupby对象的聚合函数,而 map是Series的矢量化函数。
# 因而,agg里的函数 f一般也是由聚合函数组成的。
def get_range(x):
'''接收一个数字序列,或数字列表,得到数字的范围'''
return x.max()-x.min()
# tips_range=tips.groupby('sex')['tip'].agg(get_range)
tips_range=tips.groupby('sex')['tip'].agg(lambda x:x.max()-x.min())
tips_range
# 4,多函数应用:
# 4-1) 一列多函数 agg([f1,f2,f3...])
# get_range=lambda x:x.max()-x.min()
def get_range(x):
'''接收一个数字序列,或数字列表,得到数字的范围'''
return x.max()-x.min()
tips.groupby(['sex','smoker'])['tip'].agg(['mean','std',get_range]) #自定义的函数不能使用'', 默认列名为函数名
tips.groupby(['sex','smoker'])['tip'].agg([('tip_mean','mean'),('range',get_range)]) #指定列名
# 4-2) 多列多函数: 产生列的层次化索引
tips.groupby(['day','time'])['tip','total_bill'].agg([('tip_mean','mean'),('range',get_range)]) # 将来版本要用列表替代元组?
# 4-3) 不同列,不同函数: 使用字典映射
tips.groupby(['day','time'])['total_bill','tip'].agg({'total_bill':['sum','mean'],'tip':'mean'}) # 将要被废弃
# 5, 分组运算:
# 运行下面代码,体会 transform 和 apply的不同效果:
tips.groupby('sex').transform('mean')
tips.groupby('sex')['tip'].transform('mean')
tips.groupby('sex').apply(lambda x:x.mean())
tips.groupby('sex')['tip'].apply(lambda x:x.mean())
# 速记:
tips.groupby('sex').transform('mean') # 只计算可以计算的列,比如3个可计算列,并返回新的 由3个列组成的 DataFrame
tips.groupby('sex')['tip'].transform('mean') # 只计算 tip列,返回一个 Series.
df.groupby('sex').apply(lambda x:x.fillna(x.mean())) # 返回一个 对【所有数值列】缺失值填充后的 DataFrame
df.groupby('sex')['math'].apply(lambda x:x.fillna(x.mean())) # 返回一个 只对【Math】列缺失值填充后的Series
# grouped.perform(),grouped.apply(),都不改变原数据结构,如果想要做改变,可以赋值,比如:
tips['tip_mean_by_sex']=tips.groupby('sex')['tip'].transform('mean') # 增加一个新的列 tip_mean_by_sex
# 5-1) tips.groupby('sex')['tip'].transform('mean').transform()方法: 返回
# 对于小费数据集 tips,新建一列用于存放男性和女性小费的平均值。
# 1)常用方法是,先分组聚合运算,再 merge按 sex键合并,出现一个新的列。
tip_mean_by_sex=tips.groupby('sex')['tip'].mean()
tip_mean_by_sex
tip_mean_by_sex_df=DataFrame(tip_mean_by_sex) # 注意,参数是 tips.groupby('sex')['tip'].mean() 不是 tips.groupby('sex')['tip']
tip_mean_by_sex_df # 此时行索引的 name为 sex,行索引的值为[Female,Male]
new_tips=pd.merge(tips,tip_mean_by_sex_df,left_on='sex',right_index=True,suffixes=('','_mean_by_sex'),how='left') # 指定left,tips的索引顺序就不会改变
new_tips.head(10)
# 2) 使用 transform('mean')方法将参数里的函数运算结果分布到每一行,非聚合函数,dataframe的矢量化函数:
new_tips=tips.copy()
new_tips['tip_mean_by_sex']=tips.groupby('sex')['tip'].transform('mean') # 增加一个新的列 tip_mean_by_sex
new_tips.head(10)
# 5-2)df.groupby('sex').apply()方法: 返回DataFrame数据
# 更加强大:
# 计算根据性别分组后的小费金额前 5名的 DataFrame数据:默认结果以分组键作为行索引,可以用 groupby()里使用group_keys=False来改变:
tips.groupby('sex').apply(lambda x:x.sort_values(by='tip',ascending=False)[:5])
tips.groupby('sex',group_keys=False).apply(lambda x:x.sort_values(by='tip',ascending=False)[:5])
# groupby()的 group_keys=False 参数只有在调用 apply()的时候好使。
# 对缺失值的处理,前面数据处理那部分,有使用平均值进行填充缺失值的例子,如:
data={
'name':['张三','李四',np.nan,'王五','小明','马六'],
'sex':['female','female','male','male','male','female'],
'math':[67,77,np.nan,82,90,np.nan],
'English':[67,77,np.nan,82,90,np.nan]
}
df=DataFrame(data)
df.fillna(df['math'].mean()) # 使用 math列的平均值填充缺失值
df.fillna(df['English'].mean()) # 使用 English列的平均值填充缺失值
df.groupby('sex').apply(lambda x:x.fillna(x.mean())) # 根据性别计算每个性别的 math和 english的平均数,来填充不同性别对应的缺失值.
df.groupby('sex')['math'].apply(lambda x:x.fillna(x.mean())) # 根据性别计算每个性别的 math的平均数,来填充不同性别对应的缺失值.
# 6,数据透视表
# 关于 Excel数据透视表的使用教程,请见: https://www.zhihu.com/question/24341252
# df.pivot(values=要计算的列名, index=行名, columns=列名, aggfunc='sum', margins=True) # 由 df调用
# pd.cross_table(index=tips['day'],columns=tips['size']) # 由 pd调用,传入 df的两个整列作为行列索引
# 6-1)透视表:
# pandas里也有数据透视表功能,pivot_table 函数。
tips.pivot_table(values='tip',index='sex',columns='smoker') # 默认计算 mean()
tips.pivot_table(values='tip',index='sex',columns='smoker',aggfunc='sum') # 默认计算 mean(), aggfunc='sum' 指定计算 sum
tips.pivot_table(values='tip',index='sex',columns='smoker',aggfunc='sum',margins=True) # margins=True 对其他列做小计
# 用 groupby()来实现:
tips.groupby(['sex','smoker'])['tip'].mean().unstack() # 按多个列名组合分组 unstack()的默认参数为 1,表示操作内层行索引。
tips.groupby(['sex','smoker'])['tip'].sum().unstack() # sum
sex_smoker=tips.groupby(['sex','smoker'])['tip'].sum().unstack() # sum
sex_smoker['All']=sex_smoker['No']+sex_smoker['Yes'] #增加一列
sex_smoker=sex_smoker.append({'No':sex_smoker['No'].sum(),'Yes':sex_smoker['Yes'].sum()},ignore_index=True) # 增加一行
sex_smoker.index.name='Sex' # 恢复行索引名称
sex_smoker.index=['Female','Male','All'] # 恢复原来的行索引
sex_smoker
# 所以,使用透视表更简单些
# 6-1)交叉表:
# 用于计算分组频次与频率的特殊透视表
cross_table=pd.cross_table(index=tips['day'],columns=tips['size']) # 频次
cross_table
df=cross_table.div(cross_table.sum(axis=1),axis=0) # 频率 每行的和为1
df
# 频率频次堆积图:
df.plot(kind='bar',stacked=True)
Pandas_分组与聚合的更多相关文章
- mysql 分组和聚合函数
mysql 分组和聚合函数 Mysql 聚集函数有5个: 1.COUNT() 记录个数(count(1),count(*)统计表中行数,count(列名)统计列中非null数) 2.MAX() 最大值 ...
- MongoDB学习(使用分组、聚合和映射-归并)
使用分组.聚合和映射-归并 MongoDB的强大功能之一,是直接在服务器对文档的值进行复杂的操作,而不用先发文档发送到客户端在进行处理. 结果分组 对大型数据集进行查询操作时,通常会根据文档的字段值对 ...
- pd.qcut, pd.cut, df.groupby()等在分组和聚合方面的应用
pd.qcut, pd.cut, df.groupby()等在分组和聚合方面的应用 量化交易里, 需要进行大量的分组和统计, 以方便自己处优势的位置/机会. 比如对股价进行趋势分析, 波动性分析, 量 ...
- 70 多表查询的分组F 聚合 Q 查询
聚合查询和分组查询 聚合 aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典.键的名称是聚合值的标识符,值是计算出来的聚合值.键的名称是按照字段和聚合函 ...
- pandas分组和聚合
Pandas分组与聚合 分组 (groupby) 对数据集进行分组,然后对每组进行统计分析 SQL能够对数据进行过滤,分组聚合 pandas能利用groupby进行更加复杂的分组运算 分组运算过程:s ...
- FreeSql (二十三)分组、聚合
IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnectionString(FreeSql.DataType.MySql, "Data ...
- 20-2 orm分组和聚合以及在项目中执行的一些方法
一 orm分组和聚合 参考:https://www.cnblogs.com/liwenzhou/p/8660826.html 1 表结构: # 第一张表 class Employee1(models ...
- FastReport分组与聚合
本来看上去都觉得简单顺便训练下,是想对Customer表中的Company字段以第1个开头的字母分组,结果自己因喜欢将那些东西都集中在一起进行训练,在那个Master-Slave上做例子,并且没用另外 ...
- pandas_分类与聚合
# 分组与聚合 import pandas as pd import numpy as np # 设置列对齐 pd.set_option("display.unicode.ambiguous ...
随机推荐
- Docker笔记4:在 CentOS 上安装 Docker
Docker 是一个开源的应用容器引擎,主要有两个分支,一个是社区免费版(Docker CE),一个是企业版(Docker EE). 第1步:系统环境要求 Docker 支持的 CentOS 版本: ...
- 16.Android-activity生命周期与启动模式
1.activity共有4个状态 如下图所示: 运行状态 如果一个活动位于屏幕的前台(可见的),那么它就是活动的或正在运行的. 暂停状态 如果一个活动失去了焦点,但仍然可见(也就是说,一个新的非全尺寸 ...
- linux CentOS7 防火墙操作
1, 查看防火墙状态: firewall-cmd --state systemctl status firewalld.service 2, 开启防火墙: systemctl start firewa ...
- linux处理l2tp协议的示意图
- html学习(2)
标签的语义化,也就是标签的用途. html.css.javascript作用: HTML是网页内容的载体.内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字.图片.视频等. CSS样式是表 ...
- 用 C 语言游戏编程开发!果然最担心的事又发生了!
30了.我要怎么办,老了.人就像一头小毛驴,方向都是牵着的人定的. 这个项目从去年开始的,一个手机游戏,当时接这个项目的时候其实没有太多考虑,我一向都喜欢打肿脸充胖子的,好面子,人家找上门来,不能不给 ...
- 转 Swoole】用swoole简单实现MySQL连接池
MySQL连接池 在传统的网站开发中,比如LNMP模式,由Nginx的master进程接收请求然后分给多个worker进程,每个worker进程再链接php-fpm的master进程,php-fpm再 ...
- centos8平台使用stress做压力测试
一,安装stress: 说明:el8的源里面还没有,先用el7的rpm包 [root@centos8 source]# wget https://download-ib01.fedoraproject ...
- Win10中装Win10---virtualbox虚拟机的安装及拓展
最近在准备一档专栏时,发现我电脑中已经把一些环境配置完了,卸掉重装又显得麻烦,于是我就求助于虚拟机,虚拟机确实是个很好的东西,不久前我的一个伙伴向我请教虚拟机怎么装,发现这玩意三言两语还很难说清,于是 ...
- C++学习笔记---数据类型
1.整型 C++中能够表示整型的类型有几下几种方式,区别在于所占内存空间不足 数据类型 占用空间 取值范围 short(短整型) 2字节 (-2^15~2^15-1) int(整型) 4字节 (-2^ ...