Skip to content

План курса: 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 pandas
python
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: float64
python
# Так же можно в явном виде указать индексы, чтобы потом было более удобно обращаться к элементам
ind = ['1st day', '2nd day', '3rd day', '4th day', '5rd day', '6th day']

ser_2 = pd.Series(some_list, index=ind)
ser_2
text
1st day    1.0
2nd day    3.0
3rd day    5.0
4th day    NaN
5rd day    6.0
6th day    8.0
dtype: float64
python
ser_2['4th day']
text
nan
python
# А еще можно дать pd.Series имя, чтобы было совсем красиво
ser_3 = pd.Series(some_list, index=ind, name='Temperature')
ser_3
text
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_4
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: float64
python
ser_4 > 0.5
text
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: float64
python
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: float64
python
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: float64
python
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_4
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

Операции с series ​

Тип pd.Series можно модифицировать проще, чем стандартный list из Python.

python
ser_4 + 100
text
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: float64
python
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: float64
python
term_1 = pd.Series(np.random.randint(0, 10, 5))
term_2 = pd.Series(np.random.randint(0, 10, 6))

term_1 + term_2
text
0    14.0
1     8.0
2     6.0
3    14.0
4    14.0
5     NaN
dtype: float64
python
term_1.shape
text
(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)
df
text
   one  two  three
a  1.0    1      5
b  2.0    2      6
c  3.0    3      7
d  NaN    4      8
python
# Альтернативно, из списка списков с аргументом 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'])
df
text
   one  two  three
a  1.0    1      5
b  2.0    2      6
c  3.0    3      7
d  NaN    4      8
python
df.values
text
array([[ 1.,  1.,  5.],
       [ 2.,  2.,  6.],
       [ 3.,  3.,  7.],
       [nan,  4.,  8.]])
python
df.columns
text
Index(['one', 'two', 'three'], dtype='object')
python
df.columns = ['first_column', 'second_column', 'third_column']
df.index = [1,2,3,4]
df
text
   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_column
text
1    1.0
2    2.0
3    3.0
4    NaN
Name: first_column, dtype: float64
python
df.first_column
text
1    1.0
2    2.0
3    3.0
4    NaN
Name: first_column, dtype: float64
python
subset_dataframe = df[['first_column', 'second_column']]
subset_dataframe
text
   first_column  second_column
1           1.0              1
2           2.0              2
3           3.0              3
4           NaN              4
python
one_column_dataframe = df[['first_column']]
one_column_dataframe
text
   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: 1
python
df[:1]
text
   first_column  second_column  third_column
1           1.0              1             5
python
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              3
python
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
df
text
   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
df
text
   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.shape
text
(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.675550
python
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
342
python
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.org
python
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.