# -*- coding:utf-8 -*-
# 《python for data analysis》第九章
# 数据聚合与分组运算
import pandas as pd
import numpy as np
import time # 分组运算过程 -> split-apply-combine
# 拆分 应用 合并
start = time.time()
np.random.seed(10)
# 1、GroupBy技术
# 1.1、引文
df = pd.DataFrame({
'key1': ['a', 'b', 'a', 'b', 'a'],
'key2': ['one', 'two', 'two', 'two', 'one'],
'data1': np.random.randint(1, 10, 5),
'data2': np.random.randn(5)
})
print(df)
print('\n')
grouped = df['data1'].groupby(df['key1']) # split,将data1列按照key1列进行分组
res = grouped.mean() # apply and combine, 将各组数据取平均之后汇合成一个DataFrame or Series
print(res)
print('\n')
# 上面的data['key1'](即传入groupby的对象)称为分组键,分组键可以是多个列
print(df['data1'].groupby([df['key1'], df['key2']]).mean()) # 结果为一个层次化索引的Series
print('\n')
# print(df['data1'].groupby(['key1', 'key2'])) # 与上一行等价,即可用columns名来替代series作为分组键
print(df.groupby('key1').mean()) # 聚合(split+apply+combine)只对数值列(data1、data2)进行操作,非数值列(key2)会被过滤
print('\n')
print(df.groupby('key1').size()) # 各分组的元素个数
print('\n')
# 1.2、对分组进行迭代
# groupby对象像list、dictionary那样支持迭代
for name, group in df.groupby('key1'):
print(name)
print(group) # split之后仍然保留非数值列
# 多重键用元组(tuple)表示
print('\n')
for (key1, key2), group in df.groupby(['key1', 'key2']):
print(key1)
print(key2)
print(group)
# groupby缺省在axis=0上进行分组,可显示指定axis=1进行分组
# 可理解为对样本进行分组和对特征进行分组
# 1.3、选取一个或一组列
# 实质:groupby对象的索引
# 1.1节中对部分列进行聚合操作写为df['data1'].groupby('key1'),该操作也可以通过对整个dataframe的groupby对象进行索引获得
print('\n')
print(df.groupby('key1')['data1'].mean())
print('\n')
# 1.4、通过字典或Series进行分组
df = pd.DataFrame(np.random.randn(5, 5), index=['a', 'b', 'c', 'd', 'a'], columns=['zoo', 'zip', 'zero', 'zz', 'zzz'])
mapping = {'a': 'red', 'b': 'green', 'c': 'red', 'd': 'green', 'e': 'pink'}
print(df.groupby(mapping).mean())
print('\n')
# 1.5、通过函数进行分组
print(df.groupby(len, axis=1).sum()) # 对axis=1上的各列名求取字符串长度,长度值作为分组依据
print('\n')
# 注意,传入groupby的分组键可以是多种类型的混合
key = ['one', 'two', 'one', 'two', 'one']
print(df.groupby([len, key], axis=1).sum())
print('\n')
# 1.6、根据索引级别分组
# 当index或者columns为层次化的索引时,在groupby中可以指定按照哪一层索引进行分组
columns = pd.MultiIndex.from_arrays([['A', 'A', 'A', 'B', 'B'], [1, 2, 3, 4, 5]], names=['level1', 'level2'])
df = pd.DataFrame(np.random.randn(5, 5), columns=columns)
print(df.groupby(level='level1', axis=1).sum()) # level关键字用于指定需要进行分组的索引层次
print('-----------------------------------↑section1') # 2、数据聚合
# 2.1、引文
# groupby方法实现了split(分组),配合.sum()、.mean()等方法又实现了apply和combine,即聚合
# 具体地,聚合的方法可以是Series的各种方法,具体实现过程为
# step1——通过groupby将series进行切片(分组)——split
# step2——应用各种聚合函数,即上文提到的Series的各种方法,对各个切片进行操作——apply
# step3——将各个切片的运算结果进行组装——combine
# 除了Series已有的各种方法,还可以自己定义聚合函数并应用于groupby对象,通过agg或者aggregate方法传入
def pk2pk(gb):
return gb.max() - gb.min() pk2pk_lambda = lambda gb: gb.max() - gb.min()
df = pd.DataFrame({
'key1': ['a', 'b', 'a', 'b', 'a'],
'key2': ['one', 'two', 'two', 'two', 'one'],
'data1': np.random.randint(1, 10, 5),
'data2': np.random.randn(5)
})
print(df)
print(df.groupby('key1').agg(pk2pk)) # 普通函数
print(df.groupby('key1').aggregate(pk2pk_lambda)) # lambda函数,agg和aggregat等价
print('\n')
# 2.2、面向列的多函数应用
# 2.2与2.3节介绍高级的聚合功能,以某个关于小费的数据集为例。
data = pd.read_csv('./data_set/tips.csv')
# 新增一列“小费占总额的比例”
data['tip_p'] = data['tip'] / data['total_bill']
print(data.head())
print('\n')
# 高级聚合:对不同的列采用不同的聚合函数,或一次性采用多个聚合函数
grouped = data.groupby(['smoker', 'day']) # groupby object
grouped_p = grouped['tip_p'] # groupby object的一个切片
print(grouped_p.agg('mean')) # 对切片使用mean方法
print('\n')
# 注意:agg里面传入预设函数以string形式,传入自定义函数以函数名形式
# 传入一组函数,则会形成一个以函数名为列名的columns
print(grouped_p.agg(['mean', 'std', pk2pk, pk2pk_lambda]))
print('\n')
# lambda函数的缺省函数名均为<lambda>,无辨识度,需要别的方式来区分,即自定义函数名
# 自定义列名,以(name,function)的元组形式传入即可,其中name为自定义的名称,function为函数名
print(grouped_p.agg([('Mean', 'mean'), ('Std', 'std'), ('Peak2Peak', pk2pk), ('Peak2Peak_2', pk2pk_lambda)]))
print('\n')
# 更一般的情形,可以对dataframe的多个列采用多个聚合函数,此时的聚合结果将是一个层次化索引的dataframe
# 这相当于先对各列进行聚合再concat(axis=1)到一起
print(grouped['tip', 'tip_p'].agg(['mean', 'std', pk2pk, pk2pk_lambda]))
print('\n')
# 若对不同列采用不同的聚合函数,通过向agg方法传入一个从列名映射到函数名的字典即可
print(grouped['tip', 'tip_p'].agg({'tip': 'mean', 'tip_p': 'std'}))
print('')
print(grouped['tip', 'tip_p'].agg({'tip': ['mean', 'std', pk2pk], 'tip_p': ['sum', pk2pk_lambda]}))
print('\n')
# 2.3、以“无索引”的形式返回聚合数据
# 默认情况下,分组键会成为结果的索引,通过groupby函数的as_index关键字置为False即可以无索引方式返回,分组键会转而成为聚合结果的列(Series)
print(data.groupby(['smoker'], as_index=False).mean())
print('---------------------------------------↑section2')
# 3、分组级运算与转换
# 分组运算除了上面提到的聚合(各种聚合函数),还可以通过transform和apply实现更多的分组运算
# transform不改变原有dataframe(or series)的index,将分组运算的结果广播到各分组的各个元素中去,形成一个或多个新列
print(data)
print('\n')
print(data.groupby('day').transform(np.mean)) # 可用concat和原dataframe拼接到一起,axis = 1
# 3.1、apply:一般性的'拆分-应用-合并'
# apply可传入任意处理序列的函数,返回的结果完全由apply传入的函数决定
sort = lambda df, column, n: df.sort_values(by=column)[-n:]
print(data.groupby('smoker').apply(sort, column='tip', n=10)) # 返回按tip从大到小排列的前10行
print('')
# 上例中分组键会和原index构成层次化索引,但其实分组键的信息已经包含在原dataframe中了,可在分组时设置group_keys关键字为False来禁用分组键
print(data.groupby('smoker', group_keys=False).apply(sort, column='tip', n=10))
print('\n')
# 3.2、分位数与桶分析
# 这一节的内容是将qcut和cut的运算结果传入groupby函数实现按区间分组
df = pd.DataFrame({
'data1': np.random.randn(100),
'data2': np.random.randn(100)})
cut_data1 = pd.cut(df['data1'], 5) # 等区间长度切割成5段
# 按照data1的分段结果对data2进行分组,并统计每个分组的数量、平均值、标准差、最大值与最小值
print(df['data2'].groupby(cut_data1).apply(
lambda gp: {'count': gp.count(), 'max': gp.max(), 'min': gp.min(), 'std': gp.std(), 'mean': gp.mean()}).unstack())
print('')
# qcut也是同理,将桶由等长度变成了等数量
print(df['data2'].groupby(pd.qcut(df['data1'], 5)).apply(
lambda gp: {'count': gp.count(), 'max': gp.max(), 'min': gp.min(), 'std': gp.std(), 'mean': gp.mean()}).unstack())
print('\n')
# 3.3、示例:用特定于分组的值填充缺失值
# 其实就是先分组,再每组apply填充缺失值函数fillna
df = pd.DataFrame({
'key1': ['a', 'b', 'a', 'b', 'a'],
'key2': ['one', 'two', 'two', 'two', 'one'],
'data1': np.random.randint(1, 10, 5),
'data2': np.random.randn(5)
})
df.ix[2:3,'data2']=np.nan
print(df)
print('')
df = df.groupby('key1',group_keys=False).apply(lambda gp:gp.fillna(gp.mean()))
print(df)
print('-------------------------------------↑section3')
# 其余实例,均为关于apply的应用实例,传入不同函数,包括随机采样、取相关系数、线性回归等
# 4、透视表与交叉表
# 透视表与交叉表均可通过groupby实现,可以认为是groupby的快捷方式
# 4.1、透视表(pivot)
# 以day和time为axis=0方向分组,smoker为axis=1方向分组,透视表方法缺省聚合类型为计算各分组的平均数
print(data.pivot_table(['tip','size'], index=['day', 'time'], columns='smoker'))
# 上述过程也可通过groupby实现
print(data.groupby(['day', 'time', 'smoker'])['size', 'tip'].mean().unstack())
# pivot_table()函数中关键字margins设为True可以添加分项小计,包括行与列
print('\n')
print(data.pivot_table(['tip','size'], index=['day', 'time'], columns='smoker', margins=True))
# pivot_table默认的聚合函数是取平均,可通过aggfunc关键字进行显式指定
print('')
print(data.pivot_table(['tip','size'], index=['day', 'time'], columns='smoker', margins=True, aggfunc=sum))
# 4.2、交叉表(crosstab)
# 交叉表是一种用于计算分组的频率(频数)的特殊透视表
print('\n')
print(pd.crosstab([data['time'], data['day']], data['smoker'], margins=True))
print('--------------total time is %.5f s' % (time.time() - start))
# that's all

《python for data analysis》第九章,数据聚合与分组运算的更多相关文章

  1. Python 数据分析—第九章 数据聚合与分组运算

    打算从后往前来做笔记 第九章 数据聚合与分组运算 分组 #生成数据,五行四列 df = pd.DataFrame({'key1':['a','a','b','b','a'], 'key2':['one ...

  2. 《利用python进行数据分析》读书笔记--第九章 数据聚合与分组运算(一)

    http://www.cnblogs.com/batteryhp/p/5046450.html 对数据进行分组并对各组应用一个函数,是数据分析的重要环节.数据准备好之后,通常的任务就是计算分组统计或生 ...

  3. Python数据聚合和分组运算(1)-GroupBy Mechanics

    前言 Python的pandas包提供的数据聚合与分组运算功能很强大,也很灵活.<Python for Data Analysis>这本书第9章详细的介绍了这方面的用法,但是有些细节不常用 ...

  4. Python 数据分析(二 本实验将学习利用 Python 数据聚合与分组运算,时间序列,金融与经济数据应用等相关知识

    Python 数据分析(二) 本实验将学习利用 Python 数据聚合与分组运算,时间序列,金融与经济数据应用等相关知识 第1节 groupby 技术 第2节 数据聚合 第3节 分组级运算和转换 第4 ...

  5. Python之数据聚合与分组运算

    Python之数据聚合与分组运算 1. 关系型数据库方便对数据进行连接.过滤.转换和聚合. 2. Hadley Wickham创建了用于表示分组运算术语"split-apply-combin ...

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

    对数据集进行分组并对各分组应用函数是数据分析中的重要环节. group by技术 pandas对象中的数据会根据你所提供的一个或多个键被拆分为多组,拆分操作是在对象的特定轴上执行的,然后将一个函数应用 ...

  7. 利用Python进行数据分析-Pandas(第六部分-数据聚合与分组运算)

    对数据集进行分组并对各组应用一个函数(无论是聚合还是转换),通常是数据分析工作中的重要环节.在将数据集加载.融合.准备好之后,通常是计算分组统计或生成透视表.pandas提供了一个灵活高效的group ...

  8. python数据分析之:数据聚合与分组运算

    在数据库中,我们可以对数据进行分类,聚合运算.例如groupby操作.在pandas中同样也有类似的功能.通过这些聚合,分组操作,我们可以很容易的对数据进行转换,清洗,运算.比如如下图,首先通过不同的 ...

  9. 【学习】数据聚合和分组运算【groupby】

    分组键可以有多种方式,且类型不必相同 列表或数组, 某长度与待分组的轴一样 表示DataFrame某个列名的值 字典或Series,给出待分组轴上的值与分组名之间的对应关系 函数用于处理轴索引或索引中 ...

随机推荐

  1. JS一些简单的问题

    冒泡排序1 <script> //冒泡排序:把一组数据按照从大到小,或者从小到大的进行一定的排序 //从小到大排序 var num=[10,2,58,3,56,4,12]; //比较轮数 ...

  2. 磁盘挂载方法 fdisk parted

    1创建磁盘分区 [root@web01 ~]# fdisk -cu /dev/sdc -c 关闭dos兼容模式-u 使用扇区进行分区 (默认位柱面)[root@web01 ~]# partprobe ...

  3. cin.get();cin.clear();cin.sync()

    先看代码: #include<iostream> using namespace std; int main(){ int c,x; cout<<"输入大小" ...

  4. 解决spring3升级到spring4后jackjson报错

    1.这里说的是基于spring+springmvc+hibernate框架(其实跟持久层框架也没关系) 2.首先是springmvc的配置,处理json数据都会用到的.第5行是spring-4.x的写 ...

  5. ecplise中设置字体大小和背景

    1 将ecplise中的代码背景设置为豆沙色 2 设置ecplise中的字体大小

  6. 非关系数据库一Memcached

    第三十四课 非关系数据库一Memcached 目录 一.nosql介绍 二.memrcached介绍 三.安装memcached 四.查看memcachedq状态 五.memcached命令行 六.m ...

  7. Problem A: 重载字符的加减法

    Description 定义一个字符类Character,只有一个char类型的数据成员. 重载它的+.-.<<和>>运算符,其中+.-的第二个操作数是int类型的整数n.“+ ...

  8. C# FTP操作报550错误

    最近在做FTP创建文件夹和上传文件的功能,测试之后一直提示“远程服务器返回错误: (550) 文件不可用(例如,未找到文件,无法访问文件)”,我在网上找了很久的解决方案也没有解决掉这个问题,网上找到的 ...

  9. oracle 查询年月日连在一起

    SELECT B.YEAR || replace(lpad(B.MONTH, 2), ' ', '0') || replace(lpad(B.WEEK, 2), ' ', '0') from TT_U ...

  10. Vue中transition和animation的使用

    一:二者的对比 1.动画循环就用animation.在animation中有一个animation-iteration-count属性可以定义循环次数.transition是执行一次以后就不会执行,但 ...