解析pandas apply() 函数用法(推荐)

作者:stone0823 时间:2022-09-02 15:10:09 

理解 pandas 的函数,要对函数式编程有一定的概念和理解。函数式编程,包括函数式编程思维,当然是一个很复杂的话题,但对今天介绍的 apply() 函数,只需要理解:函数作为一个对象,能作为参数传递给其它函数,也能作为函数的返回值。

函数作为对象能带来代码风格的巨大改变。举一个例子,有一个类型为 list 的变量,包含 从 1 到 10 的数据,需要从其中找出能被 3 整除的所有数字。用传统的方法:


def can_divide_by_three(number):
   if number % 3 == 0:
       return True
   else:
       return False

selected_numbers = []
for number in range(1, 11):
   if can_divide_by_three(number):
       selected_numbers.append(number)

循环是不可少的,因为 can_divide_by_three() 函数只用一次,考虑用 lambda 表达式简化:


divide_by_three = lambda x : True if x % 3 == 0 else False

selected_numbers = []
for number in range(1, 11):
   if divide_by_three(item):
       selected_numbers.append(item)

以上是传统编程思维方式,而函数式编程思维则完全不同。我们可以这样想:从 list 中取出特定规则的数字,能不能只关注和设置规则,循环这种事情交给编程语言去处理呢?当然可以。当编程人员只关心规则(规则可能是一个条件,或者由某一个 function 来定义),代码将大大简化,可读性也更强。

Python 语言提供 filter() 函数,语法如下:


filter(function, sequence)

filter() 函数的功能:对 sequence 中的 item 依次执行 function(item),将结果为 True 的 item 组成一个 List/String/Tuple(取决于 sequence 的类型)并返回。有了这个函数,上面的代码可以简化为:


divide_by_three = lambda x : True if x % 3 == 0 else False
selected_numbers = filter(divide_by_three, range(1, 11))

将 lambda 表达式放在语句中,代码简化到只需要一句话就够了:


selected_numbers = filter(lambda x: x % 3 == 0, range(1, 11))

Series.apply()

回到主题, pandas 的 apply() 函数可以作用于 Series 或者整个 DataFrame,功能也是自动遍历整个 Series 或者 DataFrame, 对每一个元素运行指定的函数。

举一个例子,现在有这样一组数据,学生的考试成绩:


 Name Nationality  Score
  张           汉    400
  李           回    450
  王           汉    460

如果民族不是汉族,则总分在考试分数上再加 5 分,现在需要用 pandas 来做这种计算,我们在 Dataframe 中增加一列。当然如果只是为了得到结果, numpy.where() 函数更简单,这里主要为了演示 Series.apply() 函数的用法。


import pandas as pd

df = pd.read_csv("studuent-score.csv")
df['ExtraScore'] = df['Nationality'].apply(lambda x : 5 if x != '汉' else 0)
df['TotalScore'] = df['Score'] + df['ExtraScore']

对于 Nationality 这一列, pandas 遍历每一个值,并且对这个值执行 lambda 匿名函数,将计算结果存储在一个新的 Series 中返回。上面代码在 jupyter notebook 中显示的结果如下:

  Name Nationality  Score  ExtraScore  TotalScore
0    张           汉    400           0         400
1    李           回    450           5         455
2    王           汉    460           0         460

apply() 函数当然也可执行 python 内置的函数,比如我们想得到 Name 这一列字符的个数,如果用 apply() 的话:


df['NameLength'] = df['Name'].apply(len)

apply 函数接收带有参数的函数

根据 pandas 帮助文档 pandas.Series.apply — pandas 1.3.1 documentation,该函数可以接收位置参数或者关键字参数,语法如下:


Series.apply(func, convert_dtype=True, args=(), **kwargs)

对于 func 参数来说,该函数定义中的第一个参数是必须的,所以 funct() 除第一个参数之外的其它参数则被视为额外的参数,作为参数来传递。我们仍以刚才的示例进行说明,假设除汉族外,其他少数名族有加分,我们把加分放在函数的参数中,先定义一个 add_extra() 函数:


def add_extra(nationality, extra):
   if nationality != "汉":
       return extra
   else:
       return 0

对 df 新增一列:


df['ExtraScore'] = df.Nationality.apply(add_extra, args=(5,))

位置参数通过 args = () 来传递参数,类型为 tuple。也可用下面的方法调用:


df['ExtraScore'] = df.Nationality.apply(add_extra, extra=5)

运行后结果为:

  Name Nationality  Score  ExtraScore
0    张           汉    400           0
1    李           回    450           5
2    王           汉    460           0

将 add_extra 作为 lambda 函数:


df['Extra'] = df.Nationality.apply(lambda n, extra : extra if n == '汉' else 0, args=(5,))

下面继续讲解关键字参数。假设我们对不同的民族可以给不同的加分,定义 add_extra2() 函数:


def add_extra2(nationaltiy, **kwargs):
   return kwargs[nationaltiy]

df['Extra'] = df.Nationality.apply(add_extra2, 汉=0, 回=10, 藏=5)

运行结果为:

  Name Nationality  Score  Extra
0    张           汉    400      0
1    李           回    450     10
2    王           汉    460      0

对照 apply 函数的语法,不难理解。

DataFrame.apply()

DataFrame.apply() 函数则会遍历每一个元素,对元素运行指定的 function。比如下面的示例:


import pandas as pd
import numpy as np

matrix = [
   [1,2,3],
   [4,5,6],
   [7,8,9]
]

df = pd.DataFrame(matrix, columns=list('xyz'), index=list('abc'))
df.apply(np.square)

对 df 执行 square() 函数后,所有的元素都执行平方运算:


   x   y   z
a   1   4   9
b  16  25  36
c  49  64  81

如果只想 apply() 作用于指定的行和列,可以用行或者列的 name 属性进行限定。比如下面的示例将 x 列进行平方运算:


df.apply(lambda x : np.square(x) if x.name=='x' else x)

   x  y  z
a   1  2  3
b  16  5  6
c  49  8  9

下面的示例对 x 和 y 列进行平方运算:


df.apply(lambda x : np.square(x) if x.name in ['x', 'y'] else x)

   x   y  z
a   1   4  3
b  16  25  6
c  49  64  9

下面的示例对第一行 (a 标签所在行)进行平方运算:


df.apply(lambda x : np.square(x) if x.name == 'a' else x, axis=1)

默认情况下 axis=0 表示按列,axis=1 表示按行。

apply() 计算日期相减示例

平时我们会经常用到日期的计算,比如要计算两个日期的间隔,比如下面的一组关于 wbs 起止日期的数据:


   wbs   date_from     date_to
 job1  2019-04-01  2019-05-01
 job2  2019-04-07  2019-05-17
 job3  2019-05-16  2019-05-31
 job4  2019-05-20  2019-06-11

假定要计算起止日期间隔的天数。比较简单的方法就是两列相减(datetime 类型):


import pandas as pd
import datetime as dt

wbs = {
   "wbs": ["job1", "job2", "job3", "job4"],
   "date_from": ["2019-04-01", "2019-04-07", "2019-05-16","2019-05-20"],
   "date_to": ["2019-05-01", "2019-05-17", "2019-05-31", "2019-06-11"]
}

df = pd.DataFrame(wbs)
df['elpased'] = df['date_to'].apply(pd.to_datetime) -  
              df['date_from'].apply(pd.to_datetime)

apply() 函数将 date_fromdate_to 两列转换成 datetime 类型。我们 print 一下 df:


   wbs   date_from     date_to elapsed
0  job1  2019-04-01  2019-05-01 30 days
1  job2  2019-04-07  2019-05-17 40 days
2  job3  2019-05-16  2019-05-31 15 days
3  job4  2019-05-20  2019-06-11 22 days

日期间隔已经计算出来,但后面带有一个单位 days,这是因为两个 datetime 类型相减,得到的数据类型是 timedelta64,如果只要数字,还需要使用 timedeltadays 属性转换一下。


elapsed= df['date_to'].apply(pd.to_datetime) -
   df['date_from'].apply(pd.to_datetime)
df['elapsed'] = elapsed.apply(lambda x : x.days)

使用 DataFrame.apply() 函数也能达到同样的效果,我们需要先定义一个函数 get_interval_days() 函数的第一列是一个 Series 类型的变量,执行的时候,依次接收 DataFrame 的每一行。


import pandas as pd
import datetime as dt

def get_interval_days(arrLike, start, end):  
   start_date = dt.datetime.strptime(arrLike[start], '%Y-%m-%d')
   end_date = dt.datetime.strptime(arrLike[end], '%Y-%m-%d')

return (end_date - start_date).days

wbs = {
   "wbs": ["job1", "job2", "job3", "job4"],
   "date_from": ["2019-04-01", "2019-04-07", "2019-05-16","2019-05-20"],
   "date_to": ["2019-05-01", "2019-05-17", "2019-05-31", "2019-06-11"]
}

df = pd.DataFrame(wbs)
df['elapsed'] = df.apply(
   get_interval_days, axis=1, args=('date_from', 'date_to'))

参考

Pandas的Apply函数——Pandas中最好用的函数
pandas.Series.apply — pandas 1.3.1 documentation

来源:https://blog.csdn.net/stone0823/article/details/100008619

标签:pandas,apply(),函数
0
投稿

猜你喜欢

  • JS延时器提示框的应用实例代码解析

    2024-05-10 14:00:28
  • JS内部事件机制之单线程原理

    2024-05-03 15:58:24
  • 如何把Mysql卸载干净(亲测有效)

    2024-01-16 09:06:06
  • Python轻松破解加密压缩包教程详解

    2021-04-12 13:26:45
  • asp连接mysql的问题(端口)

    2009-08-21 13:23:00
  • python 两个数据库postgresql对比

    2024-01-22 16:29:36
  • Python中绑定与未绑定的类方法用法分析

    2021-08-06 22:56:54
  • PHP登录验证功能示例【用户名、密码、验证码、数据库、已登陆验证、自动登录和注销登录等】

    2023-11-14 23:24:02
  • Mysql 文件配置解析

    2024-01-26 10:01:54
  • 如何结束一个session变量

    2009-08-12 19:20:00
  • PHP引用的调用方法分析

    2023-11-06 15:23:23
  • PHP fprintf()函数用法讲解

    2023-06-01 20:09:20
  • textarea的输入限制统计代码statInput

    2008-05-22 13:36:00
  • vue 监听键盘回车事件详解 @keyup.enter || @keyup.enter.native

    2023-07-02 17:01:35
  • Python并行分布式框架Celery详解

    2023-06-23 10:05:21
  • Javascript中Math.max和Math.max.apply的区别和用法详解

    2024-04-10 10:55:04
  • SQL Server本地时间和UTC时间的相互转换实现代码

    2024-01-21 06:35:33
  • Python练习之读取XML节点和属性值的方法

    2021-03-25 19:01:06
  • python实现淘宝秒杀聚划算抢购自动提醒源码

    2022-12-04 11:43:15
  • 详解python列表(list)的使用技巧及高级操作

    2021-05-12 15:26:47
  • asp之家 网络编程 m.aspxhome.com