You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
28 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "1b560955ff39a2bcf2a049fce474a951",
"translation_date": "2025-09-06T06:08:48+00:00",
"source_file": "2-Working-With-Data/08-data-preparation/README.md",
"language_code": "ru"
}
-->
# Работа с данными: Подготовка данных
|![ Скетчноут от [(@sketchthedocs)](https://sketchthedocs.dev) ](../../sketchnotes/08-DataPreparation.png)|
|:---:|
|Подготовка данных - _Скетчноут от [@nitya](https://twitter.com/nitya)_ |
## [Тест перед лекцией](https://ff-quizzes.netlify.app/en/ds/quiz/14)
В зависимости от источника, необработанные данные могут содержать несоответствия, которые создают сложности при анализе и моделировании. Другими словами, такие данные можно классифицировать как "грязные", и их необходимо очистить. Этот урок посвящен техникам очистки и преобразования данных для решения проблем, связанных с отсутствующими, неточными или неполными данными. Темы, рассмотренные в этом уроке, будут использовать Python и библиотеку Pandas и будут [продемонстрированы в ноутбуке](../../../../2-Working-With-Data/08-data-preparation/notebook.ipynb) в этом каталоге.
## Важность очистки данных
- **Удобство использования и повторного использования**: Когда данные правильно организованы и нормализованы, их легче искать, использовать и делиться ими с другими.
- **Согласованность**: В области науки о данных часто приходится работать с несколькими наборами данных, которые необходимо объединить. Убедившись, что каждый отдельный набор данных имеет общую стандартизацию, можно гарантировать, что данные останутся полезными после их объединения в один набор.
- **Точность моделей**: Очищенные данные повышают точность моделей, которые на них основаны.
## Общие цели и стратегии очистки
- **Исследование набора данных**: Исследование данных, которое будет рассмотрено в [позднем уроке](https://github.com/microsoft/Data-Science-For-Beginners/tree/main/4-Data-Science-Lifecycle/15-analyzing), помогает выявить данные, которые необходимо очистить. Визуальное наблюдение за значениями в наборе данных позволяет установить ожидания относительно его структуры или выявить проблемы, которые можно решить. Исследование может включать базовые запросы, визуализации и выборки.
- **Форматирование**: В зависимости от источника данные могут иметь несоответствия в представлении. Это может вызывать проблемы при поиске и отображении значений, когда они видны в наборе данных, но неправильно представлены в визуализациях или результатах запросов. Общие проблемы форматирования включают устранение пробелов, корректировку дат и типов данных. Решение таких проблем обычно лежит на пользователях данных. Например, стандарты представления дат и чисел могут различаться в разных странах.
- **Дублирование**: Данные с несколькими повторениями могут давать неточные результаты и обычно должны быть удалены. Это часто происходит при объединении двух или более наборов данных. Однако бывают случаи, когда дублирование в объединенных наборах данных содержит дополнительные сведения, которые могут быть полезны и должны быть сохранены.
- **Отсутствующие данные**: Отсутствующие данные могут приводить к неточностям, слабым или предвзятым результатам. Иногда это можно исправить путем "перезагрузки" данных, заполнения отсутствующих значений с помощью вычислений и кода, например, на Python, или просто удаления значения и соответствующих данных. Причины отсутствия данных могут быть различными, и действия, предпринимаемые для их устранения, зависят от того, как и почему они пропали.
## Исследование информации в DataFrame
> **Цель обучения:** К концу этого раздела вы должны уверенно находить общую информацию о данных, хранящихся в pandas DataFrame.
После загрузки данных в pandas они, скорее всего, будут представлены в виде DataFrame (см. предыдущий [урок](https://github.com/microsoft/Data-Science-For-Beginners/tree/main/2-Working-With-Data/07-python#dataframe) для подробного обзора). Однако если набор данных в вашем DataFrame содержит 60,000 строк и 400 столбцов, с чего начать, чтобы понять, с чем вы работаете? К счастью, [pandas](https://pandas.pydata.org/) предоставляет удобные инструменты для быстрого просмотра общей информации о DataFrame, а также первых и последних строк.
Чтобы изучить эту функциональность, мы импортируем библиотеку Python scikit-learn и используем знаковый набор данных: **набор данных Iris**.
```python
import pandas as pd
from sklearn.datasets import load_iris
iris = load_iris()
iris_df = pd.DataFrame(data=iris['data'], columns=iris['feature_names'])
```
| |sepal length (cm)|sepal width (cm)|petal length (cm)|petal width (cm)|
|----------------------------------------|-----------------|----------------|-----------------|----------------|
|0 |5.1 |3.5 |1.4 |0.2 |
|1 |4.9 |3.0 |1.4 |0.2 |
|2 |4.7 |3.2 |1.3 |0.2 |
|3 |4.6 |3.1 |1.5 |0.2 |
|4 |5.0 |3.6 |1.4 |0.2 |
- **DataFrame.info**: Для начала метод `info()` используется для вывода сводки содержимого, присутствующего в `DataFrame`. Давайте посмотрим на этот набор данных:
```python
iris_df.info()
```
```
RangeIndex: 150 entries, 0 to 149
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 sepal length (cm) 150 non-null float64
1 sepal width (cm) 150 non-null float64
2 petal length (cm) 150 non-null float64
3 petal width (cm) 150 non-null float64
dtypes: float64(4)
memory usage: 4.8 KB
```
Из этого мы узнаем, что набор данных *Iris* содержит 150 записей в четырех столбцах без пропущенных значений. Все данные хранятся в виде 64-битных чисел с плавающей точкой.
- **DataFrame.head()**: Далее, чтобы проверить фактическое содержимое `DataFrame`, мы используем метод `head()`. Давайте посмотрим, как выглядят первые несколько строк нашего `iris_df`:
```python
iris_df.head()
```
```
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)
0 5.1 3.5 1.4 0.2
1 4.9 3.0 1.4 0.2
2 4.7 3.2 1.3 0.2
3 4.6 3.1 1.5 0.2
4 5.0 3.6 1.4 0.2
```
- **DataFrame.tail()**: Напротив, чтобы проверить последние несколько строк `DataFrame`, мы используем метод `tail()`:
```python
iris_df.tail()
```
```
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)
145 6.7 3.0 5.2 2.3
146 6.3 2.5 5.0 1.9
147 6.5 3.0 5.2 2.0
148 6.2 3.4 5.4 2.3
149 5.9 3.0 5.1 1.8
```
> **Вывод:** Даже просто взглянув на метаданные о содержимом DataFrame или на первые и последние значения, можно сразу получить представление о размере, форме и содержании данных, с которыми вы работаете.
## Работа с отсутствующими данными
> **Цель обучения:** К концу этого раздела вы должны знать, как заменять или удалять нулевые значения из DataFrame.
Чаще всего наборы данных, которые вы хотите использовать (или вынуждены использовать), содержат отсутствующие значения. То, как вы обрабатываете отсутствующие данные, несет с собой тонкие компромиссы, которые могут повлиять на ваш окончательный анализ и реальные результаты.
Pandas обрабатывает отсутствующие значения двумя способами. Первый вы уже видели в предыдущих разделах: `NaN`, или Not a Number. Это специальное значение, которое является частью спецификации IEEE для чисел с плавающей точкой и используется только для указания отсутствующих значений с плавающей точкой.
Для отсутствующих значений, кроме чисел с плавающей точкой, pandas использует объект Python `None`. Хотя может показаться запутанным, что вы столкнетесь с двумя различными типами значений, которые говорят по сути одно и то же, есть веские программные причины для такого выбора дизайна, и на практике это позволяет pandas предложить хороший компромисс для подавляющего большинства случаев. Тем не менее, и `None`, и `NaN` имеют ограничения, которые необходимо учитывать в отношении их использования.
Узнайте больше о `NaN` и `None` из [ноутбука](https://github.com/microsoft/Data-Science-For-Beginners/blob/main/4-Data-Science-Lifecycle/15-analyzing/notebook.ipynb)!
- **Обнаружение нулевых значений**: В `pandas` методы `isnull()` и `notnull()` являются основными для обнаружения отсутствующих данных. Оба возвращают булевы маски для ваших данных. Мы будем использовать `numpy` для значений `NaN`:
```python
import numpy as np
example1 = pd.Series([0, np.nan, '', None])
example1.isnull()
```
```
0 False
1 True
2 False
3 True
dtype: bool
```
Внимательно посмотрите на вывод. Вас что-то удивляет? Хотя `0` является арифметическим нулем, он, тем не менее, является вполне допустимым целым числом, и pandas рассматривает его как таковое. `''` немного сложнее. Хотя мы использовали его в разделе 1 для представления пустого строкового значения, он, тем не менее, является строковым объектом, а не представлением null с точки зрения pandas.
Теперь давайте перевернем это и используем эти методы так, как вы будете использовать их на практике. Вы можете использовать булевы маски непосредственно как индекс ``Series`` или ``DataFrame``, что может быть полезно при работе с отдельными отсутствующими (или присутствующими) значениями.
> **Вывод:** Методы `isnull()` и `notnull()` дают схожие результаты при использовании в `DataFrame`: они показывают результаты и индекс этих результатов, что значительно поможет вам в работе с данными.
- **Удаление нулевых значений**: Помимо идентификации отсутствующих значений, pandas предоставляет удобный способ удаления нулевых значений из `Series` и `DataFrame`. (Особенно в больших наборах данных часто более целесообразно просто удалить отсутствующие [NA] значения из анализа, чем обрабатывать их другими способами.) Чтобы увидеть это в действии, вернемся к `example1`:
```python
example1 = example1.dropna()
example1
```
```
0 0
2
dtype: object
```
Обратите внимание, что это должно выглядеть как ваш вывод из `example3[example3.notnull()]`. Разница здесь в том, что вместо индексации по маскированным значениям `dropna` удалил эти отсутствующие значения из `Series` `example1`.
Поскольку `DataFrame` имеет две измерения, он предоставляет больше возможностей для удаления данных.
```python
example2 = pd.DataFrame([[1, np.nan, 7],
[2, 5, 8],
[np.nan, 6, 9]])
example2
```
| | 0 | 1 | 2 |
|------|---|---|---|
|0 |1.0|NaN|7 |
|1 |2.0|5.0|8 |
|2 |NaN|6.0|9 |
(Вы заметили, что pandas преобразовал два столбца в числа с плавающей точкой, чтобы учесть `NaN`?)
Вы не можете удалить одно значение из `DataFrame`, поэтому вам придется удалять целые строки или столбцы. В зависимости от того, что вы делаете, вы можете захотеть сделать одно или другое, и pandas предоставляет вам варианты для обоих. Поскольку в науке о данных столбцы обычно представляют переменные, а строки — наблюдения, вы, скорее всего, будете удалять строки данных; настройка по умолчанию для `dropna()` — удалять все строки, содержащие любые нулевые значения:
```python
example2.dropna()
```
```
0 1 2
1 2.0 5.0 8
```
Если необходимо, вы можете удалить значения NA из столбцов. Используйте `axis=1`, чтобы сделать это:
```python
example2.dropna(axis='columns')
```
```
2
0 7
1 8
2 9
```
Обратите внимание, что это может удалить много данных, которые вы, возможно, захотите сохранить, особенно в небольших наборах данных. Что если вы хотите удалить только строки или столбцы, содержащие несколько или даже все нулевые значения? Вы можете указать эти настройки в `dropna` с помощью параметров `how` и `thresh`.
По умолчанию `how='any'` (если вы хотите проверить это самостоятельно или увидеть, какие еще параметры есть у метода, выполните `example4.dropna?` в ячейке кода). Вы можете, например, указать `how='all'`, чтобы удалять только строки или столбцы, содержащие все нулевые значения. Давайте расширим наш пример `DataFrame`, чтобы увидеть это в действии.
```python
example2[3] = np.nan
example2
```
| |0 |1 |2 |3 |
|------|---|---|---|---|
|0 |1.0|NaN|7 |NaN|
|1 |2.0|5.0|8 |NaN|
|2 |NaN|6.0|9 |NaN|
Параметр `thresh` дает вам более тонкий контроль: вы устанавливаете количество *ненулевых* значений, которые строка или столбец должны иметь, чтобы быть сохраненными:
```python
example2.dropna(axis='rows', thresh=3)
```
```
0 1 2 3
1 2.0 5.0 8 NaN
```
Здесь первая и последняя строки были удалены, так как они содержат только два ненулевых значения.
- **Заполнение нулевых значений**: В зависимости от вашего набора данных иногда имеет смысл заполнять нулевые значения допустимыми, а не удалять их. Вы могли бы использовать `isnull` для этого на месте, но это может быть трудоемким, особенно если у вас много значений для заполнения. Поскольку это такая распространенная задача в науке о данных, pandas предоставляет `fillna`, который возвращает копию `Series` или `DataFrame` с заменой отсутствующих значений на выбранные вами. Давайте создадим еще один пример `Series`, чтобы увидеть, как это работает на практике.
```python
example3 = pd.Series([1, np.nan, 2, None, 3], index=list('abcde'))
example3
```
```
a 1.0
b NaN
c 2.0
d NaN
e 3.0
dtype: float64
```
Вы можете заполнить все нулевые записи одним значением, например, `0`:
```python
example3.fillna(0)
```
```
a 1.0
b 0.0
c 2.0
d 0.0
e 3.0
dtype: float64
```
Вы можете **заполнить вперед** нулевые значения, используя последнее допустимое значение для заполнения null:
```python
example3.fillna(method='ffill')
```
```
a 1.0
b 1.0
c 2.0
d 2.0
e 3.0
dtype: float64
```
Вы также можете **заполнить назад**, чтобы распространить следующее допустимое значение назад для заполнения null:
```python
example3.fillna(method='bfill')
```
```
a 1.0
b 2.0
c 2.0
d 3.0
e 3.0
dtype: float64
```
Как вы могли догадаться, это работает так же с `DataFrame`, но вы также можете указать `axis`, вдоль которого заполнять нулевые значения. Возьмем снова ранее использованный `example2`:
```python
example2.fillna(method='ffill', axis=1)
```
```
0 1 2 3
0 1.0 1.0 7.0 7.0
1 2.0 5.0 8.0 8.0
2 NaN 6.0 9.0 9.0
```
Обратите внимание, что когда предыдущее значение недоступно для заполнения вперед, нулевое значение остается.
> **Основная мысль:** Существует множество способов справиться с отсутствующими значениями в ваших наборах данных. Конкретная стратегия (удаление, замена или способ замены) должна определяться особенностями этих данных. Чем больше вы работаете с наборами данных и взаимодействуете с ними, тем лучше вы будете понимать, как справляться с отсутствующими значениями.
## Удаление дублированных данных
> **Цель обучения:** К концу этого подраздела вы должны уверенно определять и удалять дублированные значения из DataFrame.
Помимо отсутствующих данных, в реальных наборах данных вы часто будете сталкиваться с дублированными данными. К счастью, `pandas` предоставляет простой способ обнаружения и удаления повторяющихся записей.
- **Определение дубликатов: `duplicated`**: Вы можете легко обнаружить дублированные значения с помощью метода `duplicated` в pandas, который возвращает булеву маску, указывающую, является ли запись в `DataFrame` дубликатом более ранней. Давайте создадим еще один пример `DataFrame`, чтобы увидеть это в действии.
```python
example4 = pd.DataFrame({'letters': ['A','B'] * 2 + ['B'],
'numbers': [1, 2, 1, 3, 3]})
example4
```
| |letters|numbers|
|------|-------|-------|
|0 |A |1 |
|1 |B |2 |
|2 |A |1 |
|3 |B |3 |
|4 |B |3 |
```python
example4.duplicated()
```
```
0 False
1 False
2 True
3 False
4 True
dtype: bool
```
- **Удаление дубликатов: `drop_duplicates`:** просто возвращает копию данных, для которых все значения `duplicated` равны `False`:
```python
example4.drop_duplicates()
```
```
letters numbers
0 A 1
1 B 2
3 B 3
```
Оба метода `duplicated` и `drop_duplicates` по умолчанию учитывают все столбцы, но вы можете указать, чтобы они проверяли только подмножество столбцов в вашем `DataFrame`:
```python
example4.drop_duplicates(['letters'])
```
```
letters numbers
0 A 1
1 B 2
```
> **Вывод:** Удаление дублированных данных — это важная часть практически каждого проекта в области анализа данных. Дублированные данные могут исказить результаты ваших анализов и привести к неточным выводам!
## 🚀 Задание
Все обсуждаемые материалы предоставлены в [Jupyter Notebook](https://github.com/microsoft/Data-Science-For-Beginners/blob/main/2-Working-With-Data/08-data-preparation/notebook.ipynb). Кроме того, после каждого раздела есть упражнения — попробуйте их выполнить!
## [Тест после лекции](https://ff-quizzes.netlify.app/en/ds/quiz/15)
## Обзор и самостоятельное изучение
Существует множество способов изучения и подходов к подготовке данных для анализа и моделирования, а очистка данных — это важный этап, который требует практического опыта. Попробуйте эти задания на Kaggle, чтобы изучить техники, которые не были рассмотрены в этом уроке.
- [Data Cleaning Challenge: Parsing Dates](https://www.kaggle.com/rtatman/data-cleaning-challenge-parsing-dates/)
- [Data Cleaning Challenge: Scale and Normalize Data](https://www.kaggle.com/rtatman/data-cleaning-challenge-scale-and-normalize-data)
## Задание
[Оценка данных из формы](assignment.md)
---
**Отказ от ответственности**:
Этот документ был переведен с помощью сервиса автоматического перевода [Co-op Translator](https://github.com/Azure/co-op-translator). Хотя мы стремимся к точности, пожалуйста, имейте в виду, что автоматические переводы могут содержать ошибки или неточности. Оригинальный документ на его исходном языке следует считать авторитетным источником. Для получения критически важной информации рекомендуется профессиональный перевод человеком. Мы не несем ответственности за любые недоразумения или неправильные толкования, возникшие в результате использования данного перевода.