From 1e752fb0f68adf437d4b472ed574c9ebee1ab821 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 18 Jul 2026 11:45:12 +0100 Subject: [PATCH 1/2] migrate: convert boolean-data.ipynb from pandas to polars --- boolean-data.ipynb | 55 +++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/boolean-data.ipynb b/boolean-data.ipynb index d389d25..0bd94c2 100644 --- a/boolean-data.ipynb +++ b/boolean-data.ipynb @@ -481,11 +481,11 @@ "id": "8e06930b", "metadata": {}, "source": [ - "## Booleans in **pandas** data frames\n", + "## Booleans in **polars** DataFrames\n", "\n", "### Operations on booleans in data frames\n", "\n", - "Quite often, you will run into a scenario where you're working with data that have True or False values in a data frame. It is easy to create a column of booleans in a **pandas** data frame:" + "Quite often, you will run into a scenario where you're working with data that have True or False values in a data frame. It is easy to create a column of booleans in a **polars** data frame:" ] }, { @@ -495,9 +495,9 @@ "metadata": {}, "outputs": [], "source": [ - "import pandas as pd\n", + "import polars as pl\n", "\n", - "df = pd.DataFrame.from_dict(\n", + "df = pl.DataFrame(\n", " {\n", " \"bool_col_1\": [False] * 3 + [True, True],\n", " \"bool_col_2\": [True, False, True, False, True],\n", @@ -521,7 +521,7 @@ "metadata": {}, "outputs": [], "source": [ - "df[\"bool_col_1\"] | df[\"bool_col_2\"]" + "df.select((pl.col(\"bool_col_1\") | pl.col(\"bool_col_2\")).alias(\"result\"))" ] }, { @@ -529,7 +529,7 @@ "id": "25dede69", "metadata": {}, "source": [ - "Quite often, it's useful to have a count of the number of true values. If you take the sum of boolean columns in a **pandas** data frame, it will tot up the number of `True` values:" + "Quite often, it's useful to have a count of the number of true values. If you take the sum of boolean columns in a **polars** data frame, it will tot up the number of `True` values:" ] }, { @@ -539,7 +539,7 @@ "metadata": {}, "outputs": [], "source": [ - "df.sum()" + "df.select(pl.col(\"*\").sum())" ] }, { @@ -557,8 +557,8 @@ "metadata": {}, "outputs": [], "source": [ - "df = pd.DataFrame.from_dict({\"bool_col\": [0, 1, 0, 1, 1]})\n", - "df[\"bool_col\"].astype(bool)" + "df = pl.DataFrame({\"bool_col\": [0, 1, 0, 1, 1]})\n", + "df.with_columns(pl.col(\"bool_col\").cast(pl.Boolean))" ] }, { @@ -579,7 +579,7 @@ "metadata": {}, "outputs": [], "source": [ - "diamonds = pd.read_csv(\n", + "diamonds = pl.read_csv(\n", " \"https://github.com/mwaskom/seaborn-data/raw/master/diamonds.csv\"\n", ")\n", "diamonds.head()" @@ -596,12 +596,16 @@ { "cell_type": "code", "execution_count": null, - "id": "7a27f0a0", + "id": "6b739dc5", "metadata": {}, "outputs": [], "source": [ - "diamonds[\"expensive\"] = diamonds[\"price\"] > 1000\n", - "diamonds.sample(10)" + "(\n", + " diamonds.with_columns((pl.col(\"price\") > 1000).alias(\"expensive\"))\n", + " # tweaked to display a mix of true and false values.\n", + " .select([\"cut\", \"carat\", \"color\", \"clarity\", \"price\", \"expensive\"])\n", + " .sample(10, shuffle=True)\n", + ")" ] }, { @@ -609,7 +613,7 @@ "id": "8383cab5", "metadata": {}, "source": [ - "Of course, this could also have been achieved in a call to assign:" + "Of course, this could also have been achieved with `select()` or `with_columns()`:" ] }, { @@ -619,7 +623,10 @@ "metadata": {}, "outputs": [], "source": [ - "diamonds.assign(expensive=lambda x: x[\"price\"] > 1000).head()" + "diamonds.select(\n", + " pl.all(),\n", + " (pl.col(\"price\") > 1000).alias(\"expensive\"),\n", + ").head()" ] }, { @@ -627,7 +634,7 @@ "id": "622ff486", "metadata": {}, "source": [ - "Another use of booleans that is quite useful when it comes to data frames is the `.isin()` function. For example, if you just want some True or False values for whether a set of columns is in a data frame:" + "Another use of booleans that is quite useful when it comes to data frames is checking if a set of columns exists:" ] }, { @@ -637,7 +644,8 @@ "metadata": {}, "outputs": [], "source": [ - "diamonds.columns.isin([\"x\", \"y\", \"z\"])" + "cols_to_check = [\"x\", \"y\", \"z\"]\n", + "[col in diamonds.columns for col in cols_to_check]" ] }, { @@ -647,7 +655,7 @@ "source": [ "### any() and all() in data frames\n", "\n", - "A **pandas** column of booleans behaves a lot like a list of booleans, and we can apply the same logic to it via **pandas** built-in `.any()` and `.all()` methods. We expect some entries for `\"expensive\"` to be true, so `any()` should return true:" + "A **polars** column of booleans behaves a lot like a list of booleans, and we can apply the same logic to it via **polars** built-in `.any()` and `.all()` methods. We expect some entries for `\"expensive\"` to be true, so `any()` should return true:" ] }, { @@ -657,7 +665,7 @@ "metadata": {}, "outputs": [], "source": [ - "diamonds[\"expensive\"].any()" + "diamonds.select((pl.col(\"price\") > 1000).any().alias(\"any_expensive\"))" ] }, { @@ -677,7 +685,7 @@ "metadata": {}, "outputs": [], "source": [ - "diamonds[diamonds[\"x\"] > diamonds[\"y\"]]" + "diamonds.filter(pl.col(\"x\") > pl.col(\"y\"))" ] }, { @@ -685,14 +693,11 @@ "id": "9b5906ba", "metadata": {}, "source": [ - "The expression `diamonds[\"x\"] > diamonds[\"y\"]` creates a column of booleans that is used to filter to just the rows where the condition is true." + "The expression `pl.col(\"x\") > pl.col(\"y\")` creates a column of booleans that is used to filter to just the rows where the condition is true." ] } ], "metadata": { - "interpreter": { - "hash": "9d7534ecd9fbc7d385378f8400cf4d6cb9c6175408a574f1c99c5269f08771cc" - }, "jupytext": { "cell_metadata_filter": "-all", "encoding": "# -*- coding: utf-8 -*-", @@ -700,7 +705,7 @@ "main_language": "python" }, "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": ".venv", "language": "python", "name": "python3" }, From 3e53e28093f66111887e78613c7e4cab46da6041 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 23 Jul 2026 02:42:58 +0100 Subject: [PATCH 2/2] fix: address review feedback for boolean.ipynb migration --- boolean-data.ipynb | 49 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/boolean-data.ipynb b/boolean-data.ipynb index 0bd94c2..bd4c3d6 100644 --- a/boolean-data.ipynb +++ b/boolean-data.ipynb @@ -11,9 +11,13 @@ "\n", "In this chapter, we'll introduce boolean data: data that can be `True` or `False` (which can also be encoded as 1s or 0s). We'll first look at the fundamental Python true and false boolean variables before seeing how true and false work in data frames.\n", "\n", + "### Prerequisites\n", + "\n", + "This chapter focuses on working with boolean data and expressions using **polars**. Make sure you have **polars** installed (`uv add polars`). For more on Polars boolean operations, see the [Polars boolean expression documentation](https://docs.pola.rs/api/python/stable/reference/expressions/boolean.html).\n", + "\n", "## Booleans\n", "\n", - "Some of the most important operations you will perform are with `True` and `False` values, also known as boolean data types. These are fundamental Python variables, just as numbers such as `1` are. \n", + "Some of the most important operations you will perform are with `True` and `False` values, also known as boolean data types. These are fundamental Python variables, just as numbers such as `1` are.\n", "\n", "### Boolean Variables and Conditions\n", "\n", @@ -511,7 +515,7 @@ "id": "c7a0cd32", "metadata": {}, "source": [ - "We can perform operations on these just like regular **pandas** data frame columns. These accept `&` (and), `|` (or), `==` (equal), and `!=` (not equal) as operations:" + "We can perform operations on these just like regular **polars** data frame columns. These accept `&` (and), `|` (or), `==` (equal), and `!=` (not equal) as operations:" ] }, { @@ -521,7 +525,12 @@ "metadata": {}, "outputs": [], "source": [ - "df.select((pl.col(\"bool_col_1\") | pl.col(\"bool_col_2\")).alias(\"result\"))" + "df.select(\n", + " [\n", + " (pl.col(\"bool_col_1\") & pl.col(\"bool_col_2\")).alias(\"and_result\"),\n", + " (pl.col(\"bool_col_1\") | pl.col(\"bool_col_2\")).alias(\"or_result\"),\n", + " ]\n", + ")" ] }, { @@ -600,12 +609,8 @@ "metadata": {}, "outputs": [], "source": [ - "(\n", - " diamonds.with_columns((pl.col(\"price\") > 1000).alias(\"expensive\"))\n", - " # tweaked to display a mix of true and false values.\n", - " .select([\"cut\", \"carat\", \"color\", \"clarity\", \"price\", \"expensive\"])\n", - " .sample(10, shuffle=True)\n", - ")" + "diamonds = diamonds.with_columns((pl.col(\"price\") > 1000).alias(\"expensive\"))\n", + "diamonds.select([\"cut\", \"carat\", \"color\", \"clarity\", \"price\", \"expensive\"]).head()" ] }, { @@ -624,7 +629,7 @@ "outputs": [], "source": [ "diamonds.select(\n", - " pl.all(),\n", + " [\"cut\", \"carat\", \"color\", \"clarity\", \"price\"],\n", " (pl.col(\"price\") > 1000).alias(\"expensive\"),\n", ").head()" ] @@ -634,7 +639,7 @@ "id": "622ff486", "metadata": {}, "source": [ - "Another use of booleans that is quite useful when it comes to data frames is checking if a set of columns exists:" + "Another use of booleans in data frames is checking if a set of column names exists. We can use a Python list comprehension with the Python `in` operator on `diamonds.columns`:" ] }, { @@ -648,6 +653,24 @@ "[col in diamonds.columns for col in cols_to_check]" ] }, + { + "cell_type": "markdown", + "id": "polars_is_in_markdown", + "metadata": {}, + "source": [ + "Alternatively, you can check column existence natively in **polars** using `pl.Series.is_in()`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "polars_is_in_code", + "metadata": {}, + "outputs": [], + "source": [ + "pl.Series(diamonds.columns).is_in(cols_to_check)" + ] + }, { "cell_type": "markdown", "id": "6de309a4", @@ -665,7 +688,7 @@ "metadata": {}, "outputs": [], "source": [ - "diamonds.select((pl.col(\"price\") > 1000).any().alias(\"any_expensive\"))" + "diamonds.select(pl.col(\"expensive\").any())" ] }, { @@ -705,7 +728,7 @@ "main_language": "python" }, "kernelspec": { - "display_name": ".venv", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" },