# -*- 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. flink基础教程读书笔记

    数据架构设计领域发生了重大的变化,基于流的处理是变化的核心. 分布式文件系统用来存储不经常更新的数据,他们也是大规模批量计算所以来的数据存储方式. 批处理架构(lambda架构)实现计数的方式:持续摄 ...

  2. spring cloud 随笔记录(1)-

    最近随着微服务的火热,我也开始对我服务进行了解了  毕竟程序员这一行需要及时更新自己的技能,才能更好的生存. 我理解的微服务  项目由多个独立运行的程序组成,每个服务运行在自己的进程中,服务间采用轻量 ...

  3. 关于Appium android input manager for Unicode 提示信息

    Appium调完输入法后,会弹出  Appium android input manager for Unicode 提示信息相关的提示信息,每次运行如此,如下图 网络上查找一遍,基本解决了,只要在设 ...

  4. Java 平时作业五

    使用 I/O 流和文件对象实现目录备份功能. package asg5; import java.io.File; import java.io.FileInputStream; import jav ...

  5. Python 12306登陆详细分析及操作

    前面的话: 1.第一次尝试爬虫,登陆12306,有不足的地方,望大家留言告知,谢谢. 2.前面引入了一个requests模块,我不多说,大家都知道干啥的.还有config是我的一个配置文件,因为其中涉 ...

  6. 1019. General Palindromic Number (20)

    生词以及在文中意思 forward 向前地 backward 向后地 palindromic 回文的 base 基数(如十进制的10 和二进制的2) numeral system 数制 decimal ...

  7. Unity Canvas vs Panel

    Unity guys specifically gave a performance talk about UI Canvases on some of the past Unite(s). You ...

  8. python常见的数据转化函数

    python常用类型转换函数 函数格式 使用示例 描述 int(x [,base]) int("8")   可以转换的包括String类型和其他数字类型,但是会丢失精度       ...

  9. oracle 判断字段内是否含中文

    select * from tabell(表名) where asciistr(字段) like '%\%';

  10. 喝汤 beautifulsoup 批量爬取图片

    未成功 from urllib.request import urlopen import re import random base_url = "http://www.meizitu.c ...