{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Оперирование таблицами `pandas`\n" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", "import numpy as np\n", "import pandas as pd\n", "\n", "\n", "folder = Path(\"..\", \"..\") / \"assets\" / \"data\" / \"tables\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Типы столбцов\n", "\n", "Считаем таблицу с планетами и выведем типы данных в её столбце." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Количество спутников int64\n", "Масса float64\n", "Группа object\n", "Кольца object\n", "dtype: object\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Количество спутниковМассаГруппаКольца
Название
Меркурий00.0055земная группаНет
Венера00.8150земная группаНет
Земля11.0000земная группаНет
Марс20.1070земная группаНет
Юпитер62317.8000газовый гигантДа
Сатурн3495.2000газовый гигантДа
Уран2714.3700ледяной гигантДа
Нептун1317.1500ледяной гигантДа
\n", "
" ], "text/plain": [ " Количество спутников Масса Группа Кольца\n", "Название \n", "Меркурий 0 0.0055 земная группа Нет\n", "Венера 0 0.8150 земная группа Нет\n", "Земля 1 1.0000 земная группа Нет\n", "Марс 2 0.1070 земная группа Нет\n", "Юпитер 62 317.8000 газовый гигант Да\n", "Сатурн 34 95.2000 газовый гигант Да\n", "Уран 27 14.3700 ледяной гигант Да\n", "Нептун 13 17.1500 ледяной гигант Да" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "planets = pd.read_csv(folder / \"planets.csv\", index_col=\"Название\")\n", "print(planets.dtypes)\n", "planets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Видим, что типы первых столбцов были корректно выведены из таблицы, а вот последние два столбца можно хранить более эффективно. \n", "\n", "Во-первых, значение столбца \"`Кольца`\" булевого характера. Чтобы сразу считать их сразу как булевые, в методе [read_csv](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html) можно указать какие значения следует интерпретировать в качестве `True`, а какие в качестве `False`, параметрами `true_values` и `false_values`.\n", "\n", "```{tip}\n", "По аналогии с `true_values` и `false_values` ещё есть параметр `na_values`, отвечающий за пропущенные значения.\n", "```" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Количество спутников int64\n", "Масса float64\n", "Группа object\n", "Кольца bool\n", "dtype: object\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Количество спутниковМассаГруппаКольца
Название
Меркурий00.0055земная группаFalse
Венера00.8150земная группаFalse
Земля11.0000земная группаFalse
Марс20.1070земная группаFalse
Юпитер62317.8000газовый гигантTrue
Сатурн3495.2000газовый гигантTrue
Уран2714.3700ледяной гигантTrue
Нептун1317.1500ледяной гигантTrue
\n", "
" ], "text/plain": [ " Количество спутников Масса Группа Кольца\n", "Название \n", "Меркурий 0 0.0055 земная группа False\n", "Венера 0 0.8150 земная группа False\n", "Земля 1 1.0000 земная группа False\n", "Марс 2 0.1070 земная группа False\n", "Юпитер 62 317.8000 газовый гигант True\n", "Сатурн 34 95.2000 газовый гигант True\n", "Уран 27 14.3700 ледяной гигант True\n", "Нептун 13 17.1500 ледяной гигант True" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "planets = pd.read_csv(folder / \"planets.csv\", index_col=\"Название\", true_values=[\"Да\"], false_values=[\"Нет\"])\n", "print(planets.dtypes)\n", "planets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Видим, что значения столбца \"`Кольца`\" автоматически приняли булевый тип.\n", "\n", "Во-вторых, значения столбца \"`Группа`\" принимают одно из трех значений, а хранятся в столбце типа `object`. Переменные такого характера называют [категориальными](https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F) или номинальными. Для их хранения в `pandas` эффективнее будет воспользоваться специальным категориальным типом данных. \n", "\n", "Для начала продемонстрируем работу метода [pandas.Series.astype](https://pandas.pydata.org/docs/reference/api/pandas.Series.astype.html), который позволяет преобразовать тип данных столбца (или таблицы)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Название\n", "Меркурий земная группа\n", "Венера земная группа\n", "Земля земная группа\n", "Марс земная группа\n", "Юпитер газовый гигант\n", "Сатурн газовый гигант\n", "Уран ледяной гигант\n", "Нептун ледяной гигант\n", "Name: Группа, dtype: category\n", "Categories (3, object): ['газовый гигант', 'земная группа', 'ледяной гигант']" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "planets[\"Группа\"].astype(\"category\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Видим, что метод преобразовал все к типу `\"category\"`. Эффективнее, конечно, загрузить таблицу сразу с необходимыми типами данных." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Количество спутников uint8\n", "Масса float32\n", "Группа category\n", "Кольца bool\n", "dtype: object\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Количество спутниковМассаГруппаКольца
Название
Меркурий00.005500земная группаFalse
Венера00.815000земная группаFalse
Земля11.000000земная группаFalse
Марс20.107000земная группаFalse
Юпитер62317.799988газовый гигантTrue
Сатурн3495.199997газовый гигантTrue
Уран2714.370000ледяной гигантTrue
Нептун1317.150000ледяной гигантTrue
\n", "
" ], "text/plain": [ " Количество спутников Масса Группа Кольца\n", "Название \n", "Меркурий 0 0.005500 земная группа False\n", "Венера 0 0.815000 земная группа False\n", "Земля 1 1.000000 земная группа False\n", "Марс 2 0.107000 земная группа False\n", "Юпитер 62 317.799988 газовый гигант True\n", "Сатурн 34 95.199997 газовый гигант True\n", "Уран 27 14.370000 ледяной гигант True\n", "Нептун 13 17.150000 ледяной гигант True" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dtypes = {\n", " \"Группа\": \"category\",\n", " \"Количество спутников\": np.uint8,\n", " \"Кольца\": bool,\n", " \"Масса\": \"float32\"\n", "}\n", "\n", "planets = pd.read_csv(\n", " folder / \"planets.csv\", \n", " index_col=\"Название\", \n", " true_values=[\"Да\"], \n", " false_values=[\"Нет\"],\n", " dtype=dtypes\n", ")\n", "print(planets.dtypes)\n", "planets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Названия столбцов\n", "\n", "Иногда может потребоваться переименовать столбцы и метки строк в таблице. Переведем названия столбцов и планет, чтобы продемонстрировать принцип работы метода [pd.DataFrame.rename](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.rename.html)." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
number of moonsmassgrouprings
Название
Mercury00.005500земная группаFalse
Venus00.815000земная группаFalse
Earth11.000000земная группаFalse
Mars20.107000земная группаFalse
jupyter62317.799988газовый гигантTrue
Saturn3495.199997газовый гигантTrue
Uranus2714.370000ледяной гигантTrue
Neptune1317.150000ледяной гигантTrue
\n", "
" ], "text/plain": [ " number of moons mass group rings\n", "Название \n", "Mercury 0 0.005500 земная группа False\n", "Venus 0 0.815000 земная группа False\n", "Earth 1 1.000000 земная группа False\n", "Mars 2 0.107000 земная группа False\n", "jupyter 62 317.799988 газовый гигант True\n", "Saturn 34 95.199997 газовый гигант True\n", "Uranus 27 14.370000 ледяной гигант True\n", "Neptune 13 17.150000 ледяной гигант True" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "columns = {\n", " \"Количество спутников\": \"number of moons\",\n", " \"Масса\": \"mass\",\n", " \"Группа\": \"group\",\n", " \"Кольца\": \"rings\"\n", "}\n", "index = {\n", " \"Меркурий\": \"Mercury\",\n", " \"Венера\": \"Venus\",\n", " \"Земля\": \"Earth\",\n", " \"Марс\": \"Mars\",\n", " \"Юпитер\": \"jupyter\",\n", " \"Сатурн\": \"Saturn\",\n", " \"Уран\": \"Uranus\",\n", " \"Нептун\": \"Neptune\"\n", "} \n", "\n", "\n", "planets.rename(\n", " columns=columns,\n", " index=index,\n", " inplace=True\n", ")\n", "planets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Т.е. в большинстве случаев удобнее всего указать новые названия столбцов и/или новые метки индекса в виде словаря. \n", "\n", "```{warning}\n", "Обратите внимание, что по умолчанию метод `rename` не изменяет названия столбцов на месте, а возвращает копию таблицы с переименованными столбцами. Это стандартное поведение для многих методов `pandas`: в последнее время разработчики `pandas` стараются избегать мутирующих методов. Однако если талица очень крупная, то её копирование ради совершения простых операций может оказаться накладным. В таком случае полезным может оказаться метод `inplace`.\n", "```\n", "\n", "Переименовать название индекса таблицы можно методом [pandas.Index.rename](https://pandas.pydata.org/docs/reference/api/pandas.Index.rename.html#pandas.Index.rename)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "planets.index.rename(\"name\", inplace=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Пропущенные значения\n", "\n", "Большинство методов `pandas` разработаны таким образом, чтобы они работали с пропущенными значениями. " ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
s1s2s3
a1.0-1NaN
b2.0NaNNaN
cNaNNaNNaN
\n", "
" ], "text/plain": [ " s1 s2 s3\n", "a 1.0 -1 NaN\n", "b 2.0 NaN NaN\n", "c NaN NaN NaN" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "\n", "s1 = pd.Series({\"a\": 1., \"b\": 2., \"c\": np.nan})\n", "s2 = pd.Series({\"a\": -1,}, dtype=pd.Int32Dtype)\n", "s3 = pd.Series(dtype=pd.Float64Dtype)\n", "\n", "\n", "df = pd.DataFrame({\"s1\": s1, \"s2\": s2, \"s3\": s3})\n", "df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Например, метод [mean](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.mean.html) вычисляет среднее каждого столбца с численными значениями.\n" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "s1 1.5\n", "s2 -1.0\n", "s3 NaN\n", "dtype: float64" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.mean()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Отбрасывание пропущенных значений\n", "\n", "Тем не менее иногда необходимо избавиться от строк или столбцов с пропущенными данными. Для этого удобно использовать метод [DataFrame.dropna](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.dropna.html).\n", "\n", "#### По строкам " ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
s1s2s3
a1.0-10.0
b2.0-2NaN
cNaNNaNNaN
\n", "
" ], "text/plain": [ " s1 s2 s3\n", "a 1.0 -1 0.0\n", "b 2.0 -2 NaN\n", "c NaN NaN NaN" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s1 = pd.Series({\"a\": 1., \"b\": 2., \"c\": np.nan})\n", "s2 = pd.Series({\"a\": -1, \"b\": -2}, dtype=pd.Int32Dtype)\n", "s3 = pd.Series({\"a\": 0})\n", "\n", "\n", "df = pd.DataFrame({\"s1\": s1, \"s2\": s2, \"s3\": s3})\n", "df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "По умолчанию метод [DataFrame.dropna](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.dropna.html) отбрасывает все строки, в которых есть хотя бы одно отсутствующее значение. " ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
s1s2s3
a1.0-10.0
\n", "
" ], "text/plain": [ " s1 s2 s3\n", "a 1.0 -1 0.0" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.dropna()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Параметром `how` можно указать значение `all`, если необходимо отбросить только те строки, в которых пропущены все значения." ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
s1s2s3
a1.0-10.0
b2.0-2NaN
\n", "
" ], "text/plain": [ " s1 s2 s3\n", "a 1.0 -1 0.0\n", "b 2.0 -2 NaN" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.dropna(how=\"all\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### По столбцам" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
abc
s11.02.0NaN
s2-1-2NaN
s30.0NaNNaN
\n", "
" ], "text/plain": [ " a b c\n", "s1 1.0 2.0 NaN\n", "s2 -1 -2 NaN\n", "s3 0.0 NaN NaN" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = df.T\n", "\n", "df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Параметром `axis` можно указать, отбрасывать ли строки или столбцы. " ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
a
s11.0
s2-1
s30.0
\n", "
" ], "text/plain": [ " a\n", "s1 1.0\n", "s2 -1\n", "s3 0.0" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.dropna(axis=\"columns\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Как и в случае со строками можно отбросить только те столбцы, в которых пропущены все значения, указав значение `all` по параметру `how`." ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
ab
s11.02.0
s2-1-2
s30.0NaN
\n", "
" ], "text/plain": [ " a b\n", "s1 1.0 2.0\n", "s2 -1 -2\n", "s3 0.0 NaN" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.dropna(axis=\"columns\", how=\"all\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Заполнение пропущенных значений\n", "\n", "Иногда стратегия фильтрации пропущенных значений не является оптимальной, например, в случае когда данных не хватает. " ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
booleannumericcategorical
aTrueNaNNaN
bNaN1.0NaN
cNaNNaNwhite
\n", "
" ], "text/plain": [ " boolean numeric categorical\n", "a True NaN NaN\n", "b NaN 1.0 NaN\n", "c NaN NaN white" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "boolean = pd.Series({\"a\": True})\n", "numeric = pd.Series({\"b\": 1})\n", "color_dtype = pd.CategoricalDtype(categories=[\"black\", \"white\"])\n", "categorical = pd.Series({\"c\": \"white\"}, dtype=color_dtype)\n", "\n", "categorical\n", "\n", "df = pd.DataFrame({\n", " \"boolean\": boolean,\n", " \"numeric\": numeric,\n", " \"categorical\": categorical\n", "})\n", "df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В самом простом случае можно просто заполнить пропущенные значения какими-то константами. Метод [df.fillna](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.fillna.html) можно их заполнить. Самый гибкий способ --- передать заполнители пропущенных значений для каждого столбца в виде словаря. " ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
booleannumericcategorical
aTrue0.0black
bFalse1.0black
cFalse0.0white
\n", "
" ], "text/plain": [ " boolean numeric categorical\n", "a True 0.0 black\n", "b False 1.0 black\n", "c False 0.0 white" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.fillna({\n", " \"boolean\": False,\n", " \"numeric\": 0,\n", " \"categorical\": \"black\"\n", "})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Методом [DataFrame.interpolate](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.interpolate.html) можно заполнить пропущенные значения интерполируя по непропущенным." ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1 1.000000\n", "2 2.333333\n", "4 3.666667\n", "5 5.000000\n", "6 5.000000\n", "dtype: float64" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = pd.Series({\n", " 1: 1, 2: np.nan, 4: np.nan, 5: 5, 6: np.nan\n", "})\n", "\n", "s.interpolate(method=\"linear\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## apply, map, applymap\n", "\n", "Применить некоторую функцию к всем строкам/столбцам таблицы можно методом [DataFrame.apply](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.apply.html). Передавать этому методу необходимо такую функцию, рассчитывая, что ей на вход будет подаваться объект `pd.Series`, который в зависимости от значения параметра `axis` будет или строкой или столбцом таблицы." ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
mpgcyldisphpdratwtqsecvsamgearcarb
model
Mazda RX421.06160.01103.902.62016.460144
Mazda RX4 Wag21.06160.01103.902.87517.020144
Datsun 71022.84108.0933.852.32018.611141
Hornet 4 Drive21.46258.01103.083.21519.441031
Hornet Sportabout18.78360.01753.153.44017.020032
Valiant18.16225.01052.763.46020.221031
Duster 36014.38360.02453.213.57015.840034
Merc 240D24.44146.7623.693.19020.001042
Merc 23022.84140.8953.923.15022.901042
Merc 28019.26167.61233.923.44018.301044
Merc 280C17.86167.61233.923.44018.901044
Merc 450SE16.48275.81803.074.07017.400033
Merc 450SL17.38275.81803.073.73017.600033
Merc 450SLC15.28275.81803.073.78018.000033
Cadillac Fleetwood10.48472.02052.935.25017.980034
Lincoln Continental10.48460.02153.005.42417.820034
Chrysler Imperial14.78440.02303.235.34517.420034
Fiat 12832.4478.7664.082.20019.471141
Honda Civic30.4475.7524.931.61518.521142
Toyota Corolla33.9471.1654.221.83519.901141
Toyota Corona21.54120.1973.702.46520.011031
Dodge Challenger15.58318.01502.763.52016.870032
AMC Javelin15.28304.01503.153.43517.300032
Camaro Z2813.38350.02453.733.84015.410034
Pontiac Firebird19.28400.01753.083.84517.050032
Fiat X1-927.3479.0664.081.93518.901141
Porsche 914-226.04120.3914.432.14016.700152
Lotus Europa30.4495.11133.771.51316.901152
Ford Pantera L15.88351.02644.223.17014.500154
Ferrari Dino19.76145.01753.622.77015.500156
Maserati Bora15.08301.03353.543.57014.600158
Volvo 142E21.44121.01094.112.78018.601142
\n", "
" ], "text/plain": [ " mpg cyl disp hp drat wt qsec vs am gear \\\n", "model \n", "Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 \n", "Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 \n", "Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 \n", "Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 \n", "Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 \n", "Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 \n", "Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 \n", "Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 \n", "Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 \n", "Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 \n", "Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 \n", "Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 \n", "Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 \n", "Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 \n", "Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 \n", "Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 \n", "Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 \n", "Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 \n", "Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 \n", "Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 \n", "Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 \n", "Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 \n", "AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 \n", "Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 \n", "Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 \n", "Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 \n", "Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 \n", "Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 \n", "Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 \n", "Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 \n", "Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 \n", "Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 \n", "\n", " carb \n", "model \n", "Mazda RX4 4 \n", "Mazda RX4 Wag 4 \n", "Datsun 710 1 \n", "Hornet 4 Drive 1 \n", "Hornet Sportabout 2 \n", "Valiant 1 \n", "Duster 360 4 \n", "Merc 240D 2 \n", "Merc 230 2 \n", "Merc 280 4 \n", "Merc 280C 4 \n", "Merc 450SE 3 \n", "Merc 450SL 3 \n", "Merc 450SLC 3 \n", "Cadillac Fleetwood 4 \n", "Lincoln Continental 4 \n", "Chrysler Imperial 4 \n", "Fiat 128 1 \n", "Honda Civic 2 \n", "Toyota Corolla 1 \n", "Toyota Corona 1 \n", "Dodge Challenger 2 \n", "AMC Javelin 2 \n", "Camaro Z28 4 \n", "Pontiac Firebird 2 \n", "Fiat X1-9 1 \n", "Porsche 914-2 2 \n", "Lotus Europa 2 \n", "Ford Pantera L 4 \n", "Ferrari Dino 6 \n", "Maserati Bora 8 \n", "Volvo 142E 2 " ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mtcars = pd.read_csv(folder / \"mtcars.csv\", index_col=\"model\")\n", "mtcars" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "mpg 23.50\n", "cyl 4.00\n", "disp 400.90\n", "hp 283.00\n", "drat 2.17\n", "dtype: float64" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from matplotlib import pyplot as plt\n", "\n", "def f(x: pd.Series):\n", " fig, ax = plt.subplots(figsize=(1.5, 1))\n", " if isinstance(x.dtype, float):\n", " ax.hist(x)\n", " else:\n", " vc = x.value_counts()\n", " ax.bar(vc.index, vc.array)\n", " ax.set_title(x.name)\n", " plt.show(fig)\n", " return x.max() - x.min()\n", "\n", "mtcars.apply(f, axis=\"rows\").head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Метод [Series.map](https://pandas.pydata.org/docs/reference/api/pandas.Series.map.html) позволяет применить функцию к каждому значению столбца. Чтобы продемонстрировать принцип работы этого метода, извлечем из столбца `brand` марку и модель автомобиля в разные столбцы.\n", "\n", "Для этого определим функции, которые в качестве аргумента принимают строку из столбца `brand` и возвращают марку или модель автомобиля из неё. В данной таблице, марка автомобиля всегда встречается до первого пробела, а модель автомобиля --- все после первого пробела." ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Mazda RX4 Wag -> Mazda and RX4 Wag\n" ] } ], "source": [ "def get_brand(x: pd.Series):\n", " return x.split(\" \")[0]\n", "\n", "def get_model(x: pd.Series):\n", " b, *m = x.split(\" \") # все после первого пробела попадает в переменную m\n", " return \" \".join(m)\n", "\n", "x = \"Mazda RX4 Wag\"\n", "print(f\"{x} -> {get_brand(x)} and {get_model(x)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Определив эти функции применим их к столбцу `brand`. Т.к. `brand` --- индекс, то создадим из него `pd.Series`, применим определенные функции методом `map` и запишем результаты в таблицу в качестве новых столбцов." ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
mpgcyldisphpdratwtqsecvsamgearcarbbrandmodel
car
Mazda RX421.06160.01103.902.62016.460144MazdaRX4
Mazda RX4 Wag21.06160.01103.902.87517.020144MazdaRX4 Wag
Datsun 71022.84108.0933.852.32018.611141Datsun710
Hornet 4 Drive21.46258.01103.083.21519.441031Hornet4 Drive
Hornet Sportabout18.78360.01753.153.44017.020032HornetSportabout
Valiant18.16225.01052.763.46020.221031Valiant
Duster 36014.38360.02453.213.57015.840034Duster360
Merc 240D24.44146.7623.693.19020.001042Merc240D
Merc 23022.84140.8953.923.15022.901042Merc230
Merc 28019.26167.61233.923.44018.301044Merc280
Merc 280C17.86167.61233.923.44018.901044Merc280C
Merc 450SE16.48275.81803.074.07017.400033Merc450SE
Merc 450SL17.38275.81803.073.73017.600033Merc450SL
Merc 450SLC15.28275.81803.073.78018.000033Merc450SLC
Cadillac Fleetwood10.48472.02052.935.25017.980034CadillacFleetwood
Lincoln Continental10.48460.02153.005.42417.820034LincolnContinental
Chrysler Imperial14.78440.02303.235.34517.420034ChryslerImperial
Fiat 12832.4478.7664.082.20019.471141Fiat128
Honda Civic30.4475.7524.931.61518.521142HondaCivic
Toyota Corolla33.9471.1654.221.83519.901141ToyotaCorolla
Toyota Corona21.54120.1973.702.46520.011031ToyotaCorona
Dodge Challenger15.58318.01502.763.52016.870032DodgeChallenger
AMC Javelin15.28304.01503.153.43517.300032AMCJavelin
Camaro Z2813.38350.02453.733.84015.410034CamaroZ28
Pontiac Firebird19.28400.01753.083.84517.050032PontiacFirebird
Fiat X1-927.3479.0664.081.93518.901141FiatX1-9
Porsche 914-226.04120.3914.432.14016.700152Porsche914-2
Lotus Europa30.4495.11133.771.51316.901152LotusEuropa
Ford Pantera L15.88351.02644.223.17014.500154FordPantera L
Ferrari Dino19.76145.01753.622.77015.500156FerrariDino
Maserati Bora15.08301.03353.543.57014.600158MaseratiBora
Volvo 142E21.44121.01094.112.78018.601142Volvo142E
\n", "
" ], "text/plain": [ " mpg cyl disp hp drat wt qsec vs am gear \\\n", "car \n", "Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 \n", "Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 \n", "Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 \n", "Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 \n", "Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 \n", "Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 \n", "Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 \n", "Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 \n", "Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 \n", "Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 \n", "Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 \n", "Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 \n", "Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 \n", "Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 \n", "Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 \n", "Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 \n", "Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 \n", "Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 \n", "Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 \n", "Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 \n", "Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 \n", "Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 \n", "AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 \n", "Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 \n", "Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 \n", "Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 \n", "Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 \n", "Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 \n", "Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 \n", "Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 \n", "Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 \n", "Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 \n", "\n", " carb brand model \n", "car \n", "Mazda RX4 4 Mazda RX4 \n", "Mazda RX4 Wag 4 Mazda RX4 Wag \n", "Datsun 710 1 Datsun 710 \n", "Hornet 4 Drive 1 Hornet 4 Drive \n", "Hornet Sportabout 2 Hornet Sportabout \n", "Valiant 1 Valiant \n", "Duster 360 4 Duster 360 \n", "Merc 240D 2 Merc 240D \n", "Merc 230 2 Merc 230 \n", "Merc 280 4 Merc 280 \n", "Merc 280C 4 Merc 280C \n", "Merc 450SE 3 Merc 450SE \n", "Merc 450SL 3 Merc 450SL \n", "Merc 450SLC 3 Merc 450SLC \n", "Cadillac Fleetwood 4 Cadillac Fleetwood \n", "Lincoln Continental 4 Lincoln Continental \n", "Chrysler Imperial 4 Chrysler Imperial \n", "Fiat 128 1 Fiat 128 \n", "Honda Civic 2 Honda Civic \n", "Toyota Corolla 1 Toyota Corolla \n", "Toyota Corona 1 Toyota Corona \n", "Dodge Challenger 2 Dodge Challenger \n", "AMC Javelin 2 AMC Javelin \n", "Camaro Z28 4 Camaro Z28 \n", "Pontiac Firebird 2 Pontiac Firebird \n", "Fiat X1-9 1 Fiat X1-9 \n", "Porsche 914-2 2 Porsche 914-2 \n", "Lotus Europa 2 Lotus Europa \n", "Ford Pantera L 4 Ford Pantera L \n", "Ferrari Dino 6 Ferrari Dino \n", "Maserati Bora 8 Maserati Bora \n", "Volvo 142E 2 Volvo 142E " ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fullname = pd.Series(mtcars.index, index=mtcars.index)\n", "mtcars.index.rename(\"car\", inplace=True)\n", "mtcars[\"brand\"] = fullname.map(get_brand)\n", "mtcars[\"model\"] = fullname.map(get_model)\n", "mtcars" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Вместо функции, методу `map` можно передать словарь." ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
number of moonsmassgrouprings
name
Mercury00.005500terrestrial groupFalse
Venus00.815000terrestrial groupFalse
Earth11.000000terrestrial groupFalse
Mars20.107000terrestrial groupFalse
jupyter62317.799988gas giantTrue
Saturn3495.199997gas giantTrue
Uranus2714.370000ice giantTrue
Neptune1317.150000ice giantTrue
\n", "
" ], "text/plain": [ " number of moons mass group rings\n", "name \n", "Mercury 0 0.005500 terrestrial group False\n", "Venus 0 0.815000 terrestrial group False\n", "Earth 1 1.000000 terrestrial group False\n", "Mars 2 0.107000 terrestrial group False\n", "jupyter 62 317.799988 gas giant True\n", "Saturn 34 95.199997 gas giant True\n", "Uranus 27 14.370000 ice giant True\n", "Neptune 13 17.150000 ice giant True" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "translation = {\n", " \"земная группа\": \"terrestrial group\",\n", " \"газовый гигант\": \"gas giant\",\n", " \"ледяной гигант\": \"ice giant\"\n", " }\n", "\n", "planets[\"group\"] = planets[\"group\"].map(translation)\n", "planets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Метод [DataFrame.applymap](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.applymap.html#pandas.DataFrame.applymap) применяет функцию к кажому значению в таблице.\n", "\n", "## Группировка по значениям столбца\n", "\n", "Часто необходимо сгруппировать строки таблицы по какому-то принципу и с каждой из групп проделать какие-то операции.\n", "\n", "```{figure} /_static/lecture_specific/pandas/groupby.svg\n", "```\n", "\n", "За группировку в `pandas` отвечает метод [DataFrame.groupby](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html). В качестве аргумента ей можно передать имя столбца, по значениям которого необходима группировка (можно также передать несколько столбцов в списке)." ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'gas giant': Index(['jupyter', 'Saturn'], dtype='object', name='name'),\n", " 'ice giant': Index(['Uranus', 'Neptune'], dtype='object', name='name'),\n", " 'terrestrial group': Index(['Mercury', 'Venus', 'Earth', 'Mars'], dtype='object', name='name')}\n" ] } ], "source": [ "from pprint import pprint\n", "\n", "grouped = planets.groupby(\"group\")\n", "pprint(dict(grouped.groups))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Каждую группу можно рассматривать как мини-таблицу." ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
number of moonsmassgrouprings
name
Mercury00.0055terrestrial groupFalse
Venus00.8150terrestrial groupFalse
Earth11.0000terrestrial groupFalse
Mars20.1070terrestrial groupFalse
\n", "
" ], "text/plain": [ " number of moons mass group rings\n", "name \n", "Mercury 0 0.0055 terrestrial group False\n", "Venus 0 0.8150 terrestrial group False\n", "Earth 1 1.0000 terrestrial group False\n", "Mars 2 0.1070 terrestrial group False" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grouped.get_group(\"terrestrial group\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Часто таблицу группируют по значениям одного столбца, чтобы потом посчитать какие-нибудь агрегирующие функцию к значениям других столбцов. Сделать это можно методом [DataFrameGroupBy.aggregate](https://pandas.pydata.org/docs/reference/api/pandas.core.groupby.DataFrameGroupBy.aggregate.html). " ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
minmeanamaxmediancount
group
gas giant3448.006248.02
terrestrial group00.7520.54
ice giant1320.002720.02
\n", "
" ], "text/plain": [ " min mean amax median count\n", "group \n", "gas giant 34 48.00 62 48.0 2\n", "terrestrial group 0 0.75 2 0.5 4\n", "ice giant 13 20.00 27 20.0 2" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "grouped[\"number of moons\"].aggregate([min, np.mean, np.max, \"median\", \"count\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Гораздо чаще в отдельном виде объект группировки не выделяют." ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "brand\n", "AMC 1\n", "Cadillac 1\n", "Camaro 1\n", "Chrysler 1\n", "Datsun 1\n", "Dodge 1\n", "Duster 1\n", "Ferrari 1\n", "Fiat 2\n", "Ford 1\n", "Honda 1\n", "Hornet 2\n", "Lincoln 1\n", "Lotus 1\n", "Maserati 1\n", "Mazda 2\n", "Merc 7\n", "Pontiac 1\n", "Porsche 1\n", "Toyota 2\n", "Valiant 1\n", "Volvo 1\n", "Name: mpg, dtype: int64" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mtcars.groupby(\"brand\")[\"mpg\"].aggregate(\"count\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3.8.10 ('venv': venv)", "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.10.7" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "eea3ef54c04064aa17c056cc2578c78db8b44278034b77b7225a3166c34cea02" } } }, "nbformat": 4, "nbformat_minor": 2 }