Pandas
目录
一、Pandas基础
二、Pandas三大数据结构
1.Series
2.DataFrame
3.Index
三、数据取值与选择
四、数值运算
五、缺失值处理
六、层级索引
七、合并数据集:Concat与Append操作
八、合并数据集:合并与连接
九、累计与分组
十、数据透视表
十一、向量化字符串操作
十二、时间序列处理
十三、高性能
一、Pandas基础
1.安装
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ pandas
2.库导入
import numpy as np
import pandas as pd
二、Pandas三大数据结构
1.Series
(1)Series是通用的NumPy数组
Series对象和NumPy数组的差异:NumPy数组通过隐式定义的整数索引获取数值,而Pandas的Series对象使用一种显式定义的索引与数值相关联。
data = pd.Series([0.25, 0.5, 0.75, 1.0], index=['a', 'b', 'c', 'd'])
(2)Series是特殊的字典
population_dict = {'California': 38332521,
'Texas': 26448193,
'New York': 19651127,
'Florida': 19552860,
'Illinois': 12882135}
population = pd.Series(population_dict)
Series比字典强大,支持数组形式的操作:
如:切片
population['New York': 'Illinois']
(3)创建Series对象
pd.Series(data, [index])
- 1.data可以是列表或NumPy数组
pd.Series([2, 4, 6])
- 2.data可以是一个标量
创建Series对象时会将data重复填充到每个索引上
pd.Series(5, index=[100, 200, 300])
- 3.data可以是一个字典
pd.Series({'a':1, 'b':2, 'c':3})
2.DataFrame
样例用例数据
population_dict = {'California': 38332521,
'Texas': 26448193,
'New York': 19651127,
'Florida': 19552860,
'Illinois': 12882135}
area_dict = {'California': 423967,
'Texas': 695662,
'New York': 141297,
'Florida': 170312,
'Illinois': 149995}
population = pd.Series(population_dict)
area = pd.Series(area_dict)
states = pd.DataFrame({'population': population, 'area': area})
(1)DataFrame是通用的NumPy数组
(2)DataFrame是特殊的字典
普通字典是一个键映射一个值,而DataFrame是一列映射一个Series对象。
(3)创建DataFrame对象
- 1.通过单个Series对象创建
pd.DataFrame(Series对象, columns=['索引列名称'])
示例:
pd.DataFrame(population, columns=['population'])
- 2.通过字典列表创建
data = [{'a': i, 'b': 2 * i} for i in range(3)]
pd.DataFrame(data)
如果字典中有些键不存在,Pandas会用缺失值NaN来填充:
pd.DataFrame([{'a': 1, 'b': 2}, {'b': 3, 'c': 4}])
- 3.通过Series对象字典创建
pd.DataFrame({'population': population, 'area': area})
3.Index
(1)Index是不可变数组
-
Index对象拥有与NumPy数组相似的属性
-
Index对象的不可变特征使得多个Series和DataFrame之间进行索引共享时更加安全
(2)Index是有序集合
三、数据取值与选择
1.Series数据选择方法
示例用例数据:
data = pd.Series([0.25, 0.5, 0.75, 1.0], index=['a', 'b', 'c', 'd'])
(1)将Series看作字典
(2)将Series看作一维数组
Series具有和NumPy数组一样的数组数据选择功能(索引、掩码、花哨索引等)
# 将显式索引作为切片
data['a': 'c']
# 将隐式整数索引作为切片
data[1:3]
注意:显式索引切片结果包含最后一个索引,隐式索引切片结果不包含最后一个索引。
# 掩码
data[(data > 0.3) & (data < 0.8)]
# 花哨索引
data[['a', 'e']]
(3)索引器(loc、iloc、ix)
示例用例数据:
data = pd.Series(['a', 'b', 'c'], index=[1, 3, 5])
①loc显式索引
②iloc隐式索引
③ix混合索引
2.DataFrame数据选择方法
示例用例数据:
area_dict = {'California': 423967,
'Texas': 695662,
'New York': 141297,
'Florida': 170312,
'Illinois': 149995}
population_dict = {'California': 38332521,
'Texas': 26448193,
'New York': 19651127,
'Florida': 19552860,
'Illinois': 12882135}
area = pd.Series(area_dict)
pop = pd.Series(population_dict)
data = pd.DataFrame({'area': area, 'pop': pop})
(1)将DataFrame看作字典
(2)将DataFrame看作二维数组
-
使用索引器取值
- 任何用于处理NumPy形式数据的方法,都可以用于这些索引器,如:掩码、花哨索引
-
任何一种取值方法都可以用于修改数据
(3)其他取值方法
- 对单个标签取值选择列,对多个标签切片选择行
-
切片也可以直接使用行数实现(隐式索引)
-
掩码操作可以对每一行进行过滤
四、数值运算
常见Python运算符与Pandas方法映射关系
Python运算符 | Pandas方法 |
---|---|
+ | add() |
- | sub()、subtract() |
* | mul()、multiply() |
/ | truediv()、div()、divide() |
// | floordiv() |
% | mod() |
** | pow() |
1.通用函数:保留索引
通用函数运算结果会保留索引
-
Series
-
DataFrame
2.通用函数:索引对齐
(1)Series索引对齐
- 运算结果数组的索引是两个数组索引的并集。
-
对于缺失位置的数据,Pandas会用NaN填充,表示“此处没有数据”。
-
如果NaN值不是想要的结果,可以用通用函数的fill_value参数来指定。
(2)DataFrame索引对齐
-
在计算两个DataFrame时,索引对齐规则同样会出现在共同列(并集)中。
-
df.unstack()方法可以将二维数据拆为一维数据
3.通用函数:DataFrame与Series的运算
- 二维数组减去一行会按行计算,Pandas减去一行默认也是按行计算。
-
通过通用函数的axis参数,可以指定计算的方式。
-
DataFrame和Series运算时,结果的索引也会自动对齐。
五、缺失值处理
Pandas采用标签值表示缺失值
有两种方式:1.浮点数据类型NaN
2.Python对象类型None
1.None:Pyhton对象类型的缺失值(object对象类型)
-
只能用于NumPy/Pandas数组类型中的'object'类型。
- object类型的数据会消耗更多的资源。
注意:无法对包含None的数组进行累计操作。
2.NaN:数值类型的缺失值(浮点型)
-
NaN是一种按照IEEE浮点数标准设计、在任何系统中都兼容的特殊浮点数。
-
任何数与NaN进行运算结果都是NaN。
3.Pandas中None与NaN的差异
- Pandas将None与NaN看作是等价可交换的,在适当的时候会将两者进行替换。
-
Pandas会将没有标签值的数据类型自动转换为NaN。
-
Pandas会将含缺失值的整型数组转换为浮点类型,并且将None转换为NaN。
如果是DataFrame,则会将含缺失值的列转换为浮点类型。
4.处理缺失值
Pandas对不同类型缺失值的转换规则
类型 | 缺失值转换规则 | NA标签值 |
---|---|---|
floating浮点型 | 无变化 | np.nan |
object对象类型 | 无变化 | None或np.nan |
integer整数类型 | 强制转换为float64 | np.nan |
boolean布尔类型 | 强制转换为object | None或np.nan |
注意:Pandas中字符串类型的数据通常使用object类型存储的。
(1)发现缺失值
isnull()方法和data.notnull()方法:创建一个布尔类型的掩码标签
data = pd.Series([1, np.nan, 'hello', None])
data.isnull()
data.notnull()
(2)剔除缺失值
data.dropna()
-
1.Series
dropna()方法返回一个去除缺失值的数据。
-
2.DataFrame
默认情况下剔除包含缺失值的整行数据。
可以指定删除含缺失值的整列数据。
df.dropna(axis=1)
df.dropna(axis='columns')
- 3.还可以自定删除条件
①通过how参数定义删除规则
df.dropna(axis=删除轴, how='删除规则')
②通过thresh参数设置判定是否删除的缺失值数量
df.dropna(axis=删除轴, thresh=最小缺失值数量)
(3)填充缺失值
①指定值填充
data.fillna(填充值)
②前向填充
用缺失值前面的有效值来从前往后填充(forward-fill)
data.fillna(method='ffill')
③后向填充
用缺失值后面的有效值来从后往前填充(back-fill)
data.fillna(method='bfill')
-
DataFrame填充方法与Series类似,只是在填充式需要设置坐标轴参数axis。若不指定则默认按行填充(用上一行的有效值填充下一行的缺失值)。
六、层级索引
目录
1.多级索引Series
2.多级索引的创建方法
3.多级索引的取值与切片
4.多级索引行列转换
5.多级索引的数据累计方法
1.多级索引Series
示例用例数据:
index = [('California', 2000), ('California', 2010), ('New York', 2000), ('New York', 2010), ('Texas', 2000), ('Texas', 2010)]
populations = [33871648, 37253956, 18976457, 19378102, 20851820, 25145561]
pop = pd.Series(populations, index=index)
(1)普通方法(使用普通索引)
缺点:在查询数据时需使用循环迭代,不够简洁(在处理大量数据时效率也不高)。
(2)Pandas多级索引
index = [索引元组列表]
index = pd.MultiIndex.from_tuples(index)
data = data.reindex(index)
通过多级索引可以方便地查询数据:
(3)高维数据的多级索引
- 1.unstack()方法可以将一个拥有多级索引的Series转换为普通索引的DataFrame。
- 2.stack()方法可以将使用普通索引的DataFrame转换为拥有多级索引的Series。
data_df = data.unstack()
data = data_df.stack()
-
增加一列
2.多级索引的创建方法
-
为Series或DataFrame创建多级索引最直接的办法就是讲index参数设置为至少二维的索引数组。
(1)显式地创建多级索引
显式多级索引创建完成以后,可以通过index参数指定,或者通过reindex()方法更新Series或DataFrame的索引。
(2)多级索引的等级名称
可以在构造MultiIndex时通过参数names,或在构造完成后通过MultiIndex对象的names属性来指定索引的等级名称。
(3)多级列索引
# 多级行列索引
index = pd.MultiIndex.from_product([[2013, 2014], [1, 2]], names=['year', 'visit'])
columns = pd.MultiIndex.from_product([['Bob', 'Guido', 'Sue'], ['HR', 'Temp']], names=['subject', 'type'])
# 模拟数据
data = np.round(np.random.randn(4, 6), 1)
data[:, ::2] *= 10
data += 37
# 创建DataFrame
health_data = pd.DataFrame(data, index=index, columns=columns)
health_data
3.多级索引的取值与切片
(1)Series多级索引
-
1.如果只取最高级索引,获取的结果是一个新的Series,未被选中的低层索引值会被保留。
-
2.如果想要直接使用较低层级的索引取值,第一层级的索引可以用空切片。
-
3.多级索引同样支持花哨索引、掩码等操作
(2)DataFrame多级索引
-
可以使用loc|iloc选择多行多列
-
在元组中使用切片会引起错误,因此Pandas使用IndexSlice对象进行切片操作
4.多级索引行列转换
(1)有序索引和无序索引
多级索引局部切片要求MultiIndex的各级索引是有序的。
(2)索引stack与unstack
(3)索引的设置与重置
-
1.使用name参数为列设置名称(将多级索引变成多列数据)
-
2.将多列数据设置为多级索引
5.多级索引的数据累计方法
七、合并数据集:Concat与Append操作
1.知识回顾:NumPy数组合并
2.pd.concat()方法
示例用例方法:
def make_df(cols, ind):
data = {c:[str(c) + str(i) for i in ind] for c in cols}
print(data)
return pd.DataFrame(data, ind)
-
1.Series
-
2.DataFrame
(1)索引重复
-
合并时,pd.concat方法会保留重复的索引
处理重复索引
1.捕捉索引重复异常:设置vertify_integrity=True,合并时若出现重复索引则触发异常。
2.忽略重复索引:设置ignore_index=True,合并时则将会创建一个新的整数索引。
(2)类似join的合并
示例用例数据:
df5 = make_df('ABC', [1, 2])
df6 = make_df('BCD', [3, 4])
print(df5, '\n\n', df6)
pd.concat([df5, df6], sort=False)
(3)append()方法
注意:append()方法合并会创建新对象,效率较低。
八、合并数据集:合并与连接
目录
1.数据连接的类型
2.设置数据合并的键
3.设置数据连接的集合操作规则
4.设置重复列名后缀名
1.数据连接的类型
pd.merge()实现三种类型的数据连接(一对一、一对多、多对多)
(1)一对一连接
- pd.merge()方法会发现两个DataFrame都有的列,并会自动以这列作为键进行连接,生成一个新的DataFrame。
df1 = pd.DataFrame({'employee': ['Bob', 'Jake', 'Lisa', 'Sue'], 'group': ['Accounting', 'Engineering', 'Engineering', 'HR']})
df2 = pd.DataFrame({'employee': ['Lisa', 'Bob', 'Jake', 'Sue'], 'hire_date': [2004, 2008, 2012, 2014]})
df3 = pd.merge(df1, df2)
(2)一对多连接
一个group对应多个employee:
(3)多对多连接
一个group对应多个employee,一个group对应多个skills:
2.设置数据合并的键
(1)on参数
- 通过pd.merge()方法的on参数指定关联时的键
pd.merge(df1, df2, on='参照键')
注意:on参数只能在两个DataFrame有相同的列名时使用。
(2)left_on与right_on参数
(3)left_index与right_index参数
- 通过索引连接
df1a = df1.set_index('employee')
df2a = df2.set_index('employee')
pd.merge(df1a, df2a, left_index=True, right_index=True)
-
join()方法也可以按照索引进行连接
-
可以通过 left_index|right_on或者left_on|right_index参数组合,将列和索引混合使用
3.设置数据连接的集合操作规则
用例数据:
df6 = pd.DataFrame({'name': ['Peter', 'Paul', 'Mary'], 'food': ['fish', 'beans', 'bread']}, columns=['name', 'food'])
df7 = pd.DataFrame({'name': ['Mary', 'Joseph'], 'drink': ['wine', 'beer']}, columns=['name', 'drink'])
-
默认情况下pd.merge()方法采用内连接
-
通过merge()方法的how参数指定连接规则
4.设置重复列名后缀名
用例数据:
df8 = pd.DataFrame({'name': ['Bob', 'Jake', 'Lisa', 'Sue'], 'rank': [1, 2, 3, 4]})
df9 = pd.DataFrame({'name': ['Bob', 'Jake', 'Lisa', 'Sue'], 'rank': [3, 1, 2, 4]})
-
通过suffixes参数指定重复列名后缀名
九、累计与分组
1.累计
Series和DataFrame支持所有的NumPy累计操作
Pandas常见累计方法
指标 | 描述 |
---|---|
count() | 计数项 |
first()、last() | 第一项、最后一项 |
mean()、median() | 均值、中位数 |
min()、max() | 最小值、最大值 |
std()、var() | 标准差、方差 |
mad() | 均值绝对偏差 |
prod() | 所有项乘积 |
sum() | 所有项求和 |
示例:
-
Series和DataFrame支持所有的NumPy累计操作
- 查看常见的统计值
df.describe()
2.分组:GroupBy
(1)GroupBy过程:分割、应用、组合
groupby():传入要分割的名称,返回一个DataFrameGroupBy对象,可以进行进一步操作。
(2)GroupBy对象
groupby对象主要有以下四种操作:
aggregate、filter、transform、apply(累计、过滤、转换、应用)
用例数据:
import seaborn as sns
planets = sns.load_dataset('planets')
# 查看前五行数据
planets.head()
# 查看后五行数据
planets.tail()
# 查看数据描述信息
planets.describe()
①按列取值
②按组迭代
③调用方法
-
调用方法可以让任何不由GroupBy对象直接实现的方法直接应用的每一组
(3)累计、过滤、转换、应用
用例数据:
rng = np.random.RandomState(0)
df = pd.DataFrame({'key': ['A', 'B', 'C', 'A', 'B', 'C'], 'data1': range(6), 'data2': rng.randint(0, 10, 6)}, columns=['key', 'data1', 'data2'])
①累计:aggregate()方法
-
aggregate()方法支持复杂的累计操作,如:字符串、函数、函数列表等
-
aggregate()方法可以传入一个字典,为不同的列指定不同的累计方法
②过滤:filter()方法
过滤操作:按照分组属性,丢弃若干数据(返回True保留数据,返回False过滤掉数据)。
③转换:transform()方法
转换:累计操作是对组内全量数据进行缩减的结果,而转换操作会返回一个新的全量数据。
④应用:apply()方法
apply()方法可以在每个组上应用任意方法, 输入一个DataFrame,返回一个Pandas对象(Series或DataFrame)或一个标量(scalar)。
(4)设置分割的键
①将列表、数组、Series、索引作为分组键
-
分组键可以是长度与DataFrame匹配的任意Series或列表
②用字典或Series将索引映射到分组名称
df2 = df.set_index('key')
mapping = {'A': 'vower', 'B': 'consonant', 'C': 'consonant'}
df2.groupby(mapping).sum()
注意:索引的值要与字典的键保持统一。
③任意Python函数
-
可以将任意Python函数传入groupby,函数映射到索引
-
将函数作为分组键时,会修改函数传入索引列的值,如果没有定义索引,就会传入隐式索引的值
④多个有效键构成的列表
-
只要是有效的键就可以组合起来进行分组
(5)分组案例
十、数据透视表
用例数据:
import seaborn as sns
titanic = sns.load_dataset('titanic')
1.手工制作数据透视表
2.数据透视表语法
pivot_table()方法:数据透视表
# 两条语句等效
titanic.groupby(['sex', 'class'])['survived'].aggregate('mean').unstack()
titanic.pivot_table('survived', index='sex', columns='class')
(1)多级数据透视表
-
数据透视表中的分组可以通过各种参数指定多个等级
(2)其他数据透视表选项
- 通过字典为不同列指定不同的累计函数
titanic.pivot_table(index='sex', columns='class', aggfunc={'survived': sum, 'fare': 'mean'})
-
margins_name参数:用来指定总数行的名称
十一、向量化字符串操作
1.Pandas字符串操作
Series和Index对象提供了str属性,可以方便地实现对字符串的操作,并且正确地处理缺失值。
2.Pandas字符串方法列表
(1)与Python字符串方法相似的方法
几乎所有Python内置的字符串方法都被复制到Pandas的向量化字符串方法中。
注意:这些方法的返回值可能与Python内置函数不同。
示例:
(2)正则表达式方法
Pandas向量化字符串方法与Python标准库re模块函数对应关系
方法 | 描述 |
---|---|
match() | 对每个元素调用re.match(),返回布尔类型值 |
extract() | 对每个元素调用re.match(),返回匹配的字符串组(groups) |
findall() | 对每个元素调用re.findall() |
replace() | 用正则模式替换字符串 |
contains() | 对每个元素调用re.search(),返回布尔类型值 |
count() | 统计符合正则模式的字符串数量 |
split() | 等价于str.split(),支持正则表达式 |
rsplit() | 等价于str.rsplit(),支持正则表达式 |
示例:
(3)其他字符串方法
方法 | 描述 |
---|---|
get() | 获取元素索引位置上的值,索引从0开始 |
slice() | 对元素进行切片取值 |
slice_replace() | 对元素进行切片替换 |
cat() | 连接字符串(此方法功能复杂,建议阅读文档) |
repeat() | 重复元素 |
normalize() | 将字符串转换为Unicode规范格式 |
pad() | 在字符串的左边、右边或两边增加空格 |
wrap() | 将字符串按照指定的宽度换行 |
join() | 用分隔符连接Series的每个元素 |
get_dummies() | 按照分隔符提取每个元素的dummy变量,转换为独热(one-hot)编码的DataFrame |
①向量化字符串取值与切片操作
-
切片操作
-
取值操作
②指标变量
# A=出生在美国
# B=出生在英国
# C=喜欢奶酪
# D=喜欢午餐肉
full_monte = pd.DataFrame({'name': monte, 'info': ['B|C|D', 'B|D', 'A|C', 'B|D', 'B|C', 'B|C|D']})
- 独热编码
# 快速将指标变量转换为独热编码
full_monte['info'].str.get_dummies('|')
十二、时间序列处理
基本概念
- 时间戳:表示某个具体的时间点
- 时间间隔与周期:表示开始时间点与结束时间点之间的时间长度
- 时间增量(持续时间):表示精确的时间长度
1.Python日期与时间工具
(1)原生Python日期时间工具
from datetime import datetime
from dateutil import parser
(2)时间类型数组:NumPy datetime64类型
日期与时间单位格式代码
代码 | 含义 |
---|---|
Y | 年 |
M | 月 |
W | 周 |
D | 日 |
h | 时 |
m | 分 |
s | 秒 |
ms | 毫秒 |
us | 微秒 |
ns | 纳秒 |
ps | 皮秒 |
fs | 飞秒 |
as | 原秒 |
(3)Pandas日期时间工具
-
Pandas所有关于日期时间的处理方法全部都是通过TimeStamp对象实现的。
-
可以直接进行NumPy类型的向量化运算。
2.Pandas时间序列:用时间作索引
(1)Pandas时间序列数据结构
时间戳:Timestamp类型
周期型:Period类型
时间增量(持续时间):Timedelta类型
-
能够解析多种多种日期时间格式
-
当用一个日期减去另一个日期时,返回的结果是TimedeltaIndex类型
(2)时间频率与偏移量
Pandas频率代码
代码 | 描述 |
---|---|
D | 天 |
W | 周 |
M | 月末 |
Q | 季末 |
A | 年末 |
H | 小时 |
T | 分钟 |
S | 秒 |
L | 毫秒 |
U | 微秒 |
N | 纳秒 |
B | 天(仅含工作日) |
BM | 月末(仅含工作日) |
BQ | 季末(仅含工作日) |
BA | 年末(仅含工作日) |
BH | 小时(工作时间) |
MS | 月初 |
BMS | 月初(仅含工作日) |
B- | 仅含工作日 |
-S | 初 |
- 所有代码都对应有一个偏移量,可以在pandas.tseries.offsets里找到
from pandas.tseries.offsets import BDay
(3)重新取样和频率转换
数据读取:
- 1.安装pandas-datareader
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ pandas-datareader
- 2.读取数据
from pandas_datareader import data
tencent = data.get_data_yahoo('0700.hk', start='2000-11-01', end='2019-08-20')
- 3.读取收盘价
tencent = tencent['Close']
- 4.画图
%matplotlib inline
import matplotlib.pyplot as plt
tencent.plot()
①重新取样和频率转换
重新取样
resample():数据累计
asfreq():数据选择
tencent.plot(alpha=0.5, style='-')
# resample()方法是数据累计采样,结果为上一年的均值
tencent.resample('BA').mean().plot(style=':')
# asfreq()方法是数据选择采样,结果为上一年最后一个工作日的收盘价
tencent.asfreq('BA').plot(style='k:')
plt.legend(['input', 'resample', 'asfreq'], loc='upper left')
fig, ax = plt.subplots(2, sharex=True)
data = tencent.iloc[: 10]
data.asfreq('D').plot(ax=ax[0], marker='o')
data.asfreq('D', method='bfill').plot(ax=ax[1], style=['-o'])
data.asfreq('D', method='ffill').plot(ax=ax[1], style=['--o'])
ax[1].legend(['back-fill', 'forward-fill'])
②时间迁移
时间迁移
shift():迁移数据
tshift():迁移索引
fig, ax = plt.subplots(3, sharey=True)
fig.subplots_adjust(hspace=0.36)
# 重新按天采样,向后填充缺失值
tencent = tencent.asfreq('D', method='pad')
tencent.plot(ax=ax[0])
# 迁移数据
tencent.shift(900).plot(ax=ax[1])
# 迁移索引
tencent.tshift(900).plot(ax=ax[2])
# 设置图例与标签
local_max = pd.to_datetime('2007-11-05')
offset = pd.Timedelta(900, 'D')
ax[0].legend(['input'], loc=2)
ax[0].get_xticklabels()[4].set(weight='heavy', color='red')
ax[0].axvline(local_max, alpha=0.3, color='red')
ax[1].legend(['input'], loc=2)
ax[1].get_xticklabels()[4].set(weight='heavy', color='red')
ax[1].axvline(local_max + offset, alpha=0.3, color='red')
ax[2].legend(['input'], loc=2)
ax[2].get_xticklabels()[1].set(weight='heavy', color='red')
ax[2].axvline(local_max + offset, alpha=0.3, color='red')
③移动时间窗口
- Series和DataFrame有一个rolling属性,可以实现计算移动统计值。
rolling = tencent.rolling(365, center=True)
data = pd.DataFrame({'input': tencent, 'one-year rolling_mean': rolling.mean(), 'one-year rolling_std': rolling.std()})
ax = data.plot(style=['-', '--', ':'])
ax.lines[0].set_alpha(0.3)
十三、高性能Pandas:eval()与query()
1.pandas.eval()实现高性能运算
- pandas.eval()方法用字符串代数式实现了DataFrame的高性能运算。
- pandas.eval()在执行时不需要为临时数组分配全部内存。
2.pandas.eval()支持的运算
(1)算术运算符
pd.eval()支持所有的算术运算符
result1 = -df1 * df2 / (df3 + df4) - df1
result2 = pd.eval("-df1 * df2 / (df3 + df4) - df1")
np.allclose(result1, result2)
(2)比较运算符
pd.eval()支持所有的比较运算符,包括链式代数式
result1 = (df1 < df2) & (df2 <= df3) & (df3 != df4)
result2 = pd.eval('df1 < df2 <= df3 != df4')
np.allclose(result1, result2)
(3)位运算符
pd.eval()支持&(与)、|(或)等运算符
result1 = (df1 < 0.5) & (df2 <= 0.5) & (df3 < df4)
result2 = pd.eval('(df1 < 0.5) & (df2 <= 0.5) & (df3 < df4)')
np.allclose(result1, result2)
(4)对象属性与索引
result1 = df2.T[0] + df3.iloc[1]
result2 = pd.eval('df2.T[0] + df3.iloc[1]')
np.allclose(result1, result2)
注意:目前pd.eval()尚不支持函数调用、条件语句、循环及更复杂的运算。如果需要进行这些运算,可以借助Numexpr来实现。
3.DataFrame.eval()实现列间运算
df = pd.DataFrame(np.random.rand(1000, 3), columns=['A', 'B', 'C'])
result1 = (df['A'] + df['B']) / (df['C'] - 1)
result2 = pd.eval("(df.A + df.B) / (df.C - 1)")
# 更简洁的方式
result3 = df.eval("(A + B) / (C - 1)")
np.allclose(result1, result2), np.allclose(result1, result3)
-
1.新增列
-
2.修改列
-
3.DataFrame.eval()使用局部变量
4.DataFrame.query()方法
Cmean = df['C'].mean()
result1 = df[(df.A < Cmean) & (df.B < Cmean)]
result2 = df.query("A < @Cmean and B < @Cmean")
np.allclose(result1, result2)