{
"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",
" 0 \n",
" 0.0055 \n",
" земная группа \n",
" Нет \n",
" \n",
" \n",
" Венера \n",
" 0 \n",
" 0.8150 \n",
" земная группа \n",
" Нет \n",
" \n",
" \n",
" Земля \n",
" 1 \n",
" 1.0000 \n",
" земная группа \n",
" Нет \n",
" \n",
" \n",
" Марс \n",
" 2 \n",
" 0.1070 \n",
" земная группа \n",
" Нет \n",
" \n",
" \n",
" Юпитер \n",
" 62 \n",
" 317.8000 \n",
" газовый гигант \n",
" Да \n",
" \n",
" \n",
" Сатурн \n",
" 34 \n",
" 95.2000 \n",
" газовый гигант \n",
" Да \n",
" \n",
" \n",
" Уран \n",
" 27 \n",
" 14.3700 \n",
" ледяной гигант \n",
" Да \n",
" \n",
" \n",
" Нептун \n",
" 13 \n",
" 17.1500 \n",
" ледяной гигант \n",
" Да \n",
" \n",
" \n",
"
\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",
" 0 \n",
" 0.0055 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" Венера \n",
" 0 \n",
" 0.8150 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" Земля \n",
" 1 \n",
" 1.0000 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" Марс \n",
" 2 \n",
" 0.1070 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" Юпитер \n",
" 62 \n",
" 317.8000 \n",
" газовый гигант \n",
" True \n",
" \n",
" \n",
" Сатурн \n",
" 34 \n",
" 95.2000 \n",
" газовый гигант \n",
" True \n",
" \n",
" \n",
" Уран \n",
" 27 \n",
" 14.3700 \n",
" ледяной гигант \n",
" True \n",
" \n",
" \n",
" Нептун \n",
" 13 \n",
" 17.1500 \n",
" ледяной гигант \n",
" True \n",
" \n",
" \n",
"
\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",
" 0 \n",
" 0.005500 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" Венера \n",
" 0 \n",
" 0.815000 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" Земля \n",
" 1 \n",
" 1.000000 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" Марс \n",
" 2 \n",
" 0.107000 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" Юпитер \n",
" 62 \n",
" 317.799988 \n",
" газовый гигант \n",
" True \n",
" \n",
" \n",
" Сатурн \n",
" 34 \n",
" 95.199997 \n",
" газовый гигант \n",
" True \n",
" \n",
" \n",
" Уран \n",
" 27 \n",
" 14.370000 \n",
" ледяной гигант \n",
" True \n",
" \n",
" \n",
" Нептун \n",
" 13 \n",
" 17.150000 \n",
" ледяной гигант \n",
" True \n",
" \n",
" \n",
"
\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",
" number of moons \n",
" mass \n",
" group \n",
" rings \n",
" \n",
" \n",
" Название \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" Mercury \n",
" 0 \n",
" 0.005500 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" Venus \n",
" 0 \n",
" 0.815000 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" Earth \n",
" 1 \n",
" 1.000000 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" Mars \n",
" 2 \n",
" 0.107000 \n",
" земная группа \n",
" False \n",
" \n",
" \n",
" jupyter \n",
" 62 \n",
" 317.799988 \n",
" газовый гигант \n",
" True \n",
" \n",
" \n",
" Saturn \n",
" 34 \n",
" 95.199997 \n",
" газовый гигант \n",
" True \n",
" \n",
" \n",
" Uranus \n",
" 27 \n",
" 14.370000 \n",
" ледяной гигант \n",
" True \n",
" \n",
" \n",
" Neptune \n",
" 13 \n",
" 17.150000 \n",
" ледяной гигант \n",
" True \n",
" \n",
" \n",
"
\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",
" s1 \n",
" s2 \n",
" s3 \n",
" \n",
" \n",
" \n",
" \n",
" a \n",
" 1.0 \n",
" -1 \n",
" NaN \n",
" \n",
" \n",
" b \n",
" 2.0 \n",
" NaN \n",
" NaN \n",
" \n",
" \n",
" c \n",
" NaN \n",
" NaN \n",
" NaN \n",
" \n",
" \n",
"
\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",
" s1 \n",
" s2 \n",
" s3 \n",
" \n",
" \n",
" \n",
" \n",
" a \n",
" 1.0 \n",
" -1 \n",
" 0.0 \n",
" \n",
" \n",
" b \n",
" 2.0 \n",
" -2 \n",
" NaN \n",
" \n",
" \n",
" c \n",
" NaN \n",
" NaN \n",
" NaN \n",
" \n",
" \n",
"
\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",
" s1 \n",
" s2 \n",
" s3 \n",
" \n",
" \n",
" \n",
" \n",
" a \n",
" 1.0 \n",
" -1 \n",
" 0.0 \n",
" \n",
" \n",
"
\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",
" s1 \n",
" s2 \n",
" s3 \n",
" \n",
" \n",
" \n",
" \n",
" a \n",
" 1.0 \n",
" -1 \n",
" 0.0 \n",
" \n",
" \n",
" b \n",
" 2.0 \n",
" -2 \n",
" NaN \n",
" \n",
" \n",
"
\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",
" a \n",
" b \n",
" c \n",
" \n",
" \n",
" \n",
" \n",
" s1 \n",
" 1.0 \n",
" 2.0 \n",
" NaN \n",
" \n",
" \n",
" s2 \n",
" -1 \n",
" -2 \n",
" NaN \n",
" \n",
" \n",
" s3 \n",
" 0.0 \n",
" NaN \n",
" NaN \n",
" \n",
" \n",
"
\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",
" a \n",
" \n",
" \n",
" \n",
" \n",
" s1 \n",
" 1.0 \n",
" \n",
" \n",
" s2 \n",
" -1 \n",
" \n",
" \n",
" s3 \n",
" 0.0 \n",
" \n",
" \n",
"
\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",
" a \n",
" b \n",
" \n",
" \n",
" \n",
" \n",
" s1 \n",
" 1.0 \n",
" 2.0 \n",
" \n",
" \n",
" s2 \n",
" -1 \n",
" -2 \n",
" \n",
" \n",
" s3 \n",
" 0.0 \n",
" NaN \n",
" \n",
" \n",
"
\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",
" boolean \n",
" numeric \n",
" categorical \n",
" \n",
" \n",
" \n",
" \n",
" a \n",
" True \n",
" NaN \n",
" NaN \n",
" \n",
" \n",
" b \n",
" NaN \n",
" 1.0 \n",
" NaN \n",
" \n",
" \n",
" c \n",
" NaN \n",
" NaN \n",
" white \n",
" \n",
" \n",
"
\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",
" boolean \n",
" numeric \n",
" categorical \n",
" \n",
" \n",
" \n",
" \n",
" a \n",
" True \n",
" 0.0 \n",
" black \n",
" \n",
" \n",
" b \n",
" False \n",
" 1.0 \n",
" black \n",
" \n",
" \n",
" c \n",
" False \n",
" 0.0 \n",
" white \n",
" \n",
" \n",
"
\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",
" mpg \n",
" cyl \n",
" disp \n",
" hp \n",
" drat \n",
" wt \n",
" qsec \n",
" vs \n",
" am \n",
" gear \n",
" carb \n",
" \n",
" \n",
" model \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" Mazda RX4 \n",
" 21.0 \n",
" 6 \n",
" 160.0 \n",
" 110 \n",
" 3.90 \n",
" 2.620 \n",
" 16.46 \n",
" 0 \n",
" 1 \n",
" 4 \n",
" 4 \n",
" \n",
" \n",
" Mazda RX4 Wag \n",
" 21.0 \n",
" 6 \n",
" 160.0 \n",
" 110 \n",
" 3.90 \n",
" 2.875 \n",
" 17.02 \n",
" 0 \n",
" 1 \n",
" 4 \n",
" 4 \n",
" \n",
" \n",
" Datsun 710 \n",
" 22.8 \n",
" 4 \n",
" 108.0 \n",
" 93 \n",
" 3.85 \n",
" 2.320 \n",
" 18.61 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 1 \n",
" \n",
" \n",
" Hornet 4 Drive \n",
" 21.4 \n",
" 6 \n",
" 258.0 \n",
" 110 \n",
" 3.08 \n",
" 3.215 \n",
" 19.44 \n",
" 1 \n",
" 0 \n",
" 3 \n",
" 1 \n",
" \n",
" \n",
" Hornet Sportabout \n",
" 18.7 \n",
" 8 \n",
" 360.0 \n",
" 175 \n",
" 3.15 \n",
" 3.440 \n",
" 17.02 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 2 \n",
" \n",
" \n",
" Valiant \n",
" 18.1 \n",
" 6 \n",
" 225.0 \n",
" 105 \n",
" 2.76 \n",
" 3.460 \n",
" 20.22 \n",
" 1 \n",
" 0 \n",
" 3 \n",
" 1 \n",
" \n",
" \n",
" Duster 360 \n",
" 14.3 \n",
" 8 \n",
" 360.0 \n",
" 245 \n",
" 3.21 \n",
" 3.570 \n",
" 15.84 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 4 \n",
" \n",
" \n",
" Merc 240D \n",
" 24.4 \n",
" 4 \n",
" 146.7 \n",
" 62 \n",
" 3.69 \n",
" 3.190 \n",
" 20.00 \n",
" 1 \n",
" 0 \n",
" 4 \n",
" 2 \n",
" \n",
" \n",
" Merc 230 \n",
" 22.8 \n",
" 4 \n",
" 140.8 \n",
" 95 \n",
" 3.92 \n",
" 3.150 \n",
" 22.90 \n",
" 1 \n",
" 0 \n",
" 4 \n",
" 2 \n",
" \n",
" \n",
" Merc 280 \n",
" 19.2 \n",
" 6 \n",
" 167.6 \n",
" 123 \n",
" 3.92 \n",
" 3.440 \n",
" 18.30 \n",
" 1 \n",
" 0 \n",
" 4 \n",
" 4 \n",
" \n",
" \n",
" Merc 280C \n",
" 17.8 \n",
" 6 \n",
" 167.6 \n",
" 123 \n",
" 3.92 \n",
" 3.440 \n",
" 18.90 \n",
" 1 \n",
" 0 \n",
" 4 \n",
" 4 \n",
" \n",
" \n",
" Merc 450SE \n",
" 16.4 \n",
" 8 \n",
" 275.8 \n",
" 180 \n",
" 3.07 \n",
" 4.070 \n",
" 17.40 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 3 \n",
" \n",
" \n",
" Merc 450SL \n",
" 17.3 \n",
" 8 \n",
" 275.8 \n",
" 180 \n",
" 3.07 \n",
" 3.730 \n",
" 17.60 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 3 \n",
" \n",
" \n",
" Merc 450SLC \n",
" 15.2 \n",
" 8 \n",
" 275.8 \n",
" 180 \n",
" 3.07 \n",
" 3.780 \n",
" 18.00 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 3 \n",
" \n",
" \n",
" Cadillac Fleetwood \n",
" 10.4 \n",
" 8 \n",
" 472.0 \n",
" 205 \n",
" 2.93 \n",
" 5.250 \n",
" 17.98 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 4 \n",
" \n",
" \n",
" Lincoln Continental \n",
" 10.4 \n",
" 8 \n",
" 460.0 \n",
" 215 \n",
" 3.00 \n",
" 5.424 \n",
" 17.82 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 4 \n",
" \n",
" \n",
" Chrysler Imperial \n",
" 14.7 \n",
" 8 \n",
" 440.0 \n",
" 230 \n",
" 3.23 \n",
" 5.345 \n",
" 17.42 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 4 \n",
" \n",
" \n",
" Fiat 128 \n",
" 32.4 \n",
" 4 \n",
" 78.7 \n",
" 66 \n",
" 4.08 \n",
" 2.200 \n",
" 19.47 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 1 \n",
" \n",
" \n",
" Honda Civic \n",
" 30.4 \n",
" 4 \n",
" 75.7 \n",
" 52 \n",
" 4.93 \n",
" 1.615 \n",
" 18.52 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 2 \n",
" \n",
" \n",
" Toyota Corolla \n",
" 33.9 \n",
" 4 \n",
" 71.1 \n",
" 65 \n",
" 4.22 \n",
" 1.835 \n",
" 19.90 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 1 \n",
" \n",
" \n",
" Toyota Corona \n",
" 21.5 \n",
" 4 \n",
" 120.1 \n",
" 97 \n",
" 3.70 \n",
" 2.465 \n",
" 20.01 \n",
" 1 \n",
" 0 \n",
" 3 \n",
" 1 \n",
" \n",
" \n",
" Dodge Challenger \n",
" 15.5 \n",
" 8 \n",
" 318.0 \n",
" 150 \n",
" 2.76 \n",
" 3.520 \n",
" 16.87 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 2 \n",
" \n",
" \n",
" AMC Javelin \n",
" 15.2 \n",
" 8 \n",
" 304.0 \n",
" 150 \n",
" 3.15 \n",
" 3.435 \n",
" 17.30 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 2 \n",
" \n",
" \n",
" Camaro Z28 \n",
" 13.3 \n",
" 8 \n",
" 350.0 \n",
" 245 \n",
" 3.73 \n",
" 3.840 \n",
" 15.41 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 4 \n",
" \n",
" \n",
" Pontiac Firebird \n",
" 19.2 \n",
" 8 \n",
" 400.0 \n",
" 175 \n",
" 3.08 \n",
" 3.845 \n",
" 17.05 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 2 \n",
" \n",
" \n",
" Fiat X1-9 \n",
" 27.3 \n",
" 4 \n",
" 79.0 \n",
" 66 \n",
" 4.08 \n",
" 1.935 \n",
" 18.90 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 1 \n",
" \n",
" \n",
" Porsche 914-2 \n",
" 26.0 \n",
" 4 \n",
" 120.3 \n",
" 91 \n",
" 4.43 \n",
" 2.140 \n",
" 16.70 \n",
" 0 \n",
" 1 \n",
" 5 \n",
" 2 \n",
" \n",
" \n",
" Lotus Europa \n",
" 30.4 \n",
" 4 \n",
" 95.1 \n",
" 113 \n",
" 3.77 \n",
" 1.513 \n",
" 16.90 \n",
" 1 \n",
" 1 \n",
" 5 \n",
" 2 \n",
" \n",
" \n",
" Ford Pantera L \n",
" 15.8 \n",
" 8 \n",
" 351.0 \n",
" 264 \n",
" 4.22 \n",
" 3.170 \n",
" 14.50 \n",
" 0 \n",
" 1 \n",
" 5 \n",
" 4 \n",
" \n",
" \n",
" Ferrari Dino \n",
" 19.7 \n",
" 6 \n",
" 145.0 \n",
" 175 \n",
" 3.62 \n",
" 2.770 \n",
" 15.50 \n",
" 0 \n",
" 1 \n",
" 5 \n",
" 6 \n",
" \n",
" \n",
" Maserati Bora \n",
" 15.0 \n",
" 8 \n",
" 301.0 \n",
" 335 \n",
" 3.54 \n",
" 3.570 \n",
" 14.60 \n",
" 0 \n",
" 1 \n",
" 5 \n",
" 8 \n",
" \n",
" \n",
" Volvo 142E \n",
" 21.4 \n",
" 4 \n",
" 121.0 \n",
" 109 \n",
" 4.11 \n",
" 2.780 \n",
" 18.60 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 2 \n",
" \n",
" \n",
"
\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": "iVBORw0KGgoAAAANSUhEUgAAAJoAAACPCAYAAAAC5MI/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAALX0lEQVR4nO3dbWxT1R8H8G9b125zXbfCHqgUGKBjyJPuSZhBg2QbErIHEpkvzCSKCXQkc4nkv71YV40OY4Imis6Y4AsNOvZiW4TIWObWOZ1iUAPjSVhUKlA2IXQ4Zsd2z/+F8cbSAetGT7fy/SQ3WU9P7/3d9pt77m7P7jRCCAGiINOGugC6NzBoJAWDRlIwaCQFg0ZSMGgkBYNGUjBoJAWDRlIwaCQFg0ZSMGgkBYNGUjBot9DV1YXMzExERkZiwYIF+PDDD1FTUwONRqP2aW1txeOPP464uDjExMQgNTUVVVVVPuvxer2w2+1YuHAhDAYDrFYrduzYAa/X67fNTz/9FFlZWYiOjkZ8fDxWr16NQ4cOBX1fZdBwmpC/Y8eOITs7GwkJCdi6dStGRkbw3nvvISkpCUePHoUQAsePH8ejjz6KZcuW4bnnnoPBYMDZs2dx+PBhOJ1OAICiKFi3bh26urrw0ksvIS0tDceOHUNdXR3Wr1+PpqYmdZsOhwM1NTVYtWoVioqKoNfr8f3338NqtWLnzp0heifuIkF+CgsLRWRkpPj999/VthMnTgidTif+fcvefvttAUD09/ffcj2ffPKJ0Gq14uuvv/Zpr6urEwDEN998I4QQ4syZM0Kr1YqioiIxOjrq01dRlLu1WyHFofMmo6OjaGlpQWFhIebMmaO2p6WlIS8vT30cFxcHAGhuboaiKGOuq6GhAWlpaVi0aBH+/PNPdVmzZg0AoL29HQDQ1NQERVFQXV0Nrdb3I/nvUD2dMWg36e/vx9DQEB588EG/51JTU9WfN23ahJycHLz44otISkpCSUkJ9u3b5xO6M2fO4Pjx40hISPBZHnroIQBAX18fAKC3txdarRaLFy8O8t6Fzn2hLmC6ioqKQmdnJ9rb23HgwAEcPHgQ9fX1WLNmDQ4dOgSdTgdFUbB06VLs2rVrzHVYrVbJVYdQqMfuqWZkZERERUWJkpISv+eefvppcbu37PXXXxcARGtrq9r/gQceuON51ltvvSUAiJ9++mlStU9lHDpvotPpkJeXh6amJpw7d05tP3nyJFpaWtTHV65c8XvtihUrAEC9dPHMM8/g/Pnz+Oijj/z6Dg0NYXBwEABQWFgIrVaLV1991e98T4TJRQFe3hjD0aNHkZ2djcTERGzbtg0jIyN49913fS5vlJeXo7OzE+vXr8fcuXPR19eH999/HxqNBj09PTCZTFAUBRs2bMCXX36pntONjo7i1KlT2LdvH1paWpCRkQEAqK6uxmuvvYZVq1ahuLgYBoMBP/zwAywWC2pra0P8jtwFoT2gTl1Op1Okp6cLvV4v5s+fL+rq6oTdbleHzra2NlFQUCAsFovQ6/XCYrGIZ599Vvzyyy8+6xkeHhZvvvmmePjhh4XBYBDx8fEiPT1dOBwO4fF4fPru2bNHPPLII2q/J554Qh2Gpzse0QJQU1MDh8MRNsOZTDxHIykYNJKCQSMpeI5GUvCIRlIwaCSF1O86FUXBhQsXYDQaw2ZWwr1OCIFr167BYrH4zTy5ueO4vfHGGyIjI0PExMSIhIQEUVBQIE6dOjXu17tcLgGASxguLpfrtp99QEc0p9MJm82GzMxMjIyMoKqqCrm5uThx4gTuv//+O77eaDQCAFwuF2JjYwPZNE1RAwMDsFqt6md7K5P6rbO/vx+JiYlwOp1YvXr1uIoymUzweDwMWpgY72c6qXM0j8cDADCbzWM+7/V6ff4IY2BgYDKbo2lswkFTFAXl5eXIycnBkiVLxuxTW1sLh8Mx4eKCbd7/Dtyxz28714d8neFgwpc3bDYbenp68Pnnn9+yT2VlJTwej7q4XK6Jbo6muQkd0crKyrB//350dnZi9uzZt+xnMBhgMBgmXByFj4CCJoTA9u3b0djYiI6ODqSkpASrLgozAQXNZrNh7969aG5uhtFohNvtBgCYTCZERUUFpUAKDwGdo33wwQfweDx48sknMWvWLHWpr68PVn0UJgIeOokmgl+qkxQMGknBoJEUDBpJwaCRFAwaScGgkRQMGknBoJEUDBpJwaCRFAwaScGgkRQMGknBoJEUDBpJwaCRFAwaScGgkRQMGknBoJEUDBpJwaCRFAwaScGgkRQMGknBoJEUDBpJwaCRFAwaSSH1n47d7lbh47nJMP0jGDdbnuhNnsd7+3ce0UgKBo2kYNBICgaNpGDQSAoGjaRg0EgKBo2kYNBICgaNpGDQSAoGjaRg0EgKBo2kYNBICgaNpGDQSAoGjaRg0EgKBo2kYNBICgaNpGDQSAoGjaRg0EgKBo2kYNBICgaNpGDQSAoGjaRg0EiKCQVt9+7dmDdvHiIjI5GdnY3Dhw/f7boozAQctPr6elRUVMBut+PHH3/E8uXLkZeXh76+vmDUR2Ei4KDt2rULW7ZswebNm7F48WLU1dUhOjoae/bsCUZ9FCbuC6Tz8PAwjhw5gsrKSrVNq9Vi7dq16O7u9uvv9Xrh9XrVxx6PB8A/t6O8meK9Hkgp97Sx3r/JGs/7P9Z2/2274x1qRQDOnz8vAIhvv/3Wp/2VV14RWVlZfv3tdrsAwOUeWFwu122zE9ARLVCVlZWoqKhQHyuKgitXrmDGjBnQaDQBr29gYABWqxUul+u2N+ad7qbTfgohcO3aNVgsltv2CyhoM2fOhE6nw6VLl3zaL126hOTkZL/+BoMBBoPBpy0uLi6QTY4pNjZ2yn8Ad8N02U+TyXTHPgH9MqDX65Geno62tja1TVEUtLW1YeXKlYFXSPeMgIfOiooKlJaWIiMjA1lZWXjnnXcwODiIzZs3B6M+ChMBB23Tpk3o7+9HdXU13G43VqxYgYMHDyIpKSkY9fkwGAyw2+1+w3G4Ccf9lPqfU+jexe86SQoGjaRg0EgKBo2kmJJB6+zsxIYNG2CxWKDRaNDU1OTz/PPPPw+NRuOz5Ofnh6bYCaqtrUVmZiaMRiMSExNRWFiI06dP+/T5+++/YbPZMGPGDMTExGDjxo1+F8uniykZtMHBQSxfvhy7d+++ZZ/8/HxcvHhRXT777DOJFU6e0+mEzWbDd999h9bWVty4cQO5ubkYHBxU+7z88sv44osv0NDQAKfTiQsXLqC4uDiEVU9CIF+qhwIA0djY6NNWWloqCgoKQlJPsPT19QkAwul0CiGEuHr1qoiIiBANDQ1qn5MnTwoAoru7O1RlTtiUPKKNR0dHBxITE5GamoqtW7fi8uXLoS5pUv6dQmU2mwEAR44cwY0bN7B27Vq1z6JFizBnzpwxp2RNdUGdvREs+fn5KC4uRkpKCnp7e1FVVYV169ahu7sbOp0u1OUFTFEUlJeXIycnB0uWLAEAuN1u6PV6v0kISUlJcLvdIahycqZl0EpKStSfly5dimXLlmHBggXo6OjAU089FcLKJsZms6GnpwddXV2hLiVopu3Q+V/z58/HzJkzcfbs2VCXErCysjLs378f7e3tmD17ttqenJyM4eFhXL161af/raZkTXVhEbQ//vgDly9fxqxZs0JdyrgJIVBWVobGxkZ89dVXSElJ8Xk+PT0dERERPlOyTp8+jXPnzk3LKVlTcuj866+/fI5Ov/76K37++WeYzWaYzWY4HA5s3LgRycnJ6O3txY4dO7Bw4ULk5eWFsOrA2Gw27N27F83NzTAajep5l8lkQlRUFEwmE1544QVUVFTAbDYjNjYW27dvx8qVK/HYY4+FuPoJCPWvvWNpb28fc156aWmpuH79usjNzRUJCQkiIiJCzJ07V2zZskW43e5Qlx2QsfYPgPj444/VPkNDQ2Lbtm0iPj5eREdHi6KiInHx4sXQFT0JnCZEUoTFORpNfQwaScGgkRQMGknBoJEUDBpJwaCRFAwaScGgkRQMGknBoJEUDBpJ8X9mPx3+eJWZuwAAAABJRU5ErkJggg==",
"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",
" mpg \n",
" cyl \n",
" disp \n",
" hp \n",
" drat \n",
" wt \n",
" qsec \n",
" vs \n",
" am \n",
" gear \n",
" carb \n",
" brand \n",
" model \n",
" \n",
" \n",
" car \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" Mazda RX4 \n",
" 21.0 \n",
" 6 \n",
" 160.0 \n",
" 110 \n",
" 3.90 \n",
" 2.620 \n",
" 16.46 \n",
" 0 \n",
" 1 \n",
" 4 \n",
" 4 \n",
" Mazda \n",
" RX4 \n",
" \n",
" \n",
" Mazda RX4 Wag \n",
" 21.0 \n",
" 6 \n",
" 160.0 \n",
" 110 \n",
" 3.90 \n",
" 2.875 \n",
" 17.02 \n",
" 0 \n",
" 1 \n",
" 4 \n",
" 4 \n",
" Mazda \n",
" RX4 Wag \n",
" \n",
" \n",
" Datsun 710 \n",
" 22.8 \n",
" 4 \n",
" 108.0 \n",
" 93 \n",
" 3.85 \n",
" 2.320 \n",
" 18.61 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 1 \n",
" Datsun \n",
" 710 \n",
" \n",
" \n",
" Hornet 4 Drive \n",
" 21.4 \n",
" 6 \n",
" 258.0 \n",
" 110 \n",
" 3.08 \n",
" 3.215 \n",
" 19.44 \n",
" 1 \n",
" 0 \n",
" 3 \n",
" 1 \n",
" Hornet \n",
" 4 Drive \n",
" \n",
" \n",
" Hornet Sportabout \n",
" 18.7 \n",
" 8 \n",
" 360.0 \n",
" 175 \n",
" 3.15 \n",
" 3.440 \n",
" 17.02 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 2 \n",
" Hornet \n",
" Sportabout \n",
" \n",
" \n",
" Valiant \n",
" 18.1 \n",
" 6 \n",
" 225.0 \n",
" 105 \n",
" 2.76 \n",
" 3.460 \n",
" 20.22 \n",
" 1 \n",
" 0 \n",
" 3 \n",
" 1 \n",
" Valiant \n",
" \n",
" \n",
" \n",
" Duster 360 \n",
" 14.3 \n",
" 8 \n",
" 360.0 \n",
" 245 \n",
" 3.21 \n",
" 3.570 \n",
" 15.84 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 4 \n",
" Duster \n",
" 360 \n",
" \n",
" \n",
" Merc 240D \n",
" 24.4 \n",
" 4 \n",
" 146.7 \n",
" 62 \n",
" 3.69 \n",
" 3.190 \n",
" 20.00 \n",
" 1 \n",
" 0 \n",
" 4 \n",
" 2 \n",
" Merc \n",
" 240D \n",
" \n",
" \n",
" Merc 230 \n",
" 22.8 \n",
" 4 \n",
" 140.8 \n",
" 95 \n",
" 3.92 \n",
" 3.150 \n",
" 22.90 \n",
" 1 \n",
" 0 \n",
" 4 \n",
" 2 \n",
" Merc \n",
" 230 \n",
" \n",
" \n",
" Merc 280 \n",
" 19.2 \n",
" 6 \n",
" 167.6 \n",
" 123 \n",
" 3.92 \n",
" 3.440 \n",
" 18.30 \n",
" 1 \n",
" 0 \n",
" 4 \n",
" 4 \n",
" Merc \n",
" 280 \n",
" \n",
" \n",
" Merc 280C \n",
" 17.8 \n",
" 6 \n",
" 167.6 \n",
" 123 \n",
" 3.92 \n",
" 3.440 \n",
" 18.90 \n",
" 1 \n",
" 0 \n",
" 4 \n",
" 4 \n",
" Merc \n",
" 280C \n",
" \n",
" \n",
" Merc 450SE \n",
" 16.4 \n",
" 8 \n",
" 275.8 \n",
" 180 \n",
" 3.07 \n",
" 4.070 \n",
" 17.40 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 3 \n",
" Merc \n",
" 450SE \n",
" \n",
" \n",
" Merc 450SL \n",
" 17.3 \n",
" 8 \n",
" 275.8 \n",
" 180 \n",
" 3.07 \n",
" 3.730 \n",
" 17.60 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 3 \n",
" Merc \n",
" 450SL \n",
" \n",
" \n",
" Merc 450SLC \n",
" 15.2 \n",
" 8 \n",
" 275.8 \n",
" 180 \n",
" 3.07 \n",
" 3.780 \n",
" 18.00 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 3 \n",
" Merc \n",
" 450SLC \n",
" \n",
" \n",
" Cadillac Fleetwood \n",
" 10.4 \n",
" 8 \n",
" 472.0 \n",
" 205 \n",
" 2.93 \n",
" 5.250 \n",
" 17.98 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 4 \n",
" Cadillac \n",
" Fleetwood \n",
" \n",
" \n",
" Lincoln Continental \n",
" 10.4 \n",
" 8 \n",
" 460.0 \n",
" 215 \n",
" 3.00 \n",
" 5.424 \n",
" 17.82 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 4 \n",
" Lincoln \n",
" Continental \n",
" \n",
" \n",
" Chrysler Imperial \n",
" 14.7 \n",
" 8 \n",
" 440.0 \n",
" 230 \n",
" 3.23 \n",
" 5.345 \n",
" 17.42 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 4 \n",
" Chrysler \n",
" Imperial \n",
" \n",
" \n",
" Fiat 128 \n",
" 32.4 \n",
" 4 \n",
" 78.7 \n",
" 66 \n",
" 4.08 \n",
" 2.200 \n",
" 19.47 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 1 \n",
" Fiat \n",
" 128 \n",
" \n",
" \n",
" Honda Civic \n",
" 30.4 \n",
" 4 \n",
" 75.7 \n",
" 52 \n",
" 4.93 \n",
" 1.615 \n",
" 18.52 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 2 \n",
" Honda \n",
" Civic \n",
" \n",
" \n",
" Toyota Corolla \n",
" 33.9 \n",
" 4 \n",
" 71.1 \n",
" 65 \n",
" 4.22 \n",
" 1.835 \n",
" 19.90 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 1 \n",
" Toyota \n",
" Corolla \n",
" \n",
" \n",
" Toyota Corona \n",
" 21.5 \n",
" 4 \n",
" 120.1 \n",
" 97 \n",
" 3.70 \n",
" 2.465 \n",
" 20.01 \n",
" 1 \n",
" 0 \n",
" 3 \n",
" 1 \n",
" Toyota \n",
" Corona \n",
" \n",
" \n",
" Dodge Challenger \n",
" 15.5 \n",
" 8 \n",
" 318.0 \n",
" 150 \n",
" 2.76 \n",
" 3.520 \n",
" 16.87 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 2 \n",
" Dodge \n",
" Challenger \n",
" \n",
" \n",
" AMC Javelin \n",
" 15.2 \n",
" 8 \n",
" 304.0 \n",
" 150 \n",
" 3.15 \n",
" 3.435 \n",
" 17.30 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 2 \n",
" AMC \n",
" Javelin \n",
" \n",
" \n",
" Camaro Z28 \n",
" 13.3 \n",
" 8 \n",
" 350.0 \n",
" 245 \n",
" 3.73 \n",
" 3.840 \n",
" 15.41 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 4 \n",
" Camaro \n",
" Z28 \n",
" \n",
" \n",
" Pontiac Firebird \n",
" 19.2 \n",
" 8 \n",
" 400.0 \n",
" 175 \n",
" 3.08 \n",
" 3.845 \n",
" 17.05 \n",
" 0 \n",
" 0 \n",
" 3 \n",
" 2 \n",
" Pontiac \n",
" Firebird \n",
" \n",
" \n",
" Fiat X1-9 \n",
" 27.3 \n",
" 4 \n",
" 79.0 \n",
" 66 \n",
" 4.08 \n",
" 1.935 \n",
" 18.90 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 1 \n",
" Fiat \n",
" X1-9 \n",
" \n",
" \n",
" Porsche 914-2 \n",
" 26.0 \n",
" 4 \n",
" 120.3 \n",
" 91 \n",
" 4.43 \n",
" 2.140 \n",
" 16.70 \n",
" 0 \n",
" 1 \n",
" 5 \n",
" 2 \n",
" Porsche \n",
" 914-2 \n",
" \n",
" \n",
" Lotus Europa \n",
" 30.4 \n",
" 4 \n",
" 95.1 \n",
" 113 \n",
" 3.77 \n",
" 1.513 \n",
" 16.90 \n",
" 1 \n",
" 1 \n",
" 5 \n",
" 2 \n",
" Lotus \n",
" Europa \n",
" \n",
" \n",
" Ford Pantera L \n",
" 15.8 \n",
" 8 \n",
" 351.0 \n",
" 264 \n",
" 4.22 \n",
" 3.170 \n",
" 14.50 \n",
" 0 \n",
" 1 \n",
" 5 \n",
" 4 \n",
" Ford \n",
" Pantera L \n",
" \n",
" \n",
" Ferrari Dino \n",
" 19.7 \n",
" 6 \n",
" 145.0 \n",
" 175 \n",
" 3.62 \n",
" 2.770 \n",
" 15.50 \n",
" 0 \n",
" 1 \n",
" 5 \n",
" 6 \n",
" Ferrari \n",
" Dino \n",
" \n",
" \n",
" Maserati Bora \n",
" 15.0 \n",
" 8 \n",
" 301.0 \n",
" 335 \n",
" 3.54 \n",
" 3.570 \n",
" 14.60 \n",
" 0 \n",
" 1 \n",
" 5 \n",
" 8 \n",
" Maserati \n",
" Bora \n",
" \n",
" \n",
" Volvo 142E \n",
" 21.4 \n",
" 4 \n",
" 121.0 \n",
" 109 \n",
" 4.11 \n",
" 2.780 \n",
" 18.60 \n",
" 1 \n",
" 1 \n",
" 4 \n",
" 2 \n",
" Volvo \n",
" 142E \n",
" \n",
" \n",
"
\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",
" number of moons \n",
" mass \n",
" group \n",
" rings \n",
" \n",
" \n",
" name \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" Mercury \n",
" 0 \n",
" 0.005500 \n",
" terrestrial group \n",
" False \n",
" \n",
" \n",
" Venus \n",
" 0 \n",
" 0.815000 \n",
" terrestrial group \n",
" False \n",
" \n",
" \n",
" Earth \n",
" 1 \n",
" 1.000000 \n",
" terrestrial group \n",
" False \n",
" \n",
" \n",
" Mars \n",
" 2 \n",
" 0.107000 \n",
" terrestrial group \n",
" False \n",
" \n",
" \n",
" jupyter \n",
" 62 \n",
" 317.799988 \n",
" gas giant \n",
" True \n",
" \n",
" \n",
" Saturn \n",
" 34 \n",
" 95.199997 \n",
" gas giant \n",
" True \n",
" \n",
" \n",
" Uranus \n",
" 27 \n",
" 14.370000 \n",
" ice giant \n",
" True \n",
" \n",
" \n",
" Neptune \n",
" 13 \n",
" 17.150000 \n",
" ice giant \n",
" True \n",
" \n",
" \n",
"
\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",
" number of moons \n",
" mass \n",
" group \n",
" rings \n",
" \n",
" \n",
" name \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" Mercury \n",
" 0 \n",
" 0.0055 \n",
" terrestrial group \n",
" False \n",
" \n",
" \n",
" Venus \n",
" 0 \n",
" 0.8150 \n",
" terrestrial group \n",
" False \n",
" \n",
" \n",
" Earth \n",
" 1 \n",
" 1.0000 \n",
" terrestrial group \n",
" False \n",
" \n",
" \n",
" Mars \n",
" 2 \n",
" 0.1070 \n",
" terrestrial group \n",
" False \n",
" \n",
" \n",
"
\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",
" min \n",
" mean \n",
" amax \n",
" median \n",
" count \n",
" \n",
" \n",
" group \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" gas giant \n",
" 34 \n",
" 48.00 \n",
" 62 \n",
" 48.0 \n",
" 2 \n",
" \n",
" \n",
" terrestrial group \n",
" 0 \n",
" 0.75 \n",
" 2 \n",
" 0.5 \n",
" 4 \n",
" \n",
" \n",
" ice giant \n",
" 13 \n",
" 20.00 \n",
" 27 \n",
" 20.0 \n",
" 2 \n",
" \n",
" \n",
"
\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
}