Appearance
План курса: Pandas для AI-инженера
Каждый пункт — это 1 отдельный полноценный урок (до 1 часа), включающий подробную теорию и практические упражнения с фокусом на предобработку гетерогенных данных (EDA) и Feature Engineering в ИИ.
Каждое упражнение снабжено скрытым блоком ответов ::: details Посмотреть решение для интеграции в VitePress.
- Упражнения базовые: не менее 5 штук на проработку изученного материала в данном блоке. Все переменные, индексы и комментарии в коде пишутся исключительно на английском языке с использованием полного имени библиотеки
pandas. - Упражнения смешанные: не менее 5 штук на проработку изученного материала в данном блоке и включающие пройденный материал предыдущих разделов (включая сквозную интеграцию с библиотекой NumPy).
1. Введение в Pandas: роль в ИИ, установка и окружение
Назначение библиотеки Pandas в инженерии ИИ
Почему численного NumPy недостаточно для подготовки реальных данных из физического мира. Роль библиотеки pandas как главного инструмента этапа EDA (Exploratory Data Analysis) и предобработки сырых гетерогенных (разнородных) датасетов перед их превращением в тензоры нейросетей. Понятие табличных данных в ИИ-задачах.
Окружение, установка и правила импорта
Установка библиотеки через менеджеры пакетов pip и conda. Правила импорта и соглашения промышленной разработки: полный отказ от сокращений и использование стопроцентно полного имени import pandas для обеспечения прозрачности архитектуры кода. Использование интерактивной среды Jupyter Notebook (.ipynb) как индустриального стандарта для разведочного анализа данных.
Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию)
Упражнения смешанные (5 шт) (включают сквозную интеграцию с изученным ранее NumPy)
2. Одномерные структуры: pandas.Series и основы метаданных
Понятие pandas.Series и связь с NumPy
Изучение pandas.Series как векторизованного одномерного массива с явными индексными метками. Физическая связь с ufuncs: разница между скрытым C-буфером series.values (который является массивом numpy.ndarray) и объектом series.index. Выравнивание данных по индексам на аппаратном уровне.
Фундаментальные характеристики и аудит структуры
Проверка ключевых характеристик одномерного контейнера на практике с использованием полного синтаксиса pandas. Использование встроенных атрибутов и свойств метаданных: .shape (геометрия), .dtype (тип элементов), .size (количество элементов) и .name (название признака).
Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию)
Упражнения смешанные (5 шт)
3. Индексирование и слайсинг одномерных pandas.Series
Позиционный и явный доступ к элементам
Доступ к ячейкам данных по числовому (позиционному) индексу и по строковой (явной) текстовой метке с помощью полного синтаксиса библиотеки pandas. Граничные случаи и поведение системы при совпадении числовых меток с позиционными индексами.
Слайсинг в Pandas и управление памятью
Правила расширенного среза series[start:stop:step]. Важное отличие Pandas от NumPy: включение правой границы (stop) при слайсинге по текстовым меткам. Анатомия управления памятью: особенности создания представлений (Views) и принудительных копий (Copies) при нарезке Series.
Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию)
Упражнения смешанные (5 шт)
4. Векторизованные операции и сортировки в pandas.Series
Векторизованная математика и проблема несовпадения индексов
Поэлементное выполнение арифметических операций в режимах «Series со скаляром» и «Series с Series» без использования циклов. Механизм автоматического выравнивания по индексам в pandas: почему несовпадение меток при сложении или умножении двух Series приводит к генерации маркеров NaN (IEEE 754).
Алгоритмы сортировки одномерных контейнеров
Упорядочивание данных по значениям признаков с помощью функции pandas.Series.sort_values(series) или метода объекта series.sort_values(), а также по индексным меткам через series.sort_index(). Настройка параметров направления сортировки (ascending) и контроля мутации памяти (inplace).
Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию)
Упражнения смешанные (5 шт)
5. Двумерные датасеты: pandas.DataFrame, создание и аудит структуры
Концепция pandas.DataFrame как матрицы признаков
Понимание pandas.DataFrame как двумерной коллекции выровненных по индексам столбцов pandas.Series. Способы ручного конструирования таблиц из стандартных словарей, списков и двумерных матриц numpy.ndarray с помощью конструктора pandas.DataFrame(). Метаданные структуры: .shape, .columns, .index, .dtypes.
Экспресс-аудит и оценка веса таблицы в памяти
Быстрый первичный анализ структуры загруженных данных с помощью методов .head(), .info() и .describe(). Точный расчет физического веса таблицы и каждого отдельного столбца фичей в оперативной памяти компьютера через метод .memory_usage(deep=True).
Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию)
Упражнения смешанные (5 шт)
6. Индексация в DataFrame: loc, iloc и булево маскирование
Выборка данных через .loc и .iloc
Строгие правила двумерной адресации в таблицах pandas. Использование оператора .loc[] для индексации и слайсинга исключительно по явным текстовым меткам (строк и столбцов) и оператора .iloc[] — для позиционного доступа по целым числам.
Булева фильтрация строк датасета
Векторизованная фильтрация объектов DataFrame по логическим условиям на C-скорости. Создание сложных многомерных масок с использованием побитовых операторов & (AND), | (OR), ~ (NOT) и обязательных круглых скобок для изоляциии батчей строк по условиям признаков.
Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию)
Упражнения смешанные (5 шт)
7. Универсальное индексирование и выборка подмассивов фичей
Разделение датасета на признаки X и таргет y
Извлечение подматриц фичей и векторов ответов с помощью универсального оператора .loc[:, :]. Удаление ненужных или избыточных столбцов признаков из памяти с помощью метода .drop(axis=1). Быстрое добавление новых расчетных колонок.
Условная модификация данных
Применение векторизованной функции условной замены series.where() и numpy.where() для точечной модификации и очистки элементов внутри выбранных столбцов pandas.DataFrame без использования тяжелых циклов.
Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию)
Упражнения смешанные (5 шт)
8. Чтение датасетов из файлов (CSV, JSON, Parquet) и первичный EDA
Ввод-вывод и форматы хранения данных
Работа с дисковой подсистемой. Чтение сырых текстовых таблиц через pandas.read_csv() и структур через pandas.read_json(). Изучение бинарного колоночного формата Parquet (pandas.read_parquet()) — почему он является стандартом де-факто в Big Data и AI (сжатие, скорость, строгое сохранение типов данных).
Оптимизация RAM при загрузке тяжелых файлов
Параметры ограничения ввода для предотвращения переполнения памяти (Out of Memory): использование usecols для чтения только целевых столбцов фичей, явное указание типов через dtype и настройка индексных осей через index_col.
Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию)
Упражнения смешанные (5 шт)
9. Предобработка AI-данных: обработка пропусков (NaN/None) и дубликатов
Стратегии импутации (заполнения) пропусков в ML
Поиск и подсчет скрытых пропущенных значений по всем столбцам датасета через .isna().sum(). Математические стратегии борьбы с пропусками: жесткое удаление поврежденных строк/столбцов (.dropna()) или заполнение (импутация) пустот средним значением, медианой или константой (.fillna()).
Очистка от дубликатов
Обнаружение и удаление идентичных строк-дубликатов объектов в выборке с помощью методов .duplicated() и .drop_duplicates(), обеспечивающие идеальную чистоту обучающего множества.
Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию)
Упражнения смешанные (5 шт)
10. Feature Engineering: кодирование категориальных признаков и метод .apply()
Подготовка текста и категорий к подаче в нейросети
Концепция перевода текстовых категорий в цифровые форматы. Математический смысл и реализация алгоритма One-Hot Encoding (прямое двоичное кодирование) в pandas с помощью функции pandas.get_dummies().
Кастомные трансформации через .apply()
Выполнение сложных поэлементных преобразований текста или чисел с помощью метода .apply() и лямбда-функций lambda x: .... Использование метода для токенизации, очистки строк или кастомного масштабирования признаков.
Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию)
Упражнения смешанные (5 шт)
11. Агрегация данных, группировка (groupby) и конвертация в тензоры NumPy
Группировка и расчет кумулятивных статистик
Разбиение датасета на подгруппы по категориальным признакам с помощью метода .groupby(). Расчет групповых статистических показателей (среднее, сумма, дисперсия) для анализа распределения фичей в разрезе классов.
Экспорт данных в тензорные пайплайны
Финальный шаг этапа EDA перед обучением. Бесшовная конвертация очищенного, закодированного и нормализованного объекта pandas.DataFrame в сырой низкоуровневый массив numpy.ndarray через методы .to_numpy() или .values для последующей передачи в загрузчики данных (DataLoaders) фреймворков PyTorch или TensorFlow.
Упражнения базовые (5 шт) (только с опорой на объясненную в данном уроке теорию)
Упражнения смешанные (5 шт) (включают сквозную интеграцию с изученным ранее NumPy)
Библиотека pandas активно используется в современном data science для работы с данными, которые могут быть представлены в виде таблиц (а это очень, очень большая часть данных)
pandas есть в пакете Anaconda, но если вдруг у Вас её по каким-то причинам нет, то можно установить, раскомментировав одну из следующих команд:
python
# !pip3 install pandas
# !conda install pandaspython
import numpy as np
import pandas as pd # Стандартное сокращение для pandas. Всегда используйте его!pd.Series
Тип данных pd.Series представляет собой одномерный набор данных. Отсутствующие данные записываются как np.nan (в этот день термометр сломался или метеоролог был пьян); они не участвуют в вычислении средних, среднеквадратичных отклонений и т.д.
pd.Series
Тип данных pd.Series представляет собой одномерный набор данных. Отсутствующие данные записываются как np.nan (в этот день термометр сломался или метеоролог был пьян); они не участвуют в вычислении средних, среднеквадратичных отклонений и т.д.
Создание
Создадим Series из списка температур
python
some_list = [1, 3, 5, np.nan, 6, 8]
ser_1 = pd.Series(some_list)
ser_1Может работать только с однородными данными. поэтому приобразование к float.
text
0 1.0
1 3.0
2 5.0
3 NaN
4 6.0
5 8.0
dtype: float64python
# Так же можно в явном виде указать индексы, чтобы потом было более удобно обращаться к элементам
ind = ['1st day', '2nd day', '3rd day', '4th day', '5rd day', '6th day']
ser_2 = pd.Series(some_list, index=ind)
ser_2text
1st day 1.0
2nd day 3.0
3rd day 5.0
4th day NaN
5rd day 6.0
6th day 8.0
dtype: float64python
ser_2['4th day']text
nanpython
# А еще можно дать pd.Series имя, чтобы было совсем красиво
ser_3 = pd.Series(some_list, index=ind, name='Temperature')
ser_3text
1st day 1.0
2nd day 3.0
3rd day 5.0
4th day NaN
5rd day 6.0
6th day 8.0
Name: Temperature, dtype: float64Индексирование
С индексами можно работать так же, как и в случае с обычным list.
python
print(ser_3[0])
print('-----------')
print(ser_3[1:3])
print('-----------')
print(ser_3[::-1])text
1.0
-----------
2nd day 3.0
3rd day 5.0
Name: Temperature, dtype: float64
-----------
6th day 8.0
5rd day 6.0
4th day NaN
3rd day 5.0
2nd day 3.0
1st day 1.0
Name: Temperature, dtype: float64Индексирование pd.Series по условиям
python
date_range = pd.date_range('20190101', periods=10)
ser_4 = pd.Series(np.random.rand(10), date_range)
ser_4text
2019-01-01 0.196719
2019-01-02 0.641093
2019-01-03 0.237214
2019-01-04 0.212385
2019-01-05 0.511854
2019-01-06 0.895351
2019-01-07 0.757688
2019-01-08 0.976297
2019-01-09 0.008470
2019-01-10 0.403961
Freq: D, dtype: float64python
ser_4 > 0.5text
2019-01-01 False
2019-01-02 True
2019-01-03 False
2019-01-04 False
2019-01-05 True
2019-01-06 True
2019-01-07 True
2019-01-08 True
2019-01-09 False
2019-01-10 False
Freq: D, dtype: boolВ качестве индекса можно указать выражение, и нам будут возвращены только те элементы, для которых значение является True
python
ser_4[ser_4 > 0.5]text
2019-01-02 0.641093
2019-01-05 0.511854
2019-01-06 0.895351
2019-01-07 0.757688
2019-01-08 0.976297
dtype: float64python
ser_4[(ser_4 > 0.6) | (ser_4 < 0.2)]text
2019-01-01 0.196719
2019-01-02 0.641093
2019-01-06 0.895351
2019-01-07 0.757688
2019-01-08 0.976297
2019-01-09 0.008470
dtype: float64python
ser_4[(ser_4 > 0.6) & (ser_4 < 0.2)]text
Series([], Freq: D, dtype: float64)Сортировки
Тип pd.Series можно отсортировать как по значениям, так и по индексу.
python
ser_4.sort_index()text
2019-01-01 0.196719
2019-01-02 0.641093
2019-01-03 0.237214
2019-01-04 0.212385
2019-01-05 0.511854
2019-01-06 0.895351
2019-01-07 0.757688
2019-01-08 0.976297
2019-01-09 0.008470
2019-01-10 0.403961
Freq: D, dtype: float64python
ser_4.sort_values()text
2019-01-09 0.008470
2019-01-01 0.196719
2019-01-04 0.212385
2019-01-03 0.237214
2019-01-10 0.403961
2019-01-05 0.511854
2019-01-02 0.641093
2019-01-07 0.757688
2019-01-06 0.895351
2019-01-08 0.976297
dtype: float64При сортироки не изменяется сам объект, а возвращается копия.
При перезаписи объекта сортирока сохраняется.
python
ser_4 = ser_4.sort_values()python
ser_4text
2019-01-09 0.008470
2019-01-01 0.196719
2019-01-04 0.212385
2019-01-03 0.237214
2019-01-10 0.403961
2019-01-05 0.511854
2019-01-02 0.641093
2019-01-07 0.757688
2019-01-06 0.895351
2019-01-08 0.976297
dtype: float64Операции с series
Тип pd.Series можно модифицировать проще, чем стандартный list из Python.
python
ser_4 + 100text
2019-01-09 100.008470
2019-01-01 100.196719
2019-01-04 100.212385
2019-01-03 100.237214
2019-01-10 100.403961
2019-01-05 100.511854
2019-01-02 100.641093
2019-01-07 100.757688
2019-01-06 100.895351
2019-01-08 100.976297
dtype: float64python
np.exp(ser_4)text
2019-01-09 1.008506
2019-01-01 1.217402
2019-01-04 1.236624
2019-01-03 1.267712
2019-01-10 1.497746
2019-01-05 1.668381
2019-01-02 1.898555
2019-01-07 2.133339
2019-01-06 2.448194
2019-01-08 2.654608
dtype: float64python
term_1 = pd.Series(np.random.randint(0, 10, 5))
term_2 = pd.Series(np.random.randint(0, 10, 6))
term_1 + term_2text
0 14.0
1 8.0
2 6.0
3 14.0
4 14.0
5 NaN
dtype: float64python
term_1.shapetext
(5,)pd.DataFrame
Тип данных pd.DataFrame представляет собой двумерную таблицу с данными. Имеет индекс и набор столбцов (возможно, имеющих разные типы). Таблицу можно построить, например, из словаря, значениями в котором являются одномерные наборы данных.
Создание и основные объекты
python
# Dataframe можно составить из словаря. Ключ будет соответствовать колонке
some_dict = {'one': pd.Series([1,2,3], index=['a','b','c']),
'two': pd.Series([1,2,3,4], index=['a','b','c','d']),
'three': pd.Series([5,6,7,8], index=['a','b','c','d'])}
df = pd.DataFrame(some_dict)
dftext
one two three
a 1.0 1 5
b 2.0 2 6
c 3.0 3 7
d NaN 4 8python
# Альтернативно, из списка списков с аргументом columns
some_array = [[1, 1, 5], [2, 2, 6], [3, 3, 7], [np.nan, 4, 8]]
df = pd.DataFrame(some_array, index=['a', 'b', 'c', 'd'], columns=['one', 'two', 'three'])
dftext
one two three
a 1.0 1 5
b 2.0 2 6
c 3.0 3 7
d NaN 4 8python
df.valuestext
array([[ 1., 1., 5.],
[ 2., 2., 6.],
[ 3., 3., 7.],
[nan, 4., 8.]])python
df.columnstext
Index(['one', 'two', 'three'], dtype='object')python
df.columns = ['first_column', 'second_column', 'third_column']
df.index = [1,2,3,4]
dftext
first_column second_column third_column
1 1.0 1 5
2 2.0 2 6
3 3.0 3 7
4 NaN 4 8Индексирование
Есть очень много способов индексировать DataFrame в Pandas. Не все из них хорошие! Вот несколько удобных, но не универсальных.
По колонкам
Индексирование по колонке возвращает pd.Series. Можно выбирать не одну колонку, а сразу несколько. Тогда снова вернётся pd.DataFrame.
python
first_column = df['first_column']
first_columntext
1 1.0
2 2.0
3 3.0
4 NaN
Name: first_column, dtype: float64python
df.first_columntext
1 1.0
2 2.0
3 3.0
4 NaN
Name: first_column, dtype: float64python
subset_dataframe = df[['first_column', 'second_column']]
subset_dataframetext
first_column second_column
1 1.0 1
2 2.0 2
3 3.0 3
4 NaN 4python
one_column_dataframe = df[['first_column']]
one_column_dataframetext
first_column
1 1.0
2 2.0
3 3.0
4 NaNПо строкам
Можно писать любые слайсы, как в Python-списке. Они будут применяться к строкам. Нельзя обращаться по элементу!
python
df[1] # не сработаетtext
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
/usr/local/lib/python3.7/dist-packages/pandas/core/indexes/base.py in get_loc(self, key, method, tolerance)
2897 try:
-> 2898 return self._engine.get_loc(casted_key)
2899 except KeyError as err:
pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()
pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()
pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item()
pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item()
KeyError: 1
The above exception was the direct cause of the following exception:
KeyError Traceback (most recent call last)
<ipython-input-29-000000000000> in <module>
----> 1 df[1]
/usr/local/lib/python3.7/dist-packages/pandas/core/indexes/base.py in get_loc(self, key, method, tolerance)
2899 except KeyError as err:
-> 2900 raise KeyError(key) from err
2901 if tolerance is not None:
KeyError: 1python
df[:1]text
first_column second_column third_column
1 1.0 1 5python
df[1:4]text
first_column second_column third_column
2 2.0 2 6
3 3.0 3 7
4 NaN 4 8Универсальное индексирование: .loc и .iloc
.loc и .iloc — это два взаимозаменяемых атрибута, которые позволяют индексировать по обеим осям сразу. Путаницы не возникает из-за фиксированного порядка перечисления осей.
python
# По индексам:
df.iloc[1:3, :2]text
first_column second_column
2 2.0 2
3 3.0 3python
df.loc[1:3, ['first_column', 'second_column']]text
first_column second_column
1 1.0 1
2 2.0 2
3 3.0 3Лучше использовать по умолчанию либо только loc, либо только iloc! А лучше вообще всегда только iloc, чтобы не запутаться.
Модификации датасета, создание новых колонок
Можно просто брать и создавать новую колонку. Синтаксис тут вполне естественный.
python
new_column = [5, 2, 1, 4]
df['new_column'] = new_column
dftext
first_column second_column third_column new_column
1 1.0 1 5 5
2 2.0 2 6 2
3 3.0 3 7 1
4 NaN 4 8 4Аналогично, можно применять к отдельным колонкам арифметические операции (ведь колонки — это Series!)
python
df['first_column'] = df['first_column'] * 10
dftext
first_column second_column third_column new_column
1 10.0 1 5 5
2 20.0 2 6 2
3 30.0 3 7 1
4 NaN 4 8 4Реальный датасет
Мы будем работать с датасетом Титаник. Файлы необходимо скачать локально или загрузить с помощью функции ниже.
Информация о файлах:
titanic_data.csvсодержит различную информацию о пассажирах Титаника (билет, класс, возраст и т.п.)titanic_surv.csvсодержит для каждого пассажира из первого файла информацию о том, выжил ли этот пассажир (метка 1) или нет (метка 0)
Чтение из файла
Обычно данные хранятся в виде таблиц в файлах формата .csv или .xlsx. На этом семинаре мы будем загружать данные из .csv файлов.
Загрузим первый файл
python
# df_1 = pd.read_csv('titanic_data.csv')
pass_link = 'https://dropbox.com'
titanic_passengers = pd.read_csv(pass_link, index_col='PassengerId') # index_col=?python
print('Всего пассажиров: ', len(titanic_passengers))
titanic_passengers.head()python
print('Всего пассажиров: ', len(titanic_passengers))
titanic_passengers.head(10)text
Всего пассажиров: 891
Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embar
PassengerId
1 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
2 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
3 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
4 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
5 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
6 3 Moran, Mr. James male NaN 0 0 330877 8.4583 NaN Q
7 1 McCarthy, Mr. Timothy J male 54.0 0 0 17463 51.8625 E46 S
8 3 Palsson, Master. Gosta Leonard male 2.0 3 1 349909 21.0750 NaN S
9 3 Johnson, Mrs. Oscar W (Elisabeth Vilhelmina Berg) female 27.0 0 2 347742 11.1333 NaN S
10 2 Nasser, Mrs. Nicholas (Adele Achem) female 14.0 1 0 237736 30.0708 NaN C(Примечание: названия колонок Cabin и Embar [в исходном файле Embarked] частично обрезаны на скриншоте по правому краю).
python
titanic_passengers = pd.read_csv(pass_link) # index_col=?
print('Всего пассажиров: ', len(titanic_passengers))
titanic_passengers.head(10)text
Всего пассажиров: 891
PassengerId Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Emb
0 1 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
5 6 3 Moran, Mr. James male NaN 0 0 330877 8.4583 NaN Q
6 7 1 McCarthy, Mr. Timothy J male 54.0 0 0 17463 51.8625 E46 S
7 8 3 Palsson, Master. Gosta Leonard male 2.0 3 1 349909 21.0750 NaN S
8 9 3 Johnson, Mrs. Oscar W (Elisabeth Vilhelmina Berg) female 27.0 0 2 347742 11.1333 NaN S
9 10 2 Nasser, Mrs. Nicholas (Adele Achem) female 14.0 1 0 237736 30.0708 NaN C(Примечание: названия колонок Cabin и Emb [в исходном файле Embarked] частично обрезаны на скриншоте по правому краю).
Обратите внимание на разницу с прошлым слайдом: здесь убрали параметр index_col='PassengerId'. Теперь PassengerId стал обычной колонкой, а индексом таблицы стали автоматические числа от 0 до 9.
python
# df_1 = pd.read_csv('titanic_data.csv')
pass_link = 'https://dropbox.com'
titanic_passengers = pd.read_csv(pass_link, index_col='PassengerId') # index_col=?python
print('Всего пассажиров: ', len(titanic_passengers))
titanic_passengers.head(10)text
Всего пассажиров: 891
Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embar
PassengerId
1 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
2 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
3 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
4 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
5 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
6 3 Moran, Mr. James male NaN 0 0 330877 8.4583 NaN Q
7 1 McCarthy, Mr. Timothy J male 54.0 0 0 17463 51.8625 E46 S
8 3 Palsson, Master. Gosta Leonard male 2.0 3 1 349909 21.0750 NaN S
9 3 Johnson, Mrs. Oscar W (Elisabeth Vilhelmina Berg) female 27.0 0 2 347742 11.1333 NaN S
10 2 Nasser, Mrs. Nicholas (Adele Achem) female 14.0 1 0 237736 30.0708 NaN C(Примечание: названия колонок Cabin и Embar [в оригинале Embarked] частично обрезаны на скриншоте по правому краю).
Этот вывод таблицы с установленным индексом PassengerId мы уже оцифровывали чуть ранее.
Разная информация о датасете
Можно узнать размер таблицы, информацию о значениях таблицы, различные статистики по значениям.
python
titanic_passengers.shapetext
(891, 10)python
titanic_passengers.info()text
<class 'pandas.core.frame.DataFrame'>
Int64Index: 891 entries, 1 to 891
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Pclass 891 non-null int64
1 Name 891 non-null object
2 Sex 891 non-null object
3 Age 714 non-null float64
4 SibSp 891 non-null int64
5 Parch 891 non-null int64
6 Ticket 891 non-null object
7 Fare 891 non-null float64
8 Cabin 204 non-null object
9 Embarked 889 non-null object
dtypes: float64(2), int64(3), object(5)
memory usage: 76.6+ KBМетод .info() наглядно показывает пропуски: например, в колонке Age заполнено только 714 строк из 891, а в Cabin — всего 204.
python
titanic_passengers.describe()text
Pclass Age SibSp Parch Fare
count 891.000000 714.000000 891.000000 891.000000 891.000000
mean 2.308642 29.699118 0.523008 0.381594 32.204208
std 0.836071 14.526497 1.102743 0.806057 49.693429
min 1.000000 0.420000 0.000000 0.000000 0.000000
25% 2.000000 20.125000 0.000000 0.000000 7.910400
50% 3.000000 28.000000 0.000000 0.000000 14.454200
75% 3.000000 38.000000 1.000000 0.000000 31.000000
max 3.000000 80.000000 8.000000 6.000000 512.329200Метод .describe() рассчитал основные статистические показатели для всех числовых признаков (средний возраст пассажиров оказался около 29.7 лет, а максимальная стоимость билета составила 512.33).
Задание 1
Опишите данный датасет: какое распределение женщин/мужчин в нем? Сколько пассажиров ехало в каждом classe? Какой средний/минимальный/максимальный возраст пассажиров?
python
(titanic_passengers['Age'].min(), titanic_passengers['Age'].mean(), titanic_passengers['Age'].max())text
(0.42, 29.69911764705882, 80.0)python
titanic_passengers['Sex'].value_counts()text
male 577
female 314
Name: Sex, dtype: int64Мы дошли до первого практического задания! В коде уже нашли возрастные метки и распределение по полу (мужчин 577, женщин 314).
python
titanic_passengers['Pclass'].value_counts()text
3 491
1 216
2 184
Name: Pclass, dtype: int64Эта ячейка как раз отвечает на последний вопрос из Задания 1: больше всего пассажиров (491) ехало в 3-м классе.
Задание 2.
Сгруппируйте записи по классам пассажиров, в каждой группе посчитайте средний возраст. Используйте метод pandas.DataFrame.groupby.
python
titanic_passengers.groupby(['Pclass']).mean()text
Age SibSp Parch Fare
Pclass
1 38.233441 0.416667 0.356481 84.154687
2 29.877630 0.402174 0.380435 20.662183
3 25.140620 0.615071 0.393075 13.675550python
titanic_passengers.groupby(['Pclass'])['Age'].mean()text
Pclass
1 38.233441
2 29.877630
3 25.140620
Name: Age, dtype: float64Вторая ячейка на скриншоте демонстрирует более правильный подход: мы сначала выбираем колонку ['Age'], а затем считаем её среднее, чтобы Pandas не тратил ресурсы на расчёт средних значений для всех остальных столбцов.
Слияние таблиц
Таблицы можно сливать несколькими способами. Мы рассмотрим слияние по индексу: метод называется pd.join.
python
# df_2 = pd.read_csv('titanic_surv.csv')
surv_link = 'https://dropbox.com'
df_2 = pd.read_csv(surv_link)python
df_2.head()text
Survived
0 0
1 1
2 1
3 1
4 0Как мы видим, во второй таблице находится всего одна колонка — Survived. Обратите внимание, что при чтении здесь тоже забыли указать параметр index_col, поэтому вместо реальных ID пассажиров таблица получила автоматические индексы от 0 до 4.
Задание 3.
Слейте два датасета по колонке индекса.
python
df_2.index = np.arange(1, 892)python
df_2 = df_2.sample(frac=1)
df_2.head()text
Survived
351 0
122 0
499 0
759 0
813 0Обратите внимание на важный шаг в коде:Сначала строкой df_2.index = np.arange(1, 892) исправили индексы, сделав их от 1 до 891 (чтобы они совпадали с PassengerId первой таблицы).Но затем выполнили df_2.sample(frac=1), что перемешало строки в случайном порядке.
python
titanic_passengers = titanic_passengers.join(df_2)
titanic_passengers.head()text
Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embark
PassengerId
1 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
2 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
3 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
4 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
5 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S(Примечание: названия колонок Cabin и Embark [в оригинале Embarked] частично обрезаны на скриншоте по правому краю, а колонка Survived, присоединенная в самый конец таблицы, оказалась полностью скрыта за пределами видимой области экрана).
Метод .join() успешно объединил таблицы по их индексам. Даже несмотря на то, что строки в df_2 были перемешаны, Pandas автоматически сопоставил нужные значения Survived для каждого PassengerId.
Задание 4.
Сколько всего выживших пассажиров? Выживших пассажиров по каждому из полов? Постройте матрицу корреляций факта выживания, пола и возраста.
python
titanic_passengers['Survived'].sum()text
342python
titanic_passengers.groupby(['Sex'])['Survived'].sum()text
Sex
female 233
male 109
Name: Survived, dtype: int64В коде уже посчитали общее число выживших (342) и разбили их по полу (женщин выжило значительно больше — 233 против 109).
python
corr_data = titanic_passengers[['Sex', 'Age', 'Survived']]
corr_data['Sex'] = (corr_data['Sex'] == 'female').astype(int)text
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:2: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pydata.orgpython
corr_data.head()text
Sex Age Survived
PassengerId
1 0 22.0 0
2 1 38.0 1
3 1 26.0 1
4 1 35.0 1
5 0 35.0 0Обратите внимание на предупреждение SettingWithCopyWarning: Pandas ругается, так как изменение колонки происходит во временной копии датафрейма, а не в оригинале.
python
corr_data.corr()text
Sex Age Survived
Sex 1.000000 -0.093254 0.543351
Age -0.093254 1.000000 -0.077221
Survived 0.543351 -0.077221 1.000000Задание 4 полностью выполнено! Из матрицы видно, что между полом (Sex, где 1 — это female) и выживаемостью (Survived) есть заметная положительная корреляция (0.54), что подтверждает правило «сначала женщины и дети».
python
sns.heatmap(corr_data.corr(), annot=True, cmap='coolwarm',
vmin=-1, vmax=1, annot_kws={"size": 16})text
<matplotlib.axes._subplots.AxesSubplot at 0x7f109d3b61d0>(Примечание: на скриншоте также отображён визуальный график тепловой карты корреляции [Heatmap], построенный с помощью библиотеки Seaborn, где сильный красный цвет обозначает прямую корреляцию 1, оранжевый — связь 0.54, а серо-голубой — слабые отрицательные связи -0.093 и -0.077).Мы визуализировали матрицу корреляций с помощью Seaborn.