解析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_from
和 date_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
,如果只要数字,还需要使用 timedelta
的 days
属性转换一下。
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


猜你喜欢
- 首先写一个简单的drf接口from rest_framework.views import APIViewfrom rest_framewo
- Python批量识别图片指定区域文字内容,供大家参考,具体内容如下简介对于一张图片,需求识别指定区域的内容1.截取原始图上的指定图片当做模板
- 1. rangerange是python内置的一个类,该类型表示一个不可改变(immutable)的数字序列,常常用于在for循环中迭代一组
- 一、merge(合并)的语法:pd.merge(left, right, how='inner', on=None, lef
- 1.无效数据的概念无效数据是指不符合数据收集目的或数据收集标准的数据。这些数据可能来自于不准确的测量、缺失值、错误标注、虚假的数据源或其他问
- 动态页面的模拟点击:以斗鱼直播为例:http://www.douyu.com/directory/all爬取每页的房间名、直播类型、主播名称
- 引言with 语句是从 Python 2.5 开始引入的一种与异常处理相关的功能(2.5 版本中要通过 from __future__ im
- 一、百度百科1、MySQLMySQL声称自己是最流行的开源数据库。LAMP中的M指的就是MySQL。构建在LAMP上的应用都会使用MySQL
- 前言使用np.savetxt()方法可以将数据保存为txt文件或者是csv文件。1 np.savetxt()存储txt文件1-1 基础参数n
- JAN-1(January) FEB-2(February) MAR-3(March)APR-4(April) MAY-5(Ma
- 前言:WebDriver提供了两个关闭浏览器的方法,一个是前边使用quit()方法,另一个是close()方法close():关闭当前窗口q
- 1 简介大家好,我们在日常使用 Python 的过程中,经常会使用 json 格式存储一些数据,尤其
- Ping服务ping 是基于 XML_RPC 标准协议的更新通告服务,用于Blog把内容更新快速通知给搜索引擎,以便搜索引擎及时进行抓取和更
- 本文实例为大家分享了微信小程序实现上传图片的具体代码,供大家参考,具体内容如下用到的apiwx.chooseMedia(); 用于拍摄或从手
- BeautifulSoup简介Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据。官方解释如下:Beautif
- 在使用SQL Server 的过程,中由于经常需要从多个不同地点将数据集中起来或向多个地点复制数据,所以数据的导出,导入是极为常见的操作.我
- asp fso type属性取得文件类型代码是用来返回类型指定的文件或文件夹。语法FileObject.Type FolderObject.
- 本文对于先前系列文章中实现的C/Python代码统计工具(CPLineCounter),通过C扩展接口重写核心算法加以优化,并与网上常见的统
- 见下,把数字转成条形图、条形码的一个程序:<%Sub ShowChart(ByRef aValues,
- 概述laravel服务容器就像一个高度自动化的工厂,你需要的东西,定制好模型,使用特定接口来制造。因为使用了服务容器,laravel中大部分