{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":71549,"databundleVersionId":8561470,"sourceType":"competition"},{"sourceId":8727685,"sourceType":"datasetVersion","datasetId":5236783},{"sourceId":8761420,"sourceType":"datasetVersion","datasetId":5264030},{"sourceId":13273243,"sourceType":"datasetVersion","datasetId":8411604}],"dockerImageVersionId":30733,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# RSNA2024 LSDC Submission Baseline\nThis notebook is forked [here](https://www.kaggle.com/code/itsuki9180/rsna2024-lsdc-submission-baseline). In the [previous notebook](https://www.kaggle.com/code/itsuki9180/rsna2024-lsdc-making-dataset), the author selected the images we wanted to use and exported them to png.The original notebook training. And the original other trained EfficientNet_B4 model with these images. \n\nI desided to change the model to see if there is any improvement. The reason why I choose DenseNet201 for training is that DenseNet201 has generally same number of parameters and size with EfficientNet_B4 so that I believe that Kaggle GPU could handle it and we don't need extra machine.\n\n### My other Notebooks\n- [RSNA2024 LSDC Making Dataset](https://www.kaggle.com/code/itsuki9180/rsna2024-lsdc-making-dataset) \n- [RSNA2024 LSDC Training DenseNet](https://www.kaggle.com/code/hugowjd/rsna2024-lsdc-training-densenet) \n- [RSNA2024 LSDC Submission DenseNet](https://www.kaggle.com/code/hugowjd/rsna2024-lsdc-densenet-submission) <- you're reading now\n\n### Reference:\n* [Huang, G., Liu, Z., Van Der Maaten, L., and Weinberger, K. Q. Densely connected convolutional networks. CVPR, 2017.](https://arxiv.org/abs/1608.06993)\n* [Mingxing Tan and Quoc V. Le. EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks. ICML 2019.](https://arxiv.org/abs/1905.11946)\n\n### Future Improvement\n* I'm certain that we can run other models to train these images. We can do it by changing ***MODEL_NAME*** parameters in **Config** session. I would list some CNN models which are suitable for image classification and these numbers of parameters.\n  * ResNet:\n    * ResNet-18: ~11.7 million parameters\n    * **ResNet-34: ~21.8 million parameters**\n    * **ResNet-50: ~25.6 million parameters**\n    * ResNet-101: ~44.5 million parameters\n    * ResNet-152: ~60 million parameters\n  * VGG:\n    * VGG-16: ~138 million parameters\n    * VGG-19: ~143 million parameters\n  * Inception Networks:\n    * Inception v1 (GoogleNet): ~6.8 million parameters\n    * Inception v3: ~23.8 million parameters\n  * DenseNet:\n    * DenseNet-121: ~8 million parameters\n    * **DenseNet-169: ~14 million parameters**\n        * Waiting to do\n    * **DenseNet-201: ~20 million parameters** \n        * My Submission LB: 0.61\n        * [10 folds submission LB](https://www.kaggle.com/code/sadidul012/densenet201-submission): 0.6\n    * **DenseNet-161: ~28.7 million parameters**\n        * 10 folds(This notebook V9): 0.59\n    * DenseNet-264: ~33 million parameters\n  * MobileNets (parameters can vary significantly with changes in alpha and resolution multipliers):\n    * MobileNetV1 (1.0 224): ~4.2 million parameters\n    * MobileNetV2 (1.0 224): ~3.5 million parameters\n    * MobileNetV3 Large: ~5.4 million parameters\n  * Vision Transformers (ViT):\n    * ViT-B/16 (base model with patch size 16x16): ~86 million parameters\n  * Xception:\n    * **Xception: ~22.9 million parameters**\n        * my test LB : 0.66\n  * EfficientNet\n    * EfficientNet-B0: ~5.3 million parameters\n    * EfficientNet-B1: ~7.8 million parameters\n    * EfficientNet-B2: ~9.2 million parameters\n        * [EFNetV2 LB](https://www.kaggle.com/code/shubhamcodez/rsna-efficientnet-starter-notebook): 1.01 \n    * EfficientNet-B3: ~12 million parameters\n        * [Original Notebook](https://www.kaggle.com/code/itsuki9180/rsna2024-lsdc-submission-baseline) LB: 0.69\n    * **EfficientNet-B4: ~19 million parameters**\n        * [Original Notebook](https://www.kaggle.com/code/itsuki9180/rsna2024-lsdc-submission-baseline) LB: 0.70\n    * EfficientNet-B5: ~30 million parameters\n    * EfficientNet-B6: ~43 million parameters\n    * EfficientNet-B7: ~66 million parameters\n* The original author said that we can improve the dataset making process\n* I only trained 5 **folds** and 10 **epochs**, you can modify these parameters. But take care of overfitting.","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19"}},{"cell_type":"markdown","source":"# Import Libralies","metadata":{}},{"cell_type":"code","source":"import os\nimport gc\nimport sys\nfrom PIL import Image\nimport cv2\nimport math, random\nimport numpy as np\nimport pandas as pd\nfrom glob import glob\nfrom tqdm import tqdm\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import KFold\n\nfrom collections import OrderedDict\n\nimport torch\nimport torch.nn.functional as F\nfrom torch import nn\nfrom torch.utils.data import DataLoader, Dataset\nfrom torch.optim import AdamW\n\nimport timm\nfrom timm.utils import ModelEmaV2\nfrom transformers import get_cosine_schedule_with_warmup\n\nimport albumentations as A\n\nfrom sklearn.model_selection import KFold\n\nimport re\nimport pydicom","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:57.952438Z","iopub.execute_input":"2025-10-05T23:06:57.953042Z","iopub.status.idle":"2025-10-05T23:06:57.958618Z","shell.execute_reply.started":"2025-10-05T23:06:57.953013Z","shell.execute_reply":"2025-10-05T23:06:57.957654Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"rd = '/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification'","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:57.960677Z","iopub.execute_input":"2025-10-05T23:06:57.961092Z","iopub.status.idle":"2025-10-05T23:06:57.969851Z","shell.execute_reply.started":"2025-10-05T23:06:57.961063Z","shell.execute_reply":"2025-10-05T23:06:57.969136Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Config","metadata":{}},{"cell_type":"code","source":"DENSE201_DIR = \"\" #f'/kaggle/input/densenet-weights-for-rsna-2024/'\nDENSE161_DIR = f'/kaggle/input/rsna2024-densenet0001/rsna24-results/'\ndevice = 'cuda:0' if torch.cuda.is_available() else 'cpu'\nN_WORKERS = os.cpu_count()\nUSE_AMP = True\nSEED = 8620\n\nIMG_SIZE = [512, 512]\nIN_CHANS = 30\nN_LABELS = 25\nN_CLASSES = 3 * N_LABELS\n\nN_FOLDS = 5\n\n# MODEL_NAME = \"tf_efficientnet_b4.ns_jft_in1k\"\n# DENSE_MODEL_NAME = \"densenet201\"\nDENSE_MODEL_NAME = 'densenet121'\nBATCH_SIZE = 1","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:57.971013Z","iopub.execute_input":"2025-10-05T23:06:57.971552Z","iopub.status.idle":"2025-10-05T23:06:57.980919Z","shell.execute_reply.started":"2025-10-05T23:06:57.971514Z","shell.execute_reply":"2025-10-05T23:06:57.980195Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"rd = '/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification'","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:57.982067Z","iopub.execute_input":"2025-10-05T23:06:57.982746Z","iopub.status.idle":"2025-10-05T23:06:57.991452Z","shell.execute_reply.started":"2025-10-05T23:06:57.982724Z","shell.execute_reply":"2025-10-05T23:06:57.990695Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device('cuda:0') if torch.cuda.is_available() else torch.device('cpu')\ndevice","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:57.993156Z","iopub.execute_input":"2025-10-05T23:06:57.993382Z","iopub.status.idle":"2025-10-05T23:06:58.000709Z","shell.execute_reply.started":"2025-10-05T23:06:57.993359Z","shell.execute_reply":"2025-10-05T23:06:57.999977Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(f'{rd}/test_series_descriptions.csv')\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.001572Z","iopub.execute_input":"2025-10-05T23:06:58.001789Z","iopub.status.idle":"2025-10-05T23:06:58.019127Z","shell.execute_reply.started":"2025-10-05T23:06:58.001770Z","shell.execute_reply":"2025-10-05T23:06:58.018283Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"study_ids = list(df['study_id'].unique())","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.020148Z","iopub.execute_input":"2025-10-05T23:06:58.020388Z","iopub.status.idle":"2025-10-05T23:06:58.024302Z","shell.execute_reply.started":"2025-10-05T23:06:58.020368Z","shell.execute_reply":"2025-10-05T23:06:58.023428Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_sub = pd.read_csv(f'{rd}/sample_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.025266Z","iopub.execute_input":"2025-10-05T23:06:58.025487Z","iopub.status.idle":"2025-10-05T23:06:58.037268Z","shell.execute_reply.started":"2025-10-05T23:06:58.025468Z","shell.execute_reply":"2025-10-05T23:06:58.036418Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"LABELS = list(sample_sub.columns[1:])\nLABELS","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.038293Z","iopub.execute_input":"2025-10-05T23:06:58.038854Z","iopub.status.idle":"2025-10-05T23:06:58.044658Z","shell.execute_reply.started":"2025-10-05T23:06:58.038825Z","shell.execute_reply":"2025-10-05T23:06:58.043842Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"CONDITIONS = [\n    'spinal_canal_stenosis', \n    'left_neural_foraminal_narrowing', \n    'right_neural_foraminal_narrowing',\n    'left_subarticular_stenosis',\n    'right_subarticular_stenosis'\n]\n\nLEVELS = [\n    'l1_l2',\n    'l2_l3',\n    'l3_l4',\n    'l4_l5',\n    'l5_s1',\n]","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.045602Z","iopub.execute_input":"2025-10-05T23:06:58.045869Z","iopub.status.idle":"2025-10-05T23:06:58.053886Z","shell.execute_reply.started":"2025-10-05T23:06:58.045849Z","shell.execute_reply":"2025-10-05T23:06:58.053142Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def atoi(text):\n    return int(text) if text.isdigit() else text\n\ndef natural_keys(text):\n    return [ atoi(c) for c in re.split(r'(\\d+)', text) ]","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.054805Z","iopub.execute_input":"2025-10-05T23:06:58.055067Z","iopub.status.idle":"2025-10-05T23:06:58.062350Z","shell.execute_reply.started":"2025-10-05T23:06:58.055048Z","shell.execute_reply":"2025-10-05T23:06:58.061561Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Define Dataset","metadata":{}},{"cell_type":"code","source":"class RSNA24TestDataset(Dataset):\n    def __init__(self, df, study_ids, phase='test', transform=None):\n        self.df = df\n        self.study_ids = study_ids\n        self.transform = transform\n        self.phase = phase\n    \n    def __len__(self):\n        return len(self.study_ids)\n    \n    def get_img_paths(self, study_id, series_desc):\n        pdf = self.df[self.df['study_id']==study_id]\n        pdf_ = pdf[pdf['series_description']==series_desc]\n        allimgs = []\n        for i, row in pdf_.iterrows():\n            pimgs = glob.glob(f'{rd}/test_images/{study_id}/{row[\"series_id\"]}/*.dcm')\n            pimgs = sorted(pimgs, key=natural_keys)\n            allimgs.extend(pimgs)\n            \n        return allimgs\n    \n    def read_dcm_ret_arr(self, src_path):\n        dicom_data = pydicom.dcmread(src_path)\n        image = dicom_data.pixel_array\n        image = (image - image.min()) / (image.max() - image.min() + 1e-6) * 255\n        img = cv2.resize(image, (IMG_SIZE[0], IMG_SIZE[1]),interpolation=cv2.INTER_CUBIC)\n        assert img.shape==(IMG_SIZE[0], IMG_SIZE[1])\n        return img\n\n    def __getitem__(self, idx):\n        x = np.zeros((IMG_SIZE[0], IMG_SIZE[1], IN_CHANS), dtype=np.uint8)\n        st_id = self.study_ids[idx]        \n        \n        # Sagittal T1\n        allimgs_st1 = self.get_img_paths(st_id, 'Sagittal T1')\n        if len(allimgs_st1)==0:\n            print(st_id, ': Sagittal T1, has no images')\n        \n        else:\n            step = len(allimgs_st1) / 10.0\n            st = len(allimgs_st1)/2.0 - 4.0*step\n            end = len(allimgs_st1)+0.0001\n            for j, i in enumerate(np.arange(st, end, step)):\n                try:\n                    ind2 = max(0, int((i-0.5001).round()))\n                    img = self.read_dcm_ret_arr(allimgs_st1[ind2])\n                    x[..., j] = img.astype(np.uint8)\n                except:\n                    print(f'failed to load on {st_id}, Sagittal T1')\n                    pass\n            \n        # Sagittal T2/STIR\n        allimgs_st2 = self.get_img_paths(st_id, 'Sagittal T2/STIR')\n        if len(allimgs_st2)==0:\n            print(st_id, ': Sagittal T2/STIR, has no images')\n            \n        else:\n            step = len(allimgs_st2) / 10.0\n            st = len(allimgs_st2)/2.0 - 4.0*step\n            end = len(allimgs_st2)+0.0001\n            for j, i in enumerate(np.arange(st, end, step)):\n                try:\n                    ind2 = max(0, int((i-0.5001).round()))\n                    img = self.read_dcm_ret_arr(allimgs_st2[ind2])\n                    x[..., j+10] = img.astype(np.uint8)\n                except:\n                    print(f'failed to load on {st_id}, Sagittal T2/STIR')\n                    pass\n            \n        # Axial T2\n        allimgs_at2 = self.get_img_paths(st_id, 'Axial T2')\n        if len(allimgs_at2)==0:\n            print(st_id, ': Axial T2, has no images')\n            \n        else:\n            step = len(allimgs_at2) / 10.0\n            st = len(allimgs_at2)/2.0 - 4.0*step\n            end = len(allimgs_at2)+0.0001\n\n            for j, i in enumerate(np.arange(st, end, step)):\n                try:\n                    ind2 = max(0, int((i-0.5001).round()))\n                    img = self.read_dcm_ret_arr(allimgs_at2[ind2])\n                    x[..., j+20] = img.astype(np.uint8)\n                except:\n                    print(f'failed to load on {st_id}, Axial T2')\n                    pass  \n            \n            \n        if self.transform is not None:\n            x = self.transform(image=x)['image']\n\n        x = x.transpose(2, 0, 1)\n                \n        return x, str(st_id)","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.136254Z","iopub.execute_input":"2025-10-05T23:06:58.136556Z","iopub.status.idle":"2025-10-05T23:06:58.150820Z","shell.execute_reply.started":"2025-10-05T23:06:58.136529Z","shell.execute_reply":"2025-10-05T23:06:58.150003Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transforms_test = A.Compose([\n    A.Resize(IMG_SIZE[0], IMG_SIZE[1]),\n    A.Normalize(mean=0.5, std=0.5)\n])","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.152548Z","iopub.execute_input":"2025-10-05T23:06:58.153075Z","iopub.status.idle":"2025-10-05T23:06:58.161153Z","shell.execute_reply.started":"2025-10-05T23:06:58.153042Z","shell.execute_reply":"2025-10-05T23:06:58.160344Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_ds = RSNA24TestDataset(df, study_ids, transform=transforms_test)\ntest_dl = DataLoader(\n    test_ds, \n    batch_size=1, \n    shuffle=False,\n    num_workers=N_WORKERS,\n    pin_memory=True,\n    drop_last=False\n)","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.162112Z","iopub.execute_input":"2025-10-05T23:06:58.162342Z","iopub.status.idle":"2025-10-05T23:06:58.170648Z","shell.execute_reply.started":"2025-10-05T23:06:58.162323Z","shell.execute_reply":"2025-10-05T23:06:58.169983Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Define Model","metadata":{}},{"cell_type":"code","source":"class RSNA24Model(nn.Module):\n    def __init__(self, model_name, in_c=30, n_classes=75, pretrained=True, features_only=False):\n        super().__init__()\n        self.model = timm.create_model(\n                                    model_name,\n                                    pretrained=pretrained, \n                                    features_only=features_only,\n                                    in_chans=in_c,\n                                    num_classes=n_classes,\n                                    global_pool='avg'\n                                    )\n    \n    def forward(self, x):\n        y = self.model(x)\n        return y","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.171625Z","iopub.execute_input":"2025-10-05T23:06:58.171928Z","iopub.status.idle":"2025-10-05T23:06:58.182756Z","shell.execute_reply.started":"2025-10-05T23:06:58.171896Z","shell.execute_reply":"2025-10-05T23:06:58.182052Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Load Models","metadata":{}},{"cell_type":"code","source":"models = []","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.184335Z","iopub.execute_input":"2025-10-05T23:06:58.184567Z","iopub.status.idle":"2025-10-05T23:06:58.192313Z","shell.execute_reply.started":"2025-10-05T23:06:58.184549Z","shell.execute_reply":"2025-10-05T23:06:58.191647Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import glob\nDENSE_CKPT_PATHS = glob.glob(f'{DENSE161_DIR}best_wll_model_fold-*.pt')\nDENSE_CKPT_PATHS = sorted(DENSE_CKPT_PATHS)","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.193134Z","iopub.execute_input":"2025-10-05T23:06:58.193389Z","iopub.status.idle":"2025-10-05T23:06:58.200270Z","shell.execute_reply.started":"2025-10-05T23:06:58.193370Z","shell.execute_reply":"2025-10-05T23:06:58.199558Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for i, cp in enumerate(DENSE_CKPT_PATHS):\n    print(f'loading {cp}...')\n    model = RSNA24Model(DENSE_MODEL_NAME, IN_CHANS, N_CLASSES, pretrained=False)\n    model.load_state_dict(torch.load(cp))\n    model.eval()\n    model.half()\n    model.to(device)\n    models.append(model)","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.201084Z","iopub.execute_input":"2025-10-05T23:06:58.201309Z","iopub.status.idle":"2025-10-05T23:06:58.543565Z","shell.execute_reply.started":"2025-10-05T23:06:58.201290Z","shell.execute_reply":"2025-10-05T23:06:58.542660Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Inference loop","metadata":{}},{"cell_type":"code","source":"autocast = torch.cuda.amp.autocast(enabled=USE_AMP, dtype=torch.half)\ny_preds = []\nrow_names = []\n\nwith tqdm(test_dl, leave=True) as pbar:\n    with torch.no_grad():\n        for idx, (x, si) in enumerate(pbar):\n            x = x.to(device)\n            pred_per_study = np.zeros((25, 3))\n            \n            for cond in CONDITIONS:\n                for level in LEVELS:\n                    row_names.append(si[0] + '_' + cond + '_' + level)\n            \n            with autocast:\n                for m in models:\n                    y = m(x)[0]\n                    for col in range(N_LABELS):\n                        pred = y[col*3:col*3+3]\n                        y_pred = pred.float().softmax(0).cpu().numpy()\n                        pred_per_study[col] += y_pred / len(models)\n                y_preds.append(pred_per_study)\n\ny_preds = np.concatenate(y_preds, axis=0)","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:06:58.544446Z","iopub.execute_input":"2025-10-05T23:06:58.544654Z","iopub.status.idle":"2025-10-05T23:07:00.703142Z","shell.execute_reply.started":"2025-10-05T23:06:58.544636Z","shell.execute_reply":"2025-10-05T23:07:00.702122Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Make Submission","metadata":{}},{"cell_type":"code","source":"sub = pd.DataFrame()\nsub['row_id'] = row_names\nsub[LABELS] = y_preds\nsub.head(25)","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:07:00.704288Z","iopub.execute_input":"2025-10-05T23:07:00.704533Z","iopub.status.idle":"2025-10-05T23:07:00.724898Z","shell.execute_reply.started":"2025-10-05T23:07:00.704509Z","shell.execute_reply":"2025-10-05T23:07:00.723917Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sub.to_csv('submission.csv', index=False)\npd.read_csv('submission.csv').head()","metadata":{"execution":{"iopub.status.busy":"2025-10-05T23:07:00.726092Z","iopub.execute_input":"2025-10-05T23:07:00.726625Z","iopub.status.idle":"2025-10-05T23:07:00.744035Z","shell.execute_reply.started":"2025-10-05T23:07:00.726593Z","shell.execute_reply":"2025-10-05T23:07:00.743240Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Conclusion\nWe created the dataset, performed training, and inference in this notebook. \n\nThis competition is a bit complicated to handle the dataset, so there may be a better way.\n\nI think there are many other areas to improve in my notebook. I hope you can learn from my notebook and get a better score.","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}