Робота з даними з використанням NumPy і pandas
Робота з даними з використанням NumPy і pandas
Завдання, яке розкриє правду про чистий Python
Уявіть: вам надіслали CSV-файл із 10 000 рядків — дані про продажі магазину за рік. Кожен рядок — одна транзакція: дата, категорія товару, ціна, кількість.
Ваш менеджер хоче знати:
- Яка середня ціна товарів у категорії «Електроніка»?
- Який товар продали найбільше разів?
- Скільки продажів було у грудні?
Здається, нічого складного. Спробуємо зробити це «чистим Python» — тобто тільки вбудованими засобами мови без жодних бібліотек:
import csv
# Читаємо CSV вручну
data = []
with open("sales.csv", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
data.append(row)
# Завдання 1: середня ціна в категорії "Електроніка"
total = 0
count = 0
for row in data:
if row["category"] == "Електроніка":
total += float(row["price"])
count += 1
average = total / count if count > 0 else 0
print(f"Середня ціна: {average:.2f}")
# Завдання 2: найпопулярніший товар
product_counts = {}
for row in data:
name = row["product"]
product_counts[name] = product_counts.get(name, 0) + int(row["quantity"])
best_product = max(product_counts, key=product_counts.get)
print(f"Лідер продажів: {best_product}")
# Завдання 3: продажі у грудні
december_sales = 0
for row in data:
if row["date"].startswith("2024-12"):
december_sales += 1
print(f"Продажів у грудні: {december_sales}")
Ось правда: цей код працює, але він:
- займає ~25 рядків для трьох простих запитань
- виконується повільно (цикл
forпо 10 000 рядків — три рази!) - важко читати і підтримувати
- не масштабується — для 1 000 000 рядків буде ще гірше
А тепер подивіться на те саме з pandas:
import pandas as pd
df = pd.read_csv("sales.csv")
# Завдання 1: середня ціна в "Електроніці"
average = df[df["category"] == "Електроніка"]["price"].mean()
# Завдання 2: найпопулярніший товар
best_product = df.groupby("product")["quantity"].sum().idxmax()
# Завдання 3: продажі у грудні
december_sales = df[df["date"].str.startswith("2024-12")].shape[0]
print(f"Середня ціна: {average:.2f}")
print(f"Лідер продажів: {best_product}")
print(f"Продажів у грудні: {december_sales}")
Три рядки замість 25. Швидше у 10–100 разів. Читається як англійська мова.
Аналогія: чистий Python для роботи з даними — це як рахувати тисячі транзакцій на звичайному калькуляторі. NumPy та pandas — це як Excel із формулами, але на стероїдах: не тільки швидше та потужніше, а й у тисячу разів зручніше для складних запитань.
У цій статті ми побудуємо розуміння обох бібліотек з нуля: спочатку NumPy — бо саме він є «двигуном» усіх обчислень, а потім pandas — інструмент для роботи з таблицями.
Частина 1. NumPy — фундамент числових обчислень
Чому стандартного списку Python недостатньо
Ви вже знаєте списки Python — це один із найбільш гнучких типів даних:
numbers = [1, 2, 3, 4, 5]
mixed = [1, "два", 3.0, True, None] # Список може містити будь-що
Саме ця гнучкість і є проблемою. Розберемо, що відбувається в пам'яті комп'ютера, коли ви створюєте список [1, 2, 3, 4, 5]:
Список Python в пам'яті:
┌─────────────────────────────────────────────────────┐
│ Список (list object) │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ ptr │ │ ptr │ │ ptr │ │ ptr │ │ ptr │ ... │
│ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ ┌───────┐ ┌───────┐ ┌───────┐ ... │
│ │ тип │ │ тип │ │ тип │ │
│ │ лічил.│ │ лічил.│ │ лічил.│ │
│ │ знач=1│ │ знач=2│ │ знач=3│ │
│ └───────┘ └───────┘ └───────┘ │
└─────────────────────────────────────────────────────┘
Кожен елемент списку — це вказівник (pointer) на окремий об'єкт у пам'яті. Кожен об'єкт містить:
- тип даних (int? str? float?)
- лічильник посилань (скільки змінних вказують на цей об'єкт)
- саме значення
Це надає гнучкість (можна мати елементи різних типів), але коштує дорого — і пам'яттю, і часом.
Що відбувається при for циклі по списку?
total = 0
for x in numbers: # Python: знайти вказівник → зайти в пам'ять →
total += x # прочитати тип → прочитати значення → виконати операцію
# → повернути вказівник → перейти до наступного...
Для кожного елемента — серія окремих операцій із перевіркою типу. На 10 000 елементів це помітно. На 10 мільйонах — катастрофа.
NumPy ndarray: однорідний масив у пам'яті
NumPy (Numerical Python) — бібліотека для ефективних математичних обчислень. Її основний тип — ndarray (N-dimensional array, N-вимірний масив).
Ось як той самий масив [1, 2, 3, 4, 5] виглядає в NumPy:
NumPy масив в пам'яті:
┌─────────────────────────────┐
│ ndarray (масив об'єкт) │
│ dtype: int64 │
│ shape: (5,) │
│ ┌────┬────┬────┬────┬────┐ │
│ │ 1 │ 2 │ 3 │ 4 │ 5 │ │
│ └────┴────┴────┴────┴────┘ │
│ Суцільний блок пам'яті! │
└─────────────────────────────┘
Всі елементи одного типу (int64), лежать впритул у пам'яті. Не потрібні вказівники, не потрібна перевірка типів для кожного елемента.
Аналогія: список Python — це шафа, де кожна річ загорнута в окрему коробку з підписом (що це, кому належить, скільки місця займає). NumPy масив — це монолітна полиця, де однакові предмети лежать рівно, один біля одного. Дістати будь-який — миттєво, бо ви знаєте точну відстань від початку.
Встановлення та перший запуск
pip install numpy
uv pip install numpy
poetry add numpy
import numpy as np # np — загальноприйнятий псевдонім
import numpy as np, а не просто import numpy? Суто зручність — np.array(...) коротше, ніж numpy.array(...). Це загальноприйнятий стандарт — весь світ пише np.Створення масивів
import numpy as np
# 1. З Python-списку
arr1 = np.array([1, 2, 3, 4, 5])
print(arr1) # [1 2 3 4 5]
print(type(arr1)) # <class 'numpy.ndarray'>
# 2. Масив нулів
zeros = np.zeros(5) # [0. 0. 0. 0. 0.]
zeros_2d = np.zeros((3, 4)) # Матриця 3×4 з нулів
# 3. Масив одиниць
ones = np.ones(5) # [1. 1. 1. 1. 1.]
# 4. Послідовність чисел (аналог range())
seq = np.arange(0, 10, 2) # [0 2 4 6 8]
# 5. Рівномірно розподілені числа в діапазоні
lin = np.linspace(0, 1, 5) # [0. 0.25 0.5 0.75 1. ]
# 6. Випадкові числа
rand = np.random.rand(5) # 5 випадкових числа від 0 до 1
randn = np.random.randn(5) # 5 чисел з нормального розподілу
Атрибути масиву
Кожен ndarray «знає» про себе важливу інформацію:
arr = np.array([[1, 2, 3],
[4, 5, 6]])
print(arr.shape) # (2, 3) — 2 рядки, 3 стовпці
print(arr.ndim) # 2 — кількість вимірів
print(arr.size) # 6 — загальна кількість елементів
print(arr.dtype) # int64 — тип елементів
shape — один із найважливіших атрибутів у ML. Форма масиву (наприклад, (1000, 28, 28)) говорить вам: 1000 зображень розміром 28×28 пікселів. Ви будете бачити arr.shape у кожному ML-проєкті.Векторизовані операції — головна сила NumPy
Ось де починається магія. Замість циклів — прямі математичні операції над усім масивом:
arr = np.array([1, 2, 3, 4, 5])
# Операції зі скалярами — застосовуються до КОЖНОГО елемента
print(arr + 10) # [11 12 13 14 15]
print(arr * 2) # [ 2 4 6 8 10]
print(arr ** 2) # [ 1 4 9 16 25]
print(arr > 3) # [False False False True True]
# Операції між масивами — поелементно
a = np.array([1, 2, 3])
b = np.array([10, 20, 30])
print(a + b) # [11 22 33]
print(a * b) # [10 40 90]
Порівняємо швидкість — наочний тест:
import time
# Зі списком Python
python_list = list(range(1_000_000))
start = time.time()
python_result = [x * 2 for x in python_list]
print(f"Python: {time.time() - start:.3f}с")
# З NumPy масивом
numpy_arr = np.arange(1_000_000)
start = time.time()
numpy_result = numpy_arr * 2
print(f"NumPy: {time.time() - start:.3f}с")
Індексація та зрізи
Синтаксис схожий на списки Python, але потужніший:
arr = np.array([10, 20, 30, 40, 50])
# Індексація (як у списках)
print(arr[0]) # 10 — перший елемент
print(arr[-1]) # 50 — останній елемент
# Зрізи [start:stop:step]
print(arr[1:4]) # [20 30 40]
print(arr[::2]) # [10 30 50] — кожен другий
# 2D масив (матриця)
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(matrix[1, 2]) # 6 — рядок 1, стовпець 2
print(matrix[:, 1]) # [2 5 8] — весь стовпець 1
print(matrix[0, :]) # [1 2 3] — весь рядок 0
print(matrix[1:, 1:]) # [[5 6] [8 9]] — підматриця
Булева індексація — фільтрація без циклів
Одна з найпотужніших можливостей NumPy:
scores = np.array([85, 42, 91, 67, 78, 55, 96, 33])
# Знайти всі оцінки вище 70
mask = scores > 70 # [True False True False True False True False]
good_scores = scores[mask] # [85 91 78 96]
# Або коротше — в одну дію
good_scores = scores[scores > 70]
print(f"Хороших оцінок: {len(good_scores)}") # 4
print(f"Середня серед хороших: {good_scores.mean():.1f}") # 87.5
Аналогія: булева індексація — це як фільтр у Excel. Ви задаєте умову («ціна > 1000»), і Excel автоматично показує лише відповідні рядки. Тільки NumPy робить це для масивів з мільйонами елементів — миттєво.
Агрегатні функції
data = np.array([23, 45, 12, 67, 89, 34, 56, 78, 90, 11])
print(f"Сума: {data.sum()}") # 505
print(f"Середнє: {data.mean():.1f}") # 50.5
print(f"Мінімум: {data.min()}") # 11
print(f"Максимум: {data.max()}") # 90
print(f"Стд. відхилення: {data.std():.1f}") # 27.7
print(f"Індекс мінімуму: {data.argmin()}") # 9
print(f"Індекс максимуму: {data.argmax()}") # 8
Для 2D масивів можна вказати вісь (axis):
matrix = np.array([[1, 2, 3],
[4, 5, 6]])
print(matrix.sum()) # 21 — сума всіх елементів
print(matrix.sum(axis=0)) # [5 7 9] — сума по стовпцях
print(matrix.sum(axis=1)) # [6 15] — сума по рядках
Зміна форми: reshape
arr = np.arange(12) # [ 0 1 2 3 4 5 6 7 8 9 10 11]
matrix = arr.reshape(3, 4) # Перетворити у матрицю 3×4
# [[0 1 2 3]
# [4 5 6 7]
# [8 9 10 11]]
flat = matrix.flatten() # Знову в 1D: [0 1 2 3 4 5 6 7 8 9 10 11]
reshape — фундаментальна операція в ML. Зображення 28×28 пікселів потрібно перетворити у вектор із 784 елементів для подачі в нейронну мережу? image.reshape(784). Або навпаки — вектор у 2D зображення? flat.reshape(28, 28). Ви будете використовувати це постійно.Порівняльна таблиця: список Python vs NumPy
| Операція | Список Python | NumPy ndarray |
|---|---|---|
| Тип елементів | Будь-які (гнучко, повільно) | Однаковий (компактно, швидко) |
| Пам'ять | Вказівники + обгортки об'єктів | Суцільний блок пам'яті |
Швидкість + | Конкатенація списків | Поелементне додавання |
| Цикли | Потрібні для кожної операції | Не потрібні — векторизація |
| Багатовимірність | Список списків (незручно) | Вбудована підтримка (ndarray) |
| Булева індексація | Немає | Є — фільтрація без циклів |
| Математичні функції | Потрібні цикли | np.sin(), np.exp() і т.д. |
| Відносна швидкість | 1× | 10–100× |
Частина 2. pandas — робота з таблицями даних
Що таке pandas і чому він скрізь
pandas — бібліотека для роботи з табличними даними. Назва походить від "Panel Data" (панельні дані) — термін з економетрики. Саме pandas перетворив Python на мову №1 для Data Science.
Pandas побудований поверх NumPy — усередині кожного pandas-об'єкту лежить NumPy-масив. Тому pandas поєднує зручність роботи з таблицями (індекси, назви стовпців, перемішані типи) зі швидкістю NumPy.
pip install pandas
uv pip install pandas
poetry add pandas
import pandas as pd # pd — загальноприйнятий псевдонім
Series: одновимірна структура даних
Series — це одновимірна структура даних pandas. Уявіть її як один стовпець Excel-таблиці: зліва — мітка рядка (індекс), справа — значення.
import pandas as pd
# Найпростіший Series: зі списку Python
temperatures = pd.Series([22, 25, 19, 27, 23])
print(temperatures)
# 0 22
# 1 25
# 2 19
# 3 27
# 4 23
# dtype: int64
За замовчуванням індекс — це числа 0, 1, 2... Але можна задати власний:
# Series з іменованим індексом
grades = pd.Series(
[85, 92, 78, 96, 71],
index=["Іван", "Олена", "Петро", "Марія", "Андрій"]
)
print(grades)
# Іван 85
# Олена 92
# Петро 78
# Марія 96
# Андрій 71
# dtype: int64
Аналогія: Series — це як стовпець «Оцінки» у класному журналі. Зліва — прізвища учнів (індекс), справа — їхні бали (значення). Кожен рядок — пара «ім'я: оцінка».
Доступ до елементів Series:
print(grades["Олена"]) # 92 — за ім'ям індексу
print(grades.iloc[1]) # 92 — за числовою позицією (iloc = integer location)
print(grades[1]) # 92 — теж за позицією (якщо індекс числовий)
# Зрізи
print(grades["Іван":"Петро"]) # Іван, Олена, Петро
print(grades.iloc[0:3]) # Перші три елементи
Векторизовані операції над Series:
# Операції зі скалярами — застосовуються до кожного елемента
print(grades + 5) # Додати 5 балів усім
print(grades * 1.1) # Підвищити всі оцінки на 10%
print(grades > 80) # Хто пройшов поріг у 80 балів?
# Відбір лише тих, хто має оцінку > 80
excellent = grades[grades > 80]
print(excellent)
# Іван 85
# Олена 92
# Марія 96
# dtype: int64
# Агрегатні функції
print(f"Середня оцінка: {grades.mean():.1f}") # 84.4
print(f"Найвища: {grades.max()}") # 96
print(f"Найнижча: {grades.min()}") # 71
Series зі словника Python:
# Словник автоматично перетворюється на Series
city_populations = pd.Series({
"Київ": 2952301,
"Харків": 1421125,
"Одеса": 1015826,
"Дніпро": 980775
})
print(city_populations.sort_values(ascending=False))
# Київ 2952301
# Харків 1421125
# Одеса 1015826
# Дніпро 980775
DataFrame: двовимірна таблиця даних
DataFrame — це двовимірна структура даних pandas, аналог Excel-таблиці або SQL-таблиці бази даних. Складається зі стовпців (кожен стовпець — це Series) та рядків (кожен рядок — одне спостереження).
Аналогія: якщо Series — це один стовпець класного журналу (скажімо, оцінки з математики), то DataFrame — це весь журнал з усіма предметами. У кожному рядку — один учень, у кожному стовпці — один предмет.
Створення DataFrame зі словника:
data = {
"Ім'я": ["Іван", "Олена", "Петро", "Марія"],
"Вік": [20, 22, 21, 23],
"Математика":[85, 92, 78, 96],
"Фізика": [78, 88, 82, 91],
"Python": [91, 95, 73, 89]
}
df = pd.DataFrame(data)
print(df)
Структура DataFrame:
- Рядки (rows): кожен рядок — один студент (спостереження)
- Стовпці (columns): кожен стовпець — одна характеристика (ознака)
- Індекс (index): автоматичний (0, 1, 2...) або кастомний — мітки рядків
Доступ до даних у DataFrame
Це одна з найважливіших тем — є кілька різних способів, і кожен для свого випадку:
1. Доступ до стовпця — як до ключа словника:
# Один стовпець → Series
ages = df["Вік"]
print(type(ages)) # <class 'pandas.core.series.Series'>
print(ages)
# 0 20
# 1 22
# 2 21
# 3 23
# Name: Вік, dtype: int64
# Кілька стовпців → DataFrame (передайте список)
subjects = df[["Математика", "Фізика", "Python"]]
2. Доступ до рядків через .iloc — за числовою позицією:
# iloc = integer location (позиція, як у списку)
first_row = df.iloc[0] # Перший рядок (Іван)
last_row = df.iloc[-1] # Останній рядок (Марія)
slice_df = df.iloc[1:3] # Рядки 1 та 2 (Олена і Петро)
# Конкретна комірка: рядок 1, стовпець 2
value = df.iloc[1, 2] # 92 — оцінка Олени з математики
3. Доступ до рядків через .loc — за міткою індексу:
# loc = label-based location (за міткою)
# Якщо індекс числовий, він збігається з iloc:
row = df.loc[0] # Рядок з індексом 0 (Іван)
# Але якщо задати кастомний індекс:
df_named = df.set_index("Ім'я") # Тепер індекс — імена студентів
ivan_data = df_named.loc["Іван"] # Доступ за ім'ям
iloc та loc:df.iloc[0]— завжди перший рядок (за позицією)df.loc[0]— рядок з міткою 0 (якщо індекс числовий, збігається; якщо ні — інша поведінка)
iloc. Якщо «мені потрібен рядок з конкретним ім'ям або ID» — loc.4. Фільтрація рядків за умовою:
# Студенти, яким більше 21 року
older = df[df["Вік"] > 21]
# Студенти з оцінкою з Python вище 85
python_good = df[df["Python"] > 85]
# Кілька умов (& = AND, | = OR)
top_students = df[(df["Математика"] > 85) & (df["Python"] > 85)]
print(top_students[["Ім'я", "Математика", "Python"]])
# Ім'я Математика Python
# 1 Олена 92 95
5. Додавання нових стовпців:
# Обчислити середню оцінку кожного студента
df["Середня"] = df[["Математика", "Фізика", "Python"]].mean(axis=1)
print(df[["Ім'я", "Середня"]])
# Ім'я Середня
# 0 Іван 84.666667
# 1 Олена 91.666667
# 2 Петро 77.666667
# 3 Марія 92.000000
6. Сортування:
# Відсортувати за середньою оцінкою (від найвищої)
df_sorted = df.sort_values("Середня", ascending=False)
print(df_sorted[["Ім'я", "Середня"]])
# Ім'я Середня
# 3 Марія 92.000000
# 1 Олена 91.666667
# 0 Іван 84.666667
# 2 Петро 77.666667
Частина 3. Читання та запис даних
У реальному житті дані рідко вводять вручну. Зазвичай це CSV-файли з бази даних, Excel-звіти від відділу продажів, або JSON із API сервісу.
Читання CSV файлів
CSV (Comma-Separated Values) — найпоширеніший формат обміну табличними даними:
df = pd.read_csv("sales.csv")
Але в реальних файлах часто є нюанси. read_csv має десятки параметрів — ось найважливіші:
# Основні параметри read_csv
df = pd.read_csv(
"sales.csv",
sep=";", # Роздільник (за замовчуванням ",")
header=0, # Рядок із заголовками (0 = перший)
encoding="utf-8", # Кодування файлу
na_values=["N/A", "-"], # Значення, які трактувати як NaN (пропуск)
usecols=["date", "price"], # Читати лише певні стовпці
dtype={"price": float}, # Примусово задати тип стовпця
parse_dates=["date"], # Автоматично розпарсити дати
nrows=1000 # Читати лише перші 1000 рядків
)
UnicodeDecodeError, спробуйте encoding="utf-8-sig" (Excel часто додає BOM-маркер), або encoding="cp1251" (Windows-кодування для кирилиці).Приклад реального читання:
# Уявіть файл sales.csv:
# date,product,category,price,quantity
# 2024-01-15,Телефон,Електроніка,12000,3
# 2024-01-16,Ноутбук,Електроніка,28000,1
# 2024-01-17,Футболка,Одяг,450,10
df = pd.read_csv("sales.csv", parse_dates=["date"])
print(df.dtypes)
# date datetime64[ns] ← автоматично розпарсена дата!
# product object ← рядки
# category object
# price int64
# quantity int64
Читання Excel файлів
# Один аркуш (перший за замовчуванням)
df = pd.read_excel("report.xlsx")
# Конкретний аркуш за ім'ям або номером
df_sheet2 = pd.read_excel("report.xlsx", sheet_name="Продажі")
df_third = pd.read_excel("report.xlsx", sheet_name=2)
# Усі аркуші — отримаємо словник
all_sheets = pd.read_excel("report.xlsx", sheet_name=None)
# all_sheets["Продажі"] → DataFrame
# all_sheets["Витрати"] → DataFrame
.xlsx файлів pandas потребує додаткової бібліотеки — openpyxl. Встановіть її: pip install openpyxl. Для старого формату .xls — xlrd.Запис даних у файли
# Запис у CSV
df.to_csv("output.csv", index=False) # index=False — не писати стовпець індексу
# Запис у CSV із іншим роздільником
df.to_csv("output_semicolon.csv", sep=";", index=False)
# Запис у Excel
df.to_excel("output.xlsx", sheet_name="Результати", index=False)
# Запис у JSON
df.to_json("output.json", orient="records", force_ascii=False)
index=False при записі в CSV — майже завжди потрібний параметр. Без нього pandas додає зайвий стовпець із числами 0, 1, 2... ліворуч від даних, що робить файл «незрозумілим» для інших програм.Частина 4. Інформаційні методи — перше знайомство з датасетом
Щоразу коли ви отримуєте новий датасет — перший крок однаковий: дізнатися, що взагалі в цьому файлі. Для цього є кілька незамінних методів.
Будемо працювати з одним прикладом — уявний датасет продажів інтернет-магазину:
import pandas as pd
# Завантажуємо датасет
df = pd.read_csv("sales_data.csv")
df.head(n) та df.tail(n) — погляд на дані
head() показує перші рядки (за замовчуванням — 5), tail() — останні:
df.head() # Перші 5 рядків
df.head(10) # Перші 10 рядків
df.tail(3) # Останні 3 рядки
Навіщо: одразу після pd.read_csv() ви ще не знаєте, що у файлі. head() дає перший «погляд» — чи ті стовпці? Чи правильно розпарсилися дати? Чи немає зайвих символів?
tail() перевіряє кінець файлу — іноді в Excel-файлах є рядки «Разом:» або «Примітки:» в кінці, які не є даними. tail() це виявить.
df.sample(n) — випадкова вибірка
df.sample(5) # 5 випадкових рядків
df.sample(frac=0.01) # 1% випадкових рядків від усього датасету
df.sample(5, random_state=42) # Фіксований seed для відтворюваності
Навіщо: head() показує лише початок — а раптом перші 1000 рядків усі з однієї категорії? sample() дає репрезентативний погляд на різноманітність даних.
df.info() — технічна довідка про датасет
Це один із найважливіших методів для першого знайомства:
df.info()
df.info() розповідає вам відразу:
- Скільки рядків у датасеті (10 000)
- Скільки стовпців (6)
- Тип кожного стовпця —
int64,float64,object(рядки) - Кількість не-пустих значень — якщо
Non-Null Countменше загальної кількості рядків, є пропуски! - Скільки пам'яті займає датасет
Аналогія:
df.info()— це як технічний паспорт товару. Не розгортаючи упаковку, ви вже знаєте: що всередині, скільки важить, які матеріали. У випадку датасету — що за стовпці, якого типу, де є «діри».
df.describe() — статистичний портрет даних
df.describe()
df.describe() обчислює статистику для числових стовпців:
count— кількість непустих значеньmean— середнєstd— стандартне відхилення (наскільки «розкидані» дані)min,max— екстремальні значення25%,50%,75%— квартилі (медіана =50%)
Що можна дізнатися з одного погляду:
max = 120 000приmean = 5 234— є дуже дорогі товари (аутлайери!)min = 1дляquantity— алеmax = 50? Реалістично для магазинуstd > meanдляprice— дані дуже «розкидані»
# Для текстових стовпців — окремо:
df.describe(include="object")
# Або включити все:
df.describe(include="all")
Швидка перевірка пропусків
Після df.info() ми вже знаємо, де є пропуски. Але для детальної картини:
# Кількість пропусків у кожному стовпці
print(df.isnull().sum())
# order_id 0
# date 0
# product 0
# category 150
# price 0
# quantity 80
# Відсоток пропусків
print(df.isnull().sum() / len(df) * 100)
# category 1.5%
# quantity 0.8%
Підсумкова таблиця методів
Аналогія: уявіть, що вам принесли товсту папку з незнайомими документами (датасет). Ось що ви робите в першу чергу:
| Метод | Аналогія | Що дізнаєтеся |
|---|---|---|
df.head() | Переглянути першу сторінку | Структура, назви стовпців, перші дані |
df.tail() | Перегорнути до кінця | Чи немає зайвих рядків у кінці |
df.sample() | Відкрити навмання | Різноманітність та типовість даних |
df.info() | Прочитати зміст | Типи, розмір, де є пропуски |
df.describe() | Прочитати резюме | Статистичний портрет числових даних |
df.isnull().sum() | Знайти порожні аркуші | Точна кількість пропусків |
Практика
Завантажте датасет Iris — класичний набір даних у Data Science (150 рядків, 4 числових ознаки + клас квітки):
import pandas as pd
# Варіант 1: завантажити через seaborn (якщо встановлено)
import seaborn as sns
df = sns.load_dataset("iris")
# Варіант 2: завантажити напряму по URL
url = "https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv"
df = pd.read_csv(url)
Завдання:
- Виведіть перші 10 рядків (
head(10)) - Виведіть
df.info()і дайте відповідь: скільки стовпців, які типи, чи є пропуски? - Виведіть
df.describe()і дайте відповідь: яка середня довжина пелюстки (petal_length)? - Скільки пропусків у кожному стовпці?
- Скільки унікальних видів квіток? (
df["species"].unique())
Створіть датасет вручну та проведіть аналіз:
import pandas as pd
data = {
"Ім'я": ["Аліна", "Богдан", "Вікторія", "Григорій", "Дарина"],
"Курс": [2, 3, 2, 4, 1],
"Математика": [88, 72, 95, 61, 84],
"Програмування":[91, 85, 98, 70, 79],
"Статистика": [76, 68, 92, 74, 88]
}
df = pd.DataFrame(data)
Завдання:
- Додайте стовпець
"Середній бал"— середнє з трьох предметів для кожного студента - Відфільтруйте студентів із середнім балом вище 80
- Знайдіть студента з найвищим балом з програмування
- Відсортуйте датасет за середнім балом від найвищого до найнижчого
- Запишіть результат у CSV файл (
to_csv)
Реальний датасет із даними про пасажирів Titanic:
import pandas as pd
url = "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
df = pd.read_csv(url)
Завдання:
- Вивчіть датасет:
head(),info(),describe(). Які стовпці є? Де найбільше пропусків? - Обчисліть загальний відсоток виживших (
Survived) - Обчисліть відсоток виживших окремо для кожного класу каюти (
Pclass):df.groupby("Pclass")["Survived"].mean() * 100 - Яка середня вартість квитка (
Fare) для виживших і тих, хто загинув? - Скільки пропусків у стовпці
Age? Який відсоток від усіх рядків?
Резюме
NumPy ndarray
Векторизація
for. arr * 2 замість [x * 2 for x in arr]. NumPy передає роботу оптимізованому C-коду всередині.pandas Series
pandas DataFrame
iloc vs loc
df.iloc[0] — рядок за числовою позицією (0, 1, 2...). df.loc["Іван"] — рядок за міткою індексу. Якщо індекс числовий — збігаються. Якщо ні — поведінка різна.read_csv / to_csv
pd.read_csv("file.csv") — читання CSV. Ключові параметри: sep, encoding, parse_dates, na_values. df.to_csv("out.csv", index=False) — запис. index=False майже завжди потрібний.head / tail / sample
info / describe
df.info() — технічна довідка: типи, кількість non-null, пам'ять. df.describe() — статистичний портрет числових стовпців: mean, std, min, max, квартилі.df.describe() мають саме такі значення та що за ними стоїть.Знайомство з Jupyter Notebook та JupyterLab
Чому Data Science використовує Jupyter замість .py файлів, як встановити та запустити JupyterLab, що таке комірки коду та Markdown, і як ефективно працювати з нотбуком
Що таке Tailwind CSS і навіщо він потрібен
Глибоке занурення у філософію utility-first CSS. Чому Tailwind вирішує реальні проблеми CSS у великих проєктах, як він працює під капотом і коли його варто, а коли не варто використовувати.