前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >独家 | Pandas 2.0 数据科学家的游戏改变者(附链接)

独家 | Pandas 2.0 数据科学家的游戏改变者(附链接)

作者头像
数据派THU
发布2023-08-08 13:12:08
3220
发布2023-08-08 13:12:08
举报
文章被收录于专栏:数据派THU数据派THU
作者:Miriam Santos 翻译:陈超 校对:Zrx 本文约4800字,建议阅读12分钟本文介绍了新版本pandas 2.0中引入的主要优势以及代码实现。

高效数据操纵的特征前五名。

图片来自Unsplash的Yancy Min

四月,官方发布pandas 2.0.0,在数据科学社区内掀起了轩然大波。

由于其广泛的功能性和多功能性,如果没有 importpandas as pd,几乎不可能做到数据操纵,对吧?

现在,请听我说:在过去的几个月里,随着大语言模型的火爆,我不知怎么地漏掉了pandas刚刚经历了一次重大发布的事实!是的,pandas 2.0已经擦亮枪口走来了(What’s new in 2.0.0 (April 3, 2023) — pandas 2.1.0.dev0+1237.gc92b3701ef documentation (pydata.org))!

虽然我没意识到所有的大肆宣传,数据中心的人工智能社区迅速伸出了援手:

截图来自作者 2.0发行版看起来在数据科学社区造成了相当大的影响,很多用户都称赞新版本里的改进。

有趣的事实:你意识到这个发行版用了惊人的3年时间制作的吗?这就是我所说的“对社区的承诺”!

所以pandas 2.0带来了什么?让我们立刻深入看一下!

1.表现,速度以及记忆效率

正如我们所知,pandas是使用numpy建立的,并非有意设计为数据帧库的后端。因为这个原因,pandas的主要局限之一就是较大数据集的内存处理。

在这一版本里,大的改变来自于为pandas数据引入Apache Arrow后端。

从本质上讲,Arrow 是一种标准化的内存中列式数据格式,具有适用于多种编程语言(C、C++、R、Python 等)的可用库。对于Python,有PyArrow,它基于Arrow的C++实现,因此速度很快!

所以,长话短说,PyArrow考虑到了我们以往1点几版本的内存限制,允许我们执行更快、内存更高效的数据操作,尤其对大型数据集来说。

以下是使用Hacker News数据集(大约650 MB)读取没有pyarrow后端的数据与使用pyarrow后端读取数据之间的比较(许可证CC BY-NC-SA 4.0):

代码语言:javascript
复制
%timeit df = pd.read_csv("data/hn.csv")
# 12 s ± 304 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit df_arrow = pd.read_csv("data/hn.csv", engine='pyarrow', dtype_backend='pyarrow')
# 329 ms ± 65 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

比较read_csv(): 使用pyarrow后台快了35倍多。作者代码段。

如您所见,使用新的后端使读取数据的速度提高了近 35 倍。其他值得指出的方面:

  • 如果没有 pyarrow 后端,每个列/特征都存储为自己的唯一数据类型:数字特征存储为 int64 或 float64,而字符串值存储为对象;
  • 使用 pyarrow,所有功能都使用 Arrow dtypes:请注意 [pyarrow] 注释和不同类型的数据:int64、float64、字符串、时间戳和双精度:
代码语言:javascript
复制
df = pd.read_csv("data/hn.csv")
df.info()


#
# RangeIndex: 3885799 entries, 0 to 3885798
# Data columns (total 8 columns):
# #   Column              Dtype 
# ---  ------              ----- 
# 0   Object ID           int64 
# 1   Title               object
# 2   Post Type           object
# 3   Author              object
# 4   Created At          object
# 5   URL                 object
# 6   Points              int64 
# 7   Number of Comments  float64
# dtypes: float64(1), int64(2), object(5)
# memory usage: 237.2+ MB


df_arrow = pd.read_csv("data/hn.csv", dtype_backend='pyarrow', engine='pyarrow')
df_arrow.info()


#
# RangeIndex: 3885799 entries, 0 to 3885798
# Data columns (total 8 columns):
# #   Column              Dtype               
# ---  ------              -----               
# 0   Object ID           int64[pyarrow]      
# 1   Title               string[pyarrow]     
# 2   Post Type           string[pyarrow]     
# 3   Author              string[pyarrow]     
# 4   Created At          timestamp[s][pyarrow]
# 5   URL                 string[pyarrow]     
# 6   Points              int64[pyarrow]      
# 7   Number of Comments  double[pyarrow]     
# dtypes: double[pyarrow](1), int64[pyarrow](2), string[pyarrow](4), timestamp[s][pyarrow](1)
# memory usage: 660.2 MB

df.info():调查每个数据帧的 dtype。作者截图。

2.Arrow数据类型和Numpy索引

除了读取数据(这是最简单的情况)之外,您还可以期待一系列其他操作的其他改进,尤其是那些涉及字符串操作的操作,因为 pyarrow 对字符串数据类型的实现非常有效:

代码语言:javascript
复制
%timeit df["Author"].str.startswith('phy')
# 851 ms ± 7.89 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
          

%timeit df_arrow["Author"].str.startswith('phy')
# 27.9 ms ± 538 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

比较字符串操作:展示Arrow实现的效率。作者代码段。

事实上,Arrow 比 numpy 具有更多(和更好的支持的)数据类型,这些数据类型在科学(数字)范围之外是必需的:日期和时间、持续时间、二进制、小数、列表和地图。浏览 pyarrow 支持的数据类型和 numpy 数据类型之间的等效性实际上可能是一个很好的练习,以便您学习如何利用它们。

现在也可以在索引中保存更多的 numpy 数值类型。传统的 int64、uint64 和 float64 为所有 numpy 数字 dtypes Index 值打开了空间,因此我们可以指定它们的 32 位版本:

代码语言:javascript
复制
pd.Index([1, 2, 3])
# Index([1, 2, 3], dtype='int64')
          

pd.Index([1, 2, 3], dtype=np.int32)
# Index([1, 2, 3], dtype='int32')

利用 32 位 numpy 索引,使代码的内存效率更高。作者代码段。

3.更容易处理缺失值

建立在numpy之上使得pandas很难以轻松,灵活的方式处理缺失值,因为numpy不支持某些数据类型的null值。

例如,整数会自动转换为浮点数,这并不理想:

代码语言:javascript
复制
df = pd.read_csv("data/hn.csv")
          

points = df["Points"]
points.isna().sum()
# 0
          

points[0:5]
# 0    61
# 1    16
# 2     7
# 3     5
# 4     7
# Name: Points, dtype: int64
          

# Setting first position to None
points.iloc[0] = None
          

points[0:5]
# 0     NaN
# 1    16.0
# 2     7.0
# 3     5.0
# 4     7.0
# Name: Points, dtype: float64

缺失值:转换成浮点数。作者代码段

请注意在引入 singleNone 值后,点如何自动从 int64 更改为 float64。

对于数据流来说,没有什么比错误的排版更糟糕的了,尤其是在以数据为中心的 AI 范式中。

错误的排版直接影响数据准备决策,导致不同数据块之间的不兼容性,即使以静默方式传递,它们也可能损害某些输出无意义结果的操作。

例如,在以数据为中心的人工智能社区(DCAI Community (discord.com)),我们正在围绕用于数据隐私的合成数据(GitHub - Data-Centric-AI-Community/nist-crc-2023: NIST Collaborative Research Cycle on Synthetic Data. Learn about Synthetic Data week by week!)开展一个项目。其中一个功能NOC(number of children,孩子数)具有缺失值,因此在加载数据时会自动转换为浮点数。当将数据作为浮点数传递到生成模型中时,我们可能会得到小数的输出值,例如 2.5——除非你是一个有 2 个孩子、一个新生儿和奇怪的幽默感的数学家,否则有 2.5 个孩子是不行的。

在 pandas 2.0 中,我们可以利用 dtype = 'numpy_nullable',其中缺失值是在没有任何 dtype 更改的情况下考虑的,因此我们可以保留原始数据类型(在本例中为 int64):

代码语言:javascript
复制
df_null = pd.read_csv("data/hn.csv", dtype_backend='numpy_nullable')
          

points_null = df_null["Points"]
points_null.isna().sum()
# 0
          

points_null[0:5]
# 0    61
# 1    16
# 2     7
# 3     5
# 4     7
# Name: Points, dtype: Int64
          

points_null.iloc[0] = None
          

points_null[0:5]
# 0              
# 1      16
# 2       7
# 3       5
# 4       7
# Name: Points, dtype: Int64

利用“numpy_nullable”,pandas 2.0可以在不更改原始数据类型的情况下处理缺失值。作者代码段。

这似乎是一个微妙的变化,但这意味着现在pandas本身就可以使用 Arrow 处理缺失值。这使得操作更加高效,因为 pandas 不必实现自己的版本来处理每种数据类型的 null 值。

4.写入时复制优化

Pandas 2.0 还添加了一种新的惰性复制机制,该机制会延迟复制数据帧和系列对象,直到它们被修改。

这意味着在启用写入时复制时,某些方法将返回视图而不是副本,这通过最大限度地减少不必要的数据重复来提高内存效率。

这也意味着在使用链式分配时需要格外小心。

如果启用了写入时复制模式,则链式分配将不起作用,因为它们指向一个临时对象,该对象是索引操作的结果(在写入时复制下的行为类似于副本)。

禁用copy_on_write后,如果更改新数据帧,切片等操作可能会更改原始 df:

代码语言:javascript
复制
pd.options.mode.copy_on_write = False # disable copy-on-write (default in pandas 2.0)
          

df = pd.read_csv("data/hn.csv")
df.head()
          

# Throws a 'SettingWithCopy' warning
# SettingWithCopyWarning:
# A value is trying to be set on a copy of a slice from a DataFrame
df["Points"][0] = 2000
          

df.head() # <---- df changes

禁用写入时复制:在链接分配中更改原始数据帧。作者代码段。

启用copy_on_write后,将在分配时创建副本(python - What rules does Pandas use to generate a view vs a copy? - Stack Overflow),因此永远不会更改原始数据帧。Pandas 2.0 会在这些情况下引发 ChainedAssignmentError,以避免无提示错误:

代码语言:javascript
复制
pd.options.mode.copy_on_write = True
          

df = pd.read_csv("data/hn.csv")
df.head()
          

# Throws a ChainedAssignmentError
df["Points"][0] = 2000
          

# ChainedAssignmentError: A value is trying to be set on a copy of a DataFrame
# or Series through chained assignment. When using the Copy-on-Write mode,
# such chained assignment never works to update the original DataFrame
# or Series, because the intermediate object on which we are setting
# values always behaves as a copy.
# Try using '.loc[row_indexer, col_indexer] = value' instead,
# to perform the assignment in a single step.
          

df.head() # <---- df does not change

启用写入时复制:在链接分配中不会更改原始数据帧。作者代码段。

5.可依赖选项

使用 pip 时,2.0 版让我们可以灵活地安装可选依赖项,这在资源的定制和优化方面是一个加分项。

我们可以根据我们的特定要求定制安装,而无需将磁盘空间花费在我们并不真正需要的东西上。

此外,它节省了许多“依赖性难题”,减少了兼容性问题或与开发环境中可能存在的其他软件包冲突的可能性:

代码语言:javascript
复制
pip install "pandas[postgresql, aws, spss]>=2.0.0"

安装可依赖选项。作者代码片段。

让我们试用一下!

然而,问题挥之不去:这种热度真的合理吗?我很好奇pandas 2.0是否对我每天使用

的一些软件包提供了显著的改进:ydata-profiling,matplotlib,seaborn,scikit-learn。

从这些中,我决定尝试一下 ydata-profiling——它刚刚增加了对 pandas 2.0 的支持,这似乎是社区的必备品!在新版本中,用户可以休息以确保如果他们使用 pandas 2.0,他们的管道不会中断,这是一个主要优势!但除此之外呢?

说实话,ydata-profiling一直是我最喜欢的探索性数据分析工具之一,它也是一个很好的快速基准测试——我这边只有1行代码,但在此之下,它充满了作为数据科学家我需要解决的计算——描述性统计、直方图绘制、分析相关性、 等等。

那么,还有什么比以最小的努力同时测试pyarrow引擎对所有引擎的影响更好的方法呢?

代码语言:javascript
复制
import pandas as pd
from ydata_profiling import ProfileReport
          

# Using pandas 1.5.3 and ydata-profiling 4.2.0
%timeit df = pd.read_csv("data/hn.csv")
# 10.1 s ± 215 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
          

%timeit profile = ProfileReport(df, title="Pandas Profiling Report")
# 4.85 ms ± 77.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
          

%timeit profile.to_file("report.html")
# 18.5 ms ± 2.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
          

# Using pandas 2.0.2 and ydata-profiling 4.3.1
%timeit df_arrow = pd.read_csv("data/hn.csv", engine='pyarrow')
# 3.27 s ± 38.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
          

%timeit profile_arrow = ProfileReport(df_arrow, title="Pandas Profiling Report")
# 5.24 ms ± 448 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
          

%timeit profile_arrow.to_file("report.html")
# 19 ms ± 1.87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

使用 ydata-profiling进行基准测试。作者代码段。

同样,使用 pyarrow 引擎读取数据肯定更好,尽管创建数据配置文件在速度方面没有显著改变。

然而,差异可能取决于内存效率,为此我们必须进行不同的分析。此外,我们可以进一步调查对数据进行的分析类型:对于某些操作,1.5.2 和 2.0 版本之间的差异似乎可以忽略不计。

但我注意到在这方面可能产生影响的主要事情是 ydata-profiling尚未利用 pyarrow 数据类型。此更新可能会对速度和内存产生重大影响,也是我对未来发展的期望!

结论:性能、灵活性、互操作性!

这个新的 pandas 2.0 版本带来了很大的灵活性和性能优化,并在“引擎盖下”进行了微妙但关键的修改。

也许对于数据操作领域的新手来说,它们并不“华而不实”,但对于那些曾经跳过篮圈来克服以往版本局限性的资深数据科学家来说,它们就像沙漠中的水一样。

总结一下,这些是新版本中引入的主要优势:

  • 性能优化:随着 Apache Arrow 后端的引入、更多的 numpy dtype 索引和写入时复制模式;
  • 增加灵活性和自定义性:允许用户控制可选的依赖项并利用 Apache Arrow 数据类型(包括从一开始的可空性!);
  • 互操作性:也许是新版本的一个不太“广受赞誉”的优势,但影响巨大。由于 Arrow 是独立于语言的,因此内存中的数据不仅可以在基于 Python 构建的程序之间传输,还可以在 R、Spark 和其他使用 Apache Arrow 后端的程序之间传输!

伙计们,你有它!我希望这个总结可以平息你关于pandas 2.0的一些问题,以及它在我们的数据操作任务中的适用性。

我仍然很好奇,随着pandas 2.0 的引入,您是否也发现了日常编码的重大差异!如果您愿意,请来数据中心的AI社区(Discord)找我,让我知道您的想法!我们在那见?

关于我

博士、机器学习研究员、教育家、数据倡导者和整体“万事通”。在Medium上,我写了关于以数据为中心的人工智能和数据质量的文章,教育数据科学和机器学习社区如何从不完美的数据转向智能数据。

原文标题:

Pandas 2.0: A Game-Changer for Data Scientists?

原文链接:

https://medium.com/towards-data-science/pandas-2-0-a-game-changer-for-data-scientists-3cd281fcc4b4?source=topic_portal_recommended_stories---------2-85----------machine_learning----------30a1af14_d40c_416a_bc92_b752b8fd806c-------

编辑:王菁

译者简介

陈超,北京大学应用心理硕士,数据分析爱好者。本科曾混迹于计算机专业,后又在心理学的道路上不懈求索。在学习过程中越来越发现数据分析的应用范围之广,希望通过所学输出一些有意义的工作,很开心加入数据派大家庭,保持谦逊,保持渴望。

翻译组招募信息

工作内容:需要一颗细致的心,将选取好的外文文章翻译成流畅的中文。如果你是数据科学/统计学/计算机类的留学生,或在海外从事相关工作,或对自己外语水平有信心的朋友欢迎加入翻译小组。

你能得到:定期的翻译培训提高志愿者的翻译水平,提高对于数据科学前沿的认知,海外的朋友可以和国内技术应用发展保持联系,THU数据派产学研的背景为志愿者带来好的发展机遇。

其他福利:来自于名企的数据科学工作者,北大清华以及海外等名校学生他们都将成为你在翻译小组的伙伴。

点击文末“阅读原文”加入数据派团队~

转载须知

如需转载,请在开篇显著位置注明作者和出处(转自:数据派ID:DatapiTHU),并在文章结尾放置数据派醒目二维码。有原创标识文章,请发送【文章名称-待授权公众号名称及ID】至联系邮箱,申请白名单授权并按要求编辑。

未经许可的转载以及改编者,我们将依法追究其法律责任。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-07-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据派THU 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档