{
"cells": [
{
"cell_type": "markdown",
"id": "aeff477e-497d-4f08-be09-a7d0eddc8143",
"metadata": {},
"source": [
"# グループ処理"
]
},
{
"cell_type": "markdown",
"id": "aef443e8-fe28-477f-9119-fa01a1cfde59",
"metadata": {},
"source": [
"データ分析の中で、グループ処理は特に重要な役割を果たします。この章では、Polarsのグループ処理に関する主要な関数を紹介し、それぞれの使い方と応用例を説明します。\n",
"\n",
"以下の関数について詳しく見ていきます:\n",
"\n",
"- `group_by`: データフレームを特定の列でグループ化します。\n",
"- `agg`: グループ化したデータに対して集計処理を行います。\n",
"- `over`: ウィンドウ関数を使用して、グループごとに計算を行います。\n",
"- `group_by_dynamic`: 時間ベースの動的なグループ化を実現します。\n",
"- `rolling`: ローリングウィンドウによる計算を行います。\n",
"\n",
"これらの機能を活用することで、大規模なデータセットに対する高度な分析を効率的に行うことができます。"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "8c84ceee-5a9d-4ed5-a94f-e3286d24b57e",
"metadata": {},
"outputs": [],
"source": [
"import polars as pl\n",
"from helper.jupyter import row"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "c35901a0-51fb-40d2-8bac-c403dd8af0af",
"metadata": {},
"source": [
"## group_by\n",
"\n",
"`DataFrame.group_by()`メソッドを使用して、グループ化オブジェクト`GroupBy`を作成します。`maintain_order`引数を`True`に指定することで、元のデータの順序を維持したままグループ化を行います。これにより、グループの順番は元データ中に表れる順番を使用します。"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "80b54ea6-1fed-4036-9976-0b037e5e126a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"polars.dataframe.group_by.GroupBy"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = pl.DataFrame(\n",
" dict(\n",
" g=['A', 'B', 'C', 'A', 'B', 'B'], \n",
" x=[1, 2, 3, 4, 5, 6])\n",
")\n",
"g = df.group_by('g', maintain_order=True)\n",
"type(g)"
]
},
{
"cell_type": "markdown",
"id": "b9cf6c5d-5016-4b86-9679-060dbb33f214",
"metadata": {},
"source": [
"`GroupBy`オブジェクトの`.agg()`メソッドを使用して、複数の演算式でグループごとのデータを処理し、その結果をまとめます。一部のよく使用する機能は、`GroupBy`オブジェクトのメソッドとしても提供されます。たとえば、`.mean()`は各グループの平均値を計算し、`.first()`は各グループの最初の行を出力します。以下のプログラムは、`.mean()`と`.first()`に相当する演算式の例です。"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "ee4e9b1f-1d0c-4252-860c-397e226e0f54",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
" shape: (3, 2)g | x |
---|
str | f64 | "A" | 2.5 | "B" | 4.333333 | "C" | 3.0 |
| \n",
" shape: (3, 2)g | x |
---|
str | f64 | "A" | 2.5 | "B" | 4.333333 | "C" | 3.0 |
| | |
"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"row(\n",
" g.mean(), \n",
" g.agg(pl.all().mean()),\n",
" g.first(),\n",
" g.agg(pl.all().first())\n",
")"
]
},
{
"cell_type": "markdown",
"id": "2229d289-3968-46ad-a70d-c388424a19fd",
"metadata": {},
"source": [
"`.agg()`メソッド内の演算式が複数の値を出力する場合、結果列はリストになります。`GroupBy.head()`と同じ結果を得るためには、`.explode()`を使用してリスト内のデータを縦に結合する必要があります。"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "4ff9897d-4c1a-4378-861f-a8bb2b195388",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" shape: (5, 2)g | x |
---|
str | i64 | "A" | 1 | "A" | 4 | "B" | 2 | "B" | 5 | "C" | 3 |
| \n",
" shape: (3, 2)g | x |
---|
str | list[i64] | "A" | [1, 4] | "B" | [2, 5] | "C" | [3] |
| \n",
" shape: (5, 2)g | x |
---|
str | i64 | "A" | 1 | "A" | 4 | "B" | 2 | "B" | 5 | "C" | 3 |
|
"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"row(\n",
" g.head(2), \n",
" g.agg(pl.all().head(2)), \n",
" g.agg(pl.all().head(2)).explode('x')\n",
")"
]
},
{
"cell_type": "markdown",
"id": "db6b20c2-83cb-4844-b715-0949de87e945",
"metadata": {},
"source": [
"`.agg()` メソッド内で `map_batches()` を使用してユーザー関数で演算を行う場合は、[「GroupBy.agg() 内で map_batches() を使用する」](map_batches_in_agg) を参照してください。"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "37ef9604-9753-436b-adc6-89db05216b78",
"metadata": {},
"source": [
"(over)=\n",
"## over\n",
"\n",
"演算式の中で `.over()` を使うと、グループごとの処理が可能です。次のプログラムでは、`g` 列のグループごとに `x` 列の平均値を計算しています。`.group_by().agg()` を使うと、各グループにつき 1 行の結果が得られますが、`.over()` を使用すると、計算結果が元のデータに対応するすべての行に反映されます。 "
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "8cbd4c0e-0a62-474d-86e6-2d93652f44bd",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (6, 3)g | x | x_mean |
---|
str | i64 | f64 |
"A" | 1 | 2.5 |
"B" | 2 | 4.333333 |
"C" | 3 | 3.0 |
"A" | 4 | 2.5 |
"B" | 5 | 4.333333 |
"B" | 6 | 4.333333 |
"
],
"text/plain": [
"shape: (6, 3)\n",
"┌─────┬─────┬──────────┐\n",
"│ g ┆ x ┆ x_mean │\n",
"│ --- ┆ --- ┆ --- │\n",
"│ str ┆ i64 ┆ f64 │\n",
"╞═════╪═════╪══════════╡\n",
"│ A ┆ 1 ┆ 2.5 │\n",
"│ B ┆ 2 ┆ 4.333333 │\n",
"│ C ┆ 3 ┆ 3.0 │\n",
"│ A ┆ 4 ┆ 2.5 │\n",
"│ B ┆ 5 ┆ 4.333333 │\n",
"│ B ┆ 6 ┆ 4.333333 │\n",
"└─────┴─────┴──────────┘"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.with_columns(\n",
" pl.col('x').mean()\n",
" .over('g').alias('x_mean')\n",
")"
]
},
{
"cell_type": "markdown",
"id": "a4ab53ad-94ee-460f-bde7-17d19ca0e84d",
"metadata": {},
"source": [
"次のプログラムでは、`g` 列のグループごとに `x` 列の平均値を計算し、`x`列から平均値を引いた結果を新しい列`x_sub_mean`に格納します。この演算では、グループごとの計算結果のデータ数は変わらず、計算結果が元データの対応する行に反映されます。 "
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "6b637b9d-5cef-4b4a-a561-84b8acb7ef32",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (6, 3)g | x | x_sub_mean |
---|
str | i64 | f64 |
"A" | 1 | -1.5 |
"B" | 2 | -2.333333 |
"C" | 3 | 0.0 |
"A" | 4 | 1.5 |
"B" | 5 | 0.666667 |
"B" | 6 | 1.666667 |
"
],
"text/plain": [
"shape: (6, 3)\n",
"┌─────┬─────┬────────────┐\n",
"│ g ┆ x ┆ x_sub_mean │\n",
"│ --- ┆ --- ┆ --- │\n",
"│ str ┆ i64 ┆ f64 │\n",
"╞═════╪═════╪════════════╡\n",
"│ A ┆ 1 ┆ -1.5 │\n",
"│ B ┆ 2 ┆ -2.333333 │\n",
"│ C ┆ 3 ┆ 0.0 │\n",
"│ A ┆ 4 ┆ 1.5 │\n",
"│ B ┆ 5 ┆ 0.666667 │\n",
"│ B ┆ 6 ┆ 1.666667 │\n",
"└─────┴─────┴────────────┘"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.with_columns(\n",
" (pl.col('x') - pl.col('x').mean())\n",
" .over('g')\n",
" .alias('x_sub_mean')\n",
")"
]
},
{
"cell_type": "markdown",
"id": "3b60aba7-851e-4a32-9268-0f8feb45f4b5",
"metadata": {},
"source": [
"グループごとの計算結果の長さが1でも不変でもない場合、エラーになりますが、`over()`の`mapping_strategy`引数を`'join'`に設定すると、この結果を一つのリストとして元の場所に入れます。次のプログラムでは、`g`列のグループごとに`x`列の先頭2つの値を取得し、それをリストとして新しい列に格納します。"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "a8901c76-757f-4e0b-ad86-76700a37e58d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (6, 3)g | x | x_head |
---|
str | i64 | list[i64] |
"A" | 1 | [1, 4] |
"B" | 2 | [2, 5] |
"C" | 3 | [3] |
"A" | 4 | [1, 4] |
"B" | 5 | [2, 5] |
"B" | 6 | [2, 5] |
"
],
"text/plain": [
"shape: (6, 3)\n",
"┌─────┬─────┬───────────┐\n",
"│ g ┆ x ┆ x_head │\n",
"│ --- ┆ --- ┆ --- │\n",
"│ str ┆ i64 ┆ list[i64] │\n",
"╞═════╪═════╪═══════════╡\n",
"│ A ┆ 1 ┆ [1, 4] │\n",
"│ B ┆ 2 ┆ [2, 5] │\n",
"│ C ┆ 3 ┆ [3] │\n",
"│ A ┆ 4 ┆ [1, 4] │\n",
"│ B ┆ 5 ┆ [2, 5] │\n",
"│ B ┆ 6 ┆ [2, 5] │\n",
"└─────┴─────┴───────────┘"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.with_columns(\n",
" pl.col('x').head(2)\n",
" .over('g', mapping_strategy='join')\n",
" .alias('x_head')\n",
")"
]
},
{
"cell_type": "markdown",
"id": "0fcfc86a-8953-4697-8fbd-9357e4d3b1c5",
"metadata": {},
"source": [
"次のプログラムでは、`g`列のグループごとに`x`列の最小値と最大値を取得し、それをリストとして新しい列に格納します。"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "e415ddfc-d7c7-4406-af8e-850dbe917d1b",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (6, 3)g | x | x_min_max |
---|
str | i64 | list[i64] |
"A" | 1 | [1, 4] |
"B" | 2 | [2, 6] |
"C" | 3 | [3, 3] |
"A" | 4 | [1, 4] |
"B" | 5 | [2, 6] |
"B" | 6 | [2, 6] |
"
],
"text/plain": [
"shape: (6, 3)\n",
"┌─────┬─────┬───────────┐\n",
"│ g ┆ x ┆ x_min_max │\n",
"│ --- ┆ --- ┆ --- │\n",
"│ str ┆ i64 ┆ list[i64] │\n",
"╞═════╪═════╪═══════════╡\n",
"│ A ┆ 1 ┆ [1, 4] │\n",
"│ B ┆ 2 ┆ [2, 6] │\n",
"│ C ┆ 3 ┆ [3, 3] │\n",
"│ A ┆ 4 ┆ [1, 4] │\n",
"│ B ┆ 5 ┆ [2, 6] │\n",
"│ B ┆ 6 ┆ [2, 6] │\n",
"└─────┴─────┴───────────┘"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.with_columns(\n",
" pl.col('x').min().append(pl.col('x').max())\n",
" .over('g', mapping_strategy='join')\n",
" .alias('x_min_max')\n",
")"
]
},
{
"cell_type": "markdown",
"id": "82771504-730a-4493-84fa-0a5415b61581",
"metadata": {},
"source": [
"`mapping_strategy`を`'explode'`に設定すると、各グループの結果を縦に結合します。これは、`group_by().agg().explode()`と同じ結果になります。次のプログラムでは、`g`列のグループごとに`x`列の先頭2つの値を取得し、各グループの結果を縦に結合します。"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "63b1df04-89bc-4f48-a541-93dcae4cb557",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (5, 2)g | x |
---|
str | i64 |
"A" | 1 |
"A" | 4 |
"B" | 2 |
"B" | 5 |
"C" | 3 |
"
],
"text/plain": [
"shape: (5, 2)\n",
"┌─────┬─────┐\n",
"│ g ┆ x │\n",
"│ --- ┆ --- │\n",
"│ str ┆ i64 │\n",
"╞═════╪═════╡\n",
"│ A ┆ 1 │\n",
"│ A ┆ 4 │\n",
"│ B ┆ 2 │\n",
"│ B ┆ 5 │\n",
"│ C ┆ 3 │\n",
"└─────┴─────┘"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.select(\n",
" pl.col('g', 'x').head(2)\n",
" .over('g', mapping_strategy='explode')\n",
")"
]
},
{
"cell_type": "markdown",
"id": "e3a16940-cbdd-42a5-b36b-9ccefd8fda40",
"metadata": {},
"source": [
"`filter()`メソッドにも`over()`の式を使うことができます。次のプログラムでは、`g`列のグループごとに、`x`列の値がそのグループの平均値以上の行をフィルタリングして出力します。"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "38048f48-0f95-4cae-af09-3b2cc94140f2",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
"shape: (4, 2)\n",
"┌─────┬─────┐\n",
"│ g ┆ x │\n",
"│ --- ┆ --- │\n",
"│ str ┆ i64 │\n",
"╞═════╪═════╡\n",
"│ C ┆ 3 │\n",
"│ A ┆ 4 │\n",
"│ B ┆ 5 │\n",
"│ B ┆ 6 │\n",
"└─────┴─────┘"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.filter(\n",
" (pl.col('x') >= pl.col('x').mean())\n",
" .over('g')\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "717eaf6b-0c95-4e97-b1ef-1fce4cb42531",
"metadata": {},
"source": [
"## group_by_dynamic\n",
"\n",
"`group_by_dynamic(index)` メソッドは、`index` 列の値に基づいて動的にグループ化を行います。グループの開始点 `start` は、`start_by`、`every`、`offset` などの引数、および `index` 列の最初の値 `value` によって決まります。`start_by` 引数がデフォルト値の `\"window\"` の場合、`start` は次のように計算されます:\n",
"\n",
"```\n",
"start = value - (value - offset) % every\n",
"```\n",
"\n",
"`start_by` 引数が `\"datapoint\"` の場合、`start` は最初の値 `value` になります。\n",
"\n",
"`start` の値が決まると、次の式で各グループの範囲が計算されます。`period` 引数のデフォルト値は `every` と同じです。\n",
"\n",
"```\n",
"[start, start + period)\n",
"[start + every, start + every + period)\n",
"...\n",
"[start + i * every, start + i * every + period)\n",
"```\n",
"\n",
"各グループの開始値は、そのグループのキーになります。`include_boundaries` 引数が `True` の場合、集計結果に `_lower_boundary` と `_upper_boundary` の 2 つの列が追加され、それぞれグループの開始値(含まれる)と終了値(含まれない)を表します。\n",
"\n",
"たとえば、次のプログラムでは、`index` 列の値に基づき、3 単位の移動量で 3 単位ごとにグループ化し、それぞれのグループに対して集計を行います。 "
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "1652e2b2-8014-463d-9771-54a99309fd61",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
" | \n",
" shape: (4, 4)_lower_boundary | _upper_boundary | index | index_in_group |
---|
i64 | i64 | i64 | list[i64] | 0 | 3 | 0 | [1, 2] | 3 | 6 | 3 | [4, 5] | 6 | 9 | 6 | [6, 8] | 9 | 12 | 9 | [9, 10, 11] |
|
"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"index = [1, 2, 4, 5, 6, 8, 9, 10, 11]\n",
"df = pl.DataFrame(dict(index=index)).set_sorted('index')\n",
"\n",
"g = df.group_by_dynamic('index', every='3i', offset='0i', include_boundaries=True)\n",
"row(df, g.agg(pl.col(\"index\").alias('index_in_group')))"
]
},
{
"cell_type": "markdown",
"id": "afbfe4ad-1e95-4a99-81bd-e6c6a3ff0607",
"metadata": {},
"source": [
"分かりやすくするために、本書では `plot_group_by_dynamic()` 関数を使用して、`group_by_dynamic()` の結果を可視化します。出力されるグラフでは、青い線がグループ化の基準となる `index` 列の値を示し、赤い線がグループ化後のキー列の値を表します。緑のブロックは各グループの範囲を示しており、この関数は各グループに属する `index` の値も出力します。 "
]
},
{
"cell_type": "code",
"execution_count": 82,
"id": "e0d6849b-f01d-4c36-882e-9f5867eb6daa",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1, 2], [4, 5], [6, 8], [9, 10, 11]]\n"
]
},
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"execution_count": 82,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from helper import utils\n",
"from helper.utils import plot_group_by_dynamic\n",
"from matplotlib import pyplot as plt\n",
"plt.ioff()\n",
"plot_group_by_dynamic(index, every='3i', offset='0i')"
]
},
{
"cell_type": "markdown",
"id": "bdaf191e-0be5-432f-8195-2588a081d977",
"metadata": {},
"source": [
"次に、`offset` 引数の影響を示すグラフを出力します。"
]
},
{
"cell_type": "code",
"execution_count": 77,
"id": "3be7ba27-bf79-4f8f-99d5-51602f1c5f9b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1, 2], [4, 5, 6], [8, 9], [10, 11]]\n"
]
},
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"execution_count": 77,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"plot_group_by_dynamic(index, every='3i', offset='1i')"
]
},
{
"cell_type": "code",
"execution_count": 78,
"id": "7457a6f8-5c7a-4f60-8af3-57ad7f6fc0ef",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1], [2, 4], [5, 6], [8, 9, 10], [11]]\n"
]
},
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"execution_count": 78,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"plot_group_by_dynamic(index, every='3i', offset='2i')"
]
},
{
"cell_type": "code",
"execution_count": 79,
"id": "4beeb5d2-0ed8-48fb-992e-33593f9d3b1f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1], [2, 4], [5, 6], [8, 9, 10], [11]]\n"
]
},
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"execution_count": 79,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"plot_group_by_dynamic(index, every='3i', offset='-1i')"
]
},
{
"cell_type": "markdown",
"id": "9482eafa-1ad1-4d75-9c26-f5c574c4b37f",
"metadata": {},
"source": [
"`start_by` 引数を `'datapoint'` に設定すると、最初のグループの開始値は `index` 列の最初の値に固定されるため、`offset` 引数は無効になります。"
]
},
{
"cell_type": "code",
"execution_count": 80,
"id": "adab4bec-76f5-474a-b4e8-80fb85834f94",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1, 2], [4, 5, 6], [8, 9], [10, 11]]\n"
]
},
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"execution_count": 80,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"plot_group_by_dynamic(index, every='3i', start_by='datapoint')"
]
},
{
"cell_type": "markdown",
"id": "5a529907-b772-4156-8e1c-9fdf8ad57b05",
"metadata": {},
"source": [
"`period` 引数のデフォルト値は `every` と同じであるため、各グループのウィンドウは重なりません。しかし、`period` を `every` より大きく設定すると、ウィンドウが重なり、一部の `index` 値が複数のグループに属するようになります。"
]
},
{
"cell_type": "code",
"execution_count": 81,
"id": "5a371212-194a-4f24-8856-19fcfeb23991",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1, 2, 4], [4, 5, 6], [6, 8, 9, 10], [9, 10, 11]]\n"
]
},
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"execution_count": 81,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"plot_group_by_dynamic(index, every='3i', period='5i')"
]
},
{
"cell_type": "markdown",
"id": "fbfa2c5b-8832-4c30-b16c-6cbdac005ddc",
"metadata": {},
"source": [
"次のプログラムでは、`index` 列に基づいて 1 単位ずつ移動しながら、3 単位ごとにグループ化を行います。"
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "f54e7cf6-71c7-43da-84a9-6b1fd5c380d3",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
" | \n",
" shape: (11, 4)_lower_boundary | _upper_boundary | index | index_in_group |
---|
i64 | i64 | i64 | list[i64] | 1 | 4 | 1 | [1, 2] | 2 | 5 | 2 | [2, 4] | 3 | 6 | 3 | [4, 5] | 4 | 7 | 4 | [4, 5, 6] | 5 | 8 | 5 | [5, 6] | … | … | … | … | 7 | 10 | 7 | [8, 9] | 8 | 11 | 8 | [8, 9, 10] | 9 | 12 | 9 | [9, 10, 11] | 10 | 13 | 10 | [10, 11] | 11 | 14 | 11 | [11] |
|
"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"g = df.group_by_dynamic('index', every='1i', period='3i', include_boundaries=True)\n",
"row(df, g.agg(pl.col(\"index\").alias('index_in_group')))"
]
},
{
"cell_type": "markdown",
"id": "7a966590-8c08-405e-b7d4-1730e146020f",
"metadata": {},
"source": [
"上の例では、分かりやすくするために整数列を用いてグループ化の方法を示しましたが、実際には時系列データに対してグループ化を行うことが一般的です。時系列データの場合、`every`、`period`、`offset` などの単位は、次のような形式で指定できます:\n",
"\n",
"- `1ns` (1ナノ秒) \n",
"- `1us` (1マイクロ秒) \n",
"- `1ms` (1ミリ秒) \n",
"- `1s` (1秒) \n",
"- `1m` (1分) \n",
"- `1h` (1時間) \n",
"- `1d` (1暦日) \n",
"- `1w` (1暦週) \n",
"- `1mo` (1暦月) \n",
"- `1q` (1暦四半期) \n",
"- `1y` (1暦年) \n",
"\n",
"これらの単位を使用することで、時系列データを柔軟にグループ化できます。"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "0f5c11cb-13c0-4d95-af0e-9cf79247b705",
"metadata": {},
"source": [
"## rolling \n",
"\n",
"`rolling(index)` メソッドは、`index` 列の値に基づいてローリングウィンドウを作成します。`period` および `offset` 引数を指定することで、ウィンドウの相対位置を調整できます。デフォルトでは、`offset` の値は `-period` に設定されています。 \n",
"\n",
"ローリングウィンドウの範囲は次のように決まります。`()` 側の値は含まれず、`[]` 側の値は含まれるため、開始値は除外され、終了値は含まれます。 \n",
"\n",
"```\n",
"(index[0] + offset, index[0] + offset + period]\n",
"...\n",
"(index[i] + offset, index[i] + offset + period]\n",
"```\n",
"\n",
"次のプログラムでは、`index` 列に基づいて、直前の 2 つのデータ点を含む 3 点のローリングウィンドウを作成し、そのウィンドウ内で集計を行います。 "
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "21873346-2ff9-4467-9e34-29f7fe05ba67",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (7, 2)index | value |
---|
i64 | list[i64] |
4 | [4] |
5 | [4, 5] |
9 | [9] |
10 | [9, 10] |
11 | [9, 10, 11] |
12 | [10, 11, 12] |
13 | [11, 12, 13] |
"
],
"text/plain": [
"shape: (7, 2)\n",
"┌───────┬──────────────┐\n",
"│ index ┆ value │\n",
"│ --- ┆ --- │\n",
"│ i64 ┆ list[i64] │\n",
"╞═══════╪══════════════╡\n",
"│ 4 ┆ [4] │\n",
"│ 5 ┆ [4, 5] │\n",
"│ 9 ┆ [9] │\n",
"│ 10 ┆ [9, 10] │\n",
"│ 11 ┆ [9, 10, 11] │\n",
"│ 12 ┆ [10, 11, 12] │\n",
"│ 13 ┆ [11, 12, 13] │\n",
"└───────┴──────────────┘"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g = df.rolling('index', period='3i')\n",
"g.agg(pl.col(\"value\"))"
]
},
{
"cell_type": "markdown",
"id": "48097c20-e15c-4089-a58b-f44f0e12234c",
"metadata": {},
"source": [
"次のプログラムでは、`index` 列に基づき、各データ点とその後の 2 つのデータ点を含む 3 点のローリングウィンドウを作成し、そのウィンドウ内で集計を行います。 "
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "e5abb804-4859-4551-b9f4-bc03aff08652",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (7, 2)index | value |
---|
i64 | list[i64] |
4 | [4, 5] |
5 | [5] |
9 | [9, 10, 11] |
10 | [10, 11, 12] |
11 | [11, 12, 13] |
12 | [12, 13] |
13 | [13] |
"
],
"text/plain": [
"shape: (7, 2)\n",
"┌───────┬──────────────┐\n",
"│ index ┆ value │\n",
"│ --- ┆ --- │\n",
"│ i64 ┆ list[i64] │\n",
"╞═══════╪══════════════╡\n",
"│ 4 ┆ [4, 5] │\n",
"│ 5 ┆ [5] │\n",
"│ 9 ┆ [9, 10, 11] │\n",
"│ 10 ┆ [10, 11, 12] │\n",
"│ 11 ┆ [11, 12, 13] │\n",
"│ 12 ┆ [12, 13] │\n",
"│ 13 ┆ [13] │\n",
"└───────┴──────────────┘"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g = df.rolling('index', period='3i', offset='-1i')\n",
"g.agg(pl.col(\"value\"))"
]
},
{
"cell_type": "markdown",
"id": "69740434-8851-4aa6-bb02-728377a04884",
"metadata": {},
"source": [
"固定点数の移動窓で処理する場合は、`int_range()`で作成した行番号に対して`rolling`処理を行います。以下のプログラムでは、データフレームの各行に対して、前の2つの行を含む合計3行のローリングウィンドウを適用し、`A`列の最大値と`B`列の最小値を計算します。\n",
"\n",
"次のコードでは、`int_range(0, pl.len())`を使って行番号を生成し、その行番号に基づいてローリングウィンドウを作成します。ウィンドウの期間は3行(`period='3i'`)で、`offset='-2i'`により、各ウィンドウは現在の行の2行前から始まります。集計では、`A`列の最大値と`B`列の最小値が計算され、結果として各行に対してこれらの統計値が追加されます。"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "a6c8f158-6526-4a2d-871e-4530638993db",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (8, 5)index | A | B | A_max | B_min |
---|
i64 | list[i64] | list[i64] | i64 | i64 |
0 | [5, 3] | [10, 20] | 5 | 10 |
1 | [5, 3, 8] | [10, 20, 10] | 8 | 10 |
2 | [3, 8, 9] | [20, 10, 2] | 9 | 2 |
3 | [8, 9, 10] | [10, 2, 3] | 10 | 2 |
4 | [9, 10, 1] | [2, 3, 5] | 10 | 2 |
5 | [10, 1, 2] | [3, 5, 0] | 10 | 0 |
6 | [1, 2, 4] | [5, 0, 7] | 4 | 0 |
7 | [2, 4] | [0, 7] | 4 | 0 |
"
],
"text/plain": [
"shape: (8, 5)\n",
"┌───────┬────────────┬──────────────┬───────┬───────┐\n",
"│ index ┆ A ┆ B ┆ A_max ┆ B_min │\n",
"│ --- ┆ --- ┆ --- ┆ --- ┆ --- │\n",
"│ i64 ┆ list[i64] ┆ list[i64] ┆ i64 ┆ i64 │\n",
"╞═══════╪════════════╪══════════════╪═══════╪═══════╡\n",
"│ 0 ┆ [5, 3] ┆ [10, 20] ┆ 5 ┆ 10 │\n",
"│ 1 ┆ [5, 3, 8] ┆ [10, 20, 10] ┆ 8 ┆ 10 │\n",
"│ 2 ┆ [3, 8, 9] ┆ [20, 10, 2] ┆ 9 ┆ 2 │\n",
"│ 3 ┆ [8, 9, 10] ┆ [10, 2, 3] ┆ 10 ┆ 2 │\n",
"│ 4 ┆ [9, 10, 1] ┆ [2, 3, 5] ┆ 10 ┆ 2 │\n",
"│ 5 ┆ [10, 1, 2] ┆ [3, 5, 0] ┆ 10 ┆ 0 │\n",
"│ 6 ┆ [1, 2, 4] ┆ [5, 0, 7] ┆ 4 ┆ 0 │\n",
"│ 7 ┆ [2, 4] ┆ [0, 7] ┆ 4 ┆ 0 │\n",
"└───────┴────────────┴──────────────┴───────┴───────┘"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = pl.DataFrame(\n",
" dict(\n",
" A=[5, 3, 8, 9, 10, 1, 2, 4],\n",
" B=[10, 20, 10, 2, 3, 5, 0, 7]\n",
" )\n",
")\n",
"\n",
"(\n",
" df\n",
" .rolling(\n",
" pl.int_range(0, pl.len()).alias('index'), \n",
" period='3i', \n",
" offset='-2i'\n",
" )\n",
" .agg(\n",
" pl.col.A,\n",
" pl.col.B,\n",
" pl.col.A.max().alias('A_max'),\n",
" pl.col.B.min().alias('B_min'),\n",
" )\n",
")"
]
},
{
"cell_type": "markdown",
"id": "5b0f7c51-7293-469d-ba60-e5a2f9919db2",
"metadata": {},
"source": [
"Polars には `Expr.rolling()` も用意されています。引数は `DataFrame.rolling()` と同じですが、`Expr.rolling()` は列単位で適用できるため、より柔軟なデータ処理が可能です。`.rolling()` はローリングウィンドウ内の要素をコンテキストとして使用し、直前の演算に適用されます。\n",
"\n",
"次の例では、同じ `rolling()` 演算を以下の 2 つの式に適用しています。 \n",
"\n",
"- **`pl.col('A')`**: 集計処理がないため、ローリングウィンドウ内の要素をリストとしてそのまま出力します。 \n",
"- **`pl.col('A').max()`**: ローリングウィンドウ内の要素リストに対して `max()` を適用し、各ウィンドウ内の最大値を計算して出力します。"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "f78ae4fa-7544-4ef6-b9a6-dc5d7fc0f266",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (8, 2)A | A_max |
---|
list[i64] | i64 |
[5, 3] | 5 |
[5, 3, 8] | 8 |
[3, 8, 9] | 9 |
[8, 9, 10] | 10 |
[9, 10, 1] | 10 |
[10, 1, 2] | 10 |
[1, 2, 4] | 4 |
[2, 4] | 4 |
"
],
"text/plain": [
"shape: (8, 2)\n",
"┌────────────┬───────┐\n",
"│ A ┆ A_max │\n",
"│ --- ┆ --- │\n",
"│ list[i64] ┆ i64 │\n",
"╞════════════╪═══════╡\n",
"│ [5, 3] ┆ 5 │\n",
"│ [5, 3, 8] ┆ 8 │\n",
"│ [3, 8, 9] ┆ 9 │\n",
"│ [8, 9, 10] ┆ 10 │\n",
"│ [9, 10, 1] ┆ 10 │\n",
"│ [10, 1, 2] ┆ 10 │\n",
"│ [1, 2, 4] ┆ 4 │\n",
"│ [2, 4] ┆ 4 │\n",
"└────────────┴───────┘"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.with_row_index().select(\n",
" pl.col('A').rolling('index', period='3i', offset='-2i'),\n",
" pl.col('A').max().rolling('index', period='3i', offset='-2i').alias('A_max')\n",
")"
]
},
{
"cell_type": "markdown",
"id": "c2848c43-ce4c-4403-8d41-3278e51ae058",
"metadata": {},
"source": [
"注意すべき点は、`.rolling()` は **直前のすべての演算式に対して** 適用されることです。 \n",
"\n",
"1. **`pl.col('A').diff().max().rolling(...)` の挙動** ❶\n",
" - まず、A列の要素がローリングウィンドウに分割されます。 \n",
" - その後、それぞれのウィンドウ内で `.diff().max()` が適用されます。 \n",
"\n",
"2. **A列の差分を計算した後にローリングウィンドウを適用する方法** ❷\n",
" - まず `dA = pl.col('A').diff()` を計算し、新しい列 `dA` を作成します。 \n",
" - 次に、`dA` に対して `pl.col('dA').max().rolling(...)` を計算します。 \n",
"\n",
"この違いを理解することで、意図した通りにローリングウィンドウを適用できます。"
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "4f7d957b-bdf4-4bb7-9ade-5b6945dcdc45",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" shape: (8, 4)index | A | dA_rolling | dA_max_rolling |
---|
u32 | list[i64] | list[i64] | i64 | 0 | [5] | [null] | null | 1 | [5, 3] | [null, -2] | -2 | 2 | [5, 3, 8] | [null, -2, 5] | 5 | 3 | [3, 8, 9] | [null, 5, 1] | 5 | 4 | [8, 9, 10] | [null, 1, 1] | 1 | 5 | [9, 10, 1] | [null, 1, -9] | 1 | 6 | [10, 1, 2] | [null, -9, 1] | 1 | 7 | [1, 2, 4] | [null, 1, 2] | 2 |
| \n",
" shape: (8, 5)index | A | dA | dA_rolling | dA_max_rolling |
---|
u32 | i64 | i64 | list[i64] | i64 | 0 | 5 | null | [null] | null | 1 | 3 | -2 | [null, -2] | -2 | 2 | 8 | 5 | [null, -2, 5] | 5 | 3 | 9 | 1 | [-2, 5, 1] | 5 | 4 | 10 | 1 | [5, 1, 1] | 5 | 5 | 1 | -9 | [1, 1, -9] | 1 | 6 | 2 | 1 | [1, -9, 1] | 1 | 7 | 4 | 2 | [-9, 1, 2] | 2 |
|
"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"df1 = df.select('A').with_row_index().with_columns(\n",
" pl.col('A').rolling('index', period='3i'),\n",
" pl.col('A').diff().rolling('index', period='3i').alias('dA_rolling'),\n",
" pl.col('A').diff().max().rolling('index', period='3i').alias('dA_max_rolling') #❶\n",
")\n",
"\n",
"df2 = df.select('A').with_row_index().with_columns(\n",
" pl.col('A').diff().alias('dA') #❷\n",
").with_columns(\n",
" pl.col('dA').rolling('index', period='3i').alias('dA_rolling'),\n",
" pl.col('dA').max().rolling('index', period='3i').alias('dA_max_rolling') #❷\n",
")\n",
"\n",
"row(df1, df2)"
]
},
{
"cell_type": "markdown",
"id": "017e2a85-f41a-4812-a9ac-4483120c56cf",
"metadata": {},
"source": [
"## CookBook"
]
},
{
"cell_type": "markdown",
"id": "f0d77443-3a2c-446c-a30d-c11744b48567",
"metadata": {},
"source": [
"### 値の変化に応じたグループ化と集計\n",
"\n",
"次のプログラムでは、`g`列の値が変化するたびにグループを変え、各グループの最初の`g`の値と`v`列の値を取得します。`rle_id()`を使用して、`g`列の値が変化するたびに新しいグループIDを割り当てます。`rle_id()`は、連続する同じ値に同じIDを割り当て、値が変化するたびにIDを更新します。"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "20e24360-0beb-4f21-9d2d-fa8037a301cb",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (4, 3)group_id | g | v |
---|
u32 | i64 | list[i64] |
0 | 1 | [0, 1] |
1 | 2 | [2, 3, 4] |
2 | 1 | [5, 6] |
3 | 0 | [7] |
"
],
"text/plain": [
"shape: (4, 3)\n",
"┌──────────┬─────┬───────────┐\n",
"│ group_id ┆ g ┆ v │\n",
"│ --- ┆ --- ┆ --- │\n",
"│ u32 ┆ i64 ┆ list[i64] │\n",
"╞══════════╪═════╪═══════════╡\n",
"│ 0 ┆ 1 ┆ [0, 1] │\n",
"│ 1 ┆ 2 ┆ [2, 3, 4] │\n",
"│ 2 ┆ 1 ┆ [5, 6] │\n",
"│ 3 ┆ 0 ┆ [7] │\n",
"└──────────┴─────┴───────────┘"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = pl.DataFrame(\n",
" {\n",
" \"g\": [1, 1, 2, 2, 2, 1, 1, 0],\n",
" \"v\": list(range(8))\n",
" }\n",
")\n",
"\n",
"df.group_by(\n",
" pl.col('g').rle_id().alias('group_id')\n",
").agg(\n",
" pl.col('g').first(),\n",
" pl.col('v')\n",
")"
]
},
{
"cell_type": "markdown",
"id": "d1a32567-4cea-42fe-9946-08fa5e92cfd7",
"metadata": {},
"source": [
"### グループ毎に番号付け"
]
},
{
"cell_type": "markdown",
"id": "2b992706-09de-409b-bfde-63f25277339b",
"metadata": {},
"source": [
"c1列とc2列の値に番号を付けます。番号は0からスタート、新しい値が現れるたびに1増加します。"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "13ea44ad-fd3f-4c46-98a7-feea793b19e2",
"metadata": {},
"outputs": [],
"source": [
"df = pl.DataFrame(\n",
" {\n",
" \"c1\": [\"b\", \"a\", \"a\", \"b\", \"c\", \"a\", \"b\"],\n",
" \"c2\": [2, 1, 1, 1, 1, 1, 1],\n",
" }\n",
")"
]
},
{
"cell_type": "markdown",
"id": "e2621673-bc0d-483f-82ac-a594d2172b37",
"metadata": {},
"source": [
"#### group_byで計算"
]
},
{
"cell_type": "markdown",
"id": "4a7d7316-f29e-4507-848f-8ac39f712f9f",
"metadata": {},
"source": [
"1. `group_by(\"c1\", \"c2\", maintain_order=True)`:\n",
" - `df`データフレームを、`c1`列と`c2`列の組み合わせでグループ化します。これにより、`c1`と`c2`のユニークなペアごとにグループが作られます。\n",
"\n",
"2. `pl.col(\"c1\").agg_groups().alias(\"row_index\")`:\n",
" - グループ化した後、`c1`列に対して`agg_groups()`関数を使用しています。`agg_groups()`は、各グループ内で行のインデックスをリストとして取得するものです。ここでは、各グループ内のインデックスを`row_index`という名前で新しい列として追加します。\n",
"\n",
"3. `with_row_index()`:\n",
" - `with_row_index()`は、グループ化後のデータフレームに行番号(インデックス)を追加します。\n",
"\n",
"4. `explode(\"row_index\")`:\n",
" - `explode()`は、リストや配列を展開して、それぞれのリスト要素を新しい行に分割する操作です。ここでは、`row_index`列に格納されているインデックスのリストを展開して、各インデックスを新しい行として扱います。この操作によって、複数の行が作成され、`row_index`の要素が個々の行に分割されます。\n",
"\n",
"5. `sort(by=\"row_index\")`:\n",
" - `row_index`を基準にデータをソートします。このソートによって、`row_index`の値が小さい順に行が並び、元のデータフレームと同じ順序になります。\n",
"\n",
"6. `drop('row_index')`:\n",
" - 最後に、`row_index`列を削除します。これは、インデックス付けを行った後、最終的に不要な列を削除するためです。"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "a56e7d25-f3f4-4b43-b51e-f5d1c36eda27",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (7, 3)index | c1 | c2 |
---|
u32 | str | i64 |
0 | "b" | 2 |
1 | "a" | 1 |
1 | "a" | 1 |
2 | "b" | 1 |
3 | "c" | 1 |
1 | "a" | 1 |
2 | "b" | 1 |
"
],
"text/plain": [
"shape: (7, 3)\n",
"┌───────┬─────┬─────┐\n",
"│ index ┆ c1 ┆ c2 │\n",
"│ --- ┆ --- ┆ --- │\n",
"│ u32 ┆ str ┆ i64 │\n",
"╞═══════╪═════╪═════╡\n",
"│ 0 ┆ b ┆ 2 │\n",
"│ 1 ┆ a ┆ 1 │\n",
"│ 1 ┆ a ┆ 1 │\n",
"│ 2 ┆ b ┆ 1 │\n",
"│ 3 ┆ c ┆ 1 │\n",
"│ 1 ┆ a ┆ 1 │\n",
"│ 2 ┆ b ┆ 1 │\n",
"└───────┴─────┴─────┘"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(\n",
" df\n",
" .group_by(\"c1\", \"c2\", maintain_order=True)\n",
" .agg(\n",
" pl.col(\"c1\")\n",
" .agg_groups()\n",
" .alias(\"row_index\")\n",
" )\n",
" .with_row_index()\n",
" .explode(\"row_index\")\n",
" .sort(by=\"row_index\")\n",
" .drop('row_index')\n",
")"
]
},
{
"cell_type": "markdown",
"id": "188677c2-7d8c-457e-ad41-0e82ca30670b",
"metadata": {},
"source": [
"#### joinで計算"
]
},
{
"cell_type": "markdown",
"id": "a7596555-7199-4af9-b2fa-ada4e49f09f9",
"metadata": {},
"source": [
"`join`操作で同じ結果が得られます。\n",
"\n",
"1. `df.select('c1', 'c2')`:\n",
" - `df`データフレームから、`c1`列と`c2`列だけを選択しています。これにより、`df`の中でこの2つの列に関する操作が後続の処理で行われるようになります。\n",
"\n",
"2. `unique(maintain_order=True)`:\n",
" - `unique()`メソッドは、指定した列のユニークな値を取得します。この場合、`c1`列と`c2`列の組み合わせに基づいてユニークなペアを抽出します。`maintain_order=True`を指定しているため、元の順番が保持されます(ユニークな値を抽出する際、データフレームの順番が変わらないようにします)。\n",
"\n",
"3. `with_row_index()`:\n",
" - `with_row_index()`は、データフレームに行番号(インデックス)を追加します。\n",
"\n",
"4. `df.join(..., on=[\"c1\", \"c2\"])`:\n",
" - 最後に、元の`df`データフレームと、`c1`と`c2`のユニークな組み合わせ(インデックスが付けられたもの)を`join`します。`on=[\"c1\", \"c2\"]`は、`c1`と`c2`の列を基準に結合を行うことを示します。"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "d34a5417-2b03-4b87-9245-915c25a0aca3",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (7, 3)c1 | c2 | index |
---|
str | i64 | u32 |
"b" | 2 | 0 |
"a" | 1 | 1 |
"a" | 1 | 1 |
"b" | 1 | 2 |
"c" | 1 | 3 |
"a" | 1 | 1 |
"b" | 1 | 2 |
"
],
"text/plain": [
"shape: (7, 3)\n",
"┌─────┬─────┬───────┐\n",
"│ c1 ┆ c2 ┆ index │\n",
"│ --- ┆ --- ┆ --- │\n",
"│ str ┆ i64 ┆ u32 │\n",
"╞═════╪═════╪═══════╡\n",
"│ b ┆ 2 ┆ 0 │\n",
"│ a ┆ 1 ┆ 1 │\n",
"│ a ┆ 1 ┆ 1 │\n",
"│ b ┆ 1 ┆ 2 │\n",
"│ c ┆ 1 ┆ 3 │\n",
"│ a ┆ 1 ┆ 1 │\n",
"│ b ┆ 1 ┆ 2 │\n",
"└─────┴─────┴───────┘"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.join(\n",
" df.select('c1', 'c2')\n",
" .unique(maintain_order=True)\n",
" .with_row_index(),\n",
" on=[\"c1\", \"c2\"]\n",
")"
]
},
{
"cell_type": "markdown",
"id": "5a1d246f-7400-47c0-85b6-f44b5bd72815",
"metadata": {},
"source": [
"#### カテゴリカル型で計算"
]
},
{
"cell_type": "markdown",
"id": "e32b5f85-e731-4162-b5c7-62beb5d62ba5",
"metadata": {},
"source": [
"`c1`列と`c2`列の値を結合して新しい文字列を作成し、それをカテゴリカル型(`Categorical`)に変換した後、整数型に変換することで同じ結果が得られます。\n",
"\n",
"1. `pl.format(\"{} - {}\", \"c1\", \"c2\")`:\n",
" - `pl.format()`関数を使用して、`c1`列と`c2`列の値をフォーマットして結合します。\n",
" - `{}`はプレースホルダで、`c1`と`c2`の値がそれぞれここに挿入されます。この場合、`c1`と`c2`の各値を`\"c1の値 - c2の値\"`という形式で結合した文字列が生成されます。\n",
" - 例えば、`c1`が`\"a\"`、`c2`が`1`の場合、`\"a - 1\"`という文字列が作成されます。\n",
"\n",
"2. `cast(pl.Categorical)`:\n",
" - `cast(pl.Categorical)`は、作成された文字列列を`Categorical`型に変換します。`Categorical`型は、列の値が限られたユニークなカテゴリーである場合に効率的に格納できるデータ型です。\n",
"\n",
"3. `to_physical()`:\n",
" - `to_physical()`は、列を物理的に格納する形式に変換します。`Categorical`型の場合、各カテゴリーに対応する整数値が得られます。\n",
"\n",
"4. `alias(\"index\")`:\n",
" - 最後に、新しく作成した列に`index`という名前を付けます。"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "ad21994e-f9e3-4084-95a2-d41663204143",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (7, 3)c1 | c2 | index |
---|
str | i64 | u32 |
"b" | 2 | 0 |
"a" | 1 | 1 |
"a" | 1 | 1 |
"b" | 1 | 2 |
"c" | 1 | 3 |
"a" | 1 | 1 |
"b" | 1 | 2 |
"
],
"text/plain": [
"shape: (7, 3)\n",
"┌─────┬─────┬───────┐\n",
"│ c1 ┆ c2 ┆ index │\n",
"│ --- ┆ --- ┆ --- │\n",
"│ str ┆ i64 ┆ u32 │\n",
"╞═════╪═════╪═══════╡\n",
"│ b ┆ 2 ┆ 0 │\n",
"│ a ┆ 1 ┆ 1 │\n",
"│ a ┆ 1 ┆ 1 │\n",
"│ b ┆ 1 ┆ 2 │\n",
"│ c ┆ 1 ┆ 3 │\n",
"│ a ┆ 1 ┆ 1 │\n",
"│ b ┆ 1 ┆ 2 │\n",
"└─────┴─────┴───────┘"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.with_columns(\n",
" pl.format(\"{} - {}\", \"c1\", \"c2\")\n",
" .cast(pl.Categorical)\n",
" .to_physical()\n",
" .alias(\"index\")\n",
")"
]
},
{
"cell_type": "markdown",
"id": "35302147-76df-467f-9088-80053f592645",
"metadata": {},
"source": [
"#### 構造体とカテゴリカル型で計算"
]
},
{
"cell_type": "markdown",
"id": "61498ae6-3449-463c-b1de-f98234306518",
"metadata": {},
"source": [
"`pl.format()`が使えない場合は、次のように構造体列をカテゴリカル型に変換することもできます。\n",
"\n",
"1. `pl.struct(\"c1\", \"c2\")`:\n",
" - `pl.struct(\"c1\", \"c2\")`は、`c1`列と`c2`列を構造体(`struct`)としてまとめます。これにより、`c1`と`c2`のペアを一つの構造体として扱うことができます。構造体を作ることで、これらの列の組み合わせを一つの新しい単位として処理できるようになります。\n",
"\n",
"2. `rank(\"dense\")`:\n",
" - `rank(\"dense\")`は、構造体(`c1`と`c2`のペア)を基にして、データを「密なランク(dense ranking)」でランク付けします。密なランクは、同じ値に対して同じランクを与え、ランクが抜けないようにします(例えば、1位が2人の場合、次は3位になります)。この処理により、`c1`と`c2`の組み合わせに対してランクが割り当てられます。\n",
"\n",
"3. `cast(pl.String)`:\n",
" - `cast(pl.String)`は、ランク付けされた値は整数ですが、これを直接カテゴリー型に変換できないため、一旦文字列型(`String`)に変換します。"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "abe812c3-d9ff-43c0-b0d1-5108d8ce8c32",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
shape: (7, 3)c1 | c2 | index |
---|
str | i64 | u32 |
"b" | 2 | 0 |
"a" | 1 | 1 |
"a" | 1 | 1 |
"b" | 1 | 2 |
"c" | 1 | 3 |
"a" | 1 | 1 |
"b" | 1 | 2 |
"
],
"text/plain": [
"shape: (7, 3)\n",
"┌─────┬─────┬───────┐\n",
"│ c1 ┆ c2 ┆ index │\n",
"│ --- ┆ --- ┆ --- │\n",
"│ str ┆ i64 ┆ u32 │\n",
"╞═════╪═════╪═══════╡\n",
"│ b ┆ 2 ┆ 0 │\n",
"│ a ┆ 1 ┆ 1 │\n",
"│ a ┆ 1 ┆ 1 │\n",
"│ b ┆ 1 ┆ 2 │\n",
"│ c ┆ 1 ┆ 3 │\n",
"│ a ┆ 1 ┆ 1 │\n",
"│ b ┆ 1 ┆ 2 │\n",
"└─────┴─────┴───────┘"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.with_columns(\n",
" pl.struct(\"c1\", \"c2\")\n",
" .rank(\"dense\")\n",
" .cast(pl.String)\n",
" .cast(pl.Categorical)\n",
" .to_physical()\n",
" .alias(\"index\")\n",
")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}