{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":97984,"databundleVersionId":14096757,"sourceType":"competition"}],"dockerImageVersionId":31153,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-10-23T16:34:33.149398Z","iopub.execute_input":"2025-10-23T16:34:33.149694Z","iopub.status.idle":"2025-10-23T16:34:33.492792Z","shell.execute_reply.started":"2025-10-23T16:34:33.149674Z","shell.execute_reply":"2025-10-23T16:34:33.492011Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.read_csv('/kaggle/input/physionet-ecg-image-digitization/train.csv')\ntest = pd.read_csv('/kaggle/input/physionet-ecg-image-digitization/test.csv')\nsubmission = pd.read_parquet(\"/kaggle/input/physionet-ecg-image-digitization/sample_submission.parquet\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T16:34:34.637099Z","iopub.execute_input":"2025-10-23T16:34:34.637514Z","iopub.status.idle":"2025-10-23T16:34:34.721323Z","shell.execute_reply.started":"2025-10-23T16:34:34.637491Z","shell.execute_reply":"2025-10-23T16:34:34.720450Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('Train shape', train.shape)\ntrain.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T16:34:36.072161Z","iopub.execute_input":"2025-10-23T16:34:36.072491Z","iopub.status.idle":"2025-10-23T16:34:36.084028Z","shell.execute_reply.started":"2025-10-23T16:34:36.072469Z","shell.execute_reply":"2025-10-23T16:34:36.083301Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('Test shape', test.shape)\ntest.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T16:34:39.055286Z","iopub.execute_input":"2025-10-23T16:34:39.056175Z","iopub.status.idle":"2025-10-23T16:34:39.064964Z","shell.execute_reply.started":"2025-10-23T16:34:39.056143Z","shell.execute_reply":"2025-10-23T16:34:39.064355Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('Sample shape', submission.shape)\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T16:34:41.932385Z","iopub.execute_input":"2025-10-23T16:34:41.932693Z","iopub.status.idle":"2025-10-23T16:34:41.940635Z","shell.execute_reply.started":"2025-10-23T16:34:41.932672Z","shell.execute_reply":"2025-10-23T16:34:41.939652Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings('ignore')\nidx = 0\nprint(train.id[idx])\n\nTRAIN_DIR = '/kaggle/input/physionet-ecg-image-digitization/train/'\nname = str(train.id[idx])\ndf_with_id0 = TRAIN_DIR + name + '/' + name + '.csv'\n\ndf = pd.read_csv(df_with_id0)\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T16:41:33.334360Z","iopub.execute_input":"2025-10-23T16:41:33.334652Z","iopub.status.idle":"2025-10-23T16:41:33.353338Z","shell.execute_reply.started":"2025-10-23T16:41:33.334633Z","shell.execute_reply":"2025-10-23T16:41:33.352648Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nfrom scipy.signal import butter, filtfilt\n\ntrain = pd.read_csv('/kaggle/input/physionet-ecg-image-digitization/train.csv')\ntest = pd.read_csv('/kaggle/input/physionet-ecg-image-digitization/test.csv')\nTRAIN_DIR = '/kaggle/input/physionet-ecg-image-digitization/train/'\n\ndef create_submission(predictions, name):\n    submission_data = []\n    for _, test_row in test.iterrows():\n        base_id = test_row['id']\n        lead = test_row['lead']\n        n_rows = test_row['number_of_rows']\n        \n        signal = predictions[(base_id, lead)]\n        \n        for row_id, value in enumerate(signal):\n            signal_id = f\"{base_id}_{row_id}_{lead}\"\n            submission_data.append({\n                'id': signal_id,\n                'value': value\n            })\n    \n    submission_df = pd.DataFrame(submission_data)\n    \n    \n    filename = f'submission_{name}.csv' if name else 'submission.csv'\n    submission_df.to_csv(filename, index=False)\n    return submission_df\n\nprint(\"Sine Wave ECG-like Signal\")\n\npredictions_sine = {}\necg_params = {\n    'I': {'amplitude': 0.5, 'offset': 0.1}, 'II': {'amplitude': 0.8, 'offset': 0.2},\n    'III': {'amplitude': 0.4, 'offset': 0.1}, 'aVR': {'amplitude': -0.3, 'offset': -0.1},\n    'aVL': {'amplitude': 0.2, 'offset': 0.05}, 'aVF': {'amplitude': 0.3, 'offset': 0.1},\n    'V1': {'amplitude': 0.3, 'offset': 0.0}, 'V2': {'amplitude': 0.4, 'offset': 0.05},\n    'V3': {'amplitude': 0.5, 'offset': 0.1}, 'V4': {'amplitude': 0.6, 'offset': 0.15},\n    'V5': {'amplitude': 0.5, 'offset': 0.1}, 'V6': {'amplitude': 0.4, 'offset': 0.05}\n}\n\nfor _, test_row in test.iterrows():\n    base_id = test_row['id']\n    fs = test_row['fs']\n    n_rows = test_row['number_of_rows']\n    lead = test_row['lead']\n    \n    duration = 10.0 if lead == 'II' else 2.5\n    t = np.linspace(0, duration, n_rows)\n    \n    params = ecg_params.get(lead, {'amplitude': 0.3, 'offset': 0.1})\n    \n    \n    heart_rate = 1.0  \n    main_rhythm = params['amplitude'] * np.sin(2 * np.pi * heart_rate * t)\n    p_wave = 0.1 * params['amplitude'] * np.sin(2 * np.pi * 5 * t + 0.5)\n    qrs_complex = 0.3 * params['amplitude'] * np.sin(2 * np.pi * 15 * (t % (1/heart_rate)))\n    \n    ecg_signal = params['offset'] + main_rhythm + p_wave + qrs_complex\n    noise = np.random.normal(0, 0.02, n_rows)\n    \n    predictions_sine[(base_id, lead)] = ecg_signal + noise\n\nprint(\"Statistical Model\")\n\nall_ecg_stats = {}\nstats_available = False\n\nfor _, row in train.iterrows():\n    ecg_path = f\"{TRAIN_DIR}{row['id']}/{row['id']}.csv\"\n    if os.path.exists(ecg_path):\n        try:\n            ecg_data = pd.read_csv(ecg_path)\n            for lead in ecg_data.columns:\n                if lead not in all_ecg_stats:\n                    all_ecg_stats[lead] = []\n                values = ecg_data[lead].dropna().values\n                if len(values) > 0:\n                    all_ecg_stats[lead].extend(values)\n                    stats_available = True\n        except Exception as e:\n            continue\n\nglobal_stats = {}\nif stats_available:\n    for lead, values in all_ecg_stats.items():\n        if len(values) > 0:\n            values = np.array(values)\n            global_stats[lead] = {\n                'mean': np.mean(values),\n                'std': np.std(values) if len(values) > 1 else 0.1,\n                'median': np.median(values),\n                'min': np.min(values),\n                'max': np.max(values)\n            }\n\npredictions_stats = {}\nfor _, test_row in test.iterrows():\n    base_id = test_row['id']\n    fs = test_row['fs']\n    n_rows = test_row['number_of_rows']\n    lead = test_row['lead']\n    \n    duration = 10.0 if lead == 'II' else 2.5\n    \n    if lead in global_stats:\n        base_value = global_stats[lead]['median']\n        amplitude = global_stats[lead]['std'] * 0.5\n    else:\n        base_value = 0\n        amplitude = 0.1\n    \n    \n    t = np.linspace(0, duration, n_rows)\n    signal = base_value + np.random.normal(0, amplitude, n_rows)\n    \n    predictions_stats[(base_id, lead)] = signal\n\n\nprint(\"Piecewise Approximation Model\")\n\npredictions_piecewise = {}\nfor _, test_row in test.iterrows():\n    base_id = test_row['id']\n    fs = test_row['fs']\n    n_rows = test_row['number_of_rows']\n    lead = test_row['lead']\n    \n    duration = 10.0 if lead == 'II' else 2.5\n    t = np.linspace(0, duration, n_rows)\n    \n    params = ecg_params.get(lead, {'amplitude': 0.3, 'offset': 0.1})\n    stats = global_stats.get(lead, {'median': 0, 'std': 0.1})\n    \n    \n    signal = np.zeros(n_rows)\n    \n    \n    heart_period = 0.8  \n    for i in range(int(duration / heart_period) + 1):\n        start_idx = int(i * heart_period * fs)\n        if start_idx >= n_rows:\n            break\n            \n        \n        p_start = start_idx\n        p_duration = int(0.1 * fs)  # 100ms\n        if p_start + p_duration < n_rows:\n            signal[p_start:p_start+p_duration] += 0.1 * params['amplitude'] * np.sin(np.linspace(0, np.pi, p_duration))\n        \n        \n        qrs_start = start_idx + int(0.2 * fs)\n        qrs_duration = int(0.08 * fs)  # 80ms\n        if qrs_start + qrs_duration < n_rows:\n            signal[qrs_start:qrs_start+qrs_duration] += params['amplitude'] * np.sin(np.linspace(0, 2*np.pi, qrs_duration))\n        \n        \n        t_start = start_idx + int(0.4 * fs)\n        t_duration = int(0.2 * fs)  # 200ms\n        if t_start + t_duration < n_rows:\n            signal[t_start:t_start+t_duration] += 0.3 * params['amplitude'] * np.sin(np.linspace(0, np.pi, t_duration))\n    \n    signal = stats['median'] + signal + np.random.normal(0, stats['std'] * 0.05, n_rows)\n    predictions_piecewise[(base_id, lead)] = signal","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T16:58:44.831523Z","iopub.execute_input":"2025-10-23T16:58:44.831859Z","iopub.status.idle":"2025-10-23T16:58:58.127512Z","shell.execute_reply.started":"2025-10-23T16:58:44.831835Z","shell.execute_reply":"2025-10-23T16:58:58.126753Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"leads = ['I', 'II', 'III', 'aVR', 'aVL', 'aVF', 'V1', 'V2', 'V3', 'V4', 'V5', 'V6']\ntemplate_len = 500\nlead_templates = {}\n\nfor lead in leads:\n    signals = []\n    for _, row in train.iterrows():\n        csv_path = os.path.join(TRAIN_DIR, str(row['id']), f\"{row['id']}.csv\")\n        \n        if not os.path.exists(csv_path):\n            continue\n        \n        try:\n            df = pd.read_csv(csv_path)\n            if lead not in df.columns:\n                continue\n            \n            s = df[lead].dropna().values.astype(np.float32)\n            if len(s) < 50:\n                continue\n            \n            s_norm = (s - s.mean()) / (s.std() + 1e-8)\n            s_resamp = np.interp(\n                np.linspace(0, 1, template_len),\n                np.linspace(0, 1, len(s_norm)),\n                s_norm\n            )\n            signals.append(s_resamp)\n        except:\n            continue\n    \n    if signals:\n        lead_templates[lead] = np.mean(signals, axis=0)\n    else:\n        t = np.linspace(0, 1, template_len)\n        lead_templates[lead] = np.sin(2 * np.pi * t)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T16:59:06.122858Z","iopub.execute_input":"2025-10-23T16:59:06.123111Z","iopub.status.idle":"2025-10-23T16:59:52.944025Z","shell.execute_reply.started":"2025-10-23T16:59:06.123092Z","shell.execute_reply":"2025-10-23T16:59:52.942974Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions = {}\nmin_val, max_val = 0.0, 0.07\n\nfor _, row in test.iterrows():\n    base_id = row['id']\n    lead = row['lead']\n    n_rows = row['number_of_rows']\n    fs = row.get('fs', 500)\n    \n    template = lead_templates.get(lead, lead_templates['II']).copy()\n    \n    if len(template) != n_rows:\n        signal = np.interp(\n            np.linspace(0, 1, n_rows),\n            np.linspace(0, 1, len(template)),\n            template\n        )\n    else:\n        signal = template\n    \n    if len(signal) > 10:\n        nyq = 0.5 * fs\n        normal_cutoff = min(15.0 / nyq, 0.99)\n        b, a = butter(2, normal_cutoff, btype='low')\n        signal = filtfilt(b, a, signal)\n    \n    s_min, s_max = signal.min(), signal.max()\n    \n    if s_max - s_min < 1e-8:\n        signal = np.full(n_rows, (min_val + max_val) / 2)\n    else:\n        signal = (signal - s_min) / (s_max - s_min)\n        signal = min_val + signal * (max_val - min_val)\n    \n    predictions[(base_id, lead)] = signal.astype(np.float32)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T16:59:59.702574Z","iopub.execute_input":"2025-10-23T16:59:59.702878Z","iopub.status.idle":"2025-10-23T16:59:59.763690Z","shell.execute_reply.started":"2025-10-23T16:59:59.702860Z","shell.execute_reply":"2025-10-23T16:59:59.762868Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission_data = []\nfor _, row in test.iterrows():\n    base_id = row['id']\n    lead = row['lead']\n    n_rows = row['number_of_rows']\n    signal = predictions[(base_id, lead)]\n    \n    for i in range(n_rows):\n        submission_data.append({\n            'id': f\"{base_id}_{i}_{lead}\",\n            'value': float(signal[i])\n        })\n\nsubmission = pd.DataFrame(submission_data)\nsubmission.to_csv('submission.csv', index=False)\nsubmission.head(5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T17:00:43.591716Z","iopub.execute_input":"2025-10-23T17:00:43.591979Z","iopub.status.idle":"2025-10-23T17:00:43.785157Z","shell.execute_reply.started":"2025-10-23T17:00:43.591960Z","shell.execute_reply":"2025-10-23T17:00:43.784518Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}