Pandas之apply、map、applymap详细学习与比较
一. apply()
- 针对
Series
的值调用函数- 调用函数可以是,也可以是只对单个值起作用的Python函数。
1. 参数讲解
func : function
Python
函数或者Numpy内置的ufunc
(ufunc:指适用于整个Series的NumPy函数)
convert_dtype:bool, default True
- 尝试为执行函数后的结果匹配更好的数据类型.如果为False,则保留dtype 为 object.
args:tuple
- 假如我们传入的func需要携带额外的参数,则通过使用args这个关键字进行传递.
kwds
- 传递给func的其他关键字参数,感觉和args类似,但是和args还是有不同,一会实例就可以很清楚的理解。
Returns:Series or DataFrame
2.apply()案例
这里使用的事三个城市某一时刻 的对应气温
s = pd.Series([20, 21, 12],index=['London', 'New York', 'Helsinki'])
s
London 20
New York 21
Helsinki 12
dtype: int64
定义一个返回值得平方的函数square
,将该函数作为参数传入apply()中,则会对Series
按元素进行square
转换,并返回转换后的结果
def square(x):
return x ** 2
s.apply(square)
London 400
New York 441
Helsinki 144
dtype: int64
也可以传入一个匿名函数,直接进行平方的转换
s.apply(lambda x: x ** 2)
London 400
New York 441
Helsinki 144
dtype: int64
自定义函数中,需要传递更多的参数,这里就是用args
参数.
def subtract_custom_value(x, custom_value):
return x - custom_value
s.apply(subtract_custom_value, args=(5,))
London 15
New York 16
Helsinki 7
dtype: int64
在自定义函数中,使用到了** kwargs参数.
def add_custom_values(x, **kwargs):
for month in kwargs:
x += kwargs[month]
return x
s.apply(add_custom_values, june=30, july=20, augst=25)
London 95
New York 96
Helsinki 87
dtype: int64
当然也可以直接使用Numpy
内置函数.
s.apply(np.log)
London 2.995732
New York 3.044522
Helsinki 2.484907
dtype: float64
到这里,我觉得apply()
函数基本上可以说懂个八九不离十了吧!
二. map()
将一个Series
中的每一个元素值都用另外的值替换(替换值可能来源某个函数、dict或者是某一个Series
)
1. 参数讲解
- arg:函数, collections的某一个映射子类 or Series
- na_action:两种可选值,
None
或者'ignore'
.默认为None
.'ignore'
:表示将不对原Series
中存在的Nan情况进行map
操作,而是保持Nan值不变.
Returns: 返回一个Series
对象.
2. map()案例
首先定义一个简单的Series
对象
s = pd.Series(['cat', 'dog', np.nan, 'rabbit'])
s
0 cat
1 dog
2 NaN
3 rabbit
dtype: object
传入一个dict,对原有元素进行替换.
替换事项注意:当传入的arg是一个字典时,如果原来的Series
有某一个key在该字典中不存在,那么,原来Series
中,该key对应的value将会转换为NaN
. 但是,如果传入的字典是一个dict子类,并且子类在内部函数__missing__
中设置了一个方法默认值,那么上面的情况则是使用该默认值,而不是使用NaN
.
s.map({'cat': 'kitten', 'dog': 'puppy'})
0 kitten
1 puppy
2 NaN
3 NaN
dtype: object
同样,map()还支持接受函数:
s.map('I am a {}'.format)
0 I am a cat
1 I am a dog
2 I am a nan
3 I am a rabbit
dtype: object
最后,如果不希望函数对原来的Series
产生影响,我们只需要设置参数na_action='ignore'
,即可:
s.map('I am a {}'.format, na_action='ignore')
0 I am a cat
1 I am a dog
2 NaN
3 I am a rabbit
dtype: object
到这里,map()
函数也大概的了解了一下.
三. applymap()
将某个函数对一个Dataframe按元素进行转换.
简单来说,这个方法就是要对整个DataFrame进行某种Function的转换.
1. 参数讲解
参数比较少
func:调用的函数,该函数会对DataFrame的每一个元素进行转换.
Returns:返回一个转换后的DataFrame
2. applymap()案例
这里使用的是官网的一个案例修改版
df = pd.DataFrame([[1, 2.12, 5.1], [3.356, 4.567, 6.1],[2, 4, 7.1])
df
0 1 2
0 1.000 2.120 5.100
1 3.356 4.567 6.100
2 2.000 4.000 7.100
计算每一个元素的长度,并返回
df.applymap(lambda x: len(str(x)))
0 1 2
0 3 4 2
1 5 5 2
2 3 4 2
同样还可以指定列,进行转换,并可以使用匿名函数作为func传入
select = ['0','1']
df[select].applymap(lambda x: x**2)
0 1
0 1.000000 4.494400
1 11.262736 20.857489
但是请注意,面对上面的这种对多个列进行操作的情况。优先考虑numpy
中是否已经有定义好了的向量化方法,因为向量化方法的效率会更好.12
四. 三种方法之间的比较
也比较了很多文章的写法,但是都知识解释熬了使用,对于区别的介绍很少(抱歉,我没找到,所以我只好自己尝试一下)
1. map()
map()
: 一般适用于对某一个series
按元素,执行function,并对元素进行转换
- 关注对象:
Series
对象中的每一个元素,是python自带的方法 - 优点:只关注对一个
Series
执行 - 缺点:扩展性不大,调用的function,不能传入额外的参数
例如下方代码,自定义函数需要传入位的参数x
def label(element, x):
if element > x:
return 'High'
else:
return 'Low'
economy_map = happiness2015['Economy'].map(label, x = .8)
运行结果如下:
TypeError: map() got an unexpected keyword argument 'x'
2. apply()
apply()
:一般适用于DataFrame 的某一行或某一列元素
- 关注对象:只关注对一个
DataFrame
的行或列执行 - 优点:相比map来说,扩展性更好,可以为传入的function传入更多的参数用于转换(案例中已经详细写出)
- 缺点:所有操作均为按行或者列.一旦涉及到需要对每一个元素进行单独判断的操作,则
apply
也无能为力.
例如下方代码,尝试为多个列(单列效果同样)进行function转换:
import pandas as pd
import numpy as np
df = pd.DataFrame([[1,4,9],[4,9,16],[9,25,36]], columns=['A','B','C'])
df
A B C
0 1 4 9
1 4 9 16
2 9 25 36
my_columns = ['A', 'B'] # 想要执行函数元素所在的列名
def my_functions(elements):
if elements>4:
return 'High'
else:
return 'Low'
# 执行apply
df[my_columns].apply(my_functions)
抛出错误异常如下:
('The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().', 'occurred at index A')
3. applymap()
applymap()
:用于dataframe上,是元素级别的操作;
- 关注对象:DataFrame的每一个元素
- 优点:因为是元素级别的操作,所以可以使用任何向量化或者非向量化的方法,对DataFrame 中的- 元素进行转换
- 缺点:正是因为是按元素( element-wise ),所以效率肯定相对apply来说较低
大多时候,都是使用apply()和map方法。
不过没有哪种方法是更好的,看具体在实战中的场景。
只要使用恰当,结果将会使你意想不到!
最后,我在文中多次提到向量化的概念,希望引起重视。
因为之前在项目中,我用了两种方法,一种向量化,一种非向量化,结果效率查的是天高地远!
本文是我学习的一个总结。
如果文章有什么错误,希望大家指出,加油!
生活需要经的起大风大浪,才能看到那乌云背后的一缕阳光!