ms-ai-architect/skills/ms-ai-engineering/references/data-engineering/feature-stores-engineering.md
Kjell Tore Guttormsen ddce43d8b2 feat(ms-ai-architect): Spor 1 — Port-1-substrat migrert på 4 ikke-advisor-skills (243 Source + 327 Type + 325 TOC + stale-verified poison fjernet) [skip-docs]
Steg 9 (R4): unified migrate-corpus.mjs --write over engineering/governance/
infrastructure/security. 327 filer mutert, verified=null, prosa byte-identisk
(fra første ## seksjon), advisor urørt (0 endringer).

To applier-fixes oppdaget under kjøring (TDD, RED→GREEN):
- insertHeaderFields: anker faller nå tilbake når en meta-linje selv passerer
  500B (2 filer pakket et avsnitt i **Status:** → Type/Source landet utenfor
  scan-vinduet, applierens post-write-assertion fanget + restaurerte).
- normalizeStaleVerified: fjerner nå ALLE stale non-date **Verified:** i
  500B-vinduet, inkl. stray body-dup rett under --- (9 mlops-genaiops-filer var
  ellers falskt "verified"/fresh, droppet fra worklist). Operatør-godkjent
  utvidelse av carve-out; kun stray metadata-linjer, aldri prosa.

test-transform-criterion: precondition oppdatert til post-migrasjons-sannhet
(fila bærer nå Source). Suite 728/728 grønn.
2026-07-04 10:19:11 +02:00

459 lines
17 KiB
Markdown

# Feature Stores and Feature Engineering
**Last updated:** 2026-06-24
**Status:** GA
**Category:** Data Engineering for AI
**Type:** reference
**Source:** https://learn.microsoft.com/azure/machine-learning/concept-what-is-managed-feature-store
---
## Innhold
- [Introduksjon](#introduksjon)
- [Feature Definition and Storage in Silver Layer](#feature-definition-and-storage-in-silver-layer)
- [Point-in-Time Lookups for Training](#point-in-time-lookups-for-training)
- [Feature Freshness and Refresh Cadences](#feature-freshness-and-refresh-cadences)
- [Data Wrangler for Exploratory Feature Engineering](#data-wrangler-for-exploratory-feature-engineering)
- [Feature Monitoring and Drift Detection](#feature-monitoring-and-drift-detection)
- [Referanser](#referanser)
- [For Cosmo](#for-cosmo)
## Introduksjon
Feature stores er et sentralt mønster i moderne MLOps som løser problemet med feature-gjenbruk, konsistens mellom trening og inferens, og operasjonalisering av feature-pipelines. Azure Machine Learning Managed Feature Store og Microsoft Fabric Data Science gir en komplett plattform for å definere, materialisere, dele og overvåke features på tvers av ML-prosjekter.
For norsk offentlig sektor innebærer feature store-tilnærmingen at data science-team kan dele beregninger på tvers av prosjekter -- for eksempel kan trafikkdata-features brukes både for ulykkesprediksjonsmodeller og køvarslingsmodeller uten redundant feature engineering. Dette reduserer kostnader, forbedrer konsistens og forkorter tid fra eksperimentering til produksjon.
Denne referansen dekker feature-definisjon og lagring, point-in-time lookups for trening, feature-oppdateringsstrategier, Data Wrangler for utforskende feature engineering, og overvåking av feature-kvalitet og drift.
---
## Feature Definition and Storage in Silver Layer
### Feature Store Arkitektur
```
┌──────────────────────────────────────────────────────────────┐
│ Azure ML Managed Feature Store │
│ ┌──────────────┐ ┌──────────────────┐ ┌───────────────┐ │
│ │ Feature Set │ │ Materialization │ │ Feature │ │
│ │ Specification│ │ Store (ADLS Gen2) │ │ Retrieval │ │
│ │ │ │ Offline + Online │ │ Component │ │
│ └──────┬───────┘ └────────┬─────────┘ └───────┬───────┘ │
│ │ │ │ │
│ └───────────────────┴─────────────────────┘ │
└──────────────────────────────┬───────────────────────────────┘
┌──────────────────────────────▼───────────────────────────────┐
│ Microsoft Fabric │
│ ┌──────────┐ ┌──────────────┐ ┌────────────────────────┐ │
│ │ Bronze │ │ Silver Layer │ │ Gold Layer │ │
│ │ (raw) │──│ (features) │──│ (training datasets) │ │
│ └──────────┘ └──────────────┘ └────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
```
### Feature Set Specification
En feature set-spesifikasjon definerer features og valgfri transformasjonslogikk:
```python
# Feature set specification (YAML)
# feature_set_spec/transactions/spec.yaml
"""
name: transactions
version: "1"
description: "Customer transaction features"
entities:
- name: customer
version: "1"
join_keys:
- customer_id
source:
type: parquet
path: "abfss://silver@onelake.dfs.fabric.microsoft.com/transactions"
timestamp_column: transaction_date
features:
- name: transaction_7day_count
type: integer
description: "Number of transactions in last 7 days"
- name: transaction_7day_sum
type: double
description: "Total transaction amount in last 7 days"
- name: transaction_30day_avg
type: double
description: "Average transaction amount in last 30 days"
"""
```
### Feature Transformations med PySpark
```python
from pyspark.sql import functions as F
from pyspark.sql.window import Window
# Kildedataer fra Silver layer
transactions = spark.read.format("delta").table("silver.transactions")
# Definer vindus-spesifikasjoner
window_7d = (
Window
.partitionBy("customer_id")
.orderBy(F.col("transaction_date").cast("long"))
.rangeBetween(-7 * 86400, 0) # 7 dager i sekunder
)
window_30d = (
Window
.partitionBy("customer_id")
.orderBy(F.col("transaction_date").cast("long"))
.rangeBetween(-30 * 86400, 0)
)
# Beregn features
customer_features = (
transactions
.withColumn("txn_7d_count", F.count("*").over(window_7d))
.withColumn("txn_7d_sum", F.sum("amount").over(window_7d))
.withColumn("txn_30d_avg", F.avg("amount").over(window_30d))
.withColumn("txn_30d_max", F.max("amount").over(window_30d))
.withColumn("days_since_last_txn",
F.datediff(F.current_date(), F.max("transaction_date").over(
Window.partitionBy("customer_id"))))
)
# Lagre features i Silver layer
customer_features.write.format("delta") \
.mode("overwrite") \
.saveAsTable("silver.customer_transaction_features")
```
### Feature-lagring i Medallion Architecture
| Lag | Innhold | Oppdateringsfrekvens |
|---|---|---|
| **Bronze** | Råtransaksjoner fra Dataverse/kildesystemer | Sanntid / daglig |
| **Silver** | Feature-beregninger (aggregater, vindus-funksjoner) | Daglig / per time |
| **Gold** | Ferdige treningsdatasett (features + labels) | Ved behov |
| **Feature Store** | Registrerte, versjonerte features | Materialisert etter plan |
---
## Point-in-Time Lookups for Training
### Temporal Joins (tidsreise-joiner)
Point-in-time lookups er kritisk for å unngå datalekasje i ML-trening:
```python
# FEIL: Standard join inkluderer fremtidige data (data leakage!)
# features_at_prediction_time = features.join(labels, "customer_id")
# RIKTIG: Point-in-time join
from pyspark.sql.functions import col
# Observations: tidspunkter der vi vil ha features
observations = spark.createDataFrame([
("C001", "2026-01-15"),
("C002", "2026-01-20"),
("C003", "2026-02-01")
], ["customer_id", "observation_date"])
# Features: tidsseriedata
features = spark.read.format("delta").table("silver.customer_transaction_features")
# Point-in-time join: hent features som var gjeldende PÅ observation_date
pit_features = (
observations.alias("obs")
.join(
features.alias("feat"),
(col("obs.customer_id") == col("feat.customer_id")) &
(col("feat.feature_date") <= col("obs.observation_date")),
"left"
)
.withColumn("rank", F.row_number().over(
Window
.partitionBy("obs.customer_id", "obs.observation_date")
.orderBy(F.desc("feat.feature_date"))
))
.filter(col("rank") == 1) # Siste feature-verdi FØR observation_date
.drop("rank")
)
```
### Azure ML Feature Retrieval Component
```python
# Deklarativ feature retrieval i Azure ML pipeline
from azure.ai.ml import MLClient
from azure.ai.ml.entities import FeatureRetrievalSpec
# Definer feature retrieval spec
feature_retrieval_spec = FeatureRetrievalSpec(
feature_store_name="my-feature-store",
features=[
{
"feature_set": "transactions:1",
"features": ["txn_7d_count", "txn_7d_sum", "txn_30d_avg"]
},
{
"feature_set": "demographics:1",
"features": ["age_group", "region", "income_band"]
}
]
)
# Feature retrieval støtter automatisk point-in-time joins
# basert på timestamp-kolonne i feature set specification
```
---
## Feature Freshness and Refresh Cadences
### Materialiseringsstrategi
| Feature-type | Oppdateringsfrekvens | Materialiseringsmetode |
|---|---|---|
| **Statiske** (demografi) | Ukentlig / månedlig | Batch materialisering |
| **Langsom endring** (score) | Daglig | Scheduled materialisering |
| **Rask endring** (transaksjoner) | Per time / sanntid | Streaming + backfill |
| **Sanntid** (lokasjon) | Kontinuerlig | Online store (Redis) |
### Materialiserings-oppsett
```python
from azure.ai.ml.entities import (
MaterializationSettings,
MaterializationComputeResource,
RecurrenceTrigger
)
# Konfigurer materialisering for en feature set
materialization = MaterializationSettings(
schedule=RecurrenceTrigger(
interval=1,
frequency="Day",
time_of_day="02:00" # Kjør kl 02:00 UTC
),
resource=MaterializationComputeResource(
instance_type="standard_e4s_v3"
),
spark_configuration={
"spark.driver.cores": 4,
"spark.driver.memory": "36g",
"spark.executor.cores": 4,
"spark.executor.memory": "36g"
}
)
# Backfill for historisk data
from azure.ai.ml import MLClient
fs_client = MLClient(credential, subscription_id, resource_group, feature_store_name)
poller = fs_client.feature_sets.begin_backfill(
name="transactions",
version="1",
feature_window_start_time="2025-01-01T00:00:00Z",
feature_window_end_time="2026-02-11T00:00:00Z",
data_status=["None", "Incomplete"]
)
# Stream jobb-logger
fs_client.jobs.stream(poller.result().job_ids[0])
```
### Online vs. Offline Materialization
| Aspekt | Offline Store (ADLS Gen2) | Online Store (Redis) |
|---|---|---|
| **Bruksområde** | Trening, batch-inferens | Real-time inferens |
| **Latens** | Sekunder-minutter | Millisekunder |
| **Volum** | Ubegrenset | Begrenset av Redis-minne |
| **Kostnad** | Lav (lagring) | Høyere (compute) |
| **Format** | Delta/Parquet | Key-value |
---
## Data Wrangler for Exploratory Feature Engineering
### Data Wrangler i Fabric
Data Wrangler er et notebook-basert verktøy for visuell datautforsking og feature engineering:
```python
# Steg 1: Last data i Notebook
import pandas as pd
df = spark.read.format("delta").table("silver.customer_data").toPandas()
# Steg 2: Start Data Wrangler
# Klikk "Data" > "Launch Data Wrangler" i Notebook-menyen
# Velg DataFrame "df"
# Steg 3: Data Wrangler UI tilbyr:
# - Grid-visning med statistikk per kolonne
# - Innebygde visualiseringer (histogrammer, scatter plots)
# - Over 300 transformasjoner
# - AI-drevne forslag (PROSE)
# - Copilot for naturlig språk → kode
# Steg 4: Eksporter kode tilbake til Notebook
```
### Vanlige feature engineering-operasjoner i Data Wrangler
| Operasjon | Eksempel | Autogenerert kode |
|---|---|---|
| **One-hot encoding** | Kategoriske variabler | `pd.get_dummies(df, columns=[...])` |
| **Binning** | Aldersgrupper | `pd.cut(df['age'], bins=[...])` |
| **Missing values** | Imputering | `df['col'].fillna(df['col'].median())` |
| **Standardisering** | Z-score | `(df['col'] - mean) / std` |
| **Feature crossing** | Kombinasjoner | `df['new'] = df['a'] * df['b']` |
| **Dato-features** | Dag, uke, måned | `df['month'] = df['date'].dt.month` |
### PySpark Feature Engineering Templates
```python
from pyspark.sql import functions as F
from pyspark.ml.feature import VectorAssembler, StandardScaler, StringIndexer
# Kategorisk encoding
indexer = StringIndexer(inputCol="region", outputCol="region_index")
# Numerisk standardisering
assembler = VectorAssembler(
inputCols=["age", "income", "txn_count"],
outputCol="features_raw"
)
scaler = StandardScaler(
inputCol="features_raw",
outputCol="features_scaled",
withStd=True,
withMean=True
)
# Dato-baserte features
df_features = (
df
.withColumn("day_of_week", F.dayofweek("event_date"))
.withColumn("month", F.month("event_date"))
.withColumn("is_weekend", F.when(
F.dayofweek("event_date").isin([1, 7]), 1).otherwise(0))
.withColumn("hour_of_day", F.hour("event_timestamp"))
.withColumn("days_since_registration",
F.datediff(F.current_date(), "registration_date"))
)
```
---
## Feature Monitoring and Drift Detection
### Feature Drift-typer
| Drift-type | Beskrivelse | Deteksjonsmetode |
|---|---|---|
| **Data drift** | Endring i feature-distribusjon | KS-test, PSI |
| **Concept drift** | Endring i forholdet mellom features og target | Modell-ytelse over tid |
| **Schema drift** | Endring i datastruktur | Schema-validering |
| **Freshness drift** | Data er ikke oppdatert | Timestamp-sjekk |
### Monitoring i Azure ML Feature Store
```python
from azure.ai.ml.entities import (
FeatureSetMonitoringSpec,
MonitorSignal
)
# Konfigurer feature-monitoring
monitoring = FeatureSetMonitoringSpec(
signal=MonitorSignal(
feature_data_type_override={
"txn_7d_count": "numerical",
"region": "categorical"
},
metric_thresholds={
"numerical": {
"jensen_shannon_distance": 0.1,
"population_stability_index": 0.2
},
"categorical": {
"jensen_shannon_distance": 0.1
}
}
),
notification_emails=["team@example.no"]
)
```
### Manuell drift-deteksjon i Fabric Notebook
```python
from scipy.stats import ks_2samp
import numpy as np
def detect_feature_drift(reference_df, current_df, features, threshold=0.05):
"""Detekter feature drift mellom referanse- og nåværende data."""
drift_report = {}
for feature in features:
ref_values = reference_df[feature].dropna().values
curr_values = current_df[feature].dropna().values
# Kolmogorov-Smirnov test
stat, p_value = ks_2samp(ref_values, curr_values)
# Population Stability Index (PSI)
psi = calculate_psi(ref_values, curr_values, buckets=10)
drift_report[feature] = {
"ks_statistic": round(stat, 4),
"ks_p_value": round(p_value, 4),
"psi": round(psi, 4),
"drifted": p_value < threshold or psi > 0.2
}
return drift_report
def calculate_psi(reference, current, buckets=10):
"""Beregn Population Stability Index."""
breakpoints = np.linspace(
min(reference.min(), current.min()),
max(reference.max(), current.max()),
buckets + 1
)
ref_counts = np.histogram(reference, breakpoints)[0] / len(reference)
curr_counts = np.histogram(current, breakpoints)[0] / len(current)
# Unngå log(0)
ref_counts = np.clip(ref_counts, 0.001, None)
curr_counts = np.clip(curr_counts, 0.001, None)
psi = np.sum((curr_counts - ref_counts) * np.log(curr_counts / ref_counts))
return psi
```
---
## Referanser
- [What is managed feature store?](https://learn.microsoft.com/en-us/azure/machine-learning/concept-what-is-managed-feature-store) -- Konseptoversikt
- [What is a Feature Store? (AI Playbook)](https://learn.microsoft.com/en-us/ai/playbook/capabilities/model-development/feature-management/) -- Arkitektur og implementasjon
- [Tutorial 1: Develop and register a feature set](https://learn.microsoft.com/en-us/azure/machine-learning/tutorial-get-started-with-feature-store) -- Hands-on tutorial
- [Tutorial 4: Enable online materialization](https://learn.microsoft.com/en-us/azure/machine-learning/tutorial-online-materialization-inference) -- Online feature serving
- [Manage access control for managed feature store](https://learn.microsoft.com/en-us/azure/machine-learning/how-to-setup-access-control-feature-store) -- RBAC og sikkerhet
- [Accelerate data prep with Data Wrangler](https://learn.microsoft.com/en-us/fabric/data-science/data-wrangler) -- Data Wrangler guide
- [Automated ML in Fabric](https://learn.microsoft.com/en-us/fabric/data-science/automated-ml-fabric) -- AutoML med feature engineering
---
## For Cosmo
- **Bruk denne referansen** når brukeren planlegger ML-infrastruktur, trenger feature-gjenbruk på tvers av prosjekter, eller ønsker å operasjonalisere feature engineering.
- Anbefal **Azure ML Managed Feature Store** for organisasjoner med flere ML-team som trenger å dele features. For enkeltprosjekter er **Delta-tabeller i Silver layer** ofte tilstrekkelig.
- **Point-in-time lookups er ikke-forhandlingsbart** for tidsserie-features -- uten dette vil modeller lekke fremtidig informasjon og vise urealistisk god ytelse i testing.
- For norsk offentlig sektor: Feature stores muliggjør **sentral styring** av beregninger som brukes på tvers av etater -- Direktoratet for digital tjenesteutvikling kan dele trafikkfeatures med andre transportetater via feature store-deling.
- Start med **Data Wrangler** for utforskende feature engineering, deretter formaliser i feature set-spesifikasjoner når features er validert og skal til produksjon.