Polars简明基础教程六:什么是Polars的“DataFrame(数据框)_下”

Apache Arrow

经典的Pandas DataFrame将数据存储在Numpy数组中。而在Polars中,数据被存储在Arrow表中。

我们可以通过调用to_arrow来查看这个Arrow表------这是一个廉价的操作,因为它只是查看底层数据。

python 复制代码
df.to_arrow()

pyarrow.Table
survived: int64
pclass: int64
sex: large_string
age: double
sibsp: int64
parch: int64
fare: double
embarked: large_string
class: large_string
who: large_string
adult_male: bool
deck: large_string
embark_town: large_string
alive: large_string
alone: bool
----
survived: [[0,1,1,1,0,...,0,1,0,1,0]]
pclass: [[3,1,3,1,3,...,2,1,3,1,3]]
sex: [["male","female","female","female","male",...,"male","female","female","male","male"]]
age: [[22,38,26,35,35,...,27,19,null,26,32]]
sibsp: [[1,1,0,1,0,...,0,0,1,0,0]]
parch: [[0,0,0,0,0,...,0,0,2,0,0]]
fare: [[7.25,71.2833,7.925,53.1,8.05,...,13,30,23.45,30,7.75]]
embarked: [["S","C","S","S","S",...,"S","S","S","C","Q"]]
class: [["Third","First","Third","First","Third",...,"Second","First","Third","First","Third"]]
who: [["man","woman","woman","woman","man",...,"man","woman","woman","man","man"]]
...

Arrow表是Arrow数组的集合------这些是一维向量,是基本的数据存储。我们可以通过在Series上调用to_arrow来查看某列的Arrow数组。

python 复制代码
df["age"].to_arrow()


[
  22,
  38,
  26,
  35,
  35,
  null,
  54,
  2,
  27,
  14,
  ...
  33,
  22,
  28,
  25,
  39,
  27,
  19,
  null,
  26,
  32
]

Apache Arrow是什么?

Apache Arrow是一个开源的跨语言项目,用于在内存中存储表格数据。

Apache Arrow 是一个跨平台的开发库,用于在内存中高效处理大型数据集。它最初由 Databricks 开发,并于 2016 年捐赠给 Apache 软件基金会。Arrow 的主要目标是在不同的系统之间提供高性能的数据交换和处理。

以下是 Apache Arrow 的一些关键特点:

  1. 列式存储:Arrow 使用列式存储格式,这意味着每一列数据都连续存储在内存中。这种格式非常适合批量数据处理,因为它能够利用现代 CPU 的缓存行为来提高数据访问效率。

  2. 零拷贝读取:Arrow 支持零拷贝读取,这意味着数据可以在不复制的情况下被多个进程共享。这有助于减少数据传输过程中的开销。

  3. 类型安全:Arrow 数据结构是类型安全的,这意味着数据类型在内存中是明确指定的。这对于避免运行时错误和提高性能非常重要。

  4. 跨语言兼容性:Arrow 支持多种编程语言,包括 C++、Java、Python、JavaScript、Rust 和更多。这意味着使用不同语言编写的程序可以共享相同的数据格式,而不需要额外的转换步骤。

  5. 高性能矢量化操作:Arrow 提供了用于矢量化操作的库函数,这些函数可以在整个数据集上并行执行,从而显著提高数据处理的速度。

  6. 支持多种数据源:Arrow 可以与多种数据源集成,包括关系数据库、NoSQL 存储系统、文件系统等。

  7. Parquet 文件格式集成:Arrow 与 Parquet 文件格式紧密集成,使得 Arrow 可以高效地读写 Parquet 文件。

  8. 用于大数据处理的生态系统集成:Arrow 被多个大数据处理框架和工具所采用,例如 Apache Spark、Pandas、Dask、Vaex、Polars 和 Flink。

Apache Arrow是:

  • 一个关于数据如何在内存中表示的规范
  • 一组在不同语言中实现该规范的库

Polars使用了Rust库[Arrow2]中的Arrow规范实现。

为什么Polars使用Apache Arrow?

当人们意识到专为科学计算设计的Numpy数组并不是表格数据的最佳数据存储方式时,Apache Arrow项目应运而生。

Apache Arrow 在数据科学和大数据领域变得越来越流行,因为它提高了数据处理的效率,并简化了不同系统之间的数据交换。

Arrow允许:

  • 无需复制即可共享数据(称为"零拷贝")
  • 更快的向量化计算
  • 分块处理大于内存的数据
  • 缺失数据的一致表示

总体而言,由于Arrow,Polars可以更快且更少地使用内存来处理数据。

Apache Arrow的缺点是什么?

Arrow的设计优化了对一维列的操作,而Numpy的设计优化了对多维数组的操作。这种权衡意味着与Numpy相比,使用Arrow数据进行某些类型的操作会更慢:

  • 转换数据帧
  • 在数据帧上进行矩阵乘法/线性代数运算

对于这种需要按行和列访问数据的用例,转换为Numpy数组可能更快(请参阅关于转换的讲座)。

那么Polars DataFrame和Arrow数据之间的关系是什么?

Polars DataFrame持有对Arrow表的引用,该表又持有对Arrow数组的引用。我们可以将Polars DataFrame视为一个轻量级对象,它指向轻量级的Arrow表,该表又指向重量级的Arrow数组(重量级是因为它们持有实际数据)。

这种分离的结构意味着我们可以对便宜的DataFrame包装器进行更改,而不复制(或复制最小量)任何数据,因为所有实际数据都存储在Arrow数组中。这种设计允许Polars提供快速且内存高效的数据处理功能。

python 复制代码
df_shape = (1_000_000,100)
df_polars = pl.DataFrame(
    np.random.standard_normal(df_shape)
)

df_polars.shape

删除列

我们将查看从Polars DataFrame中删除一个列需要多长时间。我们使用IPython的timeit模块来比较性能(我们将在课程后面的部分中学习更多关于timeit的知识)。

python 复制代码
%%timeit -n1 -r3

df_polars.drop("column_0")

Polars执行此操作非常快(比传统的Pandas快得多)。这是因为Polars只是创建了一个新的DataFrame对象(这是一个廉价的操作),该对象指向除了column_0之外的所有Arrow数组。基本上,Polars只是遍历列名列表来执行此操作!

重命名列

当我们更改DataFrame的某些不影响列中实际数据的部分时,会产生类似的效果。例如,如果我们重命名一个列...

python 复制代码
%%timeit -n1 -r3

df_polars.rename({"column_0":"a"})

Polars再次以非常快的速度完成此操作,因为它只是更新列名并检查列名是否仍然唯一。

克隆DataFrame

或者,如果我们通过克隆来创建一个新的DataFrame...

python 复制代码
%%timeit -n1 -r3

df_polars.clone()

在这种情况下,Polars创建了一个新的DataFrame对象,它指向相同的Arrow表。

更新克隆的DataFrame

尽管新的和旧的DataFrame最初指向相同的Arrow表,但我们不需要担心对其中一个所做的更改会影响另一个。

如果我们对其中一个DataFrame(比如新的DataFrame)中的值进行修改,那么新的DataFrame将:

  • 将已更改列中的数据复制到新的Arrow数组中
  • 创建一个新的Arrow表,该表指向更新后的Arrow数组以及未更改的Arrow数组

因此,现在我们有了:

  • 两个DataFrame,它们指向:
  • 两个Arrow表,它们指向:
  • 对于未更改的列,是相同的Arrow数组;对于已更改的列,是不同的Arrow数组

通过这种方式,我们创建了一个新的DataFrame,但只需要复制已更改列中的数据。在这个示例中,我们更改了第一行中的第一个值,我们可以看到对新的DataFrame的更改不会影响旧的DataFrame。

python 复制代码
df_polars2 = df_polars.clone()
df_polars2[0,0] = 1000
df_polars2[0,0]

在原始的DataFrame中,我们仍然保留着原始的值。

python 复制代码
df_polars[0,0]

练习

在练习中,您将加深以下内容的理解:

    • 获取DataFrame的数据类型(dtypes)
    • 获取Series的数据类型(dtypes)

练习 1

这个DataFrame的数据类型(dtypes)是什么?

python 复制代码
df = pl.DataFrame({'a':[0,1,2],'b':[0,1,2.0]})

df<blank>

练习 2

通过选择df的a列来创建一个Series

python 复制代码
df = pl.DataFrame({'a':[0,1,2],'b':[0,1,2.0]})

 df<blank>

a的数据类型是什么?

b的数据类型是什么?

解决方案

练习 1 的解决方案

这个DataFrame的数据类型(dtypes)是什么?

python 复制代码
df = pl.DataFrame({'a':[0,1,2],'b':[0,1,2.0]})
df.schema

练习 2 的解决方案

通过选择df的a列来创建一个Series

python 复制代码
df = pl.DataFrame({'a':[0,1,2],'b':[0,1,2.0]})
s = df["a"]
s

"s"有一个 64 位整数数据类型(dtype)

python 复制代码
s2 = df["b"]

s2

s2 有一个 64 位浮点数据类型(dtype)

Polars简明基础教程系列

Polars简明基础教程一:Polars快速入门

Polars简明基础教程二:懒惰模式 1:引入懒惰模式

Polars简明基础教程三:懒惰模式 1:引入懒惰模式(续)

Polars简明基础教程四:懒惰模式 2:评估查询

Polars简明基础教程五:什么是Polars的"DataFrame(数据框)_上"

相关推荐
FreakStudio12 分钟前
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
python·嵌入式·面向对象·电子diy
redcocal1 小时前
地平线秋招
python·嵌入式硬件·算法·fpga开发·求职招聘
artificiali2 小时前
Anaconda配置pytorch的基本操作
人工智能·pytorch·python
RaidenQ2 小时前
2024.9.13 Python与图像处理新国大EE5731课程大作业,索贝尔算子计算边缘,高斯核模糊边缘,Haar小波计算边缘
图像处理·python·算法·课程设计
花生了什么树~.2 小时前
python基础知识(六)--字典遍历、公共运算符、公共方法、函数、变量分类、参数分类、拆包、引用
开发语言·python
酱香编程,风雨兼程2 小时前
深度学习——基础知识
人工智能·深度学习
惟长堤一痕3 小时前
医学数据分析实训 项目四回归分析--预测帕金森病病情的严重程度
数据挖掘·数据分析·回归
Lossya3 小时前
【机器学习】参数学习的基本概念以及贝叶斯网络的参数学习和马尔可夫随机场的参数学习
人工智能·学习·机器学习·贝叶斯网络·马尔科夫随机场·参数学习
Trouvaille ~3 小时前
【Python篇】深度探索NumPy(下篇):从科学计算到机器学习的高效实战技巧
图像处理·python·机器学习·numpy·信号处理·时间序列分析·科学计算
爆更小小刘3 小时前
Python基础语法(3)下
开发语言·python