{"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":"# <div id=\"chap1\">1. Load libraries and dataframes with predictions","metadata":{}},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings('ignore')\n\nimport numpy as np\nimport pandas as pd\nimport os\nfrom tqdm import tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-05-29T19:04:13.026014Z","iopub.execute_input":"2021-05-29T19:04:13.027048Z","iopub.status.idle":"2021-05-29T19:04:13.037035Z","shell.execute_reply.started":"2021-05-29T19:04:13.02699Z","shell.execute_reply":"2021-05-29T19:04:13.035464Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport pydicom\nfrom glob import glob\nfrom tqdm.notebook import tqdm\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport matplotlib.pyplot as plt\nimport matplotlib\nfrom skimage import exposure\nimport cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport warnings\nwarnings.filterwarnings('ignore')\n\nimport tensorflow as tf\n\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.models import Sequential\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:13.100457Z","iopub.execute_input":"2021-05-29T19:04:13.101204Z","iopub.status.idle":"2021-05-29T19:04:13.110845Z","shell.execute_reply.started":"2021-05-29T19:04:13.101095Z","shell.execute_reply":"2021-05-29T19:04:13.109805Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_dir = '../input/vinbigdata-chest-xray-abnormalities-detection'","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:13.213257Z","iopub.execute_input":"2021-05-29T19:04:13.213922Z","iopub.status.idle":"2021-05-29T19:04:13.218733Z","shell.execute_reply.started":"2021-05-29T19:04:13.213873Z","shell.execute_reply":"2021-05-29T19:04:13.217711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_count = len(list(glob(f'{data_dir}/train/*.dicom')))\nprint('Image count is : ' + str(image_count))","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:13.27198Z","iopub.execute_input":"2021-05-29T19:04:13.272666Z","iopub.status.idle":"2021-05-29T19:04:13.352114Z","shell.execute_reply.started":"2021-05-29T19:04:13.272611Z","shell.execute_reply":"2021-05-29T19:04:13.35056Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Time to read the csv file\n%time\ntrain = pd.read_csv(data_dir+'/train.csv')","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:13.354879Z","iopub.execute_input":"2021-05-29T19:04:13.355368Z","iopub.status.idle":"2021-05-29T19:04:13.466683Z","shell.execute_reply.started":"2021-05-29T19:04:13.355304Z","shell.execute_reply":"2021-05-29T19:04:13.465241Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.info(memory_usage=\"deep\")","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:13.468748Z","iopub.execute_input":"2021-05-29T19:04:13.469084Z","iopub.status.idle":"2021-05-29T19:04:13.551842Z","shell.execute_reply.started":"2021-05-29T19:04:13.469054Z","shell.execute_reply":"2021-05-29T19:04:13.550261Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def dicom2array(path, voi_lut=True, fix_monochrome=True):\n    dicom = pydicom.read_file(path)\n    \n    # VOI LUT (if available by DICOM device) is used to\n    # transform raw DICOM data to \"human-friendly\" view\n    if voi_lut:\n        data = apply_voi_lut(dicom.pixel_array, dicom)\n    else:\n        data = dicom.pixel_array\n    # depending on this value, X-ray may look inverted - fix that:\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = np.amax(data) - data\n    data = data - np.min(data)\n    data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n    return data","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:13.554762Z","iopub.execute_input":"2021-05-29T19:04:13.555112Z","iopub.status.idle":"2021-05-29T19:04:13.563553Z","shell.execute_reply.started":"2021-05-29T19:04:13.555079Z","shell.execute_reply":"2021-05-29T19:04:13.562229Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_img(img, size=(7, 7), is_rgb=True, title=\"\", cmap='gray'):\n    plt.figure(figsize=size)\n    plt.imshow(img, cmap=cmap)\n    plt.suptitle(title)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:13.583317Z","iopub.execute_input":"2021-05-29T19:04:13.583728Z","iopub.status.idle":"2021-05-29T19:04:13.591Z","shell.execute_reply.started":"2021-05-29T19:04:13.583695Z","shell.execute_reply":"2021-05-29T19:04:13.589138Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_imgs(imgs, cols=4, size=7, is_rgb=True, title=\"\", cmap='gray', img_size=(500,500)):\n    rows = len(imgs)//cols + 1\n    fig = plt.figure(figsize=(cols*size, rows*size))\n    for i, img in enumerate(imgs):\n        if img_size is not None:\n            img = cv2.resize(img, img_size)\n        fig.add_subplot(rows, cols, i+1)\n        plt.imshow(img, cmap=cmap)\n    plt.suptitle(title)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:13.658111Z","iopub.execute_input":"2021-05-29T19:04:13.658527Z","iopub.status.idle":"2021-05-29T19:04:13.668059Z","shell.execute_reply.started":"2021-05-29T19:04:13.658493Z","shell.execute_reply":"2021-05-29T19:04:13.66655Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\ndicom_paths = glob(f'{data_dir}/train/*.dicom')\nimgs = [dicom2array(path) for path in dicom_paths[:12]]\n\n#Without Plot\n#12.7 seconds for 12 images\n\n#Time doesn't seem to be increasing exponentially","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:13.716834Z","iopub.execute_input":"2021-05-29T19:04:13.71724Z","iopub.status.idle":"2021-05-29T19:04:26.296946Z","shell.execute_reply.started":"2021-05-29T19:04:13.717206Z","shell.execute_reply":"2021-05-29T19:04:26.295485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\ndicom_paths = glob(f'{data_dir}/train/*.dicom')\nimgs = [dicom2array(path) for path in dicom_paths[:12]]\nplot_imgs(imgs)\n\n#With Plot\n#5 seconds for 2 images\n#11 seconds for 5 images\n#18 seconds for 12 images\n\n#Time doesn't seem to be increasing exponentially","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:26.300223Z","iopub.execute_input":"2021-05-29T19:04:26.300741Z","iopub.status.idle":"2021-05-29T19:04:41.206853Z","shell.execute_reply.started":"2021-05-29T19:04:26.300695Z","shell.execute_reply":"2021-05-29T19:04:41.205865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"imgs = [exposure.equalize_hist(img) for img in imgs]\nplot_imgs(imgs)","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:41.208089Z","iopub.execute_input":"2021-05-29T19:04:41.208549Z","iopub.status.idle":"2021-05-29T19:04:47.662284Z","shell.execute_reply.started":"2021-05-29T19:04:41.208509Z","shell.execute_reply":"2021-05-29T19:04:47.659789Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data = pd.read_csv(data_dir+'/train.csv')\ntrain_data.head()","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:47.663891Z","iopub.execute_input":"2021-05-29T19:04:47.664211Z","iopub.status.idle":"2021-05-29T19:04:47.778604Z","shell.execute_reply.started":"2021-05-29T19:04:47.664182Z","shell.execute_reply":"2021-05-29T19:04:47.777424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(1, 1, figsize=(12, 4))\nx = train_data['class_name'].value_counts().keys()\ny = train_data['class_name'].value_counts().values\nax.bar(x, y)\nax.set_xticklabels(x, rotation=90)\nax.set_title('Distribution of the labels')\nplt.grid()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:47.781565Z","iopub.execute_input":"2021-05-29T19:04:47.781878Z","iopub.status.idle":"2021-05-29T19:04:48.10457Z","shell.execute_reply.started":"2021-05-29T19:04:47.781849Z","shell.execute_reply":"2021-05-29T19:04:48.103285Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = train_data[train_data['class_name']!='No finding']\nf, ax = plt.subplots(1,1, figsize=(10,8))\ntotal = float(len(train))\nax.set_xticklabels(x, rotation=90)\nsns.countplot(train['class_name'],order = train['class_name'].value_counts().index, palette='Set3')\nfor p in ax.patches:\n    height = p.get_height()\n    ax.text(p.get_x()+p.get_width()/2.,\n            height + 3,\n            '{:1.2f}%'.format(100*height/total),\n            ha=\"center\") \n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:48.10733Z","iopub.execute_input":"2021-05-29T19:04:48.107709Z","iopub.status.idle":"2021-05-29T19:04:48.500353Z","shell.execute_reply.started":"2021-05-29T19:04:48.107676Z","shell.execute_reply":"2021-05-29T19:04:48.498973Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tmp = train.groupby(['image_id','class_name'])['image_id'].count()\ndf = pd.DataFrame(data={'Exams': tmp.values}, index=tmp.index).reset_index()\ntmp = df.groupby(['Exams','class_name']).count()\ndf2 = pd.DataFrame(data=tmp.values, index=tmp.index).reset_index()\ndf2.columns = ['Exams', 'class_name', 'Entries']\ndf2\n","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:48.50199Z","iopub.execute_input":"2021-05-29T19:04:48.502305Z","iopub.status.idle":"2021-05-29T19:04:48.558408Z","shell.execute_reply.started":"2021-05-29T19:04:48.502269Z","shell.execute_reply":"2021-05-29T19:04:48.556804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import seaborn as sns\nimport matplotlib.pyplot as plt\nfig, ax = plt.subplots(nrows=1,figsize=(12,6))\nax.set_xticklabels(x, rotation=90)\nsns.barplot(ax=ax,x = 'class_name', y='Entries', hue='Exams',data=df2, palette='Set2')\nplt.title(\"Chest examinations class and class_name\")\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:48.560221Z","iopub.execute_input":"2021-05-29T19:04:48.560682Z","iopub.status.idle":"2021-05-29T19:04:52.559104Z","shell.execute_reply.started":"2021-05-29T19:04:48.560638Z","shell.execute_reply":"2021-05-29T19:04:52.558221Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"target1 = train[train['class_name']=='Aortic enlargement']\nsns.set_style('whitegrid')\nplt.figure()\nfig, ax = plt.subplots(2,2,figsize=(12,12))\nsns.distplot(target1['x_max'],kde=True,bins=50, color=\"red\", ax=ax[0,0])\nsns.distplot(target1['y_max'],kde=True,bins=50, color=\"blue\", ax=ax[0,1])\nsns.distplot(target1['x_min'],kde=True,bins=50, color=\"green\", ax=ax[1,0])\nsns.distplot(target1['y_min'],kde=True,bins=50, color=\"magenta\", ax=ax[1,1])\nlocs, labels = plt.xticks()\nplt.tick_params(axis='both', which='major', labelsize=12)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:52.560201Z","iopub.execute_input":"2021-05-29T19:04:52.560515Z","iopub.status.idle":"2021-05-29T19:04:54.355158Z","shell.execute_reply.started":"2021-05-29T19:04:52.560485Z","shell.execute_reply":"2021-05-29T19:04:54.353688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom as dicom\n\ndef plot_example(idx_list):\n    fig, axs = plt.subplots(1, 3, figsize=(15, 10))\n    fig.subplots_adjust(hspace = .1, wspace=.1)\n    axs = axs.ravel()\n    for i in range(3):\n        image_id = train_data.loc[idx_list[i], 'image_id']\n        data_file = dicom.dcmread(data_dir+'/train/'+image_id+'.dicom')\n        img = data_file.pixel_array\n        axs[i].imshow(img, cmap='gray')\n        axs[i].set_title(train_data.loc[idx_list[i], 'class_name'])\n        axs[i].set_xticklabels([])\n        axs[i].set_yticklabels([])\n        if train_data.loc[idx_list[i], 'class_name'] != 'No finding':\n            bbox = [train_data.loc[idx_list[i], 'x_min'],\n                    train_data.loc[idx_list[i], 'y_min'],\n                    train_data.loc[idx_list[i], 'x_max'],\n                    train_data.loc[idx_list[i], 'y_max']]\n            p = matplotlib.patches.Rectangle((bbox[0], bbox[1]),\n                                             bbox[2]-bbox[0],\n                                             bbox[3]-bbox[1],\n                                             ec='r', fc='none', lw=2.)\n            axs[i].add_patch(p)\n            \nfor num in range(15):\n    idx_list = train_data[train_data['class_id']==num][0:3].index.values\n    plot_example(idx_list)","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:04:54.356946Z","iopub.execute_input":"2021-05-29T19:04:54.357293Z","iopub.status.idle":"2021-05-29T19:06:06.223012Z","shell.execute_reply.started":"2021-05-29T19:04:54.357261Z","shell.execute_reply":"2021-05-29T19:06:06.221309Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(train_data)","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:06:06.22495Z","iopub.execute_input":"2021-05-29T19:06:06.225328Z","iopub.status.idle":"2021-05-29T19:06:06.242963Z","shell.execute_reply.started":"2021-05-29T19:06:06.225295Z","shell.execute_reply":"2021-05-29T19:06:06.241272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nfrom torch import nn\nimport glob\nfrom PIL import Image\nfrom tqdm.auto import tqdm\nimport torchvision.transforms as transforms\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:06:06.244646Z","iopub.execute_input":"2021-05-29T19:06:06.244969Z","iopub.status.idle":"2021-05-29T19:06:07.515021Z","shell.execute_reply.started":"2021-05-29T19:06:06.24494Z","shell.execute_reply":"2021-05-29T19:06:07.513939Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Train Data Size : {}\".format(train_data.shape[0]))\ntrain_data.head()","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:06:07.516742Z","iopub.execute_input":"2021-05-29T19:06:07.51718Z","iopub.status.idle":"2021-05-29T19:06:07.539719Z","shell.execute_reply.started":"2021-05-29T19:06:07.517138Z","shell.execute_reply":"2021-05-29T19:06:07.538232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_labels = train_data.iloc[:,[0,2]]\nclass_labels.head()","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:06:07.541308Z","iopub.execute_input":"2021-05-29T19:06:07.541719Z","iopub.status.idle":"2021-05-29T19:06:07.559758Z","shell.execute_reply.started":"2021-05-29T19:06:07.541687Z","shell.execute_reply":"2021-05-29T19:06:07.558422Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_labels.iloc[:,0:2]\nclass_labels = class_labels.drop_duplicates(subset=[\"image_id\"])\nclass_labels.head()\nclass_labels.shape","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:06:07.561464Z","iopub.execute_input":"2021-05-29T19:06:07.561766Z","iopub.status.idle":"2021-05-29T19:06:07.592211Z","shell.execute_reply.started":"2021-05-29T19:06:07.561739Z","shell.execute_reply":"2021-05-29T19:06:07.590943Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_on_gpu = False\n\nif torch.cuda.is_available():\n    train_on_gpu = True","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:06:07.593355Z","iopub.execute_input":"2021-05-29T19:06:07.593828Z","iopub.status.idle":"2021-05-29T19:06:07.597575Z","shell.execute_reply.started":"2021-05-29T19:06:07.593785Z","shell.execute_reply":"2021-05-29T19:06:07.596773Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nclass Net(nn.Module):\n    def __init__(self):\n        super(Net, self).__init__()\n        \n        # convolutional layer (sees 512x512x3 image tensor)\n        self.conv1 = nn.Conv2d(1, 4, 3, padding=1)\n\n        # convolutional layer (sees 256x256x4 tensor)\n        self.conv2 = nn.Conv2d(4, 8, 3, padding=1)\n        \n        # max pooling layer\n        self.pool = nn.MaxPool2d(2, 2)","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:06:07.598775Z","iopub.execute_input":"2021-05-29T19:06:07.599245Z","iopub.status.idle":"2021-05-29T19:06:07.611878Z","shell.execute_reply.started":"2021-05-29T19:06:07.599214Z","shell.execute_reply":"2021-05-29T19:06:07.611071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Import outputs of each selected models\nyolo = pd.read_csv('../input/vinbigdatastack/yolov5.csv')\ndetectron = pd.read_csv('../input/vinbigdatastack/detectron2.csv')\nfasterrcnn = pd.read_csv('../input/vinbigdatastack/fasterrcnn.csv')\n\nimage_ids = yolo.image_id.values","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:06:07.615272Z","iopub.execute_input":"2021-05-29T19:06:07.615621Z","iopub.status.idle":"2021-05-29T19:06:07.709277Z","shell.execute_reply.started":"2021-05-29T19:06:07.615591Z","shell.execute_reply":"2021-05-29T19:06:07.707966Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div id=\"chap2\">2. Helper functions","metadata":{}},{"cell_type":"code","source":"def getitem(dataframe, img_id):\n    \n    pred = list(dataframe.loc[dataframe.image_id == img_id, \"PredictionString\"])[0].split(' ')\n    nb_elm = len(pred)//6\n    output = {}\n    \n    for elm in range(nb_elm):\n        output[f'elm_{elm}'] = pred[elm*6 : (elm+1)*6]\n        \n    return output\n\n\ndef sortDictByProba(dict_):\n    \n    for key in dict_.keys():\n        dict_[key] = list(map(lambda x: float(x), dict_[key]))\n    \n    # item[1][1] corresponds to the second element of the value (the confidence of the class identified)\n    return {k: v for k, v in sorted(dict_.items(), key=lambda item: item[1][1], reverse = True)}\n\n\ndef getHighestProba(*list_of_dicts, n=3):\n    \n    output = {}\n    for index, dict_ in enumerate(list_of_dicts):\n        dict_length = len(dict_)\n        for i in range(dict_length):\n            if i < n:\n                output[f\"elm_{i}_dict_{index}\"] =list(dict_.values())[i]\n                \n    return output\n\n\ndef getUnique(dict_):\n    \n    dict_length = len(dict_)\n    \n    classes_non_unique = [list(dict_.values())[index][0] for index in range(dict_length)]\n    classes_unique = list(set(classes_non_unique))\n    \n    uniques, counts = np.unique(classes_non_unique, return_counts=True)\n    duplicates = uniques[counts > 1]\n    singles = np.setdiff1d(classes_unique, duplicates)\n    \n    return singles, duplicates\n\n\ndef getKeysByValue(dictOfElements, valueToFind):\n    \n    output = list()\n    listOfItems = dictOfElements.items()\n    \n    for item  in listOfItems:\n        if item[1][0] == valueToFind:\n            output.append(item[0])\n            \n    return  output\n\n\ndef getListKeysByValue(dictOfElements, valuesToFind):\n    \n    output = []\n    \n    for value in valuesToFind:\n        output.append(getKeysByValue(dictOfElements, value))\n        \n    return output\n\n\ndef averaging(from_dict, single_keys, dupl_keys):\n    \n    output = {}\n    \n    # Infer single keys\n    if len(np.ravel(single_keys)) != 0:\n        for single in np.ravel(single_keys):\n            output[single] = from_dict[single]\n\n    # For each duplicates, get index of all occurences and average boxing\n    if len(np.ravel(dupl_keys)) != 0:\n        for index, list_of_duplicate_class in enumerate(dupl_keys):\n            probs = [] \n            boxing1 = []\n            boxing2 = []\n            boxing3 = []\n            boxing4 = []\n            \n            for elm in list_of_duplicate_class:\n                probs.append(from_dict[elm][1])\n                boxing1.append(from_dict[elm][2])\n                boxing2.append(from_dict[elm][3])\n                boxing3.append(from_dict[elm][4])\n                boxing4.append(from_dict[elm][5])\n            \n            output[f\"elm_{index}\"] = [from_dict[list_of_duplicate_class[0]][0],\n                                      np.mean(probs),\n                                      np.mean(boxing1),\n                                      np.mean(boxing2),\n                                      np.mean(boxing3),\n                                      np.mean(boxing4)]\n            \n    return output\n\n\ndef toString(pred_list):\n    castedList = []\n    for index, elm in enumerate(pred_list):\n        if index%6 == 0:\n            castedList.append(str(int(elm)))\n        else:\n            castedList.append(str(elm))\n            \n    output = \" \".join(castedList)\n    \n    return output","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:06:07.710819Z","iopub.execute_input":"2021-05-29T19:06:07.711115Z","iopub.status.idle":"2021-05-29T19:06:07.735654Z","shell.execute_reply.started":"2021-05-29T19:06:07.711088Z","shell.execute_reply":"2021-05-29T19:06:07.733867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div id=\"chap3\">3. Run ensembling with appropriate strategy","metadata":{"trusted":true}},{"cell_type":"code","source":"def main():\n    \n    output = pd.DataFrame(columns = [\"image_id\", \"PredictionString\"])\n    \n    for image_id in tqdm(image_ids):\n        \n        # For each model, get PredictionString of image_id as a dict\n        fasterrcnn_pred = getitem(fasterrcnn, image_id)\n        detectron_pred = getitem(detectron, image_id)\n        yolo_pred = getitem(yolo, image_id)  \n        \n        # Sort dicts by proba\n        sorted_fasterrcnn = sortDictByProba(fasterrcnn_pred)\n        sorted_detectron = sortDictByProba(detectron_pred)\n        sorted_yolo = sortDictByProba(yolo_pred)\n\n        # Filter dicts into one dict with at most top n probs\n        highest_probs = getHighestProba(sorted_fasterrcnn, \n                                        sorted_detectron, \n                                        sorted_yolo,\n                                        n = 3)\n        \n        # Get keys of unique and duplicates values in the filtered dict\n        singles, duplicates = getUnique(highest_probs)\n        single_keys = getListKeysByValue(highest_probs, singles)\n        dupl_keys = getListKeysByValue(highest_probs, duplicates)\n        \n        # Apply averaging strategy\n        stacked_dict = averaging(highest_probs, single_keys, dupl_keys)\n        \n        # Put string in right format\n        prediction_int = np.ravel(list(stacked_dict.values()))\n        prediction_string = toString(prediction_int)\n        \n        output = output.append({\"image_id\": image_id, \n                                \"PredictionString\": prediction_string},\n                               ignore_index=True)\n        \n    return output","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:06:07.737571Z","iopub.execute_input":"2021-05-29T19:06:07.738218Z","iopub.status.idle":"2021-05-29T19:06:07.754756Z","shell.execute_reply.started":"2021-05-29T19:06:07.738171Z","shell.execute_reply":"2021-05-29T19:06:07.75361Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <div id=\"chap4\">4. Save results","metadata":{}},{"cell_type":"code","source":"final_sub = main()\npath = '/kaggle/input/vinbigdata-chest-xray-abnormalities-detection/'\nsamp_subm = pd.read_csv(path+'sample_submission.csv')\nfinal_sub.to_csv(\"submission.csv\", index=False)\nsamp_subm.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2021-05-29T19:06:07.757649Z","iopub.execute_input":"2021-05-29T19:06:07.757974Z","iopub.status.idle":"2021-05-29T19:06:27.211709Z","shell.execute_reply.started":"2021-05-29T19:06:07.757944Z","shell.execute_reply":"2021-05-29T19:06:27.210712Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# References\n\n* <a href = \"https://medium.com/inspiredbrilliance/object-detection-through-ensemble-of-models-fed015bc1ee0\">Article on object detection through ensemble of models</a>\n* detectron2 : https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection/code?competitionId=24800&sortBy=scoreDescending\n* fasterrcnn : https://www.kaggle.com/awsaf49/vinbigdata-cxr-ad-yolov5-14-class-infer\n* yolov5 : https://www.kaggle.com/basu369victor/chest-x-ray-abnormalities-detection-submission","metadata":{}}]}