Python для Data Science: NumPy, Pandas та Scikit-Learn у 2026

Практичний посібник з NumPy 2.1, Pandas 2.2 та Scikit-Learn 1.6 у Python 3.12. Від очищення даних та feature engineering до побудови продуктивного ML-конвеєра з повними прикладами коду.

Python для Data Science: приклади коду NumPy, Pandas та Scikit-Learn 2026

Python залишається беззаперечним лідером серед мов програмування для Data Science у 2026 році. Це зумовлено не модою, а зрілою екосистемою бібліотек, що покривають повний цикл роботи з даними: від завантаження та очищення до побудови продуктивних моделей машинного навчання. Три бібліотеки формують ядро цієї екосистеми: NumPy забезпечує ефективні операції над масивами та лінійну алгебру, Pandas надає гнучкі інструменти для маніпуляції табличними даними, а Scikit-Learn пропонує готові алгоритми машинного навчання з єдиним API. У цій статті розглядається наскрізний практичний приклад — аналіз та прогнозування підвищення співробітників — з використанням усіх трьох бібліотек.

Версії, що використовуються

Усі приклади коду розроблені та протестовані з Python 3.12+, NumPy 2.1, Pandas 2.2 та Scikit-Learn 1.6. Старіші версії можуть відрізнятися в окремих деталях API, зокрема у поведінці Copy-on-Write у Pandas 2.2 та нових можливостях Array API у NumPy 2.1.

Операції з масивами NumPy: основи та булева індексація

NumPy замінює стандартні списки Python та класичні цикли на векторизовані операції, що виконуються на оптимізованому C-коді. Замість ітерації через for-цикл функції NumPy обробляють увесь масив одночасно, що забезпечує прискорення у 10-100 разів для типових задач Data Science.

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

python
# numpy_basics.py
import numpy as np

# Create arrays from different sources
prices = np.array([29.99, 49.99, 19.99, 99.99, 39.99])
quantities = np.arange(1, 6)  # [1, 2, 3, 4, 5]

# Vectorized arithmetic — no loops needed
revenue = prices * quantities
print(revenue)  # [29.99, 99.98, 59.97, 399.96, 199.95]

# Statistical aggregations
print(f"Total revenue: ${revenue.sum():.2f}")   # $789.85
print(f"Mean price: ${prices.mean():.2f}")       # $47.99
print(f"Std deviation: ${prices.std():.2f}")     # $27.64

# Boolean indexing — filter without loops
premium_mask = prices > 40
premium_items = prices[premium_mask]  # [49.99, 99.99]

Булева індексація є фундаментальним патерном у NumPy: вираз prices > 40 створює масив значень True/False, що безпосередньо використовується як маска. Цей самий концепт працює і в Pandas DataFrame, оскільки Pandas побудований поверх NumPy. Статистичні агрегатні функції — sum(), mean(), std() — за замовчуванням обчислюються по всіх елементах, але параметр axis дозволяє застосовувати їх до окремих вимірів багатовимірних масивів.

Зміна форми масивів та broadcasting у NumPy

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

python
# numpy_reshape.py
import numpy as np

# Monthly sales data: 4 products x 3 months
sales = np.array([
    [120, 150, 130],  # Product A
    [200, 180, 220],  # Product B
    [90, 110, 95],    # Product C
    [300, 280, 310],  # Product D
])

# Column-wise mean (average per month)
monthly_avg = sales.mean(axis=0)  # [177.5, 180.0, 188.75]

# Row-wise sum (total per product)
product_totals = sales.sum(axis=1)  # [400, 600, 295, 890]

# Normalize each product relative to its own max
normalized = sales / sales.max(axis=1, keepdims=True)
# keepdims=True preserves the shape for broadcasting
print(normalized[0])  # [0.8, 1.0, 0.867] — Product A relative to its peak

# Reshape for Scikit-Learn (requires 2D input)
flat_sales = sales.flatten()  # 1D array of 12 values
reshaped = flat_sales.reshape(-1, 1)  # 12x1 column vector

Параметр axis є ключовим: axis=0 агрегує по стовпцях (вздовж рядків), axis=1 — по рядках (вздовж стовпців). При нормалізації з keepdims=True зберігається форма (4, 1), що забезпечує коректний broadcasting під час ділення. Конструкція reshape(-1, 1) в кінці є поширеним патерном: Scikit-Learn завжди вимагає щонайменше двовимірний масив на вході.

Маніпуляція та очищення даних у Pandas DataFrame

Pandas є основним інструментом для роботи з табличними даними в Python. DataFrame поводиться подібно до таблиці бази даних або електронної таблиці, але надає значно потужніші можливості трансформації. На практиці очищення даних є найбільш часозатратним етапом будь-якого проекту Data Science — пропущені значення, викиди, дублікати та неузгоджені типи даних потребують систематичної обробки.

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

python
# pandas_cleaning.py
import pandas as pd
import numpy as np

# Load and inspect raw data
df = pd.read_csv("candidates.csv")
print(df.shape)       # (1500, 8)
print(df.dtypes)      # Check column types
print(df.isna().sum()) # Count missing values per column

# Clean in a reproducible chain
df_clean = (
    df
    .dropna(subset=["salary", "experience_years"])      # Drop rows missing critical fields
    .assign(
        salary=lambda x: x["salary"].clip(lower=20000, upper=500000),  # Cap outliers
        experience_years=lambda x: x["experience_years"].astype(int),
        hired_date=lambda x: pd.to_datetime(x["hired_date"], errors="coerce"),
    )
    .drop_duplicates(subset=["email"])                  # Remove duplicate candidates
    .query("experience_years >= 0")                     # Filter invalid entries
    .reset_index(drop=True)
)

print(f"Cleaned: {len(df)} -> {len(df_clean)} rows")

Метод .assign() додає нові стовпці або перезаписує існуючі без зміни оригінального DataFrame. Аргумент clip() обмежує зарплати в межах реалістичного діапазону та запобігає спотворенню майбутньої моделі екстремальними значеннями. Функція pd.to_datetime(..., errors="coerce") перетворює некоректні дати на NaT (Not a Time) замість генерації помилки — надійний патерн для роботи з реальними даними.

Pandas 2.2: Copy-on-Write

Починаючи з Pandas 2.2, режим Copy-on-Write (CoW) активований за замовчуванням. Це означає, що операції над підмножинами DataFrame (slices) завжди створюють копії, а не представлення (views). Поширене попередження SettingWithCopyWarning більше не виникає. Якщо потрібен прямий доступ in-place, слід явно викликати .copy() або використовувати нові CoW-сумісні патерни.

GroupBy-агрегації та feature engineering у Pandas

Подача необроблених даних безпосередньо в модель рідко дає якісні результати. Feature engineering — цілеспрямована трансформація та комбінування вихідних даних у змістовні ознаки — часто має найбільший вплив на якість моделі. Операції GroupBy у Pandas є незамінними для цього: вони дозволяють обчислювати агреговані статистики по групах, які потім слугують новими ознаками.

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

python
# pandas_groupby.py
import pandas as pd

# Aggregate candidate stats by department
dept_stats = (
    df_clean
    .groupby("department")
    .agg(
        avg_salary=("salary", "mean"),
        median_experience=("experience_years", "median"),
        headcount=("email", "count"),
        max_salary=("salary", "max"),
    )
    .sort_values("avg_salary", ascending=False)
)
print(dept_stats.head())

# Create features for ML: encode categorical + add aggregated stats
df_features = (
    df_clean
    .assign(
        # Ratio of individual salary to department average
        salary_ratio=lambda x: x["salary"] / x.groupby("department")["salary"].transform("mean"),
        # Time since hire in days
        tenure_days=lambda x: (pd.Timestamp.now() - x["hired_date"]).dt.days,
        # Binary encoding
        is_senior=lambda x: (x["experience_years"] >= 5).astype(int),
    )
)

Патерн transform("mean") є особливо корисним: на відміну від agg(), що повертає агреговану таблицю, transform() зберігає вихідну кількість рядків і повертає для кожного рядка відповідне групове значення — ідеально для обчислення співвідношень на кшталт salary_ratio. Ознака tenure_days перетворює дату на числове значення, яке моделі можуть безпосередньо обробляти.

Готовий до співбесід з Data Science & ML?

Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.

Побудова конвеєра Scikit-Learn

Конвеєри (Pipelines) Scikit-Learn є центральним механізмом для створення відтворюваних та придатних для продакшену робочих процесів машинного навчання. Конвеєр об'єднує етапи попередньої обробки та модель в єдиний об'єкт, що запобігає витоку даних (data leakage), спрощує налаштування гіперпараметрів та забезпечує коректну серіалізацію для розгортання.

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

python
# sklearn_pipeline.py
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import classification_report
import pandas as pd

# Define column groups
numeric_features = ["salary", "experience_years", "salary_ratio", "tenure_days"]
categorical_features = ["department", "role_level"]
target = "promoted"

# Split before any preprocessing
X = df_features[numeric_features + categorical_features]
y = df_features[target]
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# Build the preprocessing + model pipeline
preprocessor = ColumnTransformer(
    transformers=[
        ("num", StandardScaler(), numeric_features),           # Scale numeric columns
        ("cat", OneHotEncoder(handle_unknown="ignore"), categorical_features),  # Encode categories
    ]
)

pipeline = Pipeline([
    ("preprocessor", preprocessor),
    ("classifier", GradientBoostingClassifier(
        n_estimators=200,
        learning_rate=0.1,
        max_depth=4,
        random_state=42,
    )),
])

# Train and evaluate
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
print(classification_report(y_test, y_pred))

ColumnTransformer дозволяє визначити різні етапи попередньої обробки для числових і категоріальних стовпців. StandardScaler нормалізує числові ознаки до середнього 0 та стандартного відхилення 1. OneHotEncoder(handle_unknown="ignore") перетворює категоріальні значення на бінарні стовпці та коректно обробляє невідомі категорії в тестовому наборі. Хоча GradientBoostingClassifier стійкий до немасштабованих ознак, наявність StandardScaler у конвеєрі дозволяє за потреби легко замінити модель на лінійну або SVM.

Крос-валідація та налаштування гіперпараметрів

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

python
# sklearn_tuning.py
from sklearn.model_selection import cross_val_score, GridSearchCV
import numpy as np

# 5-fold cross-validation on the full pipeline
scores = cross_val_score(pipeline, X_train, y_train, cv=5, scoring="f1")
print(f"F1 scores: {scores}")
print(f"Mean F1: {scores.mean():.3f} (+/- {scores.std() * 2:.3f})")

# Grid search over hyperparameters
param_grid = {
    "classifier__n_estimators": [100, 200, 300],
    "classifier__max_depth": [3, 4, 5],
    "classifier__learning_rate": [0.05, 0.1, 0.2],
}

grid_search = GridSearchCV(
    pipeline,
    param_grid,
    cv=5,
    scoring="f1",
    n_jobs=-1,      # Use all CPU cores
    verbose=1,
)

grid_search.fit(X_train, y_train)
print(f"Best params: {grid_search.best_params_}")
print(f"Best F1: {grid_search.best_score_:.3f}")

# Evaluate the best model on held-out test set
best_model = grid_search.best_estimator_
print(classification_report(y_test, best_model.predict(X_test)))

Подвійне підкреслення у "classifier__n_estimators" є конвенцією Scikit-Learn для доступу до параметрів вкладених компонентів конвеєра: classifier — це назва кроку конвеєра, n_estimators — параметр відповідного оцінювача. Параметр n_jobs=-1 використовує всі доступні ядра процесора та значно прискорює пошук: при сітці 3x3x3 комбінацій і 5-fold крос-валідації тренується 135 моделей.

Запобігання витоку даних при крос-валідації

Найпоширеніша помилка при крос-валідації з попередньою обробкою — обчислення параметрів масштабування на всьому тренувальному наборі до розбиття на фолди. Це призводить до надмірно оптимістичних результатів, оскільки валідаційні дані опосередковано впливають на масштабування. Конвеєри Scikit-Learn розв'язують цю проблему автоматично: у межах кожного фолду весь етап попередньої обробки навчається виключно на тренувальному фолді.

Збереження та завантаження моделей

Навчена модель має практичну цінність лише тоді, коли її можна зберегти та завантажити в інших середовищах — веб-серверах, пакетних процесах, мікросервісах. Конвеєри Scikit-Learn повністю серіалізуються: параметри попередньої обробки (середні значення скейлера, категорії енкодера) та ваги моделі зберігаються в одному файлі. Для глибшого ознайомлення з технологіями Data Science варто переглянути доступні навчальні матеріали.

python
# sklearn_export.py
import joblib
from pathlib import Path

# Save the complete pipeline (preprocessor + model)
model_dir = Path("models")
model_dir.mkdir(exist_ok=True)
joblib.dump(best_model, model_dir / "promotion_model_v1.joblib")

# Load and predict in a different process
loaded_model = joblib.load(model_dir / "promotion_model_v1.joblib")
new_data = pd.DataFrame({
    "salary": [75000],
    "experience_years": [4],
    "salary_ratio": [1.05],
    "tenure_days": [730],
    "department": ["Engineering"],
    "role_level": ["Mid"],
})

prediction = loaded_model.predict(new_data)
probability = loaded_model.predict_proba(new_data)[:, 1]
print(f"Promoted: {bool(prediction[0])}, Confidence: {probability[0]:.2%}")

Бібліотека joblib оптимізована для числових масивів і працює значно швидше за pickle з великими моделями. Файл .joblib містить усі параметри скейлера та словники енкодера — при завантаженні в іншому процесі не потрібно повторно обробляти тренувальні дані. Метод predict_proba() повертає ймовірності класів; зріз [:, 1] витягує ймовірність позитивного класу (підвищення), що на практиці є інформативнішим за бінарне передбачення.

Висновок

NumPy, Pandas та Scikit-Learn доповнюють одна одну: NumPy забезпечує матричну математику та операції над масивами, Pandas надбудовується над ним і надає гнучку маніпуляцію даними з іменованими стовпцями та індексами, а Scikit-Learn використовує обидві бібліотеки як формат вхідних даних для своїх алгоритмів. Продемонстрований робочий процес є стандартом у професійних командах Data Science:

  • NumPy — векторизовані операції, статистичні агрегації та булева індексація для ефективної роботи з числовими даними
  • Pandas — завантаження, очищення, трансформація табличних даних та feature engineering через ланцюжки методів і GroupBy-операції
  • Scikit-Learn — побудова конвеєрів, крос-валідація, налаштування гіперпараметрів та серіалізація моделей
  • Конвеєри (Pipelines) — єдиний об'єкт, що інкапсулює попередню обробку та модель, запобігаючи витоку даних
  • Крос-валідація — надійна оцінка якості моделі через усереднення по кількох фолдах замість одного розділення

Опанування цих трьох бібліотек відкриває шлях до складніших фреймворків, таких як PyTorch або XGBoost, адже їхні API-конвенції базуються на тих самих принципах. Поглибити знання можна на сторінці технологій Data Science.

Починай практикувати!

Перевір свої знання з нашими симуляторами співбесід та технічними тестами.

Теги

#data-science
#python
#numpy
#pandas
#scikit-learn
#machine-learning
#tutorial

Поділитися

Пов'язані статті