ホーム > python > polars > polarsの基本操作

polarsの基本操作

pythonpolars

polarsとは

pandasの様にデータフレーム形式でデータを扱うことができ、pandasより高速などの理由から最近話題のライブラリです。
polars

今回はAPI referenceを参考にしながら基本的な操作を試してみたいと思います。


インストール、バージョン

Excelファイルの読み書きにxlsx2csvというライブラリを使っているようだったので合わせてインストールしました。
どちらもpipでインストール可能です。

pip install polars
pip install xlsx2csv

バージョンは以下の通りです。 bash python 3.7.6 polars 0.15.16 xlsx2csv 0.8.1


ファイルIO

まずはファイルの読み書きを行ってみます。

csvファイルの読み書き

read_csv()write_csv()という関数があるので基本的にはこれを使えばcsvの読み書きが可能です。

データフレームを生成→csvファイルへ書き込み→作成したcsvからデータを読み込み
という処理を行ってみました。

import polars as pl
if __name__ == '__main__':
# データフレーム生成
df = pl.DataFrame({'col0': [0,1,2], 'col1': [3,4,5]})
print(df)
# shape: (3, 2)
# ┌──────┬──────┐
# │ col0 ┆ col1 │
# │ --- ┆ --- │
# │ i64 ┆ i64 │
# ╞══════╪══════╡
# │ 0 ┆ 3 │
# │ 1 ┆ 4 │
# │ 2 ┆ 5 │
# └──────┴──────┘
# csvファイルへ書き込み
df.write_csv('sample.csv')
# csvファイルの読み込み
df_csv = pl.read_csv('sample.csv')
print(df_csv)
# shape: (3, 2)
# ┌──────┬──────┐
# │ col0 ┆ col1 │
# │ --- ┆ --- │
# │ i64 ┆ i64 │
# ╞══════╪══════╡
# │ 0 ┆ 3 │
# │ 1 ┆ 4 │
# │ 2 ┆ 5 │
# └──────┴──────┘

保存したデータが読み込めていることが確認できます。

Excelファイルの読み込み

Excelファイルに関しては現状read_excel()という関数しか用意されていないようなので読み込みしか行えないようです。
下記の様なデータが入ったサンプルファイルを用意して動作確認してみました。

col0_sheet1col1_sheet1
03
14
25
import polars as pl
if __name__ == '__main__':
df_xlsx = pl.read_excel('sample.xlsx', sheet_id=1)
print(df_xlsx)
# shape: (3, 2)
# ┌─────────────┬─────────────┐
# │ col0_sheet1 ┆ col1_sheet1 │
# │ --- ┆ --- │
# │ i64 ┆ i64 │
# ╞═════════════╪═════════════╡
# │ 0 ┆ 3 │
# │ 1 ┆ 4 │
# │ 2 ┆ 5 │
# └─────────────┴─────────────┘

Excelファイルが読み込めていることがわかります。
今回は「sheet_id=1」でシート番号を指定して読み込みましたが、 「sheet_name='Sheet1'」のようにシート名を指定しても読み込み可能です。

行の抽出

ユーザーガイドと同じようにirisデータセットを使用してデータを操作してみます。
まずはデータの取得を行います。

df = pl.read_csv("https://j.mp/iriscsv")
print(df)
# shape: (150, 5)
# ┌──────────────┬─────────────┬──────────────┬─────────────┬───────────┐
# │ sepal_length ┆ sepal_width ┆ petal_length ┆ petal_width ┆ species │
# │ --- ┆ --- ┆ --- ┆ --- ┆ --- │
# │ f64 ┆ f64 ┆ f64 ┆ f64 ┆ str │
# ╞══════════════╪═════════════╪══════════════╪═════════════╪═══════════╡
# │ 5.1 ┆ 3.5 ┆ 1.4 ┆ 0.2 ┆ setosa │
# │ 4.9 ┆ 3.0 ┆ 1.4 ┆ 0.2 ┆ setosa │
# │ 4.7 ┆ 3.2 ┆ 1.3 ┆ 0.2 ┆ setosa │
# │ 4.6 ┆ 3.1 ┆ 1.5 ┆ 0.2 ┆ setosa │
# │ ... ┆ ... ┆ ... ┆ ... ┆ ... │
# │ 6.3 ┆ 2.5 ┆ 5.0 ┆ 1.9 ┆ virginica │
# │ 6.5 ┆ 3.0 ┆ 5.2 ┆ 2.0 ┆ virginica │
# │ 6.2 ┆ 3.4 ┆ 5.4 ┆ 2.3 ┆ virginica │
# │ 5.9 ┆ 3.0 ┆ 5.1 ┆ 1.8 ┆ virginica │
# └──────────────┴─────────────┴──────────────┴─────────────┴───────────┘

行を指定してデータを取得することが出来ます。

# 0番目のデータを取得
print(df[0])
# shape: (1, 5)
# ┌──────────────┬─────────────┬──────────────┬─────────────┬─────────┐
# │ sepal_length ┆ sepal_width ┆ petal_length ┆ petal_width ┆ species │
# │ --- ┆ --- ┆ --- ┆ --- ┆ --- │
# │ f64 ┆ f64 ┆ f64 ┆ f64 ┆ str │
# ╞══════════════╪═════════════╪══════════════╪═════════════╪═════════╡
# │ 5.1 ┆ 3.5 ┆ 1.4 ┆ 0.2 ┆ setosa │
# └──────────────┴─────────────┴──────────────┴─────────────┴─────────┘
# マイナスの値も指定可能
print(df[-1])
# shape: (1, 5)
# ┌──────────────┬─────────────┬──────────────┬─────────────┬───────────┐
# │ sepal_length ┆ sepal_width ┆ petal_length ┆ petal_width ┆ species │
# │ --- ┆ --- ┆ --- ┆ --- ┆ --- │
# │ f64 ┆ f64 ┆ f64 ┆ f64 ┆ str │
# ╞══════════════╪═════════════╪══════════════╪═════════════╪═══════════╡
# │ 5.9 ┆ 3.0 ┆ 5.1 ┆ 1.8 ┆ virginica │
# └──────────────┴─────────────┴──────────────┴─────────────┴───────────┘
# 複数行のデータ取得
print(df[0:5])
# shape: (5, 5)
# ┌──────────────┬─────────────┬──────────────┬─────────────┬─────────┐
# │ sepal_length ┆ sepal_width ┆ petal_length ┆ petal_width ┆ species │
# │ --- ┆ --- ┆ --- ┆ --- ┆ --- │
# │ f64 ┆ f64 ┆ f64 ┆ f64 ┆ str │
# ╞══════════════╪═════════════╪══════════════╪═════════════╪═════════╡
# │ 5.1 ┆ 3.5 ┆ 1.4 ┆ 0.2 ┆ setosa │
# │ 4.9 ┆ 3.0 ┆ 1.4 ┆ 0.2 ┆ setosa │
# │ 4.7 ┆ 3.2 ┆ 1.3 ┆ 0.2 ┆ setosa │
# │ 4.6 ┆ 3.1 ┆ 1.5 ┆ 0.2 ┆ setosa │
# │ 5.0 ┆ 3.6 ┆ 1.4 ┆ 0.2 ┆ setosa │
# └──────────────┴─────────────┴──────────────┴─────────────┴─────────┘

特定の条件のデータのみ抽出したい場合はfilter()関数を使用します。

ここでは「Expressions」という構造を用いてフィルタリング条件を指定しています。
「Expressions are the core strength of Polars」とあるようにpolars独自の構造となり、様々な計算処理を定義することが出来ます。
Expressions

計算用methodも多く用意されています。
expressions methods

# sepal_lengthの値が6より大きいデータのみ抽出
print(df.filter(pl.col('sepal_length')>6))
# shape: (61, 5)
# ┌──────────────┬─────────────┬──────────────┬─────────────┬────────────┐
# │ sepal_length ┆ sepal_width ┆ petal_length ┆ petal_width ┆ species │
# │ --- ┆ --- ┆ --- ┆ --- ┆ --- │
# │ f64 ┆ f64 ┆ f64 ┆ f64 ┆ str │
# ╞══════════════╪═════════════╪══════════════╪═════════════╪════════════╡
# │ 7.0 ┆ 3.2 ┆ 4.7 ┆ 1.4 ┆ versicolor │
# │ 6.4 ┆ 3.2 ┆ 4.5 ┆ 1.5 ┆ versicolor │
# │ 6.9 ┆ 3.1 ┆ 4.9 ┆ 1.5 ┆ versicolor │
# │ 6.5 ┆ 2.8 ┆ 4.6 ┆ 1.5 ┆ versicolor │
# │ ... ┆ ... ┆ ... ┆ ... ┆ ... │
# │ 6.7 ┆ 3.0 ┆ 5.2 ┆ 2.3 ┆ virginica │
# │ 6.3 ┆ 2.5 ┆ 5.0 ┆ 1.9 ┆ virginica │
# │ 6.5 ┆ 3.0 ┆ 5.2 ┆ 2.0 ┆ virginica │
# │ 6.2 ┆ 3.4 ┆ 5.4 ┆ 2.3 ┆ virginica │
# └──────────────┴─────────────┴──────────────┴─────────────┴────────────┘
# sepal_lengthの値が6より大きい、かつpetal_lengthの値が6より大きいデータのみ抽出
print(df.filter((pl.col('sepal_length')>6) & (pl.col('petal_length')>6)))
# shape: (9, 5)
# ┌──────────────┬─────────────┬──────────────┬─────────────┬───────────┐
# │ sepal_length ┆ sepal_width ┆ petal_length ┆ petal_width ┆ species │
# │ --- ┆ --- ┆ --- ┆ --- ┆ --- │
# │ f64 ┆ f64 ┆ f64 ┆ f64 ┆ str │
# ╞══════════════╪═════════════╪══════════════╪═════════════╪═══════════╡
# │ 7.6 ┆ 3.0 ┆ 6.6 ┆ 2.1 ┆ virginica │
# │ 7.3 ┆ 2.9 ┆ 6.3 ┆ 1.8 ┆ virginica │
# │ 7.2 ┆ 3.6 ┆ 6.1 ┆ 2.5 ┆ virginica │
# │ 7.7 ┆ 3.8 ┆ 6.7 ┆ 2.2 ┆ virginica │
# │ ... ┆ ... ┆ ... ┆ ... ┆ ... │
# │ 7.7 ┆ 2.8 ┆ 6.7 ┆ 2.0 ┆ virginica │
# │ 7.4 ┆ 2.8 ┆ 6.1 ┆ 1.9 ┆ virginica │
# │ 7.9 ┆ 3.8 ┆ 6.4 ┆ 2.0 ┆ virginica │
# │ 7.7 ┆ 3.0 ┆ 6.1 ┆ 2.3 ┆ virginica │
# └──────────────┴─────────────┴──────────────┴─────────────┴───────────┘
# 列同士の比較(sepal_widthの値がpetal_lengthより大きいデータのみ抽出)
print(df.filter(pl.col('species') == 'virginica'))
# shape: (50, 5)
# ┌──────────────┬─────────────┬──────────────┬─────────────┬─────────┐
# │ sepal_length ┆ sepal_width ┆ petal_length ┆ petal_width ┆ species │
# │ --- ┆ --- ┆ --- ┆ --- ┆ --- │
# │ f64 ┆ f64 ┆ f64 ┆ f64 ┆ str │
# ╞══════════════╪═════════════╪══════════════╪═════════════╪═════════╡
# │ 5.1 ┆ 3.5 ┆ 1.4 ┆ 0.2 ┆ setosa │
# │ 4.9 ┆ 3.0 ┆ 1.4 ┆ 0.2 ┆ setosa │
# │ 4.7 ┆ 3.2 ┆ 1.3 ┆ 0.2 ┆ setosa │
# │ 4.6 ┆ 3.1 ┆ 1.5 ┆ 0.2 ┆ setosa │
# │ ... ┆ ... ┆ ... ┆ ... ┆ ... │
# │ 5.1 ┆ 3.8 ┆ 1.6 ┆ 0.2 ┆ setosa │
# │ 4.6 ┆ 3.2 ┆ 1.4 ┆ 0.2 ┆ setosa │
# │ 5.3 ┆ 3.7 ┆ 1.5 ┆ 0.2 ┆ setosa │
# │ 5.0 ┆ 3.3 ┆ 1.4 ┆ 0.2 ┆ setosa │
# └──────────────┴─────────────┴──────────────┴─────────────┴─────────┘

列の抽出と追加

pandasと同じように列名を指定することでSeriesを取得することが出来ます。

print(df['sepal_length'])
# shape: (150,)
# Series: 'sepal_length' [f64]
# [
# 5.1
# 4.9
# 4.7
# 4.6
# 5.0
# 5.4
# 4.6
# 5.0
# 4.4
# 4.9
# 5.4
# 4.8
# ...
# 6.4
# 6.0
# 6.9
# 6.7
# 6.9
# 5.8
# 6.8
# 6.7
# 6.7
# 6.3
# 6.5
# 6.2
# 5.9
# ]

データフレーム形式で取得したい場合、複数列取得したい場合はselect()を使用することで可能です。

print(df.select('sepal_length'))
# shape: (150, 1)
# ┌──────────────┐
# │ sepal_length │
# │ --- │
# │ f64 │
# ╞══════════════╡
# │ 5.1 │
# │ 4.9 │
# │ 4.7 │
# │ 4.6 │
# │ ... │
# │ 6.3 │
# │ 6.5 │
# │ 6.2 │
# │ 5.9 │
# └──────────────┘
print(df.select(['sepal_length', 'species']))
# shape: (150, 2)
# ┌──────────────┬───────────┐
# │ sepal_length ┆ species │
# │ --- ┆ --- │
# │ f64 ┆ str │
# ╞══════════════╪═══════════╡
# │ 5.1 ┆ setosa │
# │ 4.9 ┆ setosa │
# │ 4.7 ┆ setosa │
# │ 4.6 ┆ setosa │
# │ ... ┆ ... │
# │ 6.3 ┆ virginica │
# │ 6.5 ┆ virginica │
# │ 6.2 ┆ virginica │
# │ 5.9 ┆ virginica │
# └──────────────┴───────────┘

また、「行の抽出」で使用したfilter()と同じようにselect()でも「Expressions」を使用することが出来ます。
例えば、下記の様にすることでsepal_length列のすべてのデータにに10を足したデータを取得することが出来ます。

print(df.select(pl.col('sepal_length')+10))
# shape: (150, 1)
# ┌──────────────┐
# │ sepal_length │
# │ --- │
# │ f64 │
# ╞══════════════╡
# │ 15.1 │
# │ 14.9 │
# │ 14.7 │
# │ 14.6 │
# │ ... │
# │ 16.3 │
# │ 16.5 │
# │ 16.2 │
# │ 15.9 │
# └──────────────┘

また、polarsではwith_columns()を使用することで列の追加が可能です。
先ほど作成したデータを新しい列として追加してみます。
ここで1点注意すべきなのがカラム名です。
polarsでは列名の重複が許されていないため alias()を使用して新しい列名を指定します。

print(df.with_columns((pl.col('sepal_length')+10).alias('additional')))
# shape: (150, 6)
# ┌──────────────┬─────────────┬──────────────┬─────────────┬───────────┬────────────┐
# │ sepal_length ┆ sepal_width ┆ petal_length ┆ petal_width ┆ species ┆ additional │
# │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
# │ f64 ┆ f64 ┆ f64 ┆ f64 ┆ str ┆ f64 │
# ╞══════════════╪═════════════╪══════════════╪═════════════╪═══════════╪════════════╡
# │ 5.1 ┆ 3.5 ┆ 1.4 ┆ 0.2 ┆ setosa ┆ 15.1 │
# │ 4.9 ┆ 3.0 ┆ 1.4 ┆ 0.2 ┆ setosa ┆ 14.9 │
# │ 4.7 ┆ 3.2 ┆ 1.3 ┆ 0.2 ┆ setosa ┆ 14.7 │
# │ 4.6 ┆ 3.1 ┆ 1.5 ┆ 0.2 ┆ setosa ┆ 14.6 │
# │ ... ┆ ... ┆ ... ┆ ... ┆ ... ┆ ... │
# │ 6.3 ┆ 2.5 ┆ 5.0 ┆ 1.9 ┆ virginica ┆ 16.3 │
# │ 6.5 ┆ 3.0 ┆ 5.2 ┆ 2.0 ┆ virginica ┆ 16.5 │
# │ 6.2 ┆ 3.4 ┆ 5.4 ┆ 2.3 ┆ virginica ┆ 16.2 │
# │ 5.9 ┆ 3.0 ┆ 5.1 ┆ 1.8 ┆ virginica ┆ 15.9 │
# └──────────────┴─────────────┴──────────────┴─────────────┴───────────┴────────────┘

とりあえず軽く触ってみましたが、Expressionsをどれだけ使いこなせるかがポイントの様です。
次回はもう少しExpressions周りの処理を触ってみようと思います。