【Polars】データ結合の方法 joinの使い方から最適化まで解説

PC
この記事は約14分で読めます。
記事内に広告が含まれています

Polarsは、データ操作において強力かつ高速なツールであり、特に大規模データセットの処理に優れています。この記事では、Polarsを使ったデータ結合(join)について、詳細に解説していきます。データサイエンスやデータ分析において、異なるデータセットを結合して分析を行うことはよくある作業です。Polarsは、その結合操作を効率的に行うための豊富な機能を提供しています。

amazonタイムセールのリンク

データ結合とは

データ結合(データの結合)とは、複数のデータフレームを共通のキー(列)に基づいて組み合わせる操作のことです。データベースでの「JOIN」操作と同じ概念で、結合する際に基準とする列を用いてデータフレームを統合します。

データ結合の例としては、顧客情報のテーブルと購入履歴のテーブルを顧客IDで結合し、購入者ごとの詳細な情報を得るといった操作が挙げられます。

主なデータ結合の種類

データ結合にはいくつかの種類があります。Polarsでも同様の種類がサポートされており、以下のものが基本です。

  1. 内部結合(Inner Join)
    • 両方のデータフレームに存在する共通キーのデータのみを取得します。
  2. 外部結合(Outer Join)
    • 結合キーがどちらかのデータフレームに存在するすべてのデータを取得します。存在しない部分は欠損値として扱われます。
  3. 左結合(Left Join)
    • 左側のデータフレームに存在するすべてのデータを取得し、右側に存在しない部分は欠損値とします。
  4. 右結合(Right Join)
    • 右側のデータフレームに存在するすべてのデータを取得し、左側に存在しない部分は欠損値とします。

次に、これらの結合方法をPolarsでどのように実装するかを具体的に説明します。

Polarsでのデータ結合の実装

Polarsでは、join()メソッドを使用してデータフレームを結合します。基本的な使用方法としては、以下のような流れで結合を行います。

import polars as pl

# サンプルデータフレームを作成
df1 = pl.DataFrame({
    "key": [1, 2, 3, 4],
    "value_df1": ["A", "B", "C", "D"]
})

df2 = pl.DataFrame({
    "key": [3, 4, 5, 6],
    "value_df2": ["X", "Y", "Z", "W"]
})

# 内部結合 (Inner Join)
result_inner = df1.join(df2, on="key", how="inner")
print(result_inner)

内部結合(Inner Join)

how="inner"を指定することで、内部結合を行います。上記の例では、key列を基準に両方のデータフレームに共通するデータ(key = 3と4)が結合されます。結果は以下のようになります。

shape: (2, 3)
┌─────┬──────────┬──────────┐
│ key │ value_df1│ value_df2│
├─────┼──────────┼──────────┤
│ 3   │ C        │ X        │
│ 4   │ D        │ Y        │
└─────┴──────────┴──────────┘

外部結合(Outer Join)

外部結合を行う場合は、how="outer"を指定します。これは両方のデータフレームのすべてのデータを取得し、共通でない部分には欠損値(None)が挿入されます。

# 外部結合 (Outer Join)
result_outer = df1.join(df2, on="key", how="outer")
print(result_outer)

結果は以下のようになります。

shape: (6, 3)
┌─────┬──────────┬──────────┐
│ key │ value_df1│ value_df2│
├─────┼──────────┼──────────┤
│ 1   │ A        │ null     │
│ 2   │ B        │ null     │
│ 3   │ C        │ X        │
│ 4   │ D        │ Y        │
│ 5   │ null     │ Z        │
│ 6   │ null     │ W        │
└─────┴──────────┴──────────┘

左結合(Left Join)

左結合は、how="left"を指定します。左側のデータフレームに含まれるすべての行が取得され、右側のデータフレームに一致しない部分はnullが挿入されます。

# 左結合 (Left Join)
result_left = df1.join(df2, on="key", how="left")
print(result_left)

結果は以下のようになります。

shape: (4, 3)
┌─────┬──────────┬──────────┐
│ key │ value_df1│ value_df2│
├─────┼──────────┼──────────┤
│ 1   │ A        │ null     │
│ 2   │ B        │ null     │
│ 3   │ C        │ X        │
│ 4   │ D        │ Y        │
└─────┴──────────┴──────────┘

右結合(Right Join)

右結合は、how="right"を指定します。これは左結合の逆で、右側のデータフレームに含まれるすべての行を取得し、左側に存在しない部分はnullが挿入されます。

# 右結合 (Right Join)
result_right = df1.join(df2, on="key", how="right")
print(result_right)

結果は以下のようになります。

shape: (4, 3)
┌─────┬──────────┬──────────┐
│ key │ value_df1│ value_df2│
├─────┼──────────┼──────────┤
│ 3   │ C        │ X        │
│ 4   │ D        │ Y        │
│ 5   │ null     │ Z        │
│ 6   │ null     │ W        │
└─────┴──────────┴──────────┘

Polarsの結合操作における高度な使用法

Polarsでは、複数の列をキーにして結合することもできます。これにより、より複雑なデータセットの結合が可能です。また、結合キーとして異なる列名を指定することもできます。

複数の列をキーにする結合

# サンプルデータフレームを作成
df1 = pl.DataFrame({
    "key1": [1, 2, 3, 4],
    "key2": ['A', 'B', 'C', 'D'],
    "value_df1": ["a", "b", "c", "d"]
})

df2 = pl.DataFrame({
    "key1": [3, 4, 5, 6],
    "key2": ['C', 'D', 'E', 'F'],
    "value_df2": ["x", "y", "z", "w"]
})

# 複数列での内部結合
result_multi_key = df1.join(df2, on=["key1", "key2"], how="inner")
print(result_multi_key)

異なる列名をキーにする結合

Polarsでは、結合するデータフレームの列名が異なる場合でも、キーを指定して結合できます。

# 異なる列名での結合
df1 = pl.DataFrame({
    "id": [1, 2, 3, 4],
    "value_df1": ["a", "b", "c", "d"]
})

df2 = pl.DataFrame({
    "key": [3, 4, 5, 6],
    "value_df2": ["x", "y", "z", "w"]
})

# 異なる列を結合キーに指定
result_different_keys = df1.join(df2, left_on="id", right_on="key", how="inner")
print(result_different_keys)

この場合、df1id列とdf2key列をキーとして内部結合が行われます。結果は以下のようになります。

shape: (2, 3)
┌─────┬──────────┬──────────┐
│ id  │ value_df1│ value_df2│
├─────┼──────────┼──────────┤
│ 3   │ c        │ x        │
│ 4   │ d        │ y        │
└─────┴──────────┴──────────┘

left_onright_onの引数を使うことで、異なる列名のデータフレームでもスムーズに結合できるのがPolarsの強力な特徴です。

結合におけるパフォーマンス最適化

Polarsは、パフォーマンスに優れたフレームワークであるため、大規模データの処理に適しています。しかし、データ量が非常に大きい場合には、いくつかのテクニックを活用してさらにパフォーマンスを向上させることができます。

キー列にインデックスを設定する

Polarsでは、データ結合に使用するキー列にインデックスを設定することで、結合の速度を改善できます。これは、データの検索が高速に行われるためです。

ただし、Polarsは自動的に効率的な結合方法を選択するため、特定のケースではインデックス設定は不要な場合もあります。データのサイズや結合の内容によって、インデックスの有無を検討すると良いでしょう。

メモリの使用量に注意する

大規模データを扱う場合、結合操作に大量のメモリを消費することがあります。Polarsはメモリ管理に優れているため、大量のデータも効率的に処理できますが、メモリ不足の際には以下の対策が考えられます。

  • 必要な列だけを選択して結合する。
  • データを事前にフィルタリングして、結合に不要な行を除外する。

実用的なデータ結合の例

ここまで、Polarsを使ったデータ結合の基本を説明しました。次に、より実用的なデータセットを用いて、複数の結合操作を組み合わせる例を見ていきましょう。

サンプルデータ: 顧客情報と注文履歴の結合

例えば、ある企業の顧客情報データ(customers)と、その企業が受けた注文のデータ(orders)を結合して、顧客ごとの全体的な注文履歴を分析するケースを考えます。

# 顧客情報データフレーム
customers = pl.DataFrame({
    "customer_id": [1, 2, 3, 4],
    "customer_name": ["Alice", "Bob", "Charlie", "David"]
})

# 注文データフレーム
orders = pl.DataFrame({
    "order_id": [101, 102, 103, 104, 105],
    "customer_id": [1, 2, 2, 3, 4],
    "order_amount": [250, 450, 300, 400, 500]
})

# 顧客情報と注文情報を左結合
customer_orders = customers.join(orders, on="customer_id", how="left")
print(customer_orders)

この場合、顧客情報に基づいて、注文データが結合されます。customer_id列をキーとして左結合を行っているため、すべての顧客が保持され、注文が存在しない顧客にはnullが挿入されます。

結果は以下のようになります。

shape: (5, 4)
┌─────────────┬───────────────┬───────────┬─────────────┐
│ customer_id │ customer_name │ order_id  │ order_amount│
├─────────────┼───────────────┼───────────┼─────────────┤
│ 1           │ Alice         │ 101       │ 250         │
│ 2           │ Bob           │ 102       │ 450         │
│ 2           │ Bob           │ 103       │ 300         │
│ 3           │ Charlie       │ 104       │ 400         │
│ 4           │ David         │ 105       │ 500         │
└─────────────┴───────────────┴───────────┴─────────────┘

このように、Polarsを使うことで、複数のデータフレームをシンプルかつ効率的に結合し、必要な情報を素早く得ることができます。

結合後のデータの整形

結合後のデータに対して、さらに操作を加えることで、分析に適した形に整形することができます。例えば、結合後に集計操作を行ったり、データのフィルタリングを行ったりすることができます。

注文金額の合計を顧客ごとに集計する

顧客ごとの注文金額の合計を計算する例を見てみましょう。結合後のデータをgroupby()でグループ化し、集計します。

# 顧客ごとの注文金額を集計
total_order_amounts = customer_orders.groupby("customer_name").agg([
    pl.col("order_amount").sum().alias("total_order_amount")
])
print(total_order_amounts)

結果は以下のようになります。

shape: (4, 2)
┌───────────────┬──────────────────┐
│ customer_name │ total_order_amount│
├───────────────┼──────────────────┤
│ Alice         │ 250              │
│ Bob           │ 750              │
│ Charlie       │ 400              │
│ David         │ 500              │
└───────────────┴──────────────────┘

Bobのように複数の注文がある場合は、その注文金額が合計されています。

データのフィルタリング

また、特定の条件に基づいてデータをフィルタリングすることも可能です。例えば、注文金額が400以上の顧客のみを抽出する場合は、以下のようにします。

# 注文金額が400以上の顧客をフィルタリング
high_value_customers = total_order_amounts.filter(pl.col("total_order_amount") >= 400)
print(high_value_customers)

結果は以下のようになります。

shape: (3, 2)
┌───────────────┬──────────────────┐
│ customer_name │ total_order_amount│
├───────────────┼──────────────────┤
│ Bob           │ 750              │
│ Charlie       │ 400              │
│ David         │ 500              │
└───────────────┴──────────────────┘

このように、結合後のデータに対して様々な操作を加えることで、必要な情報を抽出し、さらに深い分析を行うことができます。

Polarsの結合機能の活用例

Polarsのデータ結合は、他のデータ操作と組み合わせることで、非常に柔軟なデータ処理が可能です。ここでは、Polarsの結合機能を活用したいくつかの例を紹介します。

複数のデータセットを結合して時系列データを分析

時系列データを扱う場合、異なる期間のデータを結合し、時系列に沿って分析することがよくあります。例えば、売上データとマーケティングキャンペーンのデータを結合し、売上に与える影響を分析するケースなどです。

顧客の購入履歴を追跡してマーケティング戦略を最適化

顧客の購入履歴を結合し、特定の商品の購入パターンや購入頻度を分析することで、マーケティング戦略を最適化できます。例えば、Polarsを使って、リピーターや高額購入者を特定し、特別なキャンペーンを行う際のターゲット選定に活用することが可能です。

商品カタログデータの結合による在庫管理の改善

在庫管理において、商品カタログデータと実際の販売データを結合することで

、在庫の最適化が図れます。Polarsを用いることで、リアルタイムのデータ分析が容易になり、需要予測や補充計画の策定に役立てることができます。

まとめ

Polarsを使用したデータフレームの結合は、高速かつ効率的であり、大規模なデータセットを扱う際にも非常に有用です。本記事で紹介したように、内部結合や外部結合などの基本的な結合操作だけでなく、結合後のデータ処理も簡単に行うことができます。

Polarsを活用することで、データ分析や機械学習プロジェクトのデータ前処理をスムーズに進めることができるでしょう。

タイトルとURLをコピーしました