楔子

我们在用 pandas 处理数据的时候,经常会遇到用其中一列数据替换另一列数据的场景。比如 A 列和 B 列,对 A 列中不为空的数据不作处理,对 A 列中为空的数据使用 B 列对应索引的数据进行替换。这一类的需求估计很多人都遇到,当然还有其它更复杂的。

解决这类需求的办法有很多,这里我们来推荐几个。

combine_first

这个方法是专门用来针对空值处理的,我们来看一下用法。

import pandas as pd

df = pd.DataFrame(
    {"A": ["001", None, "003", None, "005"],
     "B": ["1", "2", "3", "4", "5"]}
)
print(df)
"""
      A  B
0   001  1
1  None  2
2   003  3
3  None  4
4   005  5
"""

# 我们现在需求如下,如果 A 列中的数据不为空,那么不做处理
# 如果为空,则用 B 列中对应的数据进行替换
df["A"] = df["A"].combine_first(df["B"])
print(df)
"""
     A  B
0  001  1
1    2  2
2  003  3
3    4  4
4  005  5
"""

使用方法很简单,首先是两个 Series 对象,假设叫 s1 和 s2,那么 s1.combine_first(s2) 就表示用 s2 替换掉 s1 中为空的数据。如果 s1 和 s2 的某个相同索引对应的数据都是空,那么结果只能是空。当然这个方法不是在原地操作,而是会返回一个新的 Series 对象。

另外这个方法的理想前提是两个 Series 对象的索引是一致的,因为替换是根据索引来指定位置的,举个例子。

import pandas as pd

s1 = pd.Series(["001", None, None, "004"], 
               index=['a', 'b', 'c', 'd'])
s2 = pd.Series(["2", "3", "4"], 
               index=['b', 'd', "e"])

print(s1)
"""
a     001
b    None
c    None
d     004
dtype: object
"""
print(s2)
"""
b    2
d    3
e    4
dtype: object
"""

print(s1.combine_first(s2))
"""
a    001
b      2
c    NaN
d    004
e      4
dtype: object
"""

解释一下,首先替换的都是 s1 中值为空的数据,如果不为空那么不做任何处理。s1 中值为空的数据有两个,索引分别为 b、c,那么会用 s2 中索引为 b、c 的数据进行替换。但 s2 中只存在索引为 b、不存在索引为 c 的数据,那么就只能替换一个值。

另外我们看到结尾还多了个索引为 e 的数据,是的,如果 s2 中的数据,s1 没有,那么会直接加上去。

注意:pandas 的很多操作都是基于自带的索引进行的,并不是简单的从上往下一一对应。即便是很多 pandas 老手,偶尔也会犯这个错误。

当然大部分情况下我们处理的都是同一个 DataFrame 的两列,对于同一个 DataFrame 中的两列,它们的索引显然是一致的,所以就是简单的从上到下,不会有太多花里胡哨的。

combine

combine 和 combine_first 类似,只是需要指定一个函数。

import pandas as pd

df = pd.DataFrame(
    {"A": ["001", None, "003", None, "005"],
     "B": ["1", "2", "3", "4", "5"]}
)
print(df)
"""
      A  B
0   001  1
1  None  2
2   003  3
3  None  4
4   005  5
"""

df["A"] = df["A"].combine(df["B"], 
                          lambda a, b: a if pd.notna(a) else b)
print(df)
"""
     A  B
0  001  1
1    2  2
2  003  3
3    4  4
4  005  5
"""

我们指定了一个匿名函数,参数 a、b 就代表 df["A"] 和 df["B"] 中对应的每一个数据。如果 a 不为空,那么返回 a,否则返回 b。

所以我们使用 combine 实现了 combine_first 的功能,combine_first 是专门对空值进行替换的,但 combine 则是可以让我们自己指定逻辑。我们可以实现 combine_first 的功能,也可以实现其它的功能。

import pandas as pd

s1 = pd.Series([1, 22, 3, 44])
s2 = pd.Series([11, 2, 33, 4])

# 哪个元素大就保留哪一个
print(s1.combine(s2, lambda a, b: a if a > b else b))
"""
0    11
1    22
2    33
3    44
dtype: int64
"""

# 两个元素进行相乘
# 当然,对于目前这个需求,最好的办法是 s1 * s2
print(s1.combine(s2, lambda a, b: a * b))
"""
0     11
1     44
2     99
3    176
dtype: int64
"""

combine 用起来还是很方便的,当然它同样是针对索引来操作的。此外combine和combine_first内部都会先对索引进行处理,如果两个 Series 对象的索引不一样,那么会先让它们索引变得一致。

import pandas as pd

s1 = pd.Series([1, 22, 3, 44], index=['a', 'b', 'c', 'd'])
s2 = pd.Series([11, 2, 33, 4], index=['c', 'd', 'e', 'f'])

# 先对两个索引取并集
index = s1.index.union(s2.index)
print(index) 
"""
Index(['a', 'b', 'c', 'd', 'e', 'f'], dtype='object')
"""

# 然后通过reindex,获取指定索引的元素
# 索引不存在就用 NaN 代替
s1 = s1.reindex(index)
s2 = s2.reindex(index)
print(s1)
"""
a     1.0
b    22.0
c     3.0
d    44.0
e     NaN
f     NaN
dtype: float64
"""
print(s2)
"""
a     NaN
b     NaN
c    11.0
d     2.0
e    33.0
f     4.0
dtype: float64
"""

combine 和 combine_first 都是先让 s1 和 s2 的索引变得一致之后,再进行操作。

import pandas as pd

s1 = pd.Series([1, 22, 3, 44],
               index=['a', 'b', 'c', 'd'])
s2 = pd.Series([11, 2, 33, 4],
               index=['c', 'd', 'e', 'f'])

print(s1.combine_first(s2))
"""
a     1.0
b    22.0
c     3.0
d    44.0
e    33.0
f     4.0
dtype: float64
"""

所以你会发现,s1 和 s2 里面都没有空值,返回的结果也没有空值,但是类型却从整型变成了浮点型。就是因为 s1 和 s2 在 reindex 的过程中出现了 NaN,所以类型变成了浮点型。

所以在使用 combine 和 combine_first 这两个方法的时候,一定要记住索引,否则可能会造成陷阱。事实上,包括 pandas 很多的其它操作也是,它们都是基于索引来的,并不是简单的依次从左到右或者从上到下。

update

update 比较野蛮,我们来看一下。

import pandas as pd

s1 = pd.Series([1, 2, 3, 4])
s2 = pd.Series([11, 22, 33, 44])

s1.update(s2)
print(s1)
"""
0    11
1    22
2    33
3    44
dtype: int64
"""

首先我们看到这个方法是在本地进行操作的,功能还是用 s2 的元素替换 s1 的元素,并且只要 s2 中的元素不为空,那么就进行替换。

import pandas as pd

s1 = pd.Series([1, 2, 3, 4])
s2 = pd.Series([11, 22, None, 44])

s1.update(s2)
print(s1)
"""
0    11
1    22
2     3
3    44
dtype: int64
"""

所以这个函数叫 update,意思就是更新。用 s2 中的元素换掉 s1 中的元素。但如果 s2 中的元素为空,那么可以认为新版本还没出来,那么还是使用老版本,所以 s1 中的 3 没有被换掉。

因此 update 和 combine_first 比较类似,但它们的区别在于:

  • combine_first:如果 s1 中的值为空,用 s2 的值替换,否则保留 s1 的值;
  • update:如果 s2 中的值不为空,那么替换 s1,否则保留 s1 的值;

另外在 combine_first 的时候,我们反复强调了索引的问题,如果 s1 和 s2 索引不一样,那么生成的结果的元素个数会增多。但是 update 不同,因为它是在本地进行操作的,也就是直接本地修改 s1,所以最终 s1 的元素个数是不会发生变化的。

import pandas as pd

s1 = pd.Series([1, 2, 3, 4], 
               index=['a', 'b', 'c', 'd'])
s2 = pd.Series([11, 22, 33, 44], 
               index=['c', 'd', 'e', 'f'])

s1.update(s2)
print(s1)
"""
a     1
b     2
c    11
d    22
dtype: int64
"""

s2 中不存在 index 为 a、b 的元素,那么可以认为新版本没有出现,因此不更新、保留原来的值。但 s2 中存在 index 为 c、d 的元素,所以有新版本,那么就更新。所以 s1 由 [1 2 3 4] 变成了 [1 2 11 22]。

至于 s2 中 index 为 e、f 的元素,它们和 s1 没有关系,因为 s1 中压根没有 index 为 e、f 的元素,s2 提供了新版本也是没用的。所以使用 update,是在 s1 本地操作的,操作前后 s1 的索引以及元素个数不会改变。

当然 update 也适用于对两个 DataFrame 进行操作,有兴趣可以自己去了解,但大部分时候我们都用在 Series 上面。

到此这篇关于详解Pandas如何高效对比处理DataFrame的两列数据的文章就介绍到这了,更多相关Pandas处理DataFrame数据内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

详解Pandas如何高效对比处理DataFrame的两列数据的更多相关文章

  1. NT IIS下用ODBC连接数据库

    $connection=intodbc_connect建立数据库连接,$query_string="查询记录的条件"如:$query_string="select*fromtable"用$cur=intodbc_exec检索数据库,将记录集放入$cur变量中。再用while{$var1=odbc_result;$var2=odbc_result;...}读取odbc_exec()返回的数据集$cur。最后是odbc_close关闭数据库的连接。odbc_result()函数是取当前记录的指定字段值。

  2. Thinkphp5框架实现获取数据库数据到视图的方法

    这篇文章主要介绍了Thinkphp5框架实现获取数据库数据到视图的方法,涉及thinkPHP5数据库配置、读取、模型操作及视图调用相关操作技巧,需要的朋友可以参考下

  3. 如何在PHP环境中使用ProtoBuf数据格式

    这篇文章主要介绍了如何在PHP环境中使用ProtoBuf数据格式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

  4. Python爬取奶茶店数据分析哪家最好喝以及性价比

    这篇文章主要介绍了用Python告诉你奶茶哪家最好喝性价比最高,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

  5. Android本地存储方法浅析介绍

    这篇文章主要介绍了Android本地存储案例,方法简单可以实现存储并达到节省内存的效果,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

  6. Pandas如何将表格的前几行生成html实战案例

    这篇文章主要介绍了Pandas如何将表格的前几行生成html实战案例,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下

  7. 详解Python如何实现Excel数据读取和写入

    这篇文章主要为大家详细介绍了python如何实现对EXCEL数据进行读取和写入,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  8. Python自动化办公之Excel数据的写入

    这篇文章主要为大家详细介绍一下Python中excel的写入模块- xlsxwriter,并利用该模块实现Excel数据的写入,感兴趣的小伙伴可以了解一下

  9. pandas如何计算同比环比增长

    这篇文章主要介绍了pandas如何计算同比环比增长,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  10. JavaScript数据扁平化详解

    这篇文章主要为大家介绍了JavaScript数据扁平化,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

随机推荐

  1. 10 个Python中Pip的使用技巧分享

    众所周知,pip 可以安装、更新、卸载 Python 的第三方库,非常方便。本文小编为大家总结了Python中Pip的使用技巧,需要的可以参考一下

  2. python数学建模之三大模型与十大常用算法详情

    这篇文章主要介绍了python数学建模之三大模型与十大常用算法详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感想取得小伙伴可以参考一下

  3. Python爬取奶茶店数据分析哪家最好喝以及性价比

    这篇文章主要介绍了用Python告诉你奶茶哪家最好喝性价比最高,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

  4. 使用pyinstaller打包.exe文件的详细教程

    PyInstaller是一个跨平台的Python应用打包工具,能够把 Python 脚本及其所在的 Python 解释器打包成可执行文件,下面这篇文章主要给大家介绍了关于使用pyinstaller打包.exe文件的相关资料,需要的朋友可以参考下

  5. 基于Python实现射击小游戏的制作

    这篇文章主要介绍了如何利用Python制作一个自己专属的第一人称射击小游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起动手试一试

  6. Python list append方法之给列表追加元素

    这篇文章主要介绍了Python list append方法如何给列表追加元素,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  7. Pytest+Request+Allure+Jenkins实现接口自动化

    这篇文章介绍了Pytest+Request+Allure+Jenkins实现接口自动化的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  8. 利用python实现简单的情感分析实例教程

    商品评论挖掘、电影推荐、股市预测……情感分析大有用武之地,下面这篇文章主要给大家介绍了关于利用python实现简单的情感分析的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

  9. 利用Python上传日志并监控告警的方法详解

    这篇文章将详细为大家介绍如何通过阿里云日志服务搭建一套通过Python上传日志、配置日志告警的监控服务,感兴趣的小伙伴可以了解一下

  10. Pycharm中运行程序在Python console中执行,不是直接Run问题

    这篇文章主要介绍了Pycharm中运行程序在Python console中执行,不是直接Run问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

返回
顶部