到本讲座结束时,您将能够:
- 在Polars和Numpy之间进行转换
- 在Polars和Pandas之间进行转换
此课程要求您的Pandas版本为1.5+,Polars版本为0.16.4+,PyArrow版本为11+。
你可以使用pl.show_versions()来检查您的安装情况
首先,我们还是以著名的“泰坦尼克号生还者数据集”作为例子(示例中用到的csv数据文件可在csdn 免费下载:“泰坦尼克号生还者数据集”):
import polars as pl
import numpy as np
import pandas as pd
csv_file = "../data/titanic.csv"
df = pl.read_csv(csv_file)
df.head(3)
shape: (3, 15)
┌──────────┬────────┬────────┬──────┬───┬──────┬─────────────┬───────┬───────┐
│ survived ┆ pclass ┆ sex ┆ age ┆ … ┆ deck ┆ embark_town ┆ alive ┆ alone │
│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ str ┆ f64 ┆ ┆ str ┆ str ┆ str ┆ bool │
╞══════════╪════════╪════════╪══════╪═══╪══════╪═════════════╪═══════╪═══════╡
│ 0 ┆ 3 ┆ male ┆ 22.0 ┆ … ┆ null ┆ Southampton ┆ no ┆ false │
│ 1 ┆ 1 ┆ female ┆ 38.0 ┆ … ┆ C ┆ Cherbourg ┆ yes ┆ false │
│ 1 ┆ 3 ┆ female ┆ 26.0 ┆ … ┆ null ┆ Southampton ┆ yes ┆ true │
└──────────┴────────┴────────┴──────┴───┴──────┴─────────────┴───────┴───────┘
将DataFrame转换为Numpy
要将DataFrame转换为Numpy,请使用 to_numpy方法。这将克隆(复制)数据。
arr = df.to_numpy()
arr
[[0 3 'male' ... 'Southampton' 'no' False]
[1 1 'female' ... 'Cherbourg' 'yes' False]
[1 3 'female' ... 'Southampton' 'yes' True]
...
[0 3 'female' ... 'Southampton' 'no' False]
[1 1 'male' ... 'Cherbourg' 'yes' True]
[0 3 'male' ... 'Queenstown' 'no' True]]
此转换将每一行转换为Numpy的ndarray,并将这些行数组垂直堆叠。
由于DataFrame具有混合类型,因此Numpy数组具有object数据类型。如果列具有统一的数值数据类型,则Numpy数组将具有相应的数据类型。
在此示例中,我们使用select来选择仅用于转换为Numpy的64位浮点列...
我们将在选择列和转换数据帧的部分中更详细地介绍select。
floats_array = (
df
.select(
pl.col(pl.Float64)
)
.to_numpy()
)
floats_array
[[22. 7.25 ]
[38. 71.2833]
[26. 7.925 ]
...
[ nan 23.45 ]
[26. 30. ]
[32. 7.75 ]]
然后我们得到一个浮点Numpy数组
floats_array.dtype
float64
将Numpy转换为DataFrame
我们可以从Numpy数组创建一个Polars DataFrame
rand_array = np.random.standard_normal((5,3))
(
pl.DataFrame(
rand_array,
)
)
shape: (5, 3)
┌───────────┬───────────┬───────────┐
│ column_0 ┆ column_1 ┆ column_2 │
│ --- ┆ --- ┆ --- │
│ f64 ┆ f64 ┆ f64 │
╞═══════════╪═══════════╪═══════════╡
│ -0.360763 ┆ 1.320892 ┆ -0.280671 │
│ 1.849615 ┆ 0.664971 ┆ -0.382902 │
│ -1.112349 ┆ -1.426877 ┆ -3.624935 │
│ 0.222936 ┆ -0.467669 ┆ 1.280407 │
│ 0.897571 ┆ -1.312517 ┆ 1.650859 │
└───────────┴───────────┴───────────┘
如果我们想指定列名,可以可选地将列名列表传递给 pl.DataFrame。
如果我们有一个一维的Numpy数组,我们可以使用零拷贝的方式创建一个Polars Series或DataFrame。首先,我们创建一个全为1的一维数组
arr = np.ones(10)
arr.shape
(10,)
然后我们可以使用“零拷贝”的方式创建一个Series或DataFrame
使用零拷贝的方式创建一个Series
pl.Series("a", arr)
shape: (10,)
Series: 'a' [f64]
[
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
]
使用零拷贝的方式创建一个 DataFrame
pl.DataFrame(
{
"a": arr,
}
)
shape: (10, 1)
┌─────┐
│ a │
│ --- │
│ f64 │
╞═════╡
│ 1.0 │
│ 1.0 │
│ 1.0 │
│ 1.0 │
│ 1.0 │
│ 1.0 │
│ 1.0 │
│ 1.0 │
│ 1.0 │
│ 1.0 │
└─────┘
零拷贝意味着数据(即全为1的数组)在内存中仅存储在一个位置。Numpy和Polars都在查看这个位置以获取原始Numpy数组或Polars Series或DataFrame的数据。
具体来说,当您将一个 NumPy 数组转换为 Polars 的 Series
或 DataFrame
时,“零拷贝”意味着 Polars 对象将不会创建数据的物理副本。相反,它会以一种方式引用或映射到原始 NumPy 数组的内存位置,以便能够直接访问这些数据。这样做的好处是减少了内存的使用,并可能提高了数据处理的效率,因为避免了不必要的数据复制。
将Series转换为Numpy
将Series转换为Numpy比将整个DataFrame转换具有更多选项。
要进行简单的转换,其中数据被克隆,请在Series上使用to_numpy
df['age'].head().to_numpy()
[22. 38. 26. 35. 35. nan 54. 2. 27. 14.]
使用零拷贝将Series转换为Numpy
在某些情况下,我们可以将Series转换为Numpy而无需复制(“零拷贝”)。
如果Series中没有null或NaN值(例如Survived列),则仅可能进行零拷贝。如果我们想确保转换为Numpy是零拷贝的,并且在需要复制时引发Exception,我们可以使用allow_copy参数
arr = (
df['survived']
.head()
.to_numpy(allow_copy=False)
)
arr
[0 1 1 1 0 0 0 0 1 1]
如果我们尝试对包含null值的Age列使用这种零拷贝方法,我们将得到一个Exception
arr = (
df['age']
.head()
.to_numpy(allow_copy=False)
)
arr
RuntimeError: copy not allowed: cannot convert to a NumPy array without copying data
在零拷贝转换中,Numpy数组是只读的,因此我们无法更改Numpy数组中的值。
在以下示例中,当我们尝试在Survived列上进行零拷贝操作后更改值时,会收到一个Exception
arr = (
df['survived']
.head()
.to_numpy(allow_copy=False)
)
arr[0] = 100
ValueError: assignment destination is read-only
Polars简明基础教程三:懒惰模式 1:引入懒惰模式(续)
Polars简明基础教程五:什么是Polars的“DataFrame(数据框)_上”
Polars简明基础教程六:什么是Polars的“DataFrame(数据框)_下”