Slotting Architecture · 5 min read
Operational Guide: Classifying SKUs by Inventory Velocity
Accurate SKU velocity classification serves as the foundational control layer for dynamic slotting, pick path optimization, and replenishment cadence planning. When velocity tiers drift from actual throughput patterns, facilities experience chronic congestion in forward pick zones, inflated travel distances for slow movers, and misaligned safety stock buffers. This guide details a deterministic, code-driven methodology for calculating velocity, assigning taxonomy tiers, and managing production-grade edge cases. The approach aligns directly with the Core Slotting Architecture & Velocity Taxonomies framework, ensuring classification logic remains auditable, version-controlled, and tightly coupled to your WMS slotting engine.
Data Pipeline Configuration & Normalization
Velocity classification degrades rapidly when input datasets contain unfiltered returns, promotional spikes, or inconsistent observation windows. Prior to calculation, standardize your transactional dataset to a rolling window that reflects true operational demand. Configuration parameters should be externalized into a centralized YAML or environment variable store to enable rapid recalibration without code deployments.
velocity_config:
observation_window_days: 90
min_transaction_count: 3
zero_velocity_grace_days: 14
outlier_method: iqr
iqr_multiplier: 1.5
tier_labels: ["A", "B", "C", "D", "Z"]
thresholds:
A: 45.0
B: 18.0
C: 5.0
D: 1.0
Ingest raw pick/issue transactions, strip internal transfers, cycle counts, and quality holds, then aggregate at the SKU_ID level. Normalize all timestamps to UTC and align to your facility’s operational calendar to exclude non-working days. Forward-fill missing data only for active SKUs; discontinued or dormant items must be explicitly flagged and excluded from velocity scoring to prevent artificial tier inflation. Transactional anomalies should be filtered using statistical bounds before aggregation, as outlined in standard NumPy Statistical Functions documentation.
Velocity Calculation & Tier Assignment (Python Implementation)
The following implementation uses pandas and numpy to compute daily velocity, apply robust outlier capping via the Interquartile Range (IQR), and map results to a standardized tier taxonomy. Designed for batch execution in nightly ETL pipelines or streaming via Kafka consumers, the function enforces strict type validation and deterministic tier assignment.
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
def classify_sku_velocity(
transactions_df: pd.DataFrame,
config: dict,
reference_date: datetime = None
) -> pd.DataFrame:
"""
Calculates inventory velocity and assigns taxonomy tiers.
Input DataFrame must contain: ['sku_id', 'transaction_date', 'quantity_picked', 'status']
"""
if reference_date is None:
reference_date = pd.Timestamp.now()
window_start = reference_date - timedelta(days=config['observation_window_days'])
# Filter valid transactions within window
mask = (
(transactions_df['transaction_date'] >= window_start) &
(transactions_df['quantity_picked'] > 0) &
(transactions_df['status'].isin(['COMPLETED', 'SHIPPED']))
)
active_txns = transactions_df.loc[mask, ['sku_id', 'transaction_date', 'quantity_picked']].copy()
# Calculate daily average velocity per SKU
daily_velocity = (
active_txns
.groupby('sku_id')['quantity_picked']
.sum()
.reset_index()
)
daily_velocity['daily_avg'] = daily_velocity['quantity_picked'] / config['observation_window_days']
# IQR Outlier Capping
q1 = daily_velocity['daily_avg'].quantile(0.25)
q3 = daily_velocity['daily_avg'].quantile(0.75)
iqr = q3 - q1
lower_bound = max(0, q1 - (config['iqr_multiplier'] * iqr))
upper_bound = q3 + (config['iqr_multiplier'] * iqr)
daily_velocity['capped_velocity'] = np.clip(daily_velocity['daily_avg'], lower_bound, upper_bound)
# Vectorized Tier Mapping
thresholds = config['thresholds']
conditions = [
daily_velocity['capped_velocity'] >= thresholds['A'],
daily_velocity['capped_velocity'] >= thresholds['B'],
daily_velocity['capped_velocity'] >= thresholds['C'],
daily_velocity['capped_velocity'] >= thresholds['D']
]
choices = ['A', 'B', 'C', 'D']
daily_velocity['velocity_tier'] = np.select(conditions, choices, default='Z')
# Handle zero-velocity grace period & merge back to master SKU list
grace_cutoff = reference_date - timedelta(days=config['zero_velocity_grace_days'])
recent_active = transactions_df[
transactions_df['transaction_date'] >= grace_cutoff
]['sku_id'].unique()
master_skus = pd.DataFrame({'sku_id': transactions_df['sku_id'].unique()})
result = master_skus.merge(
daily_velocity[['sku_id', 'capped_velocity', 'velocity_tier']],
on='sku_id',
how='left'
)
result['velocity_tier'] = result['velocity_tier'].fillna('Z')
result['status_flag'] = np.where(
(result['velocity_tier'] == 'Z') & (~result['sku_id'].isin(recent_active)),
'DORMANT',
'ACTIVE'
)
return result[['sku_id', 'capped_velocity', 'velocity_tier', 'status_flag']]
The script calculates daily average picks, caps extreme promotional spikes using IQR thresholds, and maps continuous velocity values to discrete taxonomy bands. This deterministic mapping is critical for maintaining consistency across the SKU Velocity Taxonomy Design specification. For high-throughput environments, consider leveraging pandas groupby optimizations documented in the official pandas GroupBy Documentation to reduce memory overhead during peak ETL windows.
Production Validation & Slotting Integration
Post-calculation, velocity outputs must undergo validation before pushing to the slotting engine. Implement threshold guards to detect sudden tier migrations (e.g., A to Z in a single cycle) which often indicate data pipeline failures rather than genuine demand shifts. Integrate tier assignments with your location hierarchy mapping to trigger automated slot repositioning rules.
For edge cases like new product introductions (NPIs) or highly seasonal items, apply a fallback routing logic that temporarily assigns provisional tiers based on category-level velocity proxies until sufficient transaction history accumulates. Ensure slotting configuration endpoints enforce strict access boundaries to prevent unauthorized tier overrides, particularly when integrating with third-party inventory optimization modules. Regularly audit tier distributions against physical pick density reports to validate that forward pick zones remain optimized for actual throughput rather than historical artifacts.