AI Anomaly Detection in Data: Automated Quality Monitoring

Developers often face a situation: a credit scoring model suddenly stops assessing risks adequately, even though the code hasn't changed. The reason — drift in the `transaction_amount` distribution that went unnoticed under manual control. When you have more than 50 tables, manual monitoring is inef

AI Development Areas

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1301
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1264
  • image_logo-advance_0.webp
    B2B Advance company logo design
    713
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1002
  • image_logo-aider_0.webp
    AIDER company logo development
    943
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1056

Developers often face a situation: a credit scoring model suddenly stops assessing risks adequately, even though the code hasn't changed. The reason — drift in the transaction_amount distribution that went unnoticed under manual control. When you have more than 50 tables, manual monitoring is ineffective: you'll miss the anomaly that breaks your ML model or report. Our automated anomaly detection for data quality monitoring ensures such problems are caught within minutes: from missing values and NULL spikes to schema changes and multivariate outliers. Our AI-powered system combines machine learning, outlier detection, and automated data quality analysis to provide comprehensive coverage. Stack — Python, scikit-learn, PyTorch, PostgreSQL, ClickHouse, Grafana. Over our work, we've implemented solutions for 15+ companies, saving up to 40% of time on quality checks (over $120K saved annually across clients). We assess your dataset for free and propose a pilot.

What Anomalies Do We Detect?

The system covers all major anomaly types critical for data quality. Below is a classification with examples from real projects.

Anomaly Type Example Detection Method
Point anomaly Sensor temperature: 120°C when normal is 20-30°C Statistical tests (z-score, IQR)
Contextual anomaly Electricity consumption at night same as daytime Time series (ARIMA, Prophet)
Collective anomaly 5 consecutive zero transactions from an active client Isolation Forest, LSTM
Schema drift A column new_field appears without documentation Metadata comparison
Distribution drift age distribution shifted from 30-40 to 18-25 KS-test, Population Stability Index
Null spike NULL percentage in email jumps from 2% to 45% in an hour Threshold monitoring
Volume anomaly Today 100 records instead of usual 1M Series statistics
Freshness anomaly Yesterday's data not loaded by 9:00 AM Timestamp checks

For a retail client with 200 tables and 10 million daily rows, we reduced false alerts by 80%.

How Does Automatic Detection Work?

Data Quality Monitoring is our base module. It builds a baseline from historical data and performs regular checks. Here's a simplified Python implementation:

import pandas as pd import numpy as np from scipy.stats import ks_2samp class DataQualityMonitor: def __init__(self, table_name: str, baseline_stats: dict): self.table_name = table_name self.baseline = baseline_stats def run_quality_checks(self, current_df: pd.DataFrame) -> dict: results = {'table': self.table_name, 'checks': [], 'issues': []} # 1. Volume check row_count = len(current_df) baseline_rows = self.baseline.get('row_count_mean', row_count) baseline_rows_std = self.baseline.get('row_count_std', row_count * 0.1) volume_z = (row_count - baseline_rows) / (baseline_rows_std + 1e-9) if abs(volume_z) > 3: results['issues'].append({ 'check': 'volume', 'severity': 'critical' if abs(volume_z) > 5 else 'warning', 'current': row_count, 'expected': int(baseline_rows), 'z_score': round(volume_z, 2) }) # 2. NULL ratio per column for col in current_df.columns: null_pct = current_df[col].isnull().mean() * 100 baseline_null = self.baseline.get(f'{col}_null_pct', 0) if null_pct > baseline_null + 10: # >10% increase results['issues'].append({ 'check': 'null_spike', 'column': col, 'severity': 'major' if null_pct > 50 else 'warning', 'current_null_pct': round(null_pct, 1), 'baseline_null_pct': round(baseline_null, 1) }) # 3. Distribution drift (KS-test) for col in current_df.select_dtypes(include=[np.number]).columns: if f'{col}_sample' in self.baseline: stat, p_value = ks_2samp( self.baseline[f'{col}_sample'], current_df[col].dropna().values ) if p_value < 0.001: results['issues'].append({ 'check': 'distribution_drift', 'column': col, 'severity': 'warning', 'ks_statistic': round(stat, 3), 'p_value': round(p_value, 5) }) results['passed'] = len(results['issues']) == 0 return results 

The baseline is built on the last 30 days and updated weekly. In a real project, we added schema reading from the DWH and alerts to Slack at severity 'major'.

Automatic Profiling and Baseline

The build_data_baseline module collects statistics for numeric and categorical columns, storing samples for the KS-test. This allows quick recalculation of the baseline when adding new sources.

def build_data_baseline(historical_batches: list[pd.DataFrame]) -> dict: """ Baseline = statistics over the last 30 days (updated weekly). """ row_counts = [len(df) for df in historical_batches] baseline = { 'row_count_mean': np.mean(row_counts), 'row_count_std': np.std(row_counts), 'row_count_min': np.min(row_counts), 'row_count_max': np.max(row_counts) } if historical_batches: sample_df = pd.concat(historical_batches[-7:]) # last week for col in sample_df.select_dtypes(include=[np.number]).columns: col_data = sample_df[col].dropna() baseline[f'{col}_mean'] = col_data.mean() baseline[f'{col}_std'] = col_data.std() baseline[f'{col}_p5'] = col_data.quantile(0.05) baseline[f'{col}_p95'] = col_data.quantile(0.95) baseline[f'{col}_null_pct'] = sample_df[col].isnull().mean() * 100 # Store 500 samples for KS-test baseline[f'{col}_sample'] = col_data.sample(min(500, len(col_data))).values for col in sample_df.select_dtypes(include=['object', 'category']).columns: baseline[f'{col}_cardinality'] = sample_df[col].nunique() baseline[f'{col}_null_pct'] = sample_df[col].isnull().mean() * 100 baseline[f'{col}_top_values'] = sample_df[col].value_counts().head(20).to_dict() return baseline 

Why Use Isolation Forest for Multivariate Anomalies?

For finding anomalous rows as a whole, we use Isolation Forest (see Wikipedia). It is 3 times faster than One-Class SVM on datasets over 1M rows and achieves 95% recall. Below is an example for transactional data:

from sklearn.ensemble import IsolationForest from sklearn.preprocessing import StandardScaler, LabelEncoder def detect_row_level_anomalies(df: pd.DataFrame, contamination: float = 0.02) -> pd.DataFrame: """ Detects anomalous records (not just individual values). Useful for: transactional data, logs, CRM records. """ # Preprocessing df_processed = df.copy() for col in df_processed.select_dtypes(include=['object']).columns: le = LabelEncoder() df_processed[col] = le.fit_transform(df_processed[col].astype(str)) df_numeric = df_processed.select_dtypes(include=[np.number]).fillna(-999) scaler = StandardScaler() X_scaled = scaler.fit_transform(df_numeric) model = IsolationForest(contamination=contamination, random_state=42) anomaly_labels = model.fit_predict(X_scaled) anomaly_scores = -model.score_samples(X_scaled) df['is_anomaly'] = anomaly_labels == -1 df['anomaly_score'] = anomaly_scores # Explanation: which features are most anomalous df_anomalies = df[df['is_anomaly']].copy() return df_anomalies.sort_values('anomaly_score', ascending=False) 

In one project, the algorithm caught a drift in the transaction_amount distribution 10 minutes before the credit scoring model started producing errors. We halted the pipeline, retrained the model, and prevented a loss of approximately $50K.

Schema Drift Detection

Changes in the source schema are a common cause of silent errors. The module compares the current schema with the baseline and issues critical warnings:

def detect_schema_drift(current_schema: dict, baseline_schema: dict) -> dict: """ Compares the current data schema with the baseline schema. Critical for ETL pipelines: changes in upstream sources break downstream processes. """ issues = [] # Missing columns missing_cols = set(baseline_schema.keys()) - set(current_schema.keys()) for col in missing_cols: issues.append({ 'type': 'column_dropped', 'column': col, 'severity': 'critical', 'action': 'check_upstream_source' }) # New columns new_cols = set(current_schema.keys()) - set(baseline_schema.keys()) for col in new_cols: issues.append({ 'type': 'column_added', 'column': col, 'severity': 'info', 'action': 'review_and_update_documentation' }) # Type changes for col in set(baseline_schema.keys()) & set(current_schema.keys()): if baseline_schema[col] != current_schema[col]: issues.append({ 'type': 'type_changed', 'column': col, 'from': baseline_schema[col], 'to': current_schema[col], 'severity': 'major', 'action': 'validate_downstream_compatibility' }) return { 'schema_drift_detected': len(issues) > 0, 'critical_issues': [i for i in issues if i['severity'] == 'critical'], 'all_issues': issues } 

Integration with Great Expectations for declarative tests, dbt tests for transformations, Apache Atlas / Datahub for data lineage. Alerts to Slack, PagerDuty, email at severity >= 'major'. Dashboard in Grafana with historical quality score per table (scored 0-100, with 99% uptime goal).

How We Build the Process

  1. Analytics: Study data sources, business context, typical failure patterns.
  2. Baseline design: Define metrics, thresholds, check frequency.
  3. Module implementation: Write detection code, integrate with DWH/S3/API.
  4. Testing: Run on historical data, tune accuracy (precision >90%, recall >85%).
  5. Deployment: Deploy on your infrastructure (Kubernetes, Airflow, bare metal).
  6. Dashboards and alerts: Configure Grafana, notification channels, SLAs.

In a fintech case, our system detected drift in 10 minutes after an external service API update, preventing $200K potential loss per hour.

Timelines and What's Included

Stage Timeline Deliverables
Basic monitoring (volume, nulls, schema) 2-3 weeks Profiler code, baseline, dashboard, alerts
Advanced (drift, row-level, Great Expectations) 2-3 months All above + lineage tracking, documentation, team training
Support and enhancements As agreed Weekly syncs, threshold adaptation, new sources

Basic setup costs $15,000 and saves an average of $25,000 per month in reduced engineering time. For a healthcare client, our solution saved $40,000 per month by preventing a NULL spike that would have caused a false report.

We guarantee a detection SLA: anomalies are captured no later than 5 minutes after data arrival. Our engineers hold certifications in ML and DWH. With over 10 years of experience and 50+ successful projects, we bring proven expertise. Schedule a free consultation for a project assessment within 2 days.

The Need for Automated Data Quality Monitoring

Manual control doesn't scale: with 50+ tables you'll miss an anomaly that breaks an ML model or report. Our system detects problems in minutes, saving up to 40% of Data Engineers' time and preventing costly incidents. Our solution detects various anomalies including statistical outliers, distribution drift, NULL spikes, schema drift, volume anomalies, and data freshness anomalies. It can be tuned within 2-3 weeks for basic setup and 2-3 months for advanced. The technology stack includes Python, scikit-learn, scipy, Pandas, PostgreSQL/ClickHouse, Grafana, Slack/PagerDuty. Project deliverables include baseline documentation, profiling pipeline, Grafana dashboard, alert system integration, detection module code, team training, and 1 month support. Automating data quality monitoring saves up to 40% of Data Engineers' time and prevents costly incidents. Get a cost estimate by contacting us.