# Робота з даними: Підготовка даних |![ Скетчноут від [(@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 data set**. ```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']) ``` | |довжина чашолистка (см)|ширина чашолистка (см)|довжина пелюстки (см)|ширина пелюстки (см)| |----------------------------------------|-----------------------|----------------------|---------------------|--------------------| |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 або перші та останні кілька значень, ви можете отримати миттєве уявлення про розмір, форму та вміст даних, з якими працюєте. ## Робота з відсутніми даними > **Ціль навчання:** До кінця цього підрозділу ви повинні знати, як замінювати або видаляти null-значення з 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)! - **Виявлення null-значень**: У `pandas` методи `isnull()` і `notnull()` є основними для виявлення null-даних. Обидва повертають булеві маски для ваших даних. Ми будемо використовувати `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` є арифметичним null, це все ж таки цілком допустиме ціле число, і pandas трактує його як таке. `''` трохи складніше. Хоча ми використовували його в Розділі 1 для представлення порожнього рядка, це все ж таки об'єкт рядка, а не представлення null з точки зору pandas. Тепер давайте перевернемо це і використаємо ці методи більш схоже на те, як ви будете використовувати їх на практиці. Ви можете використовувати булеві маски безпосередньо як індекс ``Series`` або ``DataFrame``, що може бути корисним при роботі з окремими відсутніми (або присутніми) значеннями. > **Висновок**: Як методи `isnull()`, так і `notnull()` дають схожі результати при використанні в `DataFrame`: вони показують результати та індекс цих результатів, що буде надзвичайно корисним, коли ви будете працювати з вашими даними. - **Видалення null-значень**: Окрім виявлення відсутніх значень, pandas надає зручний спосіб видалення null-значень з ``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()` — видалити всі рядки, які містять будь-які null-значення: ```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 ``` Зверніть увагу, що це може видалити багато даних, які ви, можливо, хочете зберегти, особливо в менших наборах даних. Що робити, якщо ви хочете видалити лише рядки або стовпці, які містять кілька або навіть усі null-значення? Ви можете вказати ці налаштування в `dropna` за допомогою параметрів `how` і `thresh`. За замовчуванням `how='any'` (якщо ви хочете перевірити самостійно або побачити, які інші параметри має метод, запустіть `example4.dropna?` у кодовій комірці). Ви можете альтернативно вказати `how='all'`, щоб видалити лише рядки або стовпці, які містять усі null-значення. Давайте розширимо наш приклад ``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` дає вам більш тонкий контроль: ви встановлюєте кількість *не-null* значень, які рядок або стовпець повинен мати, щоб бути збереженим: ```python example2.dropna(axis='rows', thresh=3) ``` ``` 0 1 2 3 1 2.0 5.0 8 NaN ``` Тут перший і останній рядки були видалені, оскільки вони містять лише два не-null значення. - **Заповнення null-значень**: Залежно від вашого набору даних, іноді може бути більш доцільно заповнити null-значення допустимими, ніж видалити їх. Ви могли б використовувати `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-значення, тобто використовувати останнє допустиме значення для заповнення 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`, уздовж якого заповнювати null-значення. Використовуючи знову раніше використаний `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 ``` Зверніть увагу, що коли попереднє значення недоступне для заповнення вперед, null-значення залишається. > **Висновок:** Існує кілька способів вирішення проблеми з відсутніми значеннями у ваших наборах даних. Конкретна стратегія, яку ви обираєте (видалення, заміна або навіть спосіб заміни), повинна залежати від особливостей цих даних. Ви будете краще розуміти, як працювати з відсутніми значеннями, чим більше ви взаємодіятимете з наборами даних. ## Видалення дубльованих даних > **Мета навчання:** Після завершення цього підрозділу ви повинні впевнено визначати та видаляти дубльовані значення з DataFrames. Окрім відсутніх даних, у реальних наборах даних ви часто зустрічатимете дубльовані дані. На щастя, `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, щоб дослідити техніки, які не були охоплені в цьому уроці. - [Завдання з очищення даних: Парсинг дат](https://www.kaggle.com/rtatman/data-cleaning-challenge-parsing-dates/) - [Завдання з очищення даних: Масштабування та нормалізація даних](https://www.kaggle.com/rtatman/data-cleaning-challenge-scale-and-normalize-data) ## Завдання [Оцінка даних з форми](assignment.md) --- **Відмова від відповідальності**: Цей документ був перекладений за допомогою сервісу автоматичного перекладу [Co-op Translator](https://github.com/Azure/co-op-translator). Хоча ми прагнемо до точності, будь ласка, майте на увазі, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ на його рідній мові слід вважати авторитетним джерелом. Для критичної інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникають внаслідок використання цього перекладу.