看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
函数是一个大杀器,如果 pandas 提供的内置方法不够用,我们可以定义函数来做特别的处理。函数也可以让我们对数据重复的工作自动化。
注:本文所使用的 df
和 s
是数据信息一文中的数据。
Pandas 提供的 pipe() 可以让我们写的分析过程标准化、流水线化,达到复用,同时也是最近非常流行的链式方法的重要担当,可在Pandas链式方法中查看它的思想和应用。
语法结构:df.pipe(<函数名>, <传给函数的参数列表>)
# 对 df 多重应用多个函数
f(g(h(df), arg1=a), arg2=b, arg3=c)
# 用 pipe 可以把它们连接起来
(df.pipe(h)
.pipe(g, arg1=a)
.pipe(f, arg2=b, arg3=c)
)
# 以下是将 'arg2' 参数给函数 f 然后作为函数整体授受后边的参数
(df.pipe(h)
.pipe(g, arg1=a)
.pipe((f, 'arg2'), arg1=a, arg3=c)
)
以下是个实例:
# 定义一个函数,给所有Q的成绩加 n,然后增加平均数
# 其中 n 中要加的值,为必传参数
def add_mean(rdf, n):
df = rdf.copy()
df = df.loc[:,'Q1':'Q4'].applymap(lambda x: x+n)
df['avg'] = df.loc[:,'Q1':'Q4'].mean(1)
return df
# 调用
df.pipe(add_mean, 100)
也可以直接使用匿名函数:
# 其中 xy 是变量,df_ 是前边的数据内容
df.pipe(lambda df_, x, y: df_[(df_.a >= x) & (df_.b <= y)], 2, 8)
更多信息,请查看专门的介绍页面:管道方法 pipe()。
对 DataFrame 中的按行和列(默认)进行函数处理。
df.apply(max) # 所有列的最大值
df.apply(lambda x: x*2) # 所有列的值乘于2 = df * 2
df.Q1.apply(lambda x: x+10 if type(x) is int else x) # 所有数字加10
df.loc[:,'Q1':'Q4'].apply(sum, axis=1) # 指定列横向相加
def mymax(x):
return x.max()
df.apply(lambda x:mymax(x)) # 应用函数
# 判断一个值是否在另外一个类似列表的列中
df.apply(lambda x: x.s in x.s_list, axis=1) # 布尔序列
df.apply(lambda x: x.s in x.s_list, axis=1).astype(int) # 0 和 1 序列
一个常用的根据条件输出结果的案例(使用 numpy 库 np.where):
fun = lambda x: np.where(x.team=='A' and x.Q1>90, 'good' ,'other')
df.apply(fun, axis=1)
# 同上效果
(df.apply(lambda x:x.team=='A' and x.Q1>90, axis=1)
.map({True:'good', False:'other'})
)
df.apply(lambda x: 'good' if x.team=='A' and x.Q1>90 else '', axis=1)
总结,apply 可以应用的函数类型包括:
df.apply(fun) # 自定义
df.apply(max) # python 内置函数
df.apply(lambda x: x*2) # lambda
df.apply(np.mean) # numpy 等其他库的函数
df.apply(pd.Series.first_valid_index) # Pandas 自己的函数
df.apply('count') # Pandas 自己的函数方法
# 多个函数
df.apply([sum, 'count']) # 相当于 .aggregate, 即.agg
df.apply({'Q1':sum, 'Q2':'count'}) # 同上
特别要说明的如果函数参数传的是字符串,先会尝试当前对象的同名方法(如 DataFrame 就是 DataFrame 的,Series 就是 Series 的),如没有会尝试 NumPy 有没有这个同名 ufunc (NumPy 中的通用函数),以上有会应用,如均没有就会报错。
其他函数调用方法基本都支持上述几类函数。更多信息,请查看专门的介绍页面:apply() 应用函数方法。
弃用预告
从 pandas 2.1 开始,使用 DataFrame.applymap 时会抛出弃用警告。意味着 applymap 在不久的将来将会不再支持,而会被 DataFrame.map 替代。这样 DataFrame 和 Series 逐元素应用函数将统一使用 map 方法,这将降低我们的学习成本。
df.applymap()
可做到元素级函数应用,就是对 DataFrame 中所有的元素(不包含索引)应用函数处理。使用 lambda 时,变量是指每一个具体的值。
df.applymap(lambda x: x*2) # 所有元素的最大值
df.applymap(lambda x: len(str(x))) # 所有的值长度
df.applymap(lambda x: x+10 if type(x) is int else x) # 所有数字加10
def mylen(x):
return len(str(x))
df.applymap(mylen) # 应用函数
# 对空值不使用函数 pandas 1.2.0+
df.applymap(mylen, na_action='ignore')
更多信息,请查看专门的介绍页面:applymap() 逐元素调用函数。
根据输入对应关系映射值修改内容,用于 Series 对象或 DataFrame 对象的逐个元素(pandas 2.1 开始支持)。
df.map('I am a {}'.format)
df.team.map({'A':'一班', 'B':'二班','C':'三班', 'D':'四班',}) # 枚举替换
df.team.map('I am a {}'.format)
df.team.map('I am a {}'.format, na_action='ignore')
t = pd.Series({'six': 6., 'seven': 7.})
s.map(t)
# 应用函数
def f(x):
return len(str(x))
# 调用
df['name'].map(f)
# 三种情况的判断
fun = lambda x: (x>60 and '及格') or (x==60 and '60分') or (x<60 and '不及格')
df.Q1.map(fun)
# 利用 np.sign 判断值为正、负、0的情况,并映射文案
label = {0: '平', 1:'涨', -1:'跌'}
ser.map(np.sign).map(label)
更多信息,请查看专门的介绍页面:map() 数值映射。同时,关于以上介绍的几个函数的异同,可以通过:map, applymap 和 apply 的异同对比 查看。
使用指定轴上的一项或多项操作进行汇总。
# 每列的最大值
df.agg('max')
# 将所有列聚合产生 sum 和 min 两行
df.agg(['sum', 'min'])
# 系列多个聚合
df.agg({'Q1' : ['sum', 'min'], 'Q2' : ['min', 'max']})
# 分组后聚合
df.groupby('team').agg('max')
df.Q1.agg(['sum', 'mean'])
def mymean(x):
return x.mean()
df.Q2.agg(['sum', mymean])
# 每列使用不同的方法进行聚合
df.agg(a=('Q1', max),
b=('Q2', 'min'),
c=('Q3', np.mean),
d=('Q4', lambda s:s.sum()+1)
)
# 按行聚合
df.loc[:,'Q1':].agg("mean", axis="columns")
# 利用 pd.Series.add 方法对所有数据加分
# other 是 add 方法的参数
df.loc[:,'Q1':].agg(pd.Series.add, other=10)
更加详细的介绍可查看教程Pandas 聚合分组部分,关于 agg() 可以查看 agg() 聚合操作 详细介绍。
自身调用函数并返回一个 DataFrame。
df.transform(lambda x: x*2) # 应用匿名函数
df.transform([np.sqrt, np.exp]) # 调用多个函数
df.transform([np.abs, lambda x: x + 1])
df.transform({'A': np.abs, 'B': lambda x: x + 1})
df.transform('abs')
df.transform(lambda x: x.abs())
可以对比下下两个操作:
# 聚合后按组显示合计
df.groupby('team').sum()
# 聚合后按原数据结构显示数据,但在指定位置上显示聚合计算后的结果
df.groupby('team').transform(sum)
更加详细的介绍可查看教程Pandas transform() 数值转换部分。
类似于 Python 中的 copy() 函数,df.copy()
方法可以返回一个新的对象,这个新的对象就与原对象断绝关系了。
s = pd.Series([1, 2], index=["a", "b"])
s_1 = s
s_copy = s.copy()
s_1 is s # True
s_copy is s # False
如果想在 Series 或者 DataFrame 上增加方法,最简单的办法如下:
import pandas as pd
ser = pd.Series([1,3,5,6])
def add_one(s):
return s + 1
pd.Series.func = func
pd.Series.add_one
# <function __main__.add_one(s)>
# 使用
ser.add_one()
ser.apply('add_one') # 可以用字符串了
'''
0 2
1 4
2 6
3 7
dtype: int64
'''
如果要增加更加通用的方法,则可以使用如下的方法:
from pandas.core.base import PandasObject
def your_fun(df):
...
PandasObject.your_fun = your_fun
# 使用方法
df.your_fun()
如果要删除,则可以使用 del:
del pd.Series.add_one
还可以使用类继承的方法:
import pandas as pd
class MyDataFrame(pd.DataFrame):
def mymethod(self):
"""Do my stuff"""
# 使用
from mymodule import *
df = MyDataFrame(np.random.randn(4,4))
df.mymethod()
再如:
import pandas as pd
class MyDF(pd.DataFrame):
def __init__(self, *args, **kwargs):
super(MyDF, self).__init__(*args, **kwargs)
@property
def _constructor(self):
return MyDF
def my_custom_method(self):
print('This actually works!')
# 使用
df = MyDF(columns=('a', 'b'))
df = df.append({'a': 1, 'b': 'test'})
print(df)
df.my_custom_method() # prints "This actually works!"
可以访问更多关注 pandas 的扩展方法:https://pandas.pydata.org/docs/development/extending.html
更新时间:2024-08-01 20:28:24 标签:pandas 函数