SECTION 1: LEARNING OBJECTIVES
By the end of this lesson, you will be able to:
-
Define data profiling and understand its role in assessing financial data quality.
-
Implement comprehensive data profiling for banking datasets using Python.
-
Understand the dimensions of data quality (accuracy, completeness, consistency, timeliness, validity, uniqueness).
-
Build automated data quality checks for financial data.
-
Create data quality dashboards for monitoring and reporting.
-
Document data quality issues and recommendations for remediation.
-
Understand regulatory requirements for data quality in banking.
-
Implement data quality monitoring for ongoing compliance.
SECTION 2: INTRODUCTION TO DATA PROFILING
2.1 What Is Data Profiling?
Data profiling is the process of examining data to understand its structure, content, relationships, and quality. In banking, data profiling answers critical questions:
| Question | Banking Example |
|---|---|
| What data exists? | What customer attributes do we have? |
| Where is the data? | Which systems store customer data? |
| What is the data quality? | Are credit scores complete and valid? |
| What are the relationships? | How are customers linked to accounts? |
| What are the patterns? | What is the typical transaction amount? |
2.2 Data Profiling vs. EDA
| Aspect | Data Profiling | Exploratory Data Analysis |
|---|---|---|
| Purpose | Assess data quality and structure | Discover patterns and insights |
| Focus | Metadata, completeness, validity | Relationships, trends, distributions |
| Output | Quality report, data dictionary | Visualizations, insights, hypotheses |
| Audience | Data engineers, compliance | Data scientists, business analysts |
| Frequency | Regular monitoring | Project-specific |
SECTION 3: IMPLEMENTING DATA PROFILING
3.1 Building a Data Profiler Class
# ============= COMPREHENSIVE DATA PROFILER ============= import pandas as pd import numpy as np from datetime import datetime import matplotlib.pyplot as plt import seaborn as sns class FinancialDataProfiler: """ Comprehensive data profiler for financial datasets. """ def __init__(self, data, dataset_name="Dataset"): """ Initialize profiler with data. Parameters: ----------- data : DataFrame Data to profile dataset_name : str Name of the dataset """ self.data = data self.dataset_name = dataset_name self.profile = {} self.quality_issues = [] def profile_basic(self): """Generate basic dataset profile.""" self.profile['basic'] = { 'rows': len(self.data), 'columns': len(self.data.columns), 'memory_usage_mb': self.data.memory_usage(deep=True).sum() / 1024**2, 'column_names': list(self.data.columns), 'dtypes': self.data.dtypes.to_dict() } return self.profile['basic'] def profile_numeric(self): """Profile numeric columns.""" numeric_cols = self.data.select_dtypes(include=[np.number]).columns numeric_profile = {} for col in numeric_cols: col_data = self.data[col].dropna() if len(col_data) > 0: numeric_profile[col] = { 'count': len(col_data), 'missing': len(self.data[col]) - len(col_data), 'mean': col_data.mean(), 'median': col_data.median(), 'std': col_data.std(), 'min': col_data.min(), 'max': col_data.max(), 'q1': col_data.quantile(0.25), 'q3': col_data.quantile(0.75), 'skewness': col_data.skew(), 'kurtosis': col_data.kurtosis(), 'unique_count': self.data[col].nunique() } self.profile['numeric'] = numeric_profile return numeric_profile def profile_categorical(self): """Profile categorical columns.""" categorical_cols = self.data.select_dtypes(include=['object', 'category']).columns categorical_profile = {} for col in categorical_cols: col_data = self.data[col].dropna() value_counts = self.data[col].value_counts() categorical_profile[col] = { 'count': len(col_data), 'missing': len(self.data[col]) - len(col_data), 'unique_values': self.data[col].nunique(), 'top_values': value_counts.head(5).to_dict(), 'top_value': value_counts.index[0] if len(value_counts) > 0 else None, 'top_value_pct': value_counts.iloc[0] / len(col_data) if len(col_data) > 0 else 0 } self.profile['categorical'] = categorical_profile return categorical_profile def profile_datetime(self): """Profile datetime columns.""" datetime_cols = self.data.select_dtypes(include=['datetime64']).columns datetime_profile = {} for col in datetime_cols: col_data = self.data[col].dropna() if len(col_data) > 0: datetime_profile[col] = { 'count': len(col_data), 'missing': len(self.data[col]) - len(col_data), 'min': col_data.min(), 'max': col_data.max(), 'unique_dates': col_data.nunique(), 'date_range_days': (col_data.max() - col_data.min()).days } self.profile['datetime'] = datetime_profile return datetime_profile def profile_missing(self): """Profile missing values.""" missing_counts = self.data.isnull().sum() missing_pcts = (missing_counts / len(self.data) * 100).round(2) missing_profile = {} for col in self.data.columns: if missing_counts[col] > 0: missing_profile[col] = { 'count': missing_counts[col], 'percentage': missing_pcts[col] } self.profile['missing'] = missing_profile return missing_profile def profile_duplicates(self): """Profile duplicate records.""" duplicate_counts = {} for col in self.data.columns: duplicates = self.data[col].duplicated().sum() if duplicates > 0: duplicate_counts[col] = { 'count': duplicates, 'percentage': duplicates / len(self.data) * 100 } # Check for duplicate rows duplicate_rows = self.data.duplicated().sum() if duplicate_rows > 0: duplicate_counts['row_duplicates'] = { 'count': duplicate_rows, 'percentage': duplicate_rows / len(self.data) * 100 } self.profile['duplicates'] = duplicate_counts return duplicate_counts def run_full_profile(self): """Run all profiling steps.""" print(f"Running full profile for: {self.dataset_name}") print("-" * 40) self.profile_basic() print("✓ Basic profiling complete") self.profile_numeric() print("✓ Numeric profiling complete") self.profile_categorical() print("✓ Categorical profiling complete") self.profile_datetime() print("✓ Datetime profiling complete") self.profile_missing() print("✓ Missing value profiling complete") self.profile_duplicates() print("✓ Duplicate profiling complete") return self.profile def generate_report(self): """Generate comprehensive profiling report.""" print("\n" + "="*80) print(f"DATA PROFILING REPORT: {self.dataset_name}") print("="*80) # Basic Information basic = self.profile.get('basic', {}) print(f"\n📊 BASIC INFORMATION:") print(f" Rows: {basic.get('rows', 0):,}") print(f" Columns: {basic.get('columns', 0)}") print(f" Memory Usage: {basic.get('memory_usage_mb', 0):.2f} MB") print(f" Column Names: {basic.get('column_names', [])}") # Missing Values missing = self.profile.get('missing', {}) if missing: print(f"\n⚠️ MISSING VALUES:") for col, info in missing.items(): print(f" {col}: {info['count']} missing ({info['percentage']}%)") else: print("\n✅ No missing values found") # Duplicates duplicates = self.profile.get('duplicates', {}) if duplicates: print(f"\n📋 DUPLICATES:") for col, info in duplicates.items(): print(f" {col}: {info['count']} duplicates ({info['percentage']:.1f}%)") else: print("\n✅ No duplicates found") # Numeric Summary numeric = self.profile.get('numeric', {}) if numeric: print(f"\n📈 NUMERIC SUMMARY:") for col, stats in list(numeric.items())[:5]: print(f"\n {col}:") print(f" Count: {stats['count']}") print(f" Missing: {stats['missing']}") print(f" Mean: {stats['mean']:.2f}") print(f" Median: {stats['median']:.2f}") print(f" Std: {stats['std']:.2f}") print(f" Range: [{stats['min']:.2f}, {stats['max']:.2f}]") print(f" Skewness: {stats['skewness']:.3f}") # Categorical Summary categorical = self.profile.get('categorical', {}) if categorical: print(f"\n📋 CATEGORICAL SUMMARY:") for col, stats in categorical.items(): print(f"\n {col}:") print(f" Unique values: {stats['unique_values']}") print(f" Top value: {stats['top_value']} ({stats['top_value_pct']:.1f}%)") top_values = stats['top_values'] for val, count in top_values.items(): print(f" {val}: {count}") return self.profile def identify_quality_issues(self): """Identify data quality issues based on profiling.""" issues = [] # Check for high missing values (>20%) for col, info in self.profile.get('missing', {}).items(): if info['percentage'] > 20: issues.append({ 'severity': 'High', 'type': 'Missing Values', 'column': col, 'details': f"{info['percentage']:.1f}% missing" }) elif info['percentage'] > 5: issues.append({ 'severity': 'Medium', 'type': 'Missing Values', 'column': col, 'details': f"{info['percentage']:.1f}% missing" }) # Check for high duplicates for col, info in self.profile.get('duplicates', {}).items(): if info['percentage'] > 10: issues.append({ 'severity': 'High', 'type': 'Duplicate Values', 'column': col, 'details': f"{info['percentage']:.1f}% duplicates" }) # Check for skewness (indicating potential outliers) for col, stats in self.profile.get('numeric', {}).items(): if abs(stats.get('skewness', 0)) > 2: issues.append({ 'severity': 'Medium', 'type': 'High Skewness', 'column': col, 'details': f"Skewness: {stats['skewness']:.3f}" }) self.quality_issues = issues return issues def generate_quality_report(self): """Generate data quality report.""" issues = self.identify_quality_issues() print("\n" + "="*80) print("DATA QUALITY REPORT") print("="*80) if not issues: print("\n✅ No data quality issues identified!") return print(f"\n⚠️ {len(issues)} Data Quality Issues Identified:\n") for i, issue in enumerate(issues, 1): severity = issue['severity'] severity_emoji = "🔴" if severity == "High" else "🟡" if severity == "Medium" else "🟢" print(f"{i}. {severity_emoji} {issue['severity']} - {issue['type']}") print(f" Column: {issue['column']}") print(f" Details: {issue['details']}") print() # Recommendations print("\n💡 RECOMMENDATIONS:") for issue in issues: if issue['type'] == 'Missing Values': if 'address' in issue['column'].lower(): print(f" • Consider using address validation services for {issue['column']}") elif 'credit_score' in issue['column'].lower(): print(f" • Consider imputing missing credit scores using bureau data") else: print(f" • Consider imputation strategies for {issue['column']}") elif issue['type'] == 'High Skewness': print(f" • Consider log transformation for {issue['column']}") elif issue['type'] == 'Duplicate Values': print(f" • Consider deduplication strategies for {issue['column']}") # Create a profiler instance profiler = FinancialDataProfiler(customers, "Customer Data") # Run full profile profiler.run_full_profile() # Generate reports profiler.generate_report() profiler.generate_quality_report()
3.2 Advanced Data Quality Checks
# ============= ADVANCED DATA QUALITY CHECKS ============= class DataQualityChecker: """ Advanced data quality checks for financial data. """ def __init__(self, data): self.data = data self.checks = [] self.results = [] def check_completeness(self, column, threshold=0.95): """Check if column has sufficient completeness.""" missing_pct = self.data[column].isnull().mean() passed = missing_pct <= (1 - threshold) self.results.append({ 'check': 'completeness', 'column': column, 'passed': passed, 'value': f"{missing_pct:.1%} missing", 'threshold': f"{threshold:.0%} complete" }) return passed def check_validity(self, column, valid_values): """Check if all values are in valid set.""" invalid_pct = (~self.data[column].isin(valid_values)).mean() passed = invalid_pct == 0 self.results.append({ 'check': 'validity', 'column': column, 'passed': passed, 'value': f"{invalid_pct:.1%} invalid", 'threshold': "0% invalid" }) return passed def check_numeric_range(self, column, min_val, max_val): """Check if values are within valid range.""" outside_range = ((self.data[column] < min_val) | (self.data[column] > max_val)).mean() passed = outside_range == 0 self.results.append({ 'check': 'range', 'column': column, 'passed': passed, 'value': f"{outside_range:.1%} outside range", 'threshold': f"Range [{min_val}, {max_val}]" }) return passed def check_consistency(self, col1, col2, relationship): """ Check consistency between two columns. relationship: 'equals', 'greater', 'less' """ if relationship == 'equals': inconsistent = (self.data[col1] != self.data[col2]).mean() elif relationship == 'greater': inconsistent = (self.data[col1] <= self.data[col2]).mean() elif relationship == 'less': inconsistent = (self.data[col1] >= self.data[col2]).mean() else: inconsistent = 1 passed = inconsistent == 0 self.results.append({ 'check': 'consistency', 'columns': f"{col1}, {col2}", 'passed': passed, 'value': f"{inconsistent:.1%} inconsistent", 'threshold': f"{relationship} relationship" }) return passed def check_uniqueness(self, column): """Check if column values are unique.""" duplicate_pct = (self.data[column].duplicated()).mean() passed = duplicate_pct < 0.01 # Less than 1% duplicates self.results.append({ 'check': 'uniqueness', 'column': column, 'passed': passed, 'value': f"{duplicate_pct:.1%} duplicates", 'threshold': "< 1% duplicates" }) return passed def check_timeliness(self, date_column, max_age_days=1): """Check if data is timely (not too old).""" if pd.api.types.is_datetime64_any_dtype(self.data[date_column]): max_date = self.data[date_column].max() age_days = (pd.Timestamp.now() - max_date).days passed = age_days <= max_age_days self.results.append({ 'check': 'timeliness', 'column': date_column, 'passed': passed, 'value': f"{age_days} days old", 'threshold': f"≤ {max_age_days} days old" }) return passed else: self.results.append({ 'check': 'timeliness', 'column': date_column, 'passed': False, 'value': 'Not datetime', 'threshold': 'Date type required' }) return False def run_all_checks(self): """Run all quality checks.""" print("\n" + "="*60) print("DATA QUALITY CHECKS") print("="*60) # Completeness checks for col in ['credit_score', 'annual_income']: if col in self.data.columns: self.check_completeness(col, threshold=0.90) # Validity checks if 'state' in self.data.columns: valid_states = ['CA', 'NY', 'TX', 'FL', 'IL', 'PA', 'OH', 'GA', 'NC', 'MI'] self.check_validity('state', valid_states) # Range checks if 'credit_score' in self.data.columns: self.check_numeric_range('credit_score', 300, 850) if 'age' in self.data.columns: self.check_numeric_range('age', 18, 100) # Uniqueness checks if 'customer_id' in self.data.columns: self.check_uniqueness('customer_id') # Generate report self.generate_quality_report() return self.results def generate_quality_report(self): """Generate comprehensive quality report.""" print("\n" + "="*60) print("QUALITY CHECK RESULTS") print("="*60) passed = sum(1 for r in self.results if r['passed']) total = len(self.results) print(f"\n📊 Summary: {passed}/{total} checks passed") for result in self.results: status = "✅ PASS" if result['passed'] else "❌ FAIL" print(f"\n{status} - {result['check'].upper()}") print(f" Column(s): {result.get('column', result.get('columns', 'N/A'))}") print(f" Value: {result['value']}") print(f" Threshold: {result['threshold']}") # Run quality checks quality_checker = DataQualityChecker(customers) quality_checker.run_all_checks()
SECTION 4: DATA QUALITY DASHBOARD
4.1 Building a Quality Dashboard
# ============= DATA QUALITY DASHBOARD ============= class DataQualityDashboard: """ Create a data quality dashboard for monitoring. """ def __init__(self, data, dataset_name): self.data = data self.dataset_name = dataset_name self.metrics = {} def calculate_metrics(self): """Calculate quality metrics.""" # Completeness completeness = 1 - (self.data.isnull().sum() / len(self.data)) self.metrics['completeness'] = completeness.to_dict() # Uniqueness self.metrics['duplicate_rate'] = self.data.duplicated().mean() # Numeric metrics numeric_cols = self.data.select_dtypes(include=[np.number]).columns for col in numeric_cols: if col in self.data.columns: col_data = self.data[col].dropna() if len(col_data) > 0: self.metrics[f'mean_{col}'] = col_data.mean() self.metrics[f'std_{col}'] = col_data.std() self.metrics[f'skew_{col}'] = col_data.skew() # Categorical metrics cat_cols = self.data.select_dtypes(include=['object']).columns for col in cat_cols: if col in self.data.columns: self.metrics[f'unique_{col}'] = self.data[col].nunique() top_val = self.data[col].value_counts().index[0] top_pct = self.data[col].value_counts().iloc[0] / len(self.data) self.metrics[f'top_{col}'] = top_val self.metrics[f'top_pct_{col}'] = top_pct def create_dashboard(self): """Create visual dashboard.""" self.calculate_metrics() fig, axes = plt.subplots(2, 2, figsize=(14, 10)) # 1. Completeness Heatmap completeness_df = pd.DataFrame({ 'Column': list(self.metrics['completeness'].keys()), 'Completeness': list(self.metrics['completeness'].values()) }) completeness_df['Completeness'] = completeness_df['Completeness'] * 100 colors = ['#2ecc71' if x > 95 else '#f1c40f' if x > 80 else '#e74c3c' for x in completeness_df['Completeness']] completeness_df.plot(kind='barh', x='Column', y='Completeness', ax=axes[0, 0], color=colors, legend=False) axes[0, 0].set_title('Data Completeness by Column', fontsize=12) axes[0, 0].set_xlabel('Completeness (%)') axes[0, 0].axvline(95, color='green', linestyle='--', alpha=0.5, label='95% target') axes[0, 0].axvline(80, color='red', linestyle='--', alpha=0.5, label='80% minimum') axes[0, 0].legend() # 2. Column Quality Summary quality_scores = [] for col in self.data.columns: missing_pct = self.data[col].isnull().mean() unique_pct = self.data[col].nunique() / len(self.data) score = (1 - missing_pct) * 0.7 + min(unique_pct * 10, 1) * 0.3 quality_scores.append({ 'column': col, 'score': score * 100 }) quality_df = pd.DataFrame(quality_scores) quality_df = quality_df.sort_values('score') colors = ['#2ecc71' if x > 80 else '#f1c40f' if x > 60 else '#e74c3c' for x in quality_df['score']] quality_df.plot(kind='barh', x='column', y='score', ax=axes[0, 1], color=colors, legend=False) axes[0, 1].set_title('Data Quality Score by Column', fontsize=12) axes[0, 1].set_xlabel('Quality Score (%)') axes[0, 1].axvline(80, color='green', linestyle='--', alpha=0.5, label='Good') axes[0, 1].axvline(60, color='red', linestyle='--', alpha=0.5, label='Poor') axes[0, 1].legend() # 3. Missing Values Overview missing_counts = self.data.isnull().sum() missing_counts = missing_counts[missing_counts > 0] if len(missing_counts) > 0: missing_counts.plot(kind='bar', ax=axes[1, 0], color='#e74c3c') axes[1, 0].set_title('Missing Values by Column', fontsize=12) axes[1, 0].set_xlabel('Column') axes[1, 0].set_ylabel('Missing Count') axes[1, 0].tick_params(axis='x', rotation=45) else: axes[1, 0].text(0.5, 0.5, '✅ No Missing Values', ha='center', va='center', fontsize=14) axes[1, 0].set_title('Missing Values', fontsize=12) axes[1, 0].axis('off') # 4. Data Type Distribution dtype_counts = self.data.dtypes.value_counts() dtype_counts.plot(kind='pie', ax=axes[1, 1], autopct='%1.1f%%', startangle=90) axes[1, 1].set_title('Data Type Distribution', fontsize=12) axes[1, 1].set_ylabel('') plt.tight_layout() plt.savefig(f'{self.dataset_name}_quality_dashboard.png', dpi=300) plt.show() return self.metrics def generate_summary(self): """Generate quality summary.""" self.calculate_metrics() print("\n" + "="*60) print(f"QUALITY SUMMARY: {self.dataset_name}") print("="*60) # Completeness avg_completeness = sum(self.metrics['completeness'].values()) / len(self.metrics['completeness']) print(f"\n📊 Completeness:") print(f" Average: {avg_completeness:.1%}") print(f" Columns with >95%: {sum(1 for v in self.metrics['completeness'].values() if v > 0.95)}") print(f" Columns with <80%: {sum(1 for v in self.metrics['completeness'].values() if v < 0.80)}") # Duplicates print(f"\n📋 Duplicates:") print(f" Duplicate rate: {self.metrics['duplicate_rate']:.1%}") # Categorical summary cat_cols = self.data.select_dtypes(include=['object']).columns if len(cat_cols) > 0: print(f"\n📋 Categorical Summary:") for col in cat_cols: unique = self.metrics.get(f'unique_{col}', 0) top = self.metrics.get(f'top_{col}', 'N/A') top_pct = self.metrics.get(f'top_pct_{col}', 0) print(f" {col}: {unique} unique values, top '{top}' ({top_pct:.1%})") # Create dashboard dashboard = DataQualityDashboard(customers, "Customer_Data") dashboard.create_dashboard() dashboard.generate_summary()
SECTION 5: REGULATORY COMPLIANCE & DATA QUALITY
5.1 Regulatory Requirements for Data Quality
# ============= REGULATORY COMPLIANCE CHECK ============= def check_regulatory_compliance(profiler): """ Check if data meets regulatory requirements. """ print("\n" + "="*80) print("REGULATORY COMPLIANCE CHECK") print("="*80) requirements = { 'Completeness': { 'threshold': 0.95, 'description': '95% completeness required for regulatory reporting' }, 'Uniqueness': { 'threshold': 0.99, 'description': '99% uniqueness for customer identifiers' }, 'Validity': { 'threshold': 1.0, 'description': '100% validity for regulatory fields' }, 'Timeliness': { 'threshold': 1, 'description': 'Data must be current (within 1 day)' } } compliance_status = [] # Check each requirement for req, details in requirements.items(): status = "✅ PASS" # Placeholder note = "" if req == 'Completeness': missing_pcts = [info['percentage'] for info in profiler.profile.get('missing', {}).values()] if missing_pcts: avg_missing = sum(missing_pcts) / len(missing_pcts) if avg_missing / 100 <= details['threshold']: status = "✅ PASS" note = f"Average completeness: {(1 - avg_missing/100):.1%}" else: status = "❌ FAIL" note = f"Average completeness: {(1 - avg_missing/100):.1%} (below {details['threshold']:.0%})" else: status = "✅ PASS" note = "100% complete" elif req == 'Uniqueness': duplicates = profiler.profile.get('duplicates', {}) if duplicates: max_dup_pct = max(info['percentage'] for info in duplicates.values()) if 1 - max_dup_pct/100 >= details['threshold']: status = "✅ PASS" note = f"Uniqueness: {(1 - max_dup_pct/100):.1%}" else: status = "❌ FAIL" note = f"Uniqueness: {(1 - max_dup_pct/100):.1%} (below {details['threshold']:.0%})" else: status = "✅ PASS" note = "100% unique" compliance_status.append({ 'requirement': req, 'status': status, 'description': details['description'], 'note': note }) # Display compliance report print("\n" + "="*80) print("COMPLIANCE REPORT") print("="*80) for item in compliance_status: print(f"\n📋 {item['requirement']}") print(f" Status: {item['status']}") print(f" Description: {item['description']}") print(f" Note: {item['note']}") # Overall compliance all_passed = all(item['status'] == "✅ PASS" for item in compliance_status) print("\n" + "-"*40) if all_passed: print("✅ OVERALL: All regulatory requirements met!") else: print("❌ OVERALL: Some regulatory requirements not met. Please address issues.") print(" Recommend reviewing data quality before regulatory submission.") return compliance_status # Run compliance check compliance_results = check_regulatory_compliance(profiler)
SECTION 6: BUSINESS RISK & FINANCIAL IMPACT
6.1 Cost of Poor Data Quality
# ============= DATA QUALITY BUSINESS IMPACT ============= def calculate_impact_of_data_quality(profiler): """ Calculate the potential business impact of data quality issues. """ print("\n" + "="*80) print("BUSINESS IMPACT OF DATA QUALITY") print("="*80) issues = profiler.identify_quality_issues() if not issues: print("\n✅ No quality issues found. Data is ready for use.") return impacts = { 'Missing Values': { 'risk': 'High', 'impact': 'Regulatory fines, incorrect decisions', 'estimated_cost': '$50M - $200M' }, 'Duplicate Values': { 'risk': 'Medium', 'impact': 'Operational inefficiency, customer confusion', 'estimated_cost': '$10M - $50M' }, 'High Skewness': { 'risk': 'Medium', 'impact': 'Model accuracy issues, risk misassessment', 'estimated_cost': '$25M - $100M' }, 'Invalid Values': { 'risk': 'High', 'impact': 'Regulatory non-compliance, operational errors', 'estimated_cost': '$100M - $500M' } } print("\n⚠️ Data Quality Risks Identified:") for issue in issues: impact_info = impacts.get(issue['type'], { 'risk': 'Unknown', 'impact': 'Unknown', 'estimated_cost': 'Unknown' }) print(f"\n🔴 Issue: {issue['type']}") print(f" Column: {issue['column']}") print(f" Risk Level: {impact_info['risk']}") print(f" Business Impact: {impact_info['impact']}") print(f" Estimated Cost: {impact_info['estimated_cost']}") print(f" Details: {issue['details']}") print("\n" + "-"*40) print("💡 Recommendations:") print(" 1. Prioritize fixing High-risk issues first") print(" 2. Implement automated data quality monitoring") print(" 3. Establish data quality SLAs (Service Level Agreements)") print(" 4. Create data quality remediation plan") print(" 5. Train teams on data quality best practices") # Calculate impact calculate_impact_of_data_quality(profiler)
SECTION 7: SUMMARY FOR THE DATA PRACTITIONER
7.1 The 1-Minute Elevator Pitch
“Data profiling is the systematic assessment of data quality in banking datasets. We analyze completeness, validity, uniqueness, consistency, and timeliness of data. A comprehensive profiler identifies missing values, duplicates, outliers, and patterns. Data quality dashboards provide ongoing monitoring for compliance. In banking, data profiling is essential for regulatory compliance, risk management, and building trust in analytics. Poor data quality can cost banks millions in fines and lost revenue.”
7.2 Key Takeaways
-
Data profiling assesses data structure, content, and quality.
-
Completeness measures how much data is present.
-
Validity checks if data conforms to expected formats and ranges.
-
Uniqueness identifies duplicate records.
-
Consistency checks relationships between columns.
-
Timeliness ensures data is up-to-date.
-
Automated quality checks enable ongoing monitoring.
-
Quality dashboards visualize data quality for stakeholders.
-
Regulatory compliance requires documented data quality.
-
Poor data quality has significant financial impact.
7.3 Recommended Next Steps
-
Implement data profiling for your banking datasets
-
Set up automated quality monitoring
-
Document data quality issues and remediation plans
-
Create quality dashboards for stakeholders
-
Establish data quality SLAs
[END OF LESSON 2]