Spaces:
Runtime error
Runtime error
Download backend/dataset_analytics.py from IDKHowToCodeFr/tinyml-backend: direct link, hf CLI and curl.
- Browser
- Download file 12 kB
-
https://huggingface.co/spaces/IDKHowToCodeFr/tinyml-backend/resolve/main/backend/dataset_analytics.py
- Command line
-
hf download hf://spaces/IDKHowToCodeFr/tinyml-backend/backend/dataset_analytics.py
-
curl -L -o dataset_analytics.py https://huggingface.co/spaces/IDKHowToCodeFr/tinyml-backend/resolve/main/backend/dataset_analytics.py
12 kB
| import os | |
| import math | |
| import pandas as pd | |
| import numpy as np | |
| _CACHED_PROFILE = None | |
| _CACHED_MTIME = None | |
| def get_dataset_profile(dataset_path: str): | |
| global _CACHED_PROFILE, _CACHED_MTIME | |
| if not os.path.exists(dataset_path): | |
| return None | |
| mtime = os.path.getmtime(dataset_path) | |
| if _CACHED_PROFILE is not None and _CACHED_MTIME == mtime: | |
| return _CACHED_PROFILE | |
| try: | |
| df = pd.read_csv(dataset_path, encoding='utf-8', encoding_errors='replace') | |
| cols = list(df.columns) | |
| for i, c in enumerate(cols): | |
| if 'Body Temperature' in c: | |
| cols[i] = 'Body Temperature (°C)' | |
| df.columns = [c.strip() for c in cols] | |
| total_records = len(df) | |
| columns_list = df.columns.tolist() | |
| # Target distribution | |
| disease_counts = df['Predicted Disease'].value_counts() if 'Predicted Disease' in df.columns else {} | |
| disease_colors = { | |
| 'Diabetes Mellitus': '#2563EB', | |
| 'Heart Disease': '#9F2F2D', | |
| 'Healthy': '#16A34A', | |
| 'Hypertension': '#D97706', | |
| 'Asthma': '#7C3AED' | |
| } | |
| target_distribution = [] | |
| for disease, count in disease_counts.items(): | |
| pct = round(count / total_records * 100, 2) | |
| target_distribution.append({ | |
| 'disease': disease, | |
| 'count': int(count), | |
| 'percentage': pct, | |
| 'color': disease_colors.get(disease, '#5A5A57') | |
| }) | |
| # Alert prevalence | |
| alerts = [ | |
| {'name': 'Blood Pressure Alert', 'col': 'Blood Pressure Alert', 'target': 'ABNORMAL'}, | |
| {'name': 'Heart Rate Alert', 'col': 'Heart Rate Alert', 'target': 'ABNORMAL'}, | |
| {'name': 'SpO2 Level Alert', 'col': 'SpO2 Level Alert', 'target': 'ABNORMAL'}, | |
| {'name': 'Temperature Alert', 'col': 'Temperature Alert', 'target': 'ABNORMAL'}, | |
| {'name': 'Fall Detection Event', 'col': 'Fall Detection', 'target': 'Yes'} | |
| ] | |
| alert_prevalence = [] | |
| for a in alerts: | |
| if a['col'] in df.columns: | |
| counts = df[a['col']].value_counts() | |
| abnormal_count = int(counts.get(a['target'], 0)) | |
| normal_count = total_records - abnormal_count | |
| alert_prevalence.append({ | |
| 'name': a['name'], | |
| 'abnormal_count': abnormal_count, | |
| 'normal_count': normal_count, | |
| 'abnormal_pct': round(abnormal_count / total_records * 100, 2) | |
| }) | |
| # Numerical specs | |
| num_features = [ | |
| { | |
| 'key': 'Heart Rate (bpm)', | |
| 'name': 'Heart Rate', | |
| 'unit': 'bpm', | |
| 'desc': 'Cardiac chronotropic telemetry frequency', | |
| 'normal_min': 60, | |
| 'normal_max': 100, | |
| 'alert': 'Pulse > 100 bpm (Tachycardia) or < 60 bpm (Bradycardia)', | |
| }, | |
| { | |
| 'key': 'SpO2 Level (%)', | |
| 'name': 'SpO2 Oxygen Saturation', | |
| 'unit': '%', | |
| 'desc': 'Arterial blood oxygen saturation telemetry', | |
| 'normal_min': 95, | |
| 'normal_max': 100, | |
| 'alert': 'Saturation < 95% (Hypoxemia threshold)', | |
| }, | |
| { | |
| 'key': 'Systolic Blood Pressure (mmHg)', | |
| 'name': 'Systolic Blood Pressure', | |
| 'unit': 'mmHg', | |
| 'desc': 'Peak ventricular contraction arterial pressure', | |
| 'normal_min': 90, | |
| 'normal_max': 120, | |
| 'alert': 'Pressure > 140 mmHg (Hypertensive crisis risk)', | |
| }, | |
| { | |
| 'key': 'Diastolic Blood Pressure (mmHg)', | |
| 'name': 'Diastolic Blood Pressure', | |
| 'unit': 'mmHg', | |
| 'desc': 'Resting ventricular filling arterial pressure', | |
| 'normal_min': 60, | |
| 'normal_max': 80, | |
| 'alert': 'Pressure > 90 mmHg (Hypertension boundary)', | |
| }, | |
| { | |
| 'key': 'Body Temperature (°C)', | |
| 'name': 'Body Temperature', | |
| 'unit': '°C', | |
| 'desc': 'Physiological thermal equilibrium reading', | |
| 'normal_min': 36.5, | |
| 'normal_max': 37.5, | |
| 'alert': 'Core Temp > 37.8°C (Pyrexia) or < 36.0°C (Hypothermia)', | |
| }, | |
| { | |
| 'key': 'Data Accuracy (%)', | |
| 'name': 'Telemetry Data Accuracy', | |
| 'unit': '%', | |
| 'desc': 'Hardware sensor packet integrity & SNR confidence', | |
| 'normal_min': 90, | |
| 'normal_max': 100, | |
| 'alert': 'SNR Packet Fidelity < 85%', | |
| } | |
| ] | |
| feature_stats = [] | |
| for feat in num_features: | |
| k = feat['key'] | |
| if k not in df.columns: | |
| continue | |
| series = pd.to_numeric(df[k], errors='coerce').dropna() | |
| desc = series.describe() | |
| counts, bin_edges = np.histogram(series, bins=12) | |
| bins = [] | |
| for b_idx in range(len(counts)): | |
| b_min = round(float(bin_edges[b_idx]), 1) | |
| b_max = round(float(bin_edges[b_idx+1]), 1) | |
| bins.append({ | |
| 'label': f"{b_min}–{b_max}", | |
| 'min': b_min, | |
| 'max': b_max, | |
| 'count': int(counts[b_idx]), | |
| 'pct': round(float(counts[b_idx]) / total_records * 100, 2) | |
| }) | |
| means_by_disease = {} | |
| if 'Predicted Disease' in df.columns: | |
| means_by_disease = df.groupby('Predicted Disease')[k].mean().round(2).to_dict() | |
| feature_stats.append({ | |
| 'key': k, | |
| 'name': feat['name'], | |
| 'unit': feat['unit'], | |
| 'desc': feat['desc'], | |
| 'normal_range': f"{feat['normal_min']}–{feat['normal_max']} {feat['unit']}", | |
| 'normal_min': feat['normal_min'], | |
| 'normal_max': feat['normal_max'], | |
| 'alert': feat['alert'], | |
| 'mean': round(float(desc['mean']), 2), | |
| 'std': round(float(desc['std']), 2), | |
| 'min': round(float(desc['min']), 2), | |
| 'q25': round(float(desc['25%']), 2), | |
| 'median': round(float(desc['50%']), 2), | |
| 'q75': round(float(desc['75%']), 2), | |
| 'max': round(float(desc['max']), 2), | |
| 'iqr': round(float(desc['75%'] - desc['25%']), 2), | |
| 'bins': bins, | |
| 'means_by_disease': {str(k2): round(float(v2), 2) for k2, v2 in means_by_disease.items()} | |
| }) | |
| # Correlations | |
| df_corr = df.copy() | |
| if 'Predicted Disease' in df.columns: | |
| df_corr['Is_Heart_Disease'] = (df['Predicted Disease'] == 'Heart Disease').astype(int) | |
| df_corr['Is_Hypertension'] = (df['Predicted Disease'] == 'Hypertension').astype(int) | |
| corr_features = [ | |
| {'key': 'Heart Rate (bpm)', 'label': 'Heart Rate'}, | |
| {'key': 'SpO2 Level (%)', 'label': 'SpO2 Oxygen'}, | |
| {'key': 'Systolic Blood Pressure (mmHg)', 'label': 'Systolic BP'}, | |
| {'key': 'Diastolic Blood Pressure (mmHg)', 'label': 'Diastolic BP'}, | |
| {'key': 'Body Temperature (°C)', 'label': 'Body Temp'}, | |
| {'key': 'Data Accuracy (%)', 'label': 'Accuracy'}, | |
| ] | |
| if 'Is_Heart_Disease' in df_corr.columns: | |
| corr_features.append({'key': 'Is_Heart_Disease', 'label': 'Heart Disease'}) | |
| if 'Is_Hypertension' in df_corr.columns: | |
| corr_features.append({'key': 'Is_Hypertension', 'label': 'Hypertension'}) | |
| keys = [f['key'] for f in corr_features if f['key'] in df_corr.columns] | |
| matrix = df_corr[keys].corr().round(3).values.tolist() | |
| corr_matrix_data = { | |
| 'labels': [f['label'] for f in corr_features if f['key'] in df_corr.columns], | |
| 'keys': keys, | |
| 'matrix': matrix | |
| } | |
| # Target feature dependency | |
| corrs_with_target = [] | |
| if 'Is_Heart_Disease' in df_corr.columns: | |
| for f in num_features: | |
| k = f['key'] | |
| if k in df_corr.columns: | |
| r_val = round(float(df_corr[k].corr(df_corr['Is_Heart_Disease'])), 3) | |
| corrs_with_target.append({ | |
| 'feature': f['name'], | |
| 'key': k, | |
| 'correlation': r_val, | |
| 'abs_corr': abs(r_val), | |
| 'unit': f['unit'], | |
| 'impact': 'High Primary Predictor' if abs(r_val) > 0.4 else ('Moderate Risk Factor' if abs(r_val) > 0.2 else 'Baseline Background') | |
| }) | |
| corrs_with_target.sort(key=lambda x: x['abs_corr'], reverse=True) | |
| file_size_mb = round(os.path.getsize(dataset_path) / (1024 * 1024), 2) | |
| profile = { | |
| 'summary': { | |
| 'total_records': total_records, | |
| 'total_features': len(columns_list), | |
| 'file_size_mb': file_size_mb, | |
| 'missing_values': int(df.isnull().sum().sum()), | |
| 'completeness_pct': 100.0 if df.isnull().sum().sum() == 0 else round((1 - df.isnull().sum().sum() / (total_records * len(columns_list))) * 100, 2), | |
| 'classes_count': len(target_distribution), | |
| 'sampling_fidelity': 'IEC-60601-1 Telemetry Validated' | |
| }, | |
| 'columns': columns_list, | |
| 'target_distribution': target_distribution, | |
| 'alert_prevalence': alert_prevalence, | |
| 'feature_stats': feature_stats, | |
| 'correlation_matrix': corr_matrix_data, | |
| 'feature_dependencies': corrs_with_target | |
| } | |
| _CACHED_PROFILE = profile | |
| _CACHED_MTIME = mtime | |
| return profile | |
| except Exception as e: | |
| print(f"Error computing dataset profile: {e}") | |
| return None | |
| def get_paginated_rows(dataset_path: str, page: int = 1, limit: int = 25, disease: str = None, search: str = None): | |
| if not os.path.exists(dataset_path): | |
| return {"error": "Dataset not found", "total": 0, "rows": []} | |
| df = pd.read_csv(dataset_path, encoding='utf-8', encoding_errors='replace') | |
| cols = list(df.columns) | |
| for i, c in enumerate(cols): | |
| if 'Body Temperature' in c: | |
| cols[i] = 'Body Temperature (°C)' | |
| df.columns = [c.strip() for c in cols] | |
| if disease and 'Predicted Disease' in df.columns and disease.lower() != 'all': | |
| df = df[df['Predicted Disease'].str.lower() == disease.lower()] | |
| if search: | |
| search_str = str(search).strip().lower() | |
| if 'Patient Number' in df.columns: | |
| df = df[df['Patient Number'].astype(str).str.contains(search_str, case=False, na=False)] | |
| total = len(df) | |
| total_pages = math.ceil(total / limit) if limit > 0 else 1 | |
| page = max(1, page) | |
| start_idx = (page - 1) * limit | |
| end_idx = start_idx + limit | |
| page_df = df.iloc[start_idx:end_idx].copy() | |
| rows = page_df.to_dict(orient="records") | |
| for r in rows: | |
| for k, v in r.items(): | |
| if isinstance(v, (np.floating, float)): | |
| r[k] = round(float(v), 2) | |
| elif isinstance(v, (np.integer, int)): | |
| r[k] = int(v) | |
| elif pd.isna(v): | |
| r[k] = None | |
| return { | |
| "total": total, | |
| "page": page, | |
| "limit": limit, | |
| "total_pages": total_pages, | |
| "features": df.columns.tolist(), | |
| "rows": rows | |
| } | |