| | """ |
| | Data Integrity Suite - Deepchecks validation for dataset integrity |
| | |
| | This module implements comprehensive data integrity checks using Deepchecks |
| | to validate the quality and consistency of the training and test datasets. |
| | |
| | Checks included: |
| | - Data duplicates detection |
| | - Missing values analysis |
| | - Feature-label correlation |
| | - Feature-feature correlation |
| | - Data type consistency |
| | - Outlier detection |
| | - Class imbalance analysis |
| | """ |
| |
|
| | import numpy as np |
| | import pandas as pd |
| | import json |
| | from pathlib import Path |
| | from deepchecks.tabular import Dataset |
| | from deepchecks.tabular.suites import data_integrity |
| |
|
| | from hopcroft_skill_classification_tool_competition.config import PROCESSED_DATA_DIR |
| |
|
| |
|
| | def load_data(use_cleaned=True): |
| | """ |
| | Load training and test datasets from processed data directory. |
| | |
| | Args: |
| | use_cleaned: If True, load cleaned data (with '_clean' suffix) - DEFAULT |
| | |
| | Returns: |
| | tuple: (X_train, y_train, X_test, y_test) |
| | """ |
| | tfidf_dir = PROCESSED_DATA_DIR / "tfidf" |
| | |
| | |
| | if use_cleaned: |
| | train_features = tfidf_dir / "features_tfidf_clean.npy" |
| | train_labels = tfidf_dir / "labels_tfidf_clean.npy" |
| | test_features = tfidf_dir / "X_test_clean.npy" |
| | test_labels = tfidf_dir / "Y_test_clean.npy" |
| | data_type = "cleaned" |
| | else: |
| | train_features = tfidf_dir / "features_tfidf.npy" |
| | train_labels = tfidf_dir / "labels_tfidf.npy" |
| | test_features = tfidf_dir / "X_test.npy" |
| | test_labels = tfidf_dir / "Y_test.npy" |
| | data_type = "original" |
| | |
| | |
| | X_train = np.load(train_features) |
| | y_train = np.load(train_labels) |
| | X_test = np.load(test_features) |
| | y_test = np.load(test_labels) |
| | |
| | print(f"Loaded {data_type} data:") |
| | print(f"Training set shape: X={X_train.shape}, y={y_train.shape}") |
| | print(f"Test set shape: X={X_test.shape}, y={y_test.shape}") |
| | |
| | return X_train, y_train, X_test, y_test |
| |
|
| |
|
| | def create_deepchecks_dataset(X, y, dataset_name="dataset"): |
| | """ |
| | Create a Deepchecks Dataset object from numpy arrays. |
| | |
| | Args: |
| | X: Feature matrix (numpy array) |
| | y: Labels (numpy array) - can be multi-label (2D) or single-label (1D) |
| | dataset_name: Name identifier for the dataset |
| | |
| | Returns: |
| | Dataset: Deepchecks Dataset object |
| | """ |
| | |
| | |
| | feature_names = [f"feature_{i}" for i in range(X.shape[1])] |
| | |
| | |
| | df = pd.DataFrame(X, columns=feature_names) |
| | |
| | |
| | if len(y.shape) > 1 and y.shape[1] > 1: |
| | |
| | |
| | y_single = np.argmax(y, axis=1) |
| | df['label'] = y_single |
| | print(f"Note: Converted multi-label ({y.shape[1]} labels) to single-label for Deepchecks") |
| | else: |
| | df['label'] = y |
| | |
| | |
| | ds = Dataset(df, label='label', cat_features=[]) |
| | |
| | return ds |
| |
|
| |
|
| | def run_data_integrity_suite(save_output=True, use_cleaned=True): |
| | """ |
| | Run the complete Data Integrity Suite on training data. |
| | |
| | This suite performs comprehensive checks including: |
| | - Data Duplicates: Identifies duplicate samples |
| | - String Mismatch: Checks for string inconsistencies |
| | - Mixed Nulls: Detects various null representations |
| | - Mixed Data Types: Validates consistent data types |
| | - String Length Out Of Bounds: Checks string length anomalies |
| | - Is Single Value: Identifies features with only one value |
| | - Special Characters: Detects special characters in data |
| | - Class Imbalance: Analyzes label distribution |
| | - Outlier Sample Detection: Identifies outlier samples |
| | - Feature Label Correlation: Checks correlation between features and labels |
| | |
| | Args: |
| | save_output: Whether to save the HTML report |
| | use_cleaned: If True, use cleaned data instead of original |
| | |
| | Returns: |
| | SuiteResult: Results from the data integrity suite |
| | """ |
| | data_type = "CLEANED" if use_cleaned else "ORIGINAL" |
| | print("="*80) |
| | print(f"DATA INTEGRITY SUITE - {data_type} TRAINING DATA") |
| | print("="*80) |
| | |
| | |
| | X_train, y_train, _, _ = load_data(use_cleaned=use_cleaned) |
| | |
| | |
| | train_dataset = create_deepchecks_dataset(X_train, y_train, "training") |
| | |
| | |
| | print("\nRunning Data Integrity checks...") |
| | suite = data_integrity() |
| | result = suite.run(train_dataset) |
| | |
| | |
| | print("\nData Integrity Suite completed!") |
| | print(f"Total checks: {len(result.results)}") |
| | |
| | |
| | if save_output: |
| | output_dir = Path("reports/deepchecks") |
| | output_dir.mkdir(parents=True, exist_ok=True) |
| | |
| | |
| | suffix = "_clean" if use_cleaned else "_original" |
| | json_path = output_dir / f"data_integrity_suite_results{suffix}.json" |
| | json_results = { |
| | "suite_name": "Data Integrity Suite", |
| | "total_checks": len(result.results), |
| | "timestamp": pd.Timestamp.now().isoformat(), |
| | "checks": [] |
| | } |
| | |
| | for check_result in result.results: |
| | check_data = { |
| | "check_name": check_result.get_header(), |
| | "passed": check_result.passed_conditions() if hasattr(check_result, 'passed_conditions') else None, |
| | "display": str(check_result.display) if hasattr(check_result, 'display') else None |
| | } |
| | json_results["checks"].append(check_data) |
| | |
| | with open(json_path, 'w', encoding='utf-8') as f: |
| | json.dump(json_results, f, indent=2, ensure_ascii=False) |
| | print(f"JSON results saved to: {json_path}") |
| | |
| | return result |
| |
|
| |
|
| | def run_custom_integrity_checks(save_output=True, use_cleaned=True): |
| | """ |
| | Run custom integrity checks tailored for the SkillScope dataset. |
| | |
| | These checks are specifically designed for NLP/Text features and |
| | multi-label classification tasks. |
| | |
| | Args: |
| | save_output: Whether to save the HTML report |
| | use_cleaned: If True, use cleaned data instead of original |
| | |
| | Returns: |
| | dict: Dictionary containing check results |
| | """ |
| | from deepchecks.tabular.checks import ( |
| | DataDuplicates, |
| | MixedNulls, |
| | IsSingleValue, |
| | ClassImbalance, |
| | OutlierSampleDetection, |
| | FeatureLabelCorrelation, |
| | ) |
| | |
| | data_type = "CLEANED" if use_cleaned else "ORIGINAL" |
| | print("="*80) |
| | print(f"CUSTOM DATA INTEGRITY CHECKS - {data_type} DATA") |
| | print("="*80) |
| | |
| | |
| | X_train, y_train, _, _ = load_data(use_cleaned=use_cleaned) |
| | train_dataset = create_deepchecks_dataset(X_train, y_train, "training") |
| | |
| | results = {} |
| | |
| | |
| | print("\n1. Checking for duplicate samples...") |
| | duplicates_check = DataDuplicates() |
| | results['duplicates'] = duplicates_check.run(train_dataset) |
| | |
| | |
| | print("2. Checking for mixed null values...") |
| | nulls_check = MixedNulls() |
| | results['nulls'] = nulls_check.run(train_dataset) |
| | |
| | |
| | print("3. Checking for single-value features...") |
| | single_value_check = IsSingleValue() |
| | results['single_value'] = single_value_check.run(train_dataset) |
| | |
| | |
| | print("4. Checking class distribution...") |
| | imbalance_check = ClassImbalance() |
| | results['class_imbalance'] = imbalance_check.run(train_dataset) |
| | |
| | |
| | print("5. Detecting outlier samples (this may take a while)...") |
| | try: |
| | outlier_check = OutlierSampleDetection(timeout=300) |
| | results['outliers'] = outlier_check.run(train_dataset) |
| | except Exception as e: |
| | print(f" Warning: Outlier detection failed or timed out: {str(e)}") |
| | results['outliers'] = None |
| | |
| | |
| | print("6. Analyzing feature-label correlation (using sample of features)...") |
| | try: |
| | |
| | correlation_check = FeatureLabelCorrelation(n_top_columns=100, timeout=300) |
| | results['correlation'] = correlation_check.run(train_dataset) |
| | except Exception as e: |
| | print(f" Warning: Correlation check failed or timed out: {str(e)}") |
| | results['correlation'] = None |
| | |
| | print("\nAll custom checks completed!") |
| | |
| | |
| | |
| | return results |
| |
|
| |
|
| | def analyze_data_statistics(use_cleaned=True): |
| | """ |
| | Print detailed statistics about the dataset. |
| | |
| | Args: |
| | use_cleaned: If True, analyze cleaned data instead of original |
| | """ |
| | data_type = "CLEANED" if use_cleaned else "ORIGINAL" |
| | print("="*80) |
| | print(f"DATASET STATISTICS - {data_type} DATA") |
| | print("="*80) |
| | |
| | X_train, y_train, X_test, y_test = load_data(use_cleaned=use_cleaned) |
| | |
| | print(f"\nTraining set:") |
| | print(f" - Samples: {X_train.shape[0]}") |
| | print(f" - Features: {X_train.shape[1]}") |
| | print(f" - Unique labels: {len(np.unique(y_train))}") |
| | print(f" - Label distribution:") |
| | unique, counts = np.unique(y_train, return_counts=True) |
| | for label, count in zip(unique[:10], counts[:10]): |
| | print(f" Label {label}: {count} samples ({count/len(y_train)*100:.2f}%)") |
| | if len(unique) > 10: |
| | print(f" ... and {len(unique)-10} more labels") |
| | |
| | print(f"\nTest set:") |
| | print(f" - Samples: {X_test.shape[0]}") |
| | print(f" - Features: {X_test.shape[1]}") |
| | print(f" - Unique labels: {len(np.unique(y_test))}") |
| | |
| | print(f"\nFeature statistics:") |
| | print(f" - Mean feature value: {X_train.mean():.4f}") |
| | print(f" - Std feature value: {X_train.std():.4f}") |
| | print(f" - Min feature value: {X_train.min():.4f}") |
| | print(f" - Max feature value: {X_train.max():.4f}") |
| | print(f" - Sparsity: {(X_train == 0).sum() / X_train.size * 100:.2f}%") |
| |
|
| |
|
| | if __name__ == "__main__": |
| | import sys |
| | |
| | |
| | use_cleaned = not ('--original' in sys.argv or '-o' in sys.argv) |
| | |
| | if use_cleaned: |
| | print("Testing CLEANED data (from data_cleaning.py) - DEFAULT\n") |
| | else: |
| | print("Testing ORIGINAL data\n") |
| | print("Note: Using --original flag to test old data\n") |
| | |
| | |
| | analyze_data_statistics(use_cleaned=use_cleaned) |
| | |
| | |
| | print("\n") |
| | suite_result = run_data_integrity_suite(save_output=True, use_cleaned=use_cleaned) |
| | |
| | |
| | print("\n") |
| | custom_results = run_custom_integrity_checks(save_output=True, use_cleaned=use_cleaned) |
| | |
| | print("\n" + "="*80) |
| | print("DATA INTEGRITY VALIDATION COMPLETED") |
| | print("="*80) |
| | print("\nCheck the reports in the 'reports/deepchecks' directory") |
| |
|