{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"### **download external packages**","metadata":{}},{"cell_type":"code","source":"HELPER_DIR = '/kaggle/input/pydicom-conda-helper/'\n\n!conda install {HELPER_DIR+'libjpeg-turbo-2.1.0-h7f98852_0.tar.bz2'} -c conda-forge -y -q\n!conda install {HELPER_DIR+'libgcc-ng-9.3.0-h2828fa1_19.tar.bz2'} -c conda-forge -y -q\n!conda install {HELPER_DIR+'gdcm-2.8.9-py37h500ead1_1.tar.bz2'} -c conda-forge -y -q\n!conda install {HELPER_DIR+'conda-4.10.1-py37h89c1867_0.tar.bz2'} -c conda-forge -y -q\n!conda install {HELPER_DIR+'certifi-2020.12.5-py37h89c1867_1.tar.bz2'} -c conda-forge -y -q\n!conda install {HELPER_DIR+'openssl-1.1.1k-h7f98852_0.tar.bz2'} -c conda-forge -y -q","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:54:43.557709Z","iopub.execute_input":"2021-06-16T16:54:43.558244Z","iopub.status.idle":"2021-06-16T16:56:02.402381Z","shell.execute_reply.started":"2021-06-16T16:54:43.558159Z","shell.execute_reply":"2021-06-16T16:56:02.401222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **import dependencies**","metadata":{}},{"cell_type":"code","source":"import os, zipfile\nimport cv2\nimport plotly.express as px\nimport numpy as np\nimport pandas as pd\nfrom tqdm.auto import tqdm\nimport matplotlib.pyplot as plt\nfrom kaggle_secrets import UserSecretsClient\nimport pydicom\nimport wandb\n\nfrom pathlib import Path","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:02.404153Z","iopub.execute_input":"2021-06-16T16:56:02.404657Z","iopub.status.idle":"2021-06-16T16:56:05.095855Z","shell.execute_reply.started":"2021-06-16T16:56:02.404614Z","shell.execute_reply":"2021-06-16T16:56:05.094719Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **configuration and initialization**","metadata":{}},{"cell_type":"code","source":"SIIM_COVID19_DETECTION_DIR = '/kaggle/input/siim-covid19-detection/'\n\nWORKING_DIR = '/kaggle/working/'\nTEMP_DIR = '/kaggle/temp/'\n\nINPUT_DIR = SIIM_COVID19_DETECTION_DIR+'train/'\nOUTPUT_DIR = WORKING_DIR+'data/'\n\nTRAIN_IMAGE_LEVEL_PATH = SIIM_COVID19_DETECTION_DIR+'train_image_level.csv'\nTRAIN_STUDY_LEVEL_PATH = SIIM_COVID19_DETECTION_DIR+'train_study_level.csv'\n\nIMG_SIZE = WIDTH = HEIGHT = 512\nN_IMAGES_WANDB = 42\n\n\nINTERPOLATION = cv2.INTER_LANCZOS4","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:05.098405Z","iopub.execute_input":"2021-06-16T16:56:05.099101Z","iopub.status.idle":"2021-06-16T16:56:05.107117Z","shell.execute_reply.started":"2021-06-16T16:56:05.099044Z","shell.execute_reply":"2021-06-16T16:56:05.105641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.makedirs(OUTPUT_DIR, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T17:34:46.135516Z","iopub.execute_input":"2021-06-16T17:34:46.135863Z","iopub.status.idle":"2021-06-16T17:34:46.139935Z","shell.execute_reply.started":"2021-06-16T17:34:46.135835Z","shell.execute_reply":"2021-06-16T17:34:46.139153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"user_secrets = UserSecretsClient()\nsecret_value_0 = user_secrets.get_secret(\"WANDB_API_KEY\")\nos.environ['WANDB_API_KEY'] = secret_value_0\n\nwandb.login()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:05.108841Z","iopub.execute_input":"2021-06-16T16:56:05.109224Z","iopub.status.idle":"2021-06-16T16:56:06.163625Z","shell.execute_reply.started":"2021-06-16T16:56:05.109192Z","shell.execute_reply":"2021-06-16T16:56:06.162532Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **load csv file**","metadata":{}},{"cell_type":"code","source":"df_train_image_level = pd.read_csv(TRAIN_IMAGE_LEVEL_PATH)\ndf_train_study_level = pd.read_csv(TRAIN_STUDY_LEVEL_PATH)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:06.164875Z","iopub.execute_input":"2021-06-16T16:56:06.165217Z","iopub.status.idle":"2021-06-16T16:56:06.234375Z","shell.execute_reply.started":"2021-06-16T16:56:06.165185Z","shell.execute_reply":"2021-06-16T16:56:06.233287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **first look**","metadata":{}},{"cell_type":"code","source":"df_train_image_level.sample(5)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:06.236000Z","iopub.execute_input":"2021-06-16T16:56:06.236458Z","iopub.status.idle":"2021-06-16T16:56:06.266527Z","shell.execute_reply.started":"2021-06-16T16:56:06.236411Z","shell.execute_reply":"2021-06-16T16:56:06.265124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train_image_level.describe()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:06.267922Z","iopub.execute_input":"2021-06-16T16:56:06.268272Z","iopub.status.idle":"2021-06-16T16:56:06.330017Z","shell.execute_reply.started":"2021-06-16T16:56:06.268239Z","shell.execute_reply":"2021-06-16T16:56:06.328764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train_study_level.sample(5)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:06.331135Z","iopub.execute_input":"2021-06-16T16:56:06.331412Z","iopub.status.idle":"2021-06-16T16:56:06.346445Z","shell.execute_reply.started":"2021-06-16T16:56:06.331386Z","shell.execute_reply":"2021-06-16T16:56:06.345133Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train_study_level.describe()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:06.349623Z","iopub.execute_input":"2021-06-16T16:56:06.349990Z","iopub.status.idle":"2021-06-16T16:56:06.385059Z","shell.execute_reply.started":"2021-06-16T16:56:06.349952Z","shell.execute_reply":"2021-06-16T16:56:06.383988Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **merge df study/image, add path image**","metadata":{}},{"cell_type":"code","source":"df_train_image_level['id'] = df_train_image_level.apply(lambda row: row.id.split('_')[0], axis=1)\ndf_train_image_level['path'] = df_train_image_level.apply(lambda row: OUTPUT_DIR+row.id+'.jpg', axis=1)\ndf_train_image_level['image_level'] = df_train_image_level.apply(lambda row: row.label.split(' ')[0], axis=1)\n\ndf_train_study_level['id'] = df_train_study_level.apply(lambda row: row.id.split('_')[0], axis=1)\ndf_train_study_level.columns = ['StudyInstanceUID', 'Negative for Pneumonia', 'Typical Appearance', 'Indeterminate Appearance', 'Atypical Appearance']","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:06.386938Z","iopub.execute_input":"2021-06-16T16:56:06.387259Z","iopub.status.idle":"2021-06-16T16:56:06.838177Z","shell.execute_reply.started":"2021-06-16T16:56:06.387229Z","shell.execute_reply":"2021-06-16T16:56:06.836996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = df_train_image_level.merge(df_train_study_level, on='StudyInstanceUID',how=\"left\")\ndf.sample(3)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:06.839444Z","iopub.execute_input":"2021-06-16T16:56:06.839751Z","iopub.status.idle":"2021-06-16T16:56:06.874246Z","shell.execute_reply.started":"2021-06-16T16:56:06.839722Z","shell.execute_reply":"2021-06-16T16:56:06.873167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"Number of images in trainset: {len(df)}\")\nprint(f\"Number of images in trainset ( without boxes): {df['boxes'].isna().sum()}\")\nprint(f\"Number of images in trainset ( with boxes): {len(df) - df['boxes'].isna().sum()}\")","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:06.875743Z","iopub.execute_input":"2021-06-16T16:56:06.876178Z","iopub.status.idle":"2021-06-16T16:56:06.884063Z","shell.execute_reply.started":"2021-06-16T16:56:06.876144Z","shell.execute_reply":"2021-06-16T16:56:06.882942Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = df[['Negative for Pneumonia','Typical Appearance','Indeterminate Appearance','Atypical Appearance']]","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:06.886046Z","iopub.execute_input":"2021-06-16T16:56:06.886499Z","iopub.status.idle":"2021-06-16T16:56:06.897118Z","shell.execute_reply.started":"2021-06-16T16:56:06.886452Z","shell.execute_reply":"2021-06-16T16:56:06.896141Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = px.bar(labels.sum(),\n             title=\"<b>Distribution images by classes</b>\",)\nfig.update_layout(showlegend=False,\n                  xaxis_title=\"\",\n                  yaxis_title=\"\")\n\n\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:06.898179Z","iopub.execute_input":"2021-06-16T16:56:06.898596Z","iopub.status.idle":"2021-06-16T16:56:07.900991Z","shell.execute_reply.started":"2021-06-16T16:56:06.898567Z","shell.execute_reply":"2021-06-16T16:56:07.899777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['study_level'] = np.argmax(labels.values, axis=1)\ndf.sample(3)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:07.902654Z","iopub.execute_input":"2021-06-16T16:56:07.903105Z","iopub.status.idle":"2021-06-16T16:56:07.921563Z","shell.execute_reply.started":"2021-06-16T16:56:07.903056Z","shell.execute_reply":"2021-06-16T16:56:07.920552Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"no_bb = df[df['boxes'].isna()].shape[0]\nhas_bb = df[df['boxes'].notna()].shape[0]\n\npx.pie(names=[\"with boxes\", \"without boxes\"],\n       values=[has_bb, no_bb], \n       title=\"<b>Distribution images by boxes</b>\")","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:07.922767Z","iopub.execute_input":"2021-06-16T16:56:07.923084Z","iopub.status.idle":"2021-06-16T16:56:08.002074Z","shell.execute_reply.started":"2021-06-16T16:56:07.923049Z","shell.execute_reply":"2021-06-16T16:56:08.000658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"no_bb = df[(df['boxes'].isna() & df['Negative for Pneumonia'] ==1)].shape[0]\nhas_bb = df[(df['boxes'].notna() & df['Negative for Pneumonia'] ==1)].shape[0]\n\npx.pie(names=[\"with boxes\", \"without boxes\"],\n       values=[has_bb, no_bb], \n       title=\"<b>Distribution images by boxes for negative study</b>\")","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:08.003750Z","iopub.execute_input":"2021-06-16T16:56:08.004212Z","iopub.status.idle":"2021-06-16T16:56:08.066390Z","shell.execute_reply.started":"2021-06-16T16:56:08.004164Z","shell.execute_reply":"2021-06-16T16:56:08.065338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"no_bb = df[(df['boxes'].isna() & df['Negative for Pneumonia'] ==0)].shape[0]\nhas_bb = df[(df['boxes'].notna() & df['Negative for Pneumonia'] ==0)].shape[0]\n\npx.pie(names=[\"with boxes\", \"without boxes\"],\n       values=[has_bb, no_bb], \n       title=\"<b>Distribution images by boxes for positive study</b>\")","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:08.067888Z","iopub.execute_input":"2021-06-16T16:56:08.068337Z","iopub.status.idle":"2021-06-16T16:56:08.127178Z","shell.execute_reply.started":"2021-06-16T16:56:08.068293Z","shell.execute_reply":"2021-06-16T16:56:08.126157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"label_to_class_id = {\n    'Negative for Pneumonia': 0,\n    'Typical Appearance': 1,\n    'Indeterminate Appearance': 2,\n    'Atypical Appearance': 3\n}\n\nclass_id_to_label = {v: k for k, v in label_to_class_id.items()}","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:08.128535Z","iopub.execute_input":"2021-06-16T16:56:08.128834Z","iopub.status.idle":"2021-06-16T16:56:08.135676Z","shell.execute_reply.started":"2021-06-16T16:56:08.128805Z","shell.execute_reply":"2021-06-16T16:56:08.134341Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **get path dicom files**","metadata":{}},{"cell_type":"code","source":"path_dicom_files = []\n\ntotal = sum([len(f) for r, d, f in os.walk(INPUT_DIR)])\n\nwith tqdm(total=total) as pbar:\n    for dirname, _, filenames in os.walk(INPUT_DIR):\n        for file in filenames:\n            path_dicom_files.append(Path(os.path.join(dirname, file)))\n            pbar.update(1)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T16:56:08.137334Z","iopub.execute_input":"2021-06-16T16:56:08.137848Z","iopub.status.idle":"2021-06-16T16:56:56.565072Z","shell.execute_reply.started":"2021-06-16T16:56:08.137802Z","shell.execute_reply":"2021-06-16T16:56:56.563715Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **rescale all train images and save to IMG_SIZE=512x512px jpg / save original width and height then export df**","metadata":{}},{"cell_type":"code","source":"img=None\nfor p in tqdm(path_dicom_files):\n    img_name = p.parts[-1][0:-4]\n    if img_name =='039159f7b61b':\n        print(True)\n        dcm = pydicom.dcmread(p)\n        img = dcm.pixel_array\n        if dcm.PhotometricInterpretation == \"MONOCHROME1\":\n            img = cv2.bitwise_not(img)\n        img = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)\n        img = cv2.resize(img, (WIDTH, HEIGHT), interpolation = INTERPOLATION)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T17:30:00.431474Z","iopub.execute_input":"2021-06-16T17:30:00.431828Z","iopub.status.idle":"2021-06-16T17:30:00.511029Z","shell.execute_reply.started":"2021-06-16T17:30:00.431795Z","shell.execute_reply":"2021-06-16T17:30:00.510018Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.loc[:,\"width\"] = np.nan\ndf.loc[:,\"height\"] = np.nan\n\n\nfor p in tqdm(path_dicom_files):\n    dcm = pydicom.dcmread(p)\n    img = dcm.pixel_array\n    img_name = p.parts[-1][0:-4]\n    \n    index = df[df['id'].str.contains(img_name)].index\n    df.loc[index, ['width']] = img.shape[0]\n    df.loc[index, ['height']] = img.shape[1]\n\n    if dcm.PhotometricInterpretation == \"MONOCHROME1\":\n        img = cv2.bitwise_not(img)\n    img = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)\n    img = cv2.resize(img, (WIDTH, HEIGHT), interpolation = INTERPOLATION)\n    \n    cv2.imwrite(OUTPUT_DIR+img_name+'.jpg', img)\n    \n#039159f7b61b image return error (or 920d7ef35702 )\n    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.to_csv(WORKING_DIR+'meta.csv', index = False)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T17:25:54.018502Z","iopub.execute_input":"2021-06-16T17:25:54.018995Z","iopub.status.idle":"2021-06-16T17:25:54.122429Z","shell.execute_reply.started":"2021-06-16T17:25:54.018962Z","shell.execute_reply":"2021-06-16T17:25:54.121340Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **df images with boxes**","metadata":{}},{"cell_type":"code","source":"opacity_df = df.dropna(subset = [\"boxes\"], inplace=False)\nopacity_df = opacity_df.reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T17:25:54.123825Z","iopub.execute_input":"2021-06-16T17:25:54.124179Z","iopub.status.idle":"2021-06-16T17:25:54.135645Z","shell.execute_reply.started":"2021-06-16T17:25:54.124147Z","shell.execute_reply":"2021-06-16T17:25:54.134161Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"opacity_df.sample(5)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T17:25:54.137435Z","iopub.execute_input":"2021-06-16T17:25:54.137826Z","iopub.status.idle":"2021-06-16T17:25:54.161560Z","shell.execute_reply.started":"2021-06-16T17:25:54.137794Z","shell.execute_reply":"2021-06-16T17:25:54.160607Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"opacity_df.describe()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T17:25:54.163028Z","iopub.execute_input":"2021-06-16T17:25:54.163533Z","iopub.status.idle":"2021-06-16T17:25:54.209141Z","shell.execute_reply.started":"2021-06-16T17:25:54.163439Z","shell.execute_reply":"2021-06-16T17:25:54.207892Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **convert train image boxes to wandb image for visualization**","metadata":{}},{"cell_type":"code","source":"def get_bbox(row):\n    bboxes = []\n    bbox = []\n    for i, l in enumerate(row.label.split(' ')):\n        if (i % 6 == 0) | (i % 6 == 1):\n            continue\n        bbox.append(float(l))\n        if i % 6 == 5:\n            bboxes.append(bbox)\n            bbox = []  \n            \n    return bboxes","metadata":{"execution":{"iopub.status.busy":"2021-06-16T17:25:54.210582Z","iopub.execute_input":"2021-06-16T17:25:54.210925Z","iopub.status.idle":"2021-06-16T17:25:54.217528Z","shell.execute_reply.started":"2021-06-16T17:25:54.210894Z","shell.execute_reply":"2021-06-16T17:25:54.216492Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def scale_bbox(row, bboxes):\n    scale_x = IMG_SIZE/row.width\n    scale_y = IMG_SIZE/row.height\n    \n    scaled_bboxes = []\n    for bbox in bboxes:\n        x = int(np.round(bbox[0]*scale_x, 4))\n        y = int(np.round(bbox[1]*scale_y, 4))\n        x1 = int(np.round(bbox[2]*(scale_x), 4))\n        y1= int(np.round(bbox[3]*scale_y, 4))\n\n        scaled_bboxes.append([x, y, x1, y1]) # xmin, ymin, xmax, ymax\n    \n    return scaled_bboxes","metadata":{"execution":{"iopub.status.busy":"2021-06-16T17:25:54.220956Z","iopub.execute_input":"2021-06-16T17:25:54.221295Z","iopub.status.idle":"2021-06-16T17:25:54.231685Z","shell.execute_reply.started":"2021-06-16T17:25:54.221265Z","shell.execute_reply":"2021-06-16T17:25:54.230636Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def wandb_bbox(image, bboxes, true_label, class_id_to_label):\n    all_boxes = []\n    for bbox in bboxes:\n        box_data = {\"position\": {\n                        \"minX\": bbox[0],\n                        \"minY\": bbox[1],\n                        \"maxX\": bbox[2],\n                        \"maxY\": bbox[3]\n                    },\n                     \"class_id\" : int(true_label),\n                     \"box_caption\": class_id_to_label[true_label],\n                     \"domain\" : \"pixel\"}\n        all_boxes.append(box_data)\n    \n\n    return wandb.Image(image, boxes={\n        \"ground_truth\": {\n            \"box_data\": all_boxes,\n          \"class_labels\": class_id_to_label\n        }\n    })","metadata":{"execution":{"iopub.status.busy":"2021-06-16T17:25:54.233224Z","iopub.execute_input":"2021-06-16T17:25:54.233628Z","iopub.status.idle":"2021-06-16T17:25:54.250227Z","shell.execute_reply.started":"2021-06-16T17:25:54.233595Z","shell.execute_reply":"2021-06-16T17:25:54.249292Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sampled_opacity_df = opacity_df.sample(N_IMAGES_WANDB).reset_index(drop=True)\n\nrun = wandb.init(project='project8-kaggle-covid19')\n\nwandb_bbox_list = []\nfor i in tqdm(range(sampled_opacity_df.shape[0])):\n    row = sampled_opacity_df.loc[i]\n    image = cv2.imread(row.path)\n    bboxes = get_bbox(row)\n    scale_bboxes = scale_bbox(row, bboxes)\n    true_label = row.study_level\n    wandb_bbox_list.append(wandb_bbox(image, \n                                      scale_bboxes, \n                                      true_label, \n                                      class_id_to_label))\n    \nwandb.log({\"radiograph\": wandb_bbox_list})\n\nrun.finish()\n\nrun","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **ref** \n\n* https://www.kaggle.com/xhlulu\n* https://www.kaggle.com/yujiariyasu\n* https://www.kaggle.com/ayuraj\n* https://www.kaggle.com/dschettler8845   \n....","metadata":{}}]}