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方法。
不过没有哪种方法是更好的,看具体在实战中的场景。
只要使用恰当,结果将会使你意想不到!

最后,我在文中多次提到向量化的概念,希望引起重视。
因为之前在项目中,我用了两种方法,一种向量化,一种非向量化,结果效率查的是天高地远!

本文是我学习的一个总结。
如果文章有什么错误,希望大家指出,加油!
在这里插入图片描述
生活需要经的起大风大浪,才能看到那乌云背后的一缕阳光!


  1. 为什么向量化可以大幅度加快速度 ↩︎

  2. 吴恩达深度学习–向量化(vectorization) ↩︎

发布了29 篇原创文章 · 获赞 46 · 访问量 8196

猜你喜欢

转载自blog.csdn.net/qq_37344125/article/details/104232820