# Feature Engineering w Machine Learning: Techniki, Pipelines i Pytania Rekrutacyjne 2026 > Kompletny przewodnik po feature engineering w uczeniu maszynowym: kodowanie zmiennych, skalowanie, transformacje, selekcja cech i pytania rekrutacyjne na 2026 rok. - Published: 2026-05-08 - Updated: 2026-05-08 - Author: SharpSkill - Tags: feature engineering, machine learning, data science, python, scikit-learn - Reading time: 12 min --- Feature engineering stanowi fundament skutecznego modelowania w uczeniu maszynowym. Surowe dane niemal nigdy nie trafiają do algorytmów w postaci gotowej do bezpośredniego wykorzystania — to właśnie transformacja danych w wartościowe cechy decyduje o przepaści między przeciętnym a wybitnym modelem predykcyjnym. Każdy doświadczony data scientist wie, że zbiór danych pobrany z bazy produkcyjnej lub API zewnętrznego wymaga gruntownego przetworzenia. Braki danych, rozkłady skośne, zmienne kategoryczne bez naturalnego porządku, wartości odstające — wszystko to wymaga świadomych decyzji inżynierskich, zanim jakikolwiek klasyfikator lub regresor otrzyma dane wejściowe. > **Dlaczego Feature Engineering ma kluczowe znaczenie** > > Badania konsekwentnie potwierdzają, że decyzje dotyczące preprocessingu i inżynierii cech mają większy wpływ na dokładność modelu niż strojenie hiperparametrów. Dobrze zaprojektowany zbiór cech potrafi sprawić, że prosta regresja logistyczna pokona źle przygotowany model gradient boosting. ## Strategie kodowania zmiennych kategorycznych Zmienne kategoryczne stanowią jedno z najczęstszych wyzwań w przygotowaniu danych. Algorytmy uczenia maszynowego operują na liczbach, więc każda wartość tekstowa musi zostać przekształcona w reprezentację numeryczną. Wybór metody kodowania zależy od natury zmiennej — czy posiada naturalny porządek (ordinalna), czy też nie (nominalna). **Label Encoding** przypisuje każdej kategorii unikalny numer całkowity. Sprawdza się doskonale w przypadku zmiennych ordinalnych, takich jak rozmiar (mały, średni, duży), gdzie istnieje logiczna hierarchia. Algorytmy drzewiaste (Random Forest, XGBoost) radzą sobie z takim kodowaniem nawet dla zmiennych nominalnych, ponieważ dokonują podziału na podstawie progów. **One-Hot Encoding** tworzy osobną kolumnę binarną dla każdej kategorii. Jest to metoda preferowana dla zmiennych nominalnych w modelach liniowych i sieciach neuronowych, ponieważ nie narzuca fałszywego porządku między kategoriami. Parametr `drop="first"` eliminuje jedną kolumnę referencyjną, co zapobiega współliniowości w modelach liniowych. ```python # encoding_strategies.py import pandas as pd from sklearn.preprocessing import LabelEncoder, OneHotEncoder from sklearn.compose import ColumnTransformer df = pd.DataFrame({ "size": ["small", "medium", "large", "medium", "small"], "color": ["red", "blue", "green", "red", "blue"], "price": [10, 25, 40, 22, 12] }) # Label encoding for ordinal feature (size has natural order) le = LabelEncoder() df["size_encoded"] = le.fit_transform(df["size"]) # large=0, medium=1, small=2 # One-hot encoding for nominal feature (color has no order) ct = ColumnTransformer( transformers=[ ("onehot", OneHotEncoder(drop="first", sparse_output=False), ["color"]) ], remainder="passthrough" # Keep other columns unchanged ) result = ct.fit_transform(df[["color", "price"]]) # Produces: color_green, color_red columns (blue dropped as reference) ``` W praktyce produkcyjnej warto również rozważyć **Target Encoding** (kodowanie średnią zmiennej docelowej) dla zmiennych o dużej liczbie kategorii. Technika ta zastępuje każdą kategorię średnią wartością zmiennej docelowej obliczoną na zbiorze treningowym, co pozwala uniknąć eksplozji wymiarowości typowej dla one-hot encoding przy setkach kategorii. ## Skalowanie cech: StandardScaler, MinMaxScaler i RobustScaler Skalowanie cech numerycznych jest niezbędne dla algorytmów wrażliwych na skalę zmiennych. Modele oparte na odległości (KNN, SVM), regresja liniowa z regularyzacją oraz sieci neuronowe wymagają, aby cechy miały porównywalne zakresy wartości. Bez skalowania cecha o zakresie 0–1000 zdominuje cechę o zakresie 0–1. **StandardScaler** transformuje dane do rozkładu o średniej 0 i odchyleniu standardowym 1. Jest to domyślny wybór w większości przypadków, ale wykazuje wrażliwość na wartości odstające, które zaburzają obliczaną średnią i odchylenie. **MinMaxScaler** mapuje wartości do zakresu [0, 1]. Przydatny, gdy algorytm wymaga danych w ściśle określonym przedziale (np. sieci neuronowe z funkcją aktywacji sigmoid). Jego słabością jest ekstremalna wrażliwość na outlinery — pojedyncza wartość odstająca może skompresować wszystkie pozostałe obserwacje do wąskiego pasma. **RobustScaler** używa mediany i rozstępu międzykwartylowego (IQR) zamiast średniej i odchylenia standardowego. Dzięki temu wartości odstające nie zaburzają skalowania rdzenia danych, co czyni go idealnym wyborem dla zbiorów z anomaliami. ```python # feature_scaling.py import numpy as np from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler # Simulated dataset: salary with outliers data = np.array([[35000], [42000], [55000], [67000], [450000]]) # 450k is an outlier # StandardScaler: mean=0, std=1 (sensitive to outliers) standard = StandardScaler().fit_transform(data) # Result: [-0.72, -0.68, -0.60, -0.53, 2.53] — outlier distorts the scale # MinMaxScaler: maps to [0, 1] (very sensitive to outliers) minmax = MinMaxScaler().fit_transform(data) # Result: [0.0, 0.017, 0.048, 0.077, 1.0] — most values crushed near zero # RobustScaler: uses median and IQR (robust to outliers) robust = RobustScaler().fit_transform(data) # Result: [-0.77, -0.5, 0.0, 0.46, 15.38] — outlier isolated, core data preserved ``` Podczas rozmowy kwalifikacyjnej warto podkreślić, że skalowanie wykonuje się **po podziale na zbiór treningowy i testowy**. Dopasowanie skalera na całym zbiorze danych przed podziałem prowadzi do wycieku danych (data leakage), ponieważ statystyki zbioru testowego wpływają na transformacje danych treningowych. ## Transformacje matematyczne dla rozkładów skośnych Wiele rzeczywistych zmiennych — dochody, ceny nieruchomości, liczba transakcji — wykazuje silną skośność prawostronną. Kilka procent obserwacji o ekstremalnie wysokich wartościach wydłuża prawy ogon rozkładu, co negatywnie wpływa na modele zakładające normalność rozkładu cech. **Transformacja logarytmiczna** (`np.log1p`) to najprostsze rozwiązanie. Kompresuje duże wartości i rozciąga małe, przybliżając rozkład do normalnego. Funkcja `log1p` (logarytm z 1+x) bezpiecznie obsługuje wartości zerowe. **Box-Cox** automatycznie dobiera optymalny parametr potęgowy lambda, który najlepiej normalizuje rozkład. Wymaga jednak ściśle dodatnich wartości — dane z zerami lub wartościami ujemnymi wymagają wstępnego przesunięcia. **Yeo-Johnson** rozszerza Box-Cox o obsługę wartości zerowych i ujemnych, co czyni go bardziej uniwersalnym wyborem w praktyce. ```python # skew_transformations.py import numpy as np from sklearn.preprocessing import PowerTransformer # Right-skewed income data (common in real datasets) income = np.array([[25000], [32000], [41000], [55000], [72000], [150000], [320000], [890000]]) # Log transform: simple, effective for right-skewed data log_income = np.log1p(income) # log1p handles zero values safely # Box-Cox: finds optimal power parameter automatically pt = PowerTransformer(method="box-cox") # Requires strictly positive values income_boxcox = pt.fit_transform(income) print(f"Optimal lambda: {pt.lambdas_[0]:.3f}") # Shows learned parameter # Yeo-Johnson: works with zero and negative values too pt_yj = PowerTransformer(method="yeo-johnson") income_yj = pt_yj.fit_transform(income) ``` Warto pamiętać, że transformacje potęgowe nie zawsze są konieczne. Modele drzewiaste (Random Forest, XGBoost, LightGBM) są z natury odporne na rozkłady skośne, ponieważ dokonują podziału na podstawie progów, a nie odległości. Transformacje mają największy sens w kontekście modeli liniowych, SVM z jądrem RBF oraz sieci neuronowych. ## Selekcja cech: eliminacja szumu przed trenowaniem Nie każda dostępna cecha przyczynia się do lepszej predykcji. Cechy irrelewantne lub redundantne zwiększają złożoność modelu, wydłużają czas trenowania i mogą prowadzić do overfittingu. Selekcja cech pozwala zidentyfikować podzbiór zmiennych, który maksymalizuje moc predykcyjną przy minimalnej złożoności. Istnieją trzy główne podejścia do selekcji cech: **Metody filtrujące** oceniają każdą cechę niezależnie od modelu, korzystając z testów statystycznych (ANOVA, chi-kwadrat, korelacja). Są szybkie obliczeniowo, ale nie uwzględniają interakcji między cechami. **Metody wrappingowe** iteracyjnie dobierają podzbiory cech, trenując model na każdym z nich i oceniając wynik. Sequential Feature Selection (SFS) dodaje lub usuwa cechy po jednej, optymalizując zadaną metrykę. Są dokładne, ale kosztowne obliczeniowo. **Metody osadzone** (embedded) realizują selekcję cech jako integralną część procesu trenowania. Regularyzacja L1 (Lasso) zeruje wagi nieistotnych cech, a modele drzewiaste obliczają ważność cech na podstawie redukcji nieczystości. ```python # feature_selection.py from sklearn.datasets import make_classification from sklearn.feature_selection import ( SelectKBest, f_classif, # Filter method SequentialFeatureSelector, # Wrapper method SelectFromModel # Embedded method ) from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LassoCV # Dataset: 20 features, only 5 are informative X, y = make_classification( n_samples=1000, n_features=20, n_informative=5, n_redundant=3, random_state=42 ) # Filter: ANOVA F-test selects top k features by statistical significance selector_filter = SelectKBest(f_classif, k=8) X_filtered = selector_filter.fit_transform(X, y) print(f"Selected features: {selector_filter.get_support(indices=True)}") # Embedded: L1 regularization (Lasso) zeros out irrelevant feature weights lasso = LassoCV(cv=5, random_state=42).fit(X, y) selector_embedded = SelectFromModel(lasso, prefit=True) X_lasso = selector_embedded.transform(X) print(f"Lasso kept {X_lasso.shape[1]} features out of {X.shape[1]}") ``` Podczas rozmowy rekrutacyjnej często pojawia się pytanie o różnicę między selekcją cech a redukcją wymiarowości (PCA). Kluczowa odpowiedź: selekcja cech zachowuje oryginalne zmienne (interpretowalność), podczas gdy PCA tworzy nowe, syntetyczne komponenty będące kombinacjami liniowymi oryginalnych cech. ## Budowanie produkcyjnych pipeline'ów z ColumnTransformer W środowisku produkcyjnym poszczególne kroki preprocessingu nie mogą istnieć jako oddzielne skrypty. `Pipeline` z scikit-learn łączy transformacje i model w jeden obiekt, który gwarantuje spójność między trenowaniem a inferencją. `ColumnTransformer` umożliwia zastosowanie różnych transformacji do różnych grup kolumn. Taki pipeline eliminuje trzy krytyczne problemy: 1. **Wyciek danych** — transformacje są dopasowywane wyłącznie na foldach treningowych podczas walidacji krzyżowej 2. **Niespójność** — ten sam obiekt pipeline obsługuje dane treningowe, walidacyjne i produkcyjne 3. **Brak powtarzalności** — pipeline można serializować (`joblib.dump`) i wdrożyć jako artefakt modelu ```python # production_pipeline.py import pandas as pd from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer from sklearn.impute import SimpleImputer from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.ensemble import GradientBoostingClassifier from sklearn.model_selection import cross_val_score # Define column groups by type numeric_features = ["age", "income", "credit_score"] categorical_features = ["education", "employment_type", "region"] # Numeric pipeline: impute missing values, then scale numeric_pipeline = Pipeline([ ("imputer", SimpleImputer(strategy="median")), # Median resists outliers ("scaler", StandardScaler()) ]) # Categorical pipeline: impute missing, then one-hot encode categorical_pipeline = Pipeline([ ("imputer", SimpleImputer(strategy="most_frequent")), ("encoder", OneHotEncoder(handle_unknown="ignore", sparse_output=False)) ]) # Combine into a single preprocessor preprocessor = ColumnTransformer([ ("num", numeric_pipeline, numeric_features), ("cat", categorical_pipeline, categorical_features) ]) # Full pipeline: preprocessing + model in one object full_pipeline = Pipeline([ ("preprocessor", preprocessor), ("classifier", GradientBoostingClassifier(n_estimators=200, random_state=42)) ]) # Cross-validation applies preprocessing correctly within each fold scores = cross_val_score(full_pipeline, X, y, cv=5, scoring="roc_auc") print(f"AUC: {scores.mean():.3f} +/- {scores.std():.3f}") ``` Parametr `handle_unknown="ignore"` w `OneHotEncoder` jest kluczowy w produkcji — jeśli pojawi się kategoria nieobecna w danych treningowych, encoder zwróci wektor zerowy zamiast rzucić wyjątek. ## Automatyczna inżynieria cech z Featuretools Ręczne tworzenie cech wymaga głębokiej znajomości domeny i jest czasochłonne. Biblioteka **Featuretools** automatyzuje ten proces za pomocą techniki Deep Feature Synthesis (DFS), która generuje cechy na podstawie relacji między tabelami. DFS operuje na dwóch typach prymitywów: - **Agregacyjne** (count, mean, max, std) — podsumowują dane z tabel podrzędnych na poziomie tabeli nadrzędnej - **Transformacyjne** (month, weekday, hour) — tworzą nowe cechy z pojedynczych kolumn Parametr `max_depth` kontroluje złożoność generowanych cech. Głębokość 1 tworzy proste agregacje (np. średnia kwota transakcji per klient), natomiast głębokość 2 generuje cechy zagnieżdżone (np. odchylenie standardowe miesięcznych średnich kwot transakcji per klient). ```python # automated_feature_engineering.py import featuretools as ft import pandas as pd # Define entities from relational tables customers = pd.DataFrame({ "customer_id": [1, 2, 3], "signup_date": pd.to_datetime(["2024-01-15", "2024-03-22", "2024-06-01"]), "region": ["US", "EU", "APAC"] }) transactions = pd.DataFrame({ "txn_id": range(1, 8), "customer_id": [1, 1, 1, 2, 2, 3, 3], "amount": [50, 120, 30, 200, 85, 340, 15], "category": ["food", "tech", "food", "tech", "travel", "food", "tech"] }) # Create an EntitySet with relationships es = ft.EntitySet(id="retail") es = es.add_dataframe(dataframe=customers, dataframe_name="customers", index="customer_id", time_index="signup_date") es = es.add_dataframe(dataframe=transactions, dataframe_name="transactions", index="txn_id") es = es.add_relationship("customers", "customer_id", "transactions", "customer_id") # DFS generates features: COUNT, MEAN, MAX, STD of transactions per customer feature_matrix, feature_defs = ft.dfs( entityset=es, target_dataframe_name="customers", max_depth=2, # Controls complexity of generated features trans_primitives=["month", "weekday"], # Transformation primitives agg_primitives=["count", "mean", "std", "max"] # Aggregation primitives ) print(f"Generated {len(feature_defs)} features from 2 tables") ``` Featuretools sprawdza się szczególnie w projektach z danymi relacyjnymi (e-commerce, bankowość, telekomunikacja), gdzie ręczne tworzenie agregacji z wielu tabel zajmuje tygodnie. Warto jednak pamiętać, że automatycznie wygenerowane cechy wymagają walidacji domenowej — nie każda statystycznie możliwa kombinacja ma sens biznesowy. ## Najczęściej zadawane pytania rekrutacyjne o Feature Engineering Poniżej znajdują się pytania, które regularnie pojawiają się na rozmowach kwalifikacyjnych na stanowiska data scientist i ML engineer w 2026 roku. **P: Czym różni się Label Encoding od One-Hot Encoding i kiedy stosować każde z nich?** Label Encoding przypisuje kolejne liczby całkowite kategoriom. Nadaje się do zmiennych ordinalnych (rozmiar, wykształcenie) oraz modeli drzewiastych. One-Hot Encoding tworzy kolumny binarne — jest konieczny dla zmiennych nominalnych w modelach liniowych, KNN i sieciach neuronowych, aby uniknąć narzucenia fałszywego porządku. **P: Dlaczego skalowanie cech jest ważne i które algorytmy tego wymagają?** Algorytmy oparte na odległości (KNN, SVM), regresja z regularyzacją (Ridge, Lasso) i sieci neuronowe wymagają skalowania, ponieważ cechy o większych zakresach dominują w obliczeniach. Modele drzewiaste nie wymagają skalowania, gdyż dokonują podziału na podstawie progów. **P: Jak radzić sobie z wartościami odstającymi podczas feature engineering?** Kilka podejść: użycie RobustScaler zamiast StandardScaler, transformacje logarytmiczne kompresujące ogony rozkładu, winsoryzacja (przycinanie do percentyli np. 1. i 99.), lub usuwanie obserwacji po analizie domenowej potwierdzającej, że są błędem pomiarowym. **P: Czym jest data leakage w kontekście feature engineering i jak mu zapobiegać?** Data leakage występuje, gdy informacja ze zbioru testowego przenika do procesu trenowania. Typowy przykład: dopasowanie skalera na całym zbiorze przed podziałem train/test. Zapobiega mu stosowanie pipeline'ów scikit-learn, które wykonują fit wyłącznie na danych treningowych w każdym foldzie walidacji krzyżowej. **P: Kiedy stosować PCA zamiast selekcji cech?** PCA redukuje wymiarowość tworząc nowe, ortogonalne komponenty — przydatne gdy cechy są silnie skorelowane lub gdy interpretowalność nie jest priorytetem (np. przetwarzanie obrazów). Selekcja cech zachowuje oryginalne zmienne, co jest kluczowe w domenach wymagających wyjaśnienia decyzji modelu (finanse, medycyna). **P: Jak obsłużyć zmienne kategoryczne o bardzo dużej liczbie kategorii (high cardinality)?** One-hot encoding staje się niepraktyczny przy setkach kategorii. Alternatywy to: target encoding (średnia zmiennej docelowej per kategoria z regularyzacją), frequency encoding (częstotliwość występowania kategorii), hash encoding (zmniejsza wymiarowość kosztem kolizji) lub embeddingi uczone w sieciach neuronowych. ## Podsumowanie Feature engineering pozostaje jedną z najważniejszych kompetencji data scientista i ML engineera. Kluczowe wnioski z tego przewodnika: - **Kodowanie kategoryczne**: Label Encoding dla zmiennych ordinalnych, One-Hot Encoding dla nominalnych, Target Encoding dla wysokiej kardynalności - **Skalowanie**: StandardScaler jako domyślny wybór, RobustScaler w obecności outlierów, MinMaxScaler dla ściśle określonych przedziałów - **Transformacje**: logarytmiczna, Box-Cox i Yeo-Johnson normalizują rozkłady skośne — kluczowe dla modeli liniowych, zbędne dla modeli drzewiastych - **Selekcja cech**: metody filtrujące (szybkie, niezależne od modelu), wrappingowe (dokładne, kosztowne) i osadzone (L1, ważność cech w drzewach) - **Pipeline'y**: `ColumnTransformer` + `Pipeline` gwarantują spójność, eliminują data leakage i umożliwiają serializację - **Automatyzacja**: Featuretools i Deep Feature Synthesis przyspieszają generowanie cech z danych relacyjnych - **Rozmowy kwalifikacyjne**: nacisk na zrozumienie trade-offów między metodami, data leakage i praktyczne zastosowanie pipeline'ów Opanowanie tych technik nie tylko poprawia wyniki modeli, ale stanowi też silny sygnał kompetencji podczas procesów rekrutacyjnych w branży data science. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pl/blog/data-science/feature-engineering-machine-learning-techniques-interview-2026