Нормалізація краудсорсингових даних за допомогою Python та Pandas

Авторка: Геллі Бернс Переклав на українську: Євген Ворожейкін Оригінал уроку: https://programminghistorian.org/en/lessons/crowdsourced-data-normalization-with-pandas

Pandas - це популярна та потужна бібліотека (збірка об'єктів чи підпрограм у відповідній мові програмування), яка використовується у Python для обробки та аналізу даних. У цьому уроці ми розглянемо краудсорсинг як форму створення даних, а також те, як Pandas можна використовувати для підготовки краудсорсингового набору даних для аналізу. Цей урок охоплює керування дублікатами та відсутніми даними та пояснює труднощі роботи з датами.

Огляд

Краудсорсинг – це спосіб роботи що делегує завдання зовнішнім співробітникам, зазвичай залученим через онлайн-платформу. Це спосіб збору ідей, отримання вхідних даних чи збору даних від громадськості, також відомої як "натовп" (англ. crowd). Є багато причин, чому проєкт може вибрати краудсорсинг як метод збору даних та їх введення. Краудсорсинг дозволяє використовувати внесок різноманітних груп людей з різними навичками та сильними сторонами. Краудсорсинг можна використовувати для генерації ідей чи для збору даних та транскрипції чи перекладу тексту. Проєктів такого характеру стає все більше, оскільки такі організації, як бібліотеки, працюють над тим, щоб зробити свої дуже великі колекції доступними в Інтернеті.

Дані можуть бути хаотичними, особливо в краудсорсингових проєктах. Дані, зібрані таким чином, завжди містять розбіжності, навіть якщо є чіткі та детальні вказівки щодо подання. Дослідники почали відходити від ідеї "очищення даних" до процесу "нормалізації даних". Частково це тому, що не всі "забруднені" дані потрібно очищати стандартизованим способом. Дані, особливо гуманітарні, містять варіації. Наприклад, різний правопис назв різними мовами чи їх зміна з часом. "Очистити" ці дані в один і той же спосіб - стандартизувати їх - стерло б історично важливу інформацію. Однак нормалізація даних є особливо корисною та необхідною для аналізу даних. Нормалізація даних складається з набору визначених кроків, які будуть пояснені у цьому посібнику.

У цьому уроці ви працюватимете з Python та бібліотекою Pandas із набором даних з платформи Kaggle, вивчатимете основи нормалізації даних та визначите поширені проблеми під час використання краудсорсингових даних.

Наприкінці уроку ви:

  • Зрозумієте проблеми, характерні для роботи з краудсорсинговими даними

  • Дізнаєтесь як використовувати pandas для впровадження загальних методів нормалізації даних

  • Використаєте Pandas, щоб видалити непотрібні стовпці та впорядкувати дані

Цей посібник для вас, якщо ви новачок у краудсорсингу та маєте невеликий попередній досвід роботи з Python.

Останніми роками краудсорсингові проєкти культурної спадщини, такі як Transcribe Bentham, уможливили нові дослідження. У цьому прикладі волонтери можуть створювати облікові записи та транскрибувати понад 60 000 рукописів англійського філософа Джеремі Бентама (1748-1832). Transcribe Bentham робить ці важливі історичні та філософські рукописи доступними для дослідників, особливо тих, хто бере участь у аналізі текстів. Інші проєкти, такі як Penguin Watch на Zooniverse, дозволили представникам громадськості класифікувати різні зображення пінгвінів, що сприяло виявленню екологічних загроз. Zooniverse - це онлайн-платформа для "досліджень за участю людей", що дозволяє мільйонам людей у всьому світі брати участь у різних дослідницьких проєктах. Це приклади того, коли дані збираються і аналізуються у великому масштабі, а громадська допомога потрібна для завершення дуже великих проєктів.

Краудсорсинг може використовуватися для цілей різного роду. Наприклад, у контексті України, краудсорсинг став важливим засобом для збору доказів злочинів російських військових. Ще один приклад, проєкт "Карта Руйнувань та Відновлення", який збирає дані щодо зруйнованих внаслідок російського вторгнення в Україну об'єктів цивільної інфраструктури та відомості щодо їх відновлення.

Методи обчислень і програмування є дуже потужними, але деякі завдання можна виконати тільки шляхом залучення людини. Певні завдання пов'язані із транскрипцією чи ідентифікацією (наприклад, специфічних об'єктів) непросто виконати за допомогою лише програмування. Люди краще можуть ідентифікувати невеликі відмінності та незвичайні дані. Однак люди також можуть робити внесок у проєкти у більший спосіб, як правило, беручи участь у конкурсах. Прикладом макрозадач - типу краудсорсингу для більш спеціалізованих проєктів - є премія Netflix. Премія Netflix закликала людей розробити алгоритм, щоб краще прогнозувати рекомендації фільмів для клієнтів, а переможці отримували винагороду чи приз.

У розділі "Поєднання краудсорсингу з місією та цінностями організацій, які займаються культурною спадщиною" з книги "Краудсорсинг нашої культурної спадщини" під редакцією Мії Рідж, Тревор Оуенс зазначає, що "люди визначають і підтримують справи та проєкти, які дають їм відчуття мети…. Люди отримують сенс, коли роблять речі, які для них важливі". Це надає нові можливості , організаціям, які займаються культурною спадщиною, зокрема музеям, архівам та бібліотекам. Оскільки все більше проєктів і колекцій культурної спадщини стають доступними в Інтернеті, установи можуть залучати своїх користувачів новими способами. Оуенс каже, що краудсорсингові завдання, такі як транскрипція, "...надають значущі способи для громадськості покращувати колекції, глибше залучаючи їх і досліджуючи їх". Акт краудсорсингу "запрошує [людей] до участі" та призводить до підвищення обізнаності громадськості про колекції, їх історію та значення.

Учасники краудсорсингу повинні отримувати певну компенсацію. У макрозадачах поширені системи змагань, тому не кожен, хто бере участь, отримує нагороду. У "Етика краудсорсингових досліджень" Ванесса Вільямсон заявляє, що багато людей, які беруть участь у краудсорсингових дослідженнях (зокрема Mechanical Turk від Amazon), роблять це не заради розваги у вільний час. Учасники цієї платформи вкладають значну кількість часу, досвіду та ресурсів, але їм платять дуже мало (у США краудсорсингова праця не є захищеною формою праці). Вільямсон пропонує учасникам краудсорсингу "встановлювати мінімальну заробітну плату для власних досліджень" і заохочує відповідальність, наприклад, вимагати від компаній звітувати про заробітну плату працівників у порівнянні з кількістю відпрацьованих годин. Крім того, Вільямсон рекомендує таким організаціям, як Інституційна ревізійна рада, розробити "інструкції щодо працевлаштування краудсорсингових працівників". Якщо ви розглядаєте краудсорсинг для проєкту, дуже важливо розробити та впровадити протоколи для підтримки та захисту ваших працівників.

Варто врахувати…

Краудсорсинг – не завжди найкраще рішення для кожного проєкту. Для різних типів проєктів краудсорсинг не завжди дає найточніші результати та може призвести до додаткової роботи, перш ніж можна буде перейти до вирішення питання дослідження. У краудсорсингу дослідники-учасники матимуть різний рівень знань і досвіду, що також може призвести до відмінностей у результатах. Якщо ви організовуєте краудсорсингове дослідження, вам також потрібно знати, скільки часу дослідники працюють над проєктом, щоб переконатися, що дослідники отримують належну винагороду. Щоб визначити, чи краудсорсинг є найкращим варіантом для вас, розгляньте ці питання, викладені в "Як ефективно використовувати краудсорсинг: вказівки та приклади" Елени Сімперл:

  1. Для чого варто використовувати краудсорсинг? Існує багато завдань, таких як введення даних, класифікація даних, транскрипція чи розробка та збір ідей, до яких можна легко підключити людей з усього світу. Багато людей з різними ідеями та навичками можуть визначити ефективні способи вирішення конкретної чи складної проблеми

  2. Який масштаб роботи? Краудсорсингові проєкти є найуспішнішими, коли складаються з невеликих частин, над якими окремі люди можуть працювати самостійно. Чи можливо це для вашого проєкту?

  3. Чи робота переважує переваги? Аутсорсинг менших проєктів і предметів за допомогою краудсорсингу може бути корисним і економічно ефективним, але вам все одно доведеться витратити час на збір інформації та, у багатьох випадках, на нормалізацію даних. Якщо ваш проєкт великий, це може потребувати багато роботи, і люди не завжди використовують свій час якомога продуктивніше для досягнення цілей проєкту/команди. Як зазначила Сімперл, Google оголосив конкурс із запитом публічних пропозицій. Вони отримали понад 150 000 заявок, і в результаті виникла велика затримка з рішеннями. В кінцевому підсумку, лише 16 проєктів було обрано для подальшого розгляду

Найкращі практики для дослідників

Якщо ви вирішите збирати дані за допомогою краудсорсингу, слід пам'ятати про деякі речі та вказівки, які слід розуміти. Це важливо для захисту працівників, а також для контролю якості проєкту.

  1. Чіткість: дослідники, які виконують краудсорсингові завдання, повинні знати свої обов'язки. Для проєктів, зосереджених на генеруванні ідей, це може мати форму вказівок, підказок чи запитань. Для введення даних, транскрипції та подібних технічних завдань дослідники повинні точно знати, що їх просять подати (див. Інструкції з подання нижче) і як. Дослідникам важливо знати, що їхня робота використовується та їхній внесок має значення для проєкту. Це означає надати дослідникам ідею проєкту та план, зазначити чому їх просять про допомогу та наскільки їхні конкретні навички важливі для успіху проєкту.

  2. Праця: делегування завдань може бути більш ефективним, але для організації та проведення краудсорсингового дослідження потрібно багато роботи та зусиль. Основна дослідницька група все ще має переглянути надану інформацію. Навіть якщо це робиться програмним шляхом за допомогою таких процесів, як нормалізація чи аналіз даних, для забезпечення точності потрібні час і додаткова праця. У великомасштабних проєктах це може бути багато роботи, і важливо мати це на увазі, щоб створити реалістичні часові рамки проєкту

  3. Контроль якості: оскільки багато людей обробляють чи транскрибують інформацію в краудсорсингових проєктах, потрібно прикласти достатньо праці для контролю якості. Якщо ви ознайомитеся зі своїми даними та розробите план нормалізації даних перед початком краудсорсингової роботи, ви зможете реалізовувати свій проєкт набагато легше та ефективніше. Покрокова документація чи автоматизований процес компіляції, сортування та нормалізації краудсорсингових даних та інформації допомагає заощадити час і кошти та сприяє кращому управлінню даними. Однак, як обговорювалося в цьому уроці, організатори здійснюють обмежений контроль над даними та внесками, отриманими з краудсорсингу

  4. Рекомендовані методи подання даних для дослідників: технічно це урок програмування, але обсяг технічної роботи з нормалізації даних може бути спрощений чи ускладнений низкою людських факторів. Ці найкращі методи зменшать кількість часу, який вам доведеться витратити на нормалізацію пізніше:

  • Правила іменування: якщо ваша робота з даними включає імена (людей чи організацій), ви повинні вказати, як ці імена мають бути написані. Наприклад, Wikipedia - це організація, заснована на використанні краудсорсингу для збору та представлення довідкової інформації, і має чіткі вказівки щодо того, як імена відображаються на веб-сайті та що робити, якщо імена не відповідають звичайному формату. Правила присвоєння імен стають складними та непростими, коли йдеться про префікси, суфікси та назви. Незалежно від ваших вказівок щодо іменування, ви повинні чітко розуміти, чого очікуєте від дослідників, які вводитимуть інформацію

  • Дати й час: як зазначається далі в цьому уроці, дати й час можуть бути записані різними способами відповідно до звичаїв і культур. Робота з різними форматами дат може бути неприємною для нормалізації даних. Для стандартизації введення даних рекомендується використовувати певний формат дати й часу, наприклад ISO 8601

  • Спеціальні символи: важливо чітко вказати, особливо для введення даних, чи прийнятні спеціальні символи. Спеціальні символи кодуються по-різному і можуть викликати труднощі при спробі нормалізувати дані. Приклади спеціальних символів включають ä (малу літеру a з умляутом), дроби чи символи валюти. Якщо використання спеціальних символів не є прийнятним, є способи обмежити це під час фази введення даних, використовуючи регулярні вирази чи інші інструменти для примусової перевірки введеного тексту

  • Інші вказівки: вказівки щодо подання даних можуть бути дуже детальними та конкретними. Ви можете детально вказати форматування чисел, використання лише певних розділових знаків чи будь-які інші вимоги до даних вашого краудсорсингу. Використання стандартів метаданих, таких як Dublin Core чи TEI, також може посприяти узгодженості даних.

Набір даних Russia vs Ukraine Tweets Dataset з платформи Kaggle

В оригінальному уроці була використана база даних оцифрованої колекції з приблизно 45 000 меню, починаючи з 1840-х років до сьогодні, Публічної бібліотеки Нью-Йорка (NYPL). Цю колекцію оприлюднили через What's on the menu? Замість використання оптичного розпізнавання символів (OCR) – способу програмного трансформування рукописних чи друкованих документів у текст, доступний для машинного пошуку – NYPL використала краудсорсинг транскрипції колекції. Такі методи, як OCR, можуть заощадити час, але не гарантують точності та часто вимагають від людей перевірки та виправлення результату. Крім того, меню NYPL включає широкий вибір рукописних текстів і складних шрифтів, що означало, що написати універсальний код для забезпечення точності OCR було дуже важко. Навіть якби можна було розробити універсальний код, NYPL визначила кілька частин кожного меню, які можна було б ідентифікувати лише людським оком.

Для локалізації уроку було вирішено вибрати базу даних, яка стосується України, а саме "Russia vs Ukraine Tweets Dataset" з платформи Kaggle.

Kaggle має краудсорсинговий підхід, який ґрунтується на змаганні у створенні найкращих моделі для прогнозування та опису даних, запропонованих компаніями чи користувачами. Kaggle дозволяє користувачам знаходити та публікувати набори даних, досліджувати та створювати моделі у веб-середовищі, працювати з іншими науковцями та інженерами та брати участь у змаганнях для вирішення завдань. Тому Kaggle також може бути корисним для пошуку бази даних чи партнерів для вашого проєкту.

"Russia vs Ukraine Tweets Dataset" містить твіти про Україну та Росію з 27 по 28 лютого 2023 року. Цей набір даних містить 36 стовпців, які складаються з тексту, чисел та дат, а також 10014 рядків, по одному для кожного твіту. Для цілей цього уроку було додано один рядок до набору даних для імітації повторюваних даних, а також змінений тип запису дати у одному з рядків.

Використовуючи бібліотеку Python, pandas, ми навчимося:

  • Видаляти непотрібні стовпці

  • Знаходити рядки з відсутніми даними

  • Визначати та видаляти дублікати даних

  • Краще розуміти складність роботи з різними форматами дат

Початок

Цей урок можна використовувати з будь-якою операційною системою. Урок було написано з використанням Python 3.7.4 і Pandas версії 1.2.0, і передбачається, що ви знайомі з Python і командним рядком чи Jupyter Notebook. Якщо ви не маєте досвіду роботи з Python, спробуйте почати з уроку "Знайомство та встановлення Python", оскільки там показано, як інсталювати Python на комп'ютері та основні операції. Для цього уроку вам потрібно буде створити віртуальне середовище Python 3. Інформацію про створення та запуск віртуального середовища Python 3 можна знайти в уроці "Візуалізація даних за допомогою Bokeh and Pandas".

Щоб встановити цю конкретну версію Pandas, використовуйте такий код у вашому віртуальному середовищі:

pip install pandas==1.2.0

Якщо pandas уже встановлено на вашому комп'ютері, ви можете впевнитися, що використовуєте останню версію pandas, запустивши такий код у терміналі чи командному рядку:

pip install --upgrade pandas

Pandas - це популярна і потужна бібліотека, яка використовується в спільнотах Python для обробки та аналізу даних. Pandas здатна зчитувати та виводити різні типи файлів, наприклад CSV, JSON, Excel і Stata.

У цьому підручнику передбачається, що ви знайомі з концепцією очищення даних (виявлення та виправлення чи видалення неправильних чи повторюваних даних) чи охайних даних (способи організації даних для покращення аналізу).

Вивчення набору даних Russia vs Ukraine Tweets Dataset

Хоча набір даних включає інформацію тільки за два дні, він все одно є великим та може бути використаним для різних дослідницьких проєктів. Безпосередній аналіз даних виходить за рамки цього уроку. Натомість ми зосередимося на етапах підготовки ваших даних для аналізу.

Завантаження набору даних і створення файлу Python

Для початку ми створимо теку, а також порожній файл Python у ньому. У цьому файлі Python ми будемо записувати та зберігати наш код. Я назвав цей файл twitter_dataset.py. Крім того, вам потрібно буде завантажити та перемістити набір даних filename_1.csv у той самий створений каталог. Важливо, щоб завантажений файл .csv і ваш файл .py знаходилися в одному каталозі, інакше ваш код працюватиме неправильно. Перш ніж запустити новий розділ коду, ви повинні зберегти свій прогрес у файлі Python.

Коли ви будете готові запустити свій код за допомогою командного рядка чи терміналу, ви перейдете до свого щойно створеного каталогу. Якщо цього не сталось, то використовуйте команду cd для переходу у потрібний каталог. Наприклад cd DH, де DH - це назва теки, у якій знаходиться файл twitter_dataset.py. Щоб запустити код через термінал введіть python twitter_dataset.py і натисніть Enter.

Якщо ви віддаєте перевагу проходженню цього уроку без необхідності переходити в командний рядок, доступний файл Jupyter Notebook Crowdsourced-Data-with-Pandas.ipynb, який містить код із цього уроку. Інформацію про те, як встановити та використовувати Jupyter Notebooks, можна знайти в уроці "Вступ до Jupyter Notebooks".

Виконуючи кроки, вказані у цьому уроці, час від часу зупиняйтесь повертайтесь на початок та очищайте свій файл Python. Це хороша практика, яка передбачає видалення операторів друку після підтвердження виводу. Це дозволяє вам потроху запускати сценарій без повторного запуску непотрібного коду. Також важливо пам'ятати, що щоразу, коли ми запускаємо наш код у форматі командного рядка, він виконується спочатку. Це означає, що ми будемо імпортувати наш набір даних кілька разів протягом цього процесу.

Імпортування пакетів і читання файлів

По-перше, у файлі .py ми імпортуємо бібліотеку pandas і завантажимо наші дані наступним чином:

import pandas as pd 
df = pd.read_csv("filename_1.csv") 
print(df.head())

Ви також можете зазначити шлях до файлу filename_1.csv. У такому випадку буде необов'язково, щоб filename_1.csv знаходився у тій самій теці, що файл з кодом. Наприклад:

df = pd.read_csv("C:/Users/Documents/Python/DH/filename_1.csv") 

Зверніть увагу, що для позначення шляху у Python використовується /, а не \.

Важливо зазначити, що бібліотека pandas часто позначається скорочено як pd, у тому числі в офіційній документації. Щоб "прочитати" наші дані (копіювати дані в пам'ять комп'ютера, щоб їх можна було обробити), ми викликаємо функцію read_csv(), яка завантажить наші дані в DataFrame pandas, який зберігається у змінній що називається df. Df містить стовпці та рядки нашого набору даних. У цьому уроці, як і зазвичай, ми будемо використовувати df для опису нашого DataFrame.

Рекомендується переглядати дані відразу після їх зчитування, щоб переконатися, що вони зчитуються належним чином і роблять це так, як ви очікували. Ви можете переглянути весь набір даних, ввівши print(df). Функція df.head() дозволить вам переглядати перші п'ять рядків вашого набору даних. Це базове значення для команди head, яким можна легко маніпулювати - наприклад df.head(30) видасть 30. Не забудьте зберегти файл .py, а потім, щоб запустити його, перейдіть до свого каталогу в командному рядку у терміналі, введіть python twitter_dataset.py і натисніть Enter. Результат буде таким:

   id                   conversation_id      ...       trans_src    trans_dest
0  1630366235354451969  1630152070530576385  ...       NaN          NaN
1  1630366226424778753  1630366226424778753  ...       NaN          NaN
2  1630366225930027011  1630366225930027011  ...       NaN          NaN
3  1630366223056662530  1630351686974992385  ...       NaN          NaN
4  1630366221483884545  1629903982255644672  ...       NaN          NaN

[5 rows x 36 columns]   

На основі інформації в дужках у нижній частині вихідних даних ми можемо побачити, що перші п'ять рядків даних надруковано, а наш набір даних має тридцять шість стовпців. Як бачите, друкуються лише перша та остання пара стовпців. За замовчуванням, для зручності читання, під час роботи з великими наборами даних середні стовпці не включені в дисплей і замінені трьома крапками. Значення NaN під заголовками trans_src і trans_dest вказує на те, що в цих клітинках не зберігаються дані. NaN означає Not a Number і є "маркером відсутнього значення за замовчуванням" для pandas, згідно з документацією. Бувають випадки, коли значення NaN чи null, можуть означати помилку та вимагати подальшого дослідження, але для цього набору даних це очікуваний результат. Знаходження нульових значень у наборі даних не є чимось незвичайним чи специфічним для краудсорсингових проєктів. Однак, якщо ви знайшли стовпець, який містить переважно чи повністю нульові значення, вам слід перевірити вихідні матеріали чи методи введення даних, щоб з'ясувати причину.

Видалення стовпців

Після прочитання нового файлу корисно дізнатися про ваші дані. Якщо додати функцію print(df.columns) до свого файлу Python, зберегти її, а потім знову запустити в командному рядку чи терміналі за допомогою python twitter_dataset.py, ви зможете побачити, які стовпці представлено в наборі даних (вивід нижче):

Index(['id', 'conversation_id', 'created_at', 'date', 'time', 'timezone',
       'user_id', 'username', 'name', 'place', 'tweet', 'language', 'mentions',
       'urls', 'photos', 'replies_count', 'retweets_count', 'likes_count',
       'hashtags', 'cashtags', 'link', 'retweet', 'quote_url', 'video',
       'thumbnail', 'near', 'geo', 'source', 'user_rt_id', 'user_rt',
       'retweet_id', 'reply_to', 'retweet_date', 'translate', 'trans_src',
       'trans_dest'],
      dtype='object')

Цей вивід відображає повний список заголовків стовпців у порядку появи з набору даних filename_1.csv. Після списку dtype чи тип даних вказується як об'єкт. Це означає, що всі заголовки стовпців є рядками чи змішаними, містять текст чи комбінацію чисел і тексту. Знання типу даних інформує про те, які операції можна виконувати з різними даними. Наприклад, якщо тип даних є int чи float, ми можемо використати математичні обчислення, наприклад знайти середнє значення.

Це великий набір даних із 36 стовпцями. Залежно від вашого дослідницького питання, ви можете визначити, які стовпці непотрібні для майбутнього аналізу. Важливо зазначити, що будь-які перетворення даних протягом цього уроку насправді не змінюють файл filename_1.csv. Усі зміни в наборі даних відбуваються всередині Python, де ми відкрили файл.

Для цілей цього уроку ми хочемо видалити будь-які стовпці, які мають додаткову інформацію, що не є потрібною у цей конкретний момент. Для цього ми створимо змінну (dropped_col), що містить стовпці, які ми хочемо видалити. Потім ця змінна передається до функції drop(), вбудованої функції в бібліотеці pandas, яка дозволяє видаляти вказані стовпці чи рядки. Вказуючи, що inplace=True, ми заявляємо, що не хочемо повертати копію об'єкта (стовпців). Крім того, axis=1 повідомляє програмі, що ми розглядаємо саме стовпці. Щоб видалити рядки в pandas, укажіть мітки, які потрібно видалити, а також axis=0 чи запам'ятайте індекс (одна мітка чи список міток). Додаткову інформацію про видалення стовпців і рядків можна знайти в офіційній документації pandas. Код для видалення стовпців буде записаний у вашому файлі Python так:

dropped_col = ['thumbnail', 'near', 'geo', 'source', 'user_rt_id', 'user_rt','retweet_id', 'reply_to', 'retweet_date', 'translate', 'trans_src','trans_dest']
df.drop(dropped_col, inplace=True, axis=1)

Якщо повторно запустити в командному рядку чи терміналі за допомогою python twitter_dataset.py, результатів не буде. Однак, додавши код print(df.shape) у ваш файл Python, а потім запустіть його за допомогою python twitter_dataset.py, буде повернено результат (10015, 24), тобто набір даних тепер має 24 стовпця.

Функція df.shape - це нова команда в бібліотеці pandas. Вона вказує розміри (у нашому випадку кількість рядків і стовпців) вашого набору даних. Команда df.shape дуже корисна для відстеження будь-яких розмірних змін, внесених до набору даних, наприклад видалення дублікатів, стовпців чи рядків.

На цьому етапі уроку ваш файл Python має містити такий код:

import pandas as pd

df = pd.read_csv("filename_1.csv")
print(df.head())

print(df.columns)

dropped_col = ['thumbnail', 'near', 'geo', 'source', 'user_rt_id', 'user_rt','retweet_id', 'reply_to', 'retweet_date', 'translate', 'trans_src','trans_dest']
df.drop(dropped_col, inplace=True, axis=1)

print(df.shape)

Дублікати

Іноді у вашому наборі даних можуть бути наявні дублікати. Під час роботи з краудсорсинговими завданнями, такими як переклад чи транскрипція, можливо, що більше ніж одна особа працювала із певним елементом набору даних, що призведе до появи дублікатів чи навіть незначних варіацій тієї самої інформації. Додавання коду

print(df[df.duplicated(keep=False)])

у ваш файл Python визначить будь-які повторювані рядки у вашому наборі даних. Вказуючи keep=False, ми створюємо логічне значення, яке позначатиме кожен дублікат як True, що повертатиме будь-які повторювані рядки.

Коли файл запускається за допомогою python twitter_dataset.py, результат(нижче) відображатиме два повторюваних рядки:

                     id      conversation_id  ...   quote_url     video
78  1630365935147143168  1627634259413331968  ...         NaN         0
79  1630365935147143168  1627634259413331968  ...         NaN         0

[2 rows x 24 columns]

Також можна шукати дублікати в певних стовпцях. Наприклад, якщо ви перевіряєте, чи немає дублікатів у стовпці ідентифікатора (ідентифікатори зазвичай мають бути унікальними), ви використаєте

df[df.duplicated(subset='id', keep=False)]

Коли дублікати даних буде виявлено, ви можете видалити їх із свого набору даних. Вбудовану функцію pandas drop_duplicates можна використовувати для видалення повторюваних рядків. Додайте таку функцію до свого файлу Python, а потім запустіть її в командному рядку за допомогою python twitter_dataset.py:

df.drop_duplicates(inplace=True)

inplace=True означає, що буде збережений принаймні один дубльований запис у остаточному наборі даних.

Знову запустивши print(df.shape), ви побачите, що початкова кількість рядків із 10015 змінилась на 10014.

На цьому етапі ваш файл Python має містити такий код:

import pandas as pd

df = pd.read_csv("filename_1.csv")
print(df.head())

print(df.columns)

dropped_col = ['thumbnail', 'near', 'geo', 'source', 'user_rt_id', 'user_rt','retweet_id', 'reply_to', 'retweet_date', 'translate', 'trans_src','trans_dest']
df.drop(dropped_col, inplace=True, axis=1)

print(df.shape)

print(df[df.duplicated(keep=False)])

df.drop_duplicates(inplace=True)

print(df.shape)

Відсутні дані

У нашому наборі даних є записи, які містять відсутню інформацію. Записи, у яких немає інформації, включаючи пробіли, називаються нульовими значеннями та відображаються як NaN. Іноді, особливо у великих дослідницьких проєктах, вам може знадобитися представити звіти про хід роботи чи підтвердження концепції як частину вашого попереднього дослідження. Це означає, що ви отримуватимете дані з неповного набору даних.

Корисно побачити, які стовпці у вашому наборі даних містять нульові значення. Функція df.isnull() визначає нульові значення записа за записом у вашому наборі даних і, якщо її запустити, поверне ваш набір даних, заповнений логічними значеннями, зі значенням True, що позначає запис як нульовий. Це може бути цікаво побачити, але таблицю, заповнену лише значеннями True/False, важко читати та інтерпретувати. Додавши .sum() у кінець функції, Python поверне огляд та покаже назви кожного заголовка стовпця та загальну кількість разів, коли запис позначається True у кожному стовпці. Введіть код

print(df.isnull().sum())

у ваш файл Python, а потім запустіть його за допомогою python twitter_dataset.py, і буде повернено звіт про заголовки стовпців та кількість нулів на стовпець, як показано нижче:

id                     0
conversation_id        0
created_at             0
date                   0
time                   0
timezone               0
user_id                0
username               0
name                   0
place              10011
tweet                  0
language               0
mentions               0
urls                   0
photos                 0
replies_count          0
retweets_count         0
likes_count            0
hashtags               0
cashtags               0
link                   0
retweet                0
quote_url           9235
video                  0
dtype: int64

Ці результати показують, що двадцать два стовпці у нашому наборі даних не містять нульових значень. Інші стовпці містять між 9325 та 10011 нулями.

Видалення стовпців на основі відсутніх даних

Ми могли б розумно припустити, що стовпці, які здебільшого (чи повністю) містять нульові значення, не будуть корисними для відображення в остаточному наборі даних що буде використовуватися для аналізу. У цьому випадку, може бути корисним видалити всі стовпці, де певний відсоток чи більше записів містять нулі. У Pandas є вбудована функція df.dropna(), яка видаляє відсутні значення зі стовпців чи рядків. Через те, як було створено цей набір даних, немає жодного рядка, у якому повністю відсутні дані, проте є фактично порожні стовпці. Отже, ми почнемо з видалення стовпців на основі відсутніх даних, а потім перейдемо до рядків (у деяких випадках ефективнішим може бути видалення рядків, а потім стовпців).

Для цього уроку припустимо, що ми хочемо зберегти всі стовпці, де менше 25% даних є нульовими. Ми можемо вирішити це з кількох причин. Якщо з понад 10014 записів кожен рядок в стовпці був залишений порожнім, очевидно, що інформація не була знайдена. Було б марно продовжувати використовувати ці стовпці та їхні заголовки в подальшому аналізі.

Щоб визначити, які стовпці ми хочемо зберегти, ми створимо нову змінну під назвою tweets. Таким чином, ми створюємо підмножину даних, яку ми можемо використовувати в наступних кроках уроку. Функція df.dropna, яку потрібно додати до вашого файлу Python записується наступним чином:

tweets = df.dropna(thresh=df.shape[0]*0.25,axis=1)

Параметр thresh у функції df.dropna() дозволяє вказати задану кількість чи відсоток рядків, які відповідають вашим критеріям, у цьому випадку 0,25 чи 25%. Крім того, як було сказано раніше, axis=1 повідомляє програмі, що ми розглядаємо саме стовпці. Також ви можете вказати параметр how='all' замість thresh, тоді буде стовпець буде видалений, якщо у ньому всі значення є нульовими.

Використовуючи функцію .shape, цього разу додавши print(tweets.shape) у ваш файл Python, повертається результат (10014, 22), і ми можемо побачити, що залишилося лише 22 стовпці. Щоб перевірити, які стовпці залишилися, додайте print(tweets.columns) до свого файлу та запустіть його за допомогою python twitter_dataset.py, щоб побачити

Index(['id', 'conversation_id', 'created_at', 'date', 'time', 'timezone',
       'user_id', 'username', 'name', 'tweet', 'language', 'mentions', 'urls',
       'photos', 'replies_count', 'retweets_count', 'likes_count', 'hashtags',
       'cashtags', 'link', 'retweet', 'video'],
      dtype='object')

що стовпці "place", "quote_url", тепер зникли. На цьому етапі ваш файл Python має містити наступний код (хоча ви могли видалити деякі старі оператори друку, якщо скористалися моєю попередньою порадою призупинити та очистити файли Python!):

import pandas as pd

df = pd.read_csv("filename_1.csv")
print(df.head())

print(df.columns)

dropped_col = ['thumbnail', 'near', 'geo', 'source', 'user_rt_id', 'user_rt','retweet_id', 'reply_to', 'retweet_date', 'translate', 'trans_src','trans_dest']
df.drop(dropped_col, inplace=True, axis=1)

print(df.shape)

print(df[df.duplicated(keep=False)])

df.drop_duplicates(inplace=True)

print(df.shape)

print(df.isnull().sum())

tweets = df.dropna(thresh=df.shape[0]*0.25,axis=1)

print(tweets.shape)

print(tweets.columns)

Видалення рядків із відсутніми даними

Ми розглянули стовпці, але в нашому наборі даних все ще можуть бути записи, які містять нульові значення. Залежно від типу аналізу, який ви бажаєте використати, і від того, чи бажаєте ви врахувати нульові значення, не завжди потрібно видаляти всі записи, які містять відсутню інформацію. Якби нульові значення були важливими для нашого дослідження - наприклад, якщо вам було цікаво дослідити, чи існує закономірність між тими типами подій, які мали чи не мали дати, - ви могли б зберегти рядки з нульовими значеннями в стовпці дати.

Однак, якщо ви хочете видалити всі рядки, у яких немає хоча б одного елементу, щоб мати набір даних лише з повними даними, створіть нову змінну та скористайтеся цією функцією:

dropped_na = tweets.dropna()
print(dropped_na)

Коли код буде збережено у файлі Python і запущено в командному рядку чи терміналі за допомогою python twitter_dataset.py, ви побачите, що наш набір даних залишився таким самим (10014 рядків), тобто всі рядки мають повні дані. Результат виглядає наступним чином:

                        id      conversation_id  ...   retweet    video
0      1630366235354451969  1630152070530576385  ...     False         0
1      1630366226424778753  1630366226424778753  ...     False         0
2      1630366225930027011  1630366225930027011  ...     False         0
3      1630366223056662530  1630351686974992385  ...     False         0
4      1630366221483884545  1629903982255644672  ...     False         0
...                    ...                  ...  ...     ...         ...
10010  1630331110415646721  1630305860298633216  ...     False         1
10011  1630331106305122304  1630202100369043459  ...     False         0
10012  1630331106296844288  1630301689818275840  ...     False         0
10013  1630331102480171009  1630181795101540357  ...     False         0
10014  1630331101817233414  1630248150954049537  ...     False         0

[10014 rows x 22 columns]

Тепер ваш файл Python має містити цей код:

import pandas as pd

df = pd.read_csv("filename_1.csv")
print(df.head())

print(df.columns)

dropped_col = ['thumbnail', 'near', 'geo', 'source', 'user_rt_id', 'user_rt','retweet_id', 'reply_to', 'retweet_date', 'translate', 'trans_src','trans_dest']
df.drop(dropped_col, inplace=True, axis=1)

print(df.shape)

print(df[df.duplicated(keep=False)])

df.drop_duplicates(inplace=True)

print(df.shape)

print(df.isnull().sum())

tweets = df.dropna(thresh=df.shape[0]*0.25,axis=1)

print(tweets.shape)

print(tweets.columns)

dropped_na = tweets.dropna()
print(dropped_na)

Робота з датами

Типи дати та часу є одними з найскладніших типів даних, коли мова заходить про нормалізацію даних, особливо якщо збір даних відбувається за допомогою краудсорсингу. Це сфера, де чіткі правила подання можуть покращити загальну якість даних і скоротити час та зусилля, необхідні для нормалізації ваших даних.

У різних частинах світу дати записують по-різному. У Сполучених Штатах прийнято використовувати формат місяць/день/рік, тоді як в інших частинах світу день/місяць/рік є нормальним, а в деяких місцях використовується рік/місяць/день. Крім того, те, як люди вводять дати, відрізняється від людини до людини. Як приклад, ось різні способи записати ту саму дату:

8 січня 1970 року 8 січня 1970 р 8 січня 1970 року 08.01.1970 р 01.08.1970 1970-01-08 Січ-08-1970

Дати, представлені лише цифрами, складно ідентифікувати: наприклад, 1970-01-08 стосується 8 січня чи 1 серпня?

Щоб уникнути цієї проблеми, вимагайте, щоб дані на основі дати чи часу відповідали стандартному формату, наприклад ISO 8601. Це можна зробити під час введення даних за допомогою додаткового умовного коду, наприклад регулярних виразів, який перевірятиме відповідності введених даних до необхідного формату.

Перетворення типу даних на дату

Якщо визначений чіткий формат, то можна використати функцію pandas, для нормалізації дати. Якщо дати, з якими ви працюєте, розташовані в стандартизованому порядку, ви можете скористатися функцією to_datetime(). Це призведе до перетворення стовпця дати з об'єктного типу даних (це означає, що вміст стовпця складається з тексту, числового чи не числового значення) на дату й час (це означає, що вміст у стовпці складається з спеціально відформатованої дати та часу) тип даних. У подальшій документації описано, як налаштувати цю функцію на основі унікальних форматів дати у вашому наборі даних.

Ця функція потужна, але також потенційно обмежена, оскільки бібліотека pandas розпізнає лише дати в межах певного періоду часу. Через те, як мітки часу та дати обчислюються у вбудованій функції, pandas може працювати лише з проміжком часу приблизно в 584 роки; мінімальна дата – 1677, а максимальна – 2262. Дати за межами цього періоду спричинять помилку. Якщо ваші набори даних датуються до 1677 року, бібліотека pandas не підходить для цього перетворення. Інші способи підходу до нормалізації даних дати включають використання регулярних виразів, однак це передбачає можливість ідентифікувати конкретні текстові шаблони, у яких проявляються помилки.

Через це обмеження некоректні формати введення даних, пов'язані з датою, викликають помилку під час запуску функції to_datetime. Наш набір даних містить такий некоректний запис, де дата введена як 27-02-2023. Такий запис може виникнути при транскрипції (людська помилка). Некоректний запис можна визначити за допомогою коду, який перетворює тип даних стовпця на дату:

pd.to_datetime(dropped_na['date'], dayfirst = False, yearfirst = False)

Цей рядок коду визначає, що ми змінюємо стовпець дати в нашому dataframe та перетворюємо його на тип даних дата й час (datetime). Специфікації dayfirst = False і yearfirst = False використовуються, щоб повідомити програмі, що наші формати дати не стандартизовані і що день чи рік можуть з'явитися першими в нашому наборі даних. Однак під час запуску наш код видасть помилку.

Помилка, створена цим кодом, буде виглядати як:

ValueError: time data "27-02-2023" doesn't match format "%Y-%m-%d", at position 2. You might want to try:
    - passing `format` if your strings have a consistent format;
    - passing `format='ISO8601'` if your strings are all ISO8601 but not necessarily in exactly the same format;
    - passing `format='mixed'`, and the format will be inferred for each element individually. You might want to use `dayfirst` alongside this.

Функція виявила дату, яка не відповідає формату.

Можна знайти цю дату та замінити її за допомогою функції pandas df.replace, але це незручний підхід для наборів даних із великою кількістю помилок введення. Функція заміни вимагає використання регулярних виразів для створення шаблону для пошуку потенційних помилок у стовпці дати чи визначення вмісту клітинки, яку потрібно замінити. Однак можна встановити будь-які повідомлення про помилки для виведення як нульові значення. Для цього змініть вихідний код to_datetime на pd.to_datetime(dropped_na['date'], errors ='coerce', dayfirst = False, yearfirst = False). Наразі ми не будемо використовувати coerce, оскільки це вимагає додаткових кроків і виходить за рамки цього уроку. Посібник LinkedIn "Змініть тип даних стовпців у Pandas" Мохіта Шарми демонструє coerce більш детально.

Щоб вручну знайти та замінити дату, запустіть код, який спричинив помилку, зверніть увагу на мітку часу, де сталася помилка, а потім запустіть код пошуку та заміни таким чином:

replaced_dates = dropped_na.replace('27-02-2023', '2023-02-27')

Ми встановлюємо функцію для нової змінної, replaced_dates, щоб ми могли викликати цю змінну знову. Перший елемент у функції df.replace зазначає точний елемент, який ви хочете знайти, у цьому випадку дату, позначену як 27-02-2023. Другим елементом є рядок, яким потрібно замінити неправильну дату. У цьому уроці ми повернемося назад і закоментуємо код to_datetime, який навмисно створює помилку, використовуючи символ Python #:

pd.to_datetime(dropped_na['date'], dayfirst = False, yearfirst = False)

Мати справу з датами складно. Є багато способів підійти до проблеми, і те, які ви виберете, залежатиме від вашого набору даних. Загалом, чіткі правила введення даних є найкращим способом уникнути помилок у даті. Якщо ви вирішите використовувати pandas для впровадження процесу нормалізації даних, то необхідною вимогою буде забезпечення того, щоб дати, які вводяться, належали до діапазону дат і часу pandas.

Після перетворення типу даних стовпця на дату й час ви зможете запустити серію інших функцій, наприклад перевірити, чи всі дати потрапляють у вказаний діапазон вашої бази даних. Ваш файл Python має містити такий код:

import pandas as pd

df = pd.read_csv("filename_1.csv")
print(df.head())

print(df.columns)

dropped_col = ['thumbnail', 'near', 'geo', 'source', 'user_rt_id', 'user_rt','retweet_id', 'reply_to', 'retweet_date', 'translate', 'trans_src','trans_dest']
df.drop(dropped_col, inplace=True, axis=1)

print(df.shape)

print(df[df.duplicated(keep=False)])

df.drop_duplicates(inplace=True)

print(df.shape)

print(df.isnull().sum())

tweets = df.dropna(thresh=df.shape[0]*0.25,axis=1)

print(tweets.shape)

print(tweets.columns)

dropped_na = tweets.dropna()
print(dropped_na)

# pd.to_datetime(dropped_na['date'], dayfirst = False, yearfirst = False)

replaced_dates = dropped_na.replace('27-02-2023', '2023-02-27')

Збереження в CSV

Коли ви задоволені нормалізацією даних, ви можете експортувати свій новий набір даних у новий файл CSV. Ви можете зробити це за допомогою вбудованої функції pandas df.to_csv. Використовуючи останню створену вами змінну, введіть та запустіть наступний код:

replaced_dates.to_csv("twitter_dataset.csv")

У тій самій папці, де зберігаються ваш файл коду та вихідний набір даних, тепер існуватиме ваш новий файл twitter_dataset.csv. Цей новий файл можна відкрити за допомогою будь-якого текстового редактора (наприклад, Notepad++) чи за допомогою таких програм, як Microsoft Excel.

Наприкінці цього уроку ваш файл Python має містити такий код:

import pandas as pd

df = pd.read_csv("filename_1.csv")
print(df.head())

print(df.columns)

dropped_col = ['thumbnail', 'near', 'geo', 'source', 'user_rt_id', 'user_rt','retweet_id', 'reply_to', 'retweet_date', 'translate', 'trans_src','trans_dest']
df.drop(dropped_col, inplace=True, axis=1)

print(df.shape)

print(df[df.duplicated(keep=False)])

df.drop_duplicates(inplace=True)

print(df.shape)

print(df.isnull().sum())

tweets = df.dropna(thresh=df.shape[0]*0.25,axis=1)

print(tweets.shape)

print(tweets.columns)

dropped_na = tweets.dropna()
print(dropped_na)

print(dropped_na['date'])

# pd.to_datetime(dropped_na['date'], dayfirst = False, yearfirst = False)

replaced_dates = dropped_na.replace('27-02-2023', '2023-02-27')

replaced_dates.to_csv("twitter_dataset.csv")

Висновок

Процес нормалізації ваших даних рідко буває простим. У статті "Проти очищення" автори Кеті Роусон і Тревор Муньос обговорюють, що ускладнює "очищення" наборів даних меню NYPL. Наприклад, з часом змінювалося написання різних продуктів, а також відмінності в тому, як згадувалися страви та напої, щоб належним чином відображати їхній період. "Очистити" ці дані – нормалізувати їх – зменшить історичну цінність. Крім того, як зазначили автори, виявилося складним розрізнити, "які варіанти назв страв відкривають нову інформацію, яку (вони) повинні врахувати у (своїх) власних даних, а які варіанти були просто випадковістю транскрипції чи верстки". Методів, які зазвичай використовуються для очищення даних, не було для цього достатньо.

Збір даних за допомогою краудсорсингу може бути дуже ефективним, але нормалізація гуманітарних даних може бути складною. Роусон і Муньос виявили, що концепція "очищення даних" більше не є точною, і процес неможливо завершити за допомогою "звичайних" методів. Гуманітарні дані унікальні. Вони різноманітні. Вони складні. І в багатьох випадках історичні деталі є життєво важливими. Багато методів нормалізації можна застосувати програмно, але комп'ютери не можуть легко інтерпретувати унікальні ситуації. Як зазначають Роусон і Муньос, мінливість не завжди є поганою річчю; це не безлад, який понад усе вимагає порядку - це складна різноманітність, яку потрібно зберегти. При краудсорсингу даних неможливо уникнути мінливості даних. Зрештою, ви самі визначаєте, чи загальні методи нормалізації підходять для ваших даних, а також для ваших дослідницьких питань.

Натхнення уроку

На створення цього уроку надихнув проєкт, який автор виконав у 2018 році як аспірант Школи інформаційних наук Університету Іллінойсу. Автор разом із колегами Дарією Орловською та Юеронгом Ху досліджували різні способи нормалізації всіх чотирьох наборів даних меню Публічної бібліотеки Нью-Йорка. Оригінальний урок розширює цей проєкт та обговорює методи краудсорсингу.

Про авторів

Геллі Бернс є доценткою університетських бібліотек Університету Невади, Лас-Вегас. Вона також є сертифікованою інструкторкою The Carpentries, міжнародної організації, яка навчає дослідників навичкам кодування та науки про дані. https://orcid.org/0000-0003-2346-2876

Переклад українською: Ворожейкін Євген, старший викладач кафедри філософської антропології філософії культури та культурології Українського державного університету імені Михайла Драгоманова https://orcid.org/0000-0001-7320-562X

Переклад рецензували: Кирило Осінський, Senior Software Engineer, Cheil Germany GmbH. Микола Махортих, PhD, викладач програми Альфреда Ландекера в Інституті комунікації та медіа-досліджень (Бернський університет).

Рекомендоване цитування: Бернс, Хеллі. "Нормалізація краудсорсингових даних за допомогою Python та Pandas", Programming Historian, переклав Євген Ворожейкін, Посібник з цифрової історії, 2024. DOI: https://doi.org/10.69915/dh0016

Last updated