article banner

Аналіз даних на Python

Це фрагмент книги Python з нуля, яка допоможе вам навчитися програмуванню з нуля. Ви можете знайти його на Allegro, Empik та в інтернет-книгарнях.

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

Дані та аналіз

Дані дуже важливі майже в кожній сфері. Репортери та блогери відстежують кількість переглядів своїх публікацій, щоб дізнатися, які з дописів популярніші. Такі сервіси як Twitter і Facebook дивляться на поведінку користувачів, щоб оптимально налаштувати вміст і самі сервіси. Страхові компанії збирають дані про аварії, завдяки чому можуть краще оцінити розмір внесків та можливу шкоди. Навіть кав’ярні збирають дані про продажі, завдяки чому кава стає все смачнішою 1.

Щоб це стало можливим, необхідно збирати дані. Це робить більшість компаній. На наступному етапі важливо обробити ці дані. Уявімо собі, що ми хочемо покращити нашу медичну службу і завдяки міжнародним угодам отримали дані про німецьких пацієнтів. Однак вони зовсім іншого формату, ніж наші. Для опису захворювань використовуються інші коди, всі атрибути інакше сформовані та описані. Щоб здійснити порівняння, нам потрібно звести дані до одного формату 2. Тут ми входимо у сферу обробки даних, також відому як data engineering. Нарешті, залишається зробити висновки з даних, тобто провести аналітику. Вона складає основу роботи аналітиків та науковців.

Аналіз даних за допомогою Python

Сьогодні Python фактично став стандартом обробки та аналізу даних. Значною мірою завдяки чудовим пакетам, таким як Pandas, SciPy або NumPy. Незабаром ми дізнаємося про їх користь. Але перед тим я покажу, що багато чого можна зробити і без них. Для аналізу ми будемо використовувати дуже типовий і популярний на курсах чи в університетах набір даних про пасажирів корабля «Титанік». Він невипадково став популярним, бо невеликий, простий і зрозумілий. Тому ми також почнемо з нього.

Дані про долю пасажирів трагічного рейсу "Титаніка" можна знайти на різних вебсайтах, зокрема за адресою kt.academy/titanic.csv на сторінці Kt.Academy. Вони записані у форматі CSV: кожен рядок містить дані окремого пасажира, а стовпці з даними розділені комою. За винятком першого рядка — заголовка, який містить назви колонок. Це дуже схоже на таблиці в таких програмах, як Excel (насправді файли CSV можна відкривати в Excel).

Щоб зчитати ці дані, ми використаємо вбудований пакет csv. Нам не потрібно його встановлювати, достатньо імпортувати. Ми будемо зчитувати цей файл за допомогою вбудованої функції open, а потім використаємо csv.reader, щоб зчитати наступні рядки, та генераторний список, щоб перетворити файл на список із даними. І відокремимо заголовок від фактичних даних.

import csv

file = open("titanic.csv")
data = [row for row in csv.reader(file)]
file.close()
header = data[0]
data = data[1:]

Погляньмо, скільки у нас пасажирів:

rows_num = len(data)
print(rows_num)  # 1313

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

print(header)
# ['Name', 'PClass', 'Age', 'Sex', 'Survived']
print(data[0])
# ['Allen, Miss Elisabeth Walton', '1st', '29',
# 'female', '1']
print(data[1])
# ['Allison, Miss Helen Loraine', '1st', '2',
# 'female', '0']
print(data[2])
# ['Allison, Mr Hudson Joshua Creighton', '1st', '30',
# 'male', '0']

Зверни увагу, що всі значення, зчитані csv.reader, мають тип string. Більш просунуті пакети (такі як pandas) можуть розрізняти типи значень.

Після заголовків колонок і прикладів значень ми можемо побачити, як виглядають наші дані. Ми маємо повне ім’я, клас квитка (1st, 2st, 3st), вік, стать (male і female), і чи вижив пасажир (1, якщо так, і 0, якщо ні).

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

Щоб вибрати людей із певного класу, ми можемо використати генераторний список з частиною if.

class_1 = [row for row in data if row[1] == '1st']
print(len(class_1))  # 322
class_2 = [row for row in data if row[1] == '2nd']
print(len(class_2))  # 279
class_3 = [row for row in data if row[1] == '3rd']
print(len(class_3))  # 711

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

class_1_survived = [row for row in class_1
                    if row[4] == '1']
print(len(class_1_survived) / len(class_1))
# 0.59...

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

def print_survival_rate(data):
    count = 0
    survived = 0
    for row in data:
        count += 1
        if row[4] == '1':
            survived += 1
    print(float(survived) / count)


print_survival_rate(class_1)  # 0.59...
print_survival_rate(class_2)  # 0.42...
print_survival_rate(class_3)  # 0.19...

Схоже, що на "Титаніку" клас квитка суттєво вплинув на шанс вижити. Вижило 59 % пасажирів першого класу і лише 19 % — третього. Аналогічно перевірмо, чи є зв’язок між рештою стовпців і виживанням. У фільмах під час катастроф часто повторюють "Спершу жінки і діти". Перевірмо, чи дотримувалися цього принципу на "Титаніку". Почнімо зі статі.

males = [row for row in data if row[3] == 'male']
print(len(males))  # 851
print_survival_rate(males)  # 0.16...

females = [row for row in data if row[3] == 'female']
print(len(females))  # 462
print_survival_rate(females)  # 0.66...

У 4 рази вищий відсоток уцілілих серед жінок свідчить про те, що їх справді пропустили першими. А що з дітьми? Я вважатиму дітьми пасажирів до 15 років. На жаль, у наших даних бракує інформації про вік багатьох людей, тому ми будемо враховувати лише для тих, чий вік нам відомий.

kids = [row for row in data if row[2] != '' and
        float(row[2]) <= 15]
print(len(kids))  # 73
print_survival_rate(kids)  # 0.64...

adults = [row for row in data if row[2] != '' and
          float(row[2]) > 15]
print(len(adults))  # 683
print_survival_rate(adults)  # 0.38...

Майже вдвічі вищий показник виживання у дітей свідчить про дотримання старого морського принципу.

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

from pandas import read_csv

titanic_df = read_csv("titanic.csv")

# Кількість осіб у класах
class_counts = titanic_df["PClass"]\
    .value_counts()\
    .sort_index()
print(class_counts)
# 1st    322
# 2nd    279
# 3rd    711

# Виживання за класами
print(titanic_df\
      .groupby("PClass")["Survived"]\
      .mean())
# 1st    0.599379
# 2nd    0.426523
# 3rd    0.194093

# Кількість осіб за статтю
print(titanic_df["Sex"]\
      .value_counts()\
      .sort_index())
# female    462
# male      851

# Виживання за статтю
print(titanic_df\
      .groupby("Sex")["Survived"]\
      .mean())
# female    0.666667
# male      0.166863

# Виживання за класом і статтю
print(titanic_df\
      .groupby(["PClass", "Sex"])["Survived"]\
      .mean())
# PClass  Sex  
# 1st     female    0.937063
#         male      0.329609
# 2nd     female    0.878505
#         male      0.145349
# 3rd     female    0.377358
#         male      0.116232
# Виживання за віком
from pandas import cut

titanic_df['AgeGroup'] = cut(
    titanic_df['Age'],
    bins=[i * 10 for i in range(8)]
)
print(titanic_df\
      .groupby("AgeGroup")["Survived"]\
      .mean())
# AgeGroup
# (0, 10]     0.672727
# (10, 20]    0.427350
# (20, 30]    0.330769
# (30, 40]    0.446667
# (40, 50]    0.423077
# (50, 60]    0.500000
# (60, 70]    0.263158

Завершення

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

1:

У багатьох компаніях використовується техніка, відома як A/B тестування. Її суть у тому, що коли ми розглядаємо певну зміну, наприклад, у процесі приготування кави, ми змінюємо її у випадкових місцях і дивимося на те, як вона вплинула на важливі для нас параметри, такі як результати продажів чи задоволеність клієнтів.

2:

Формат визначає спосіб запису даних. Наприклад, дата може бути записана як 7 Jul 2020, 07.03.2020 або 03-07-2020. Це одна і та ж дата в різних форматах.