{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Intracranial Hemorrhage Detection\nThis challenge is really interesting for me, as I have a background in psychology/neuroscience. I've been working in basic research (brain connectivity, behavior etc.) in healthy participants, with greater goal to understand stroke. So this challenge is really exciting.\nI haven't worked so far with CT, but quite a lot with (f)MRI recordings. I will put together some intuitions, basically just looking at images. \n\nI am wrong somewhere, definitely possible - Please comment :)\n\n### 11th Version\nI did a little overhaul and tried to put my words into a more concise and understandable manner, as well as putting the code in order.\n\n# Content\n1. Looking at the data\n2. Hounsfield Units (and tranforming DICOMS)\n3. Windowing (What it means and some code)\n3. Resampling (Putting the images into same space)\n4. Segmentation (Extracting the brain)\n5. Croping (Deleting non-informative rows and columns)\n6. Pading (Centering the image in the middle, creating images of equal size)\n7. Normalizing the data\n9. Conclusions\n8. Crazy ideas\n9. Using histograms to classify \"any\" the presence of any kind of hemorrhage."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# Load the required packages:\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n# Tools\nfrom glob import glob\nimport os\nfrom tqdm import tqdm_notebook\nimport pydicom\n# Plotting\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n# Image procesing\nfrom scipy import ndimage\nimport scipy.misc\nfrom skimage import morphology\nfrom skimage.segmentation import slic\nfrom skimage import measure\nfrom skimage.transform import resize, warp\nfrom skimage import exposure\n# Some machine learning as a treat\nfrom sklearn.preprocessing import MaxAbsScaler\nfrom sklearn.linear_model import LogisticRegressionCV\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.model_selection import cross_val_score, StratifiedKFold","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"PATH = '../input/rsna-intracranial-hemorrhage-detection/' # Set up the path.\n# Load the stage 1 file\ntrain_csv = pd.read_csv(f'{PATH}stage_1_train.csv')\n# Create a path to the train image location:\nimage_path = os.path.join(PATH, 'stage_1_train_images') + os.sep \nprint(image_path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Check out this kernel: https://www.kaggle.com/currypurin/simple-eda \n# This is a really nice preprocessing of ID and labels :)\ntrain_csv['Image ID'] = train_csv['ID'].apply(lambda x: x.split('_')[1]) \ntrain_csv['Sub-type'] = train_csv['ID'].apply(lambda x: x.split('_')[2]) \ntrain_csv = pd.pivot_table(train_csv, index='Image ID', columns='Sub-type')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 1. Let's have a look at some of the CT images"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# find hemorrhage images:\nhem_img = train_csv.iloc[train_csv['Label']['any'].values == 1].iloc[12:16] # We will look only at a few\nplt.figure(figsize=(15,10))\nfor n, ii in enumerate(hem_img.index):\n    plt.subplot(2, 4, n + 1)\n    img = pydicom.read_file(image_path + 'ID_' + ii + '.dcm').pixel_array # Read the pixel values\n    tmp = hem_img.loc[ii]\n    plt.title(tmp.unstack().columns[tmp.unstack().values.ravel() == 1][-1]) # Hacky way to give it a title... \n    plt.imshow(img, cmap='bone')\n    plt.subplot(2, 4, n + 5)\n    plt.hist(img.ravel())\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## First Evaluation\n1. Values in the image have huge ranges. And, very different ranges (i.e. see -3000 in the fourth image). This will provide a challenge later, when we want to normalize the images to a range useful for deep learning, etc.\n2. In fMRI one would usually do some adjustment of the contrast, just to have a better look at the images (done like in this kernel: https://www.kaggle.com/robinchao/just-visualizing-images). But I learned that values in the CT images, when transformed to Hounsfield units, have an actually meaning.\n3. We see a lot of other things in the image. Halos could be the head rest, there might be some cushions in there, or even some medical equipment. I think, I might be a good idea to cut these parts out, as there might be some non-medical information in there. "},{"metadata":{},"cell_type":"markdown","source":"#### Hounsfield Units\nRescaling images to Hounsfield images units, can help us to better understand the histograms of the images. \nSee the wikipedia article:\nhttps://en.wikipedia.org/wiki/Hounsfield_scale\n\nInterestingly, there is a table which includes an interpretation for the different values, that might be quite interesting for our analysis. \n\n|Substance\t|\t| HU |\n|-------------------\t|---------------------\t|------------------\t|\n| Subdural hematoma \t| First hours         \t| +75 to +100   \t|\n|   \t|   After 3 days       \t|        +65 to +85            \t|\n| \t|  After 10-14 days     \t|         +35 to +40           \t|\n| Other blood       \t| Unclotted           \t| +13 to +50 \t|\n|      \t|  Clotted      \t|      +50 to +75            \t| \n\nAnother important value to consider is -1024 for air and values greater than 500 for foreign bodies. "},{"metadata":{},"cell_type":"markdown","source":"## 2. Rescaling to Hounsfield Units\nFortunately rescaling to Hounsfield units is easy, it's a simple linear transformation and all the important values we need for this are provided in the dicom headers (have a look at this tutorial :https://www.raddq.com/dicom-processing-segmentation-visualization-in-python/). \nWe will just need to multiply the values by the slope (`dicom.RescaleSlope`) and add the intercept (`dicom.RescaleIntercept`)."},{"metadata":{"trusted":true},"cell_type":"code","source":"def image_to_hu(image_path, image_id):\n    ''' \n    Minimally adapted from https://www.raddq.com/dicom-processing-segmentation-visualization-in-python/\n    '''\n    dicom = pydicom.read_file(image_path + 'ID_' + image_id + '.dcm')\n    image = dicom.pixel_array.astype(np.float64)\n         \n    # Convert to Hounsfield units (HU)\n    intercept = dicom.RescaleIntercept\n    slope = dicom.RescaleSlope\n    \n    if slope != 1:\n        image = slope * image.astype(np.float64)\n        image = image.astype(np.float64)\n        \n    image += np.float64(intercept)\n    \n    image[image < -1024] = -1024 # Setting values smaller than air, to air.\n    # Values smaller than -1024, are probably just outside the scanner.\n    return image, dicom","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"# find hemorrhage images:\nhem_img = train_csv.iloc[train_csv['Label']['any'].values == 1].iloc[12:16] # We will look only at a few\nplt.figure(figsize=(15,10))\nfor n, img_id in enumerate(hem_img.index):\n    plt.subplot(2, 4, n + 1)\n    img, _ = image_to_hu(image_path, img_id)\n    tmp = hem_img.loc[img_id]\n    plt.title(tmp.unstack().columns[tmp.unstack().values.ravel() == 1][-1]) # Hacky way to give it a title... \n    plt.imshow(img, cmap='bone')\n    plt.subplot(2, 4, n + 5)\n    plt.hist(img.ravel())\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 3. Windowing\nAlthough, we can interpret the values in the image now, we cannot really see anything in the image. But now we can look at a certain value range, which we now is interesting. Typically this is done by a process called windowing, where the image is basically clipped to a certain value range. Which is defined as:  \n\n$WindowLength \\pm \\frac{WindowWidth}{2}$  \n\nA range in Hounsfield Units that might be interesting to look at is a width of 80 and a center of 40, described as useful for analyses of brains (source: https://radiopaedia.org/articles/windowing-ct), as well as a width of 130 and a center of 50. \n  \n    \nAlso check out many of the other kernels that give way better explanations, for example this amazing one: https://www.kaggle.com/allunia/rsna-ih-detection-eda-baseline, which I used for the following code.  \n\n\nIn the long run, testing different windowing values."},{"metadata":{"trusted":true},"cell_type":"code","source":"def image_windowed(image, custom_center=50, custom_width=130, out_side_val=False):\n    '''\n    Important thing to note in this function: The image migth be changed in place!\n    '''\n    # see: https://www.kaggle.com/allunia/rsna-ih-detection-eda-baseline\n    min_value = custom_center - (custom_width/2)\n    max_value = custom_center + (custom_width/2)\n    \n    # Including another value for values way outside the range, to (hopefully) make segmentation processes easier. \n    out_value_min = custom_center - custom_width\n    out_value_max = custom_center + custom_width\n    \n    if out_side_val:\n        image[np.logical_and(image < min_value, image > out_value_min)] = min_value\n        image[np.logical_and(image > max_value, image < out_value_max)] = max_value\n        image[image < out_value_min] = out_value_min\n        image[image > out_value_max] = out_value_max\n    \n    else:\n        image[image < min_value] = min_value\n        image[image > max_value] = max_value\n    \n    return image","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"# find hemorrhage images:\nhem_img = train_csv.iloc[train_csv['Label']['any'].values == 1].iloc[12:16] # We will look only at a few\nplt.figure(figsize=(15,10))\nfor n, img_id in enumerate(hem_img.index):\n    plt.subplot(2, 4, n + 1)\n    img, _ = image_to_hu(image_path, img_id)\n    img = image_windowed(img, out_side_val=False)\n    tmp = hem_img.loc[img_id]\n    plt.title(tmp.unstack().columns[tmp.unstack().values.ravel() == 1][-1]) # Hacky way to give it a title... \n    plt.imshow(img, cmap='bone')\n    plt.subplot(2, 4, n + 5)\n    plt.hist(img.ravel())\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 4. Resampling\nUsually, in neuroimaging we want to make sure that the images are in the same space. The code here https://www.raddq.com/dicom-processing-segmentation-visualization-in-python/ provides a nice code snipped to resample the images. Again this requires some information which is stored in the DICOM files. I adapted the code from the tutorial so that it works for 2D. Normaly these approaches are done in 3D. However, in this challenge we are tasked to classify slices, so using a whole volume of scans might not be possible. The information is stored in `dicom.PixelSpacing`. I decided to go for isotopic pixels of 1 by 1 mm. \n\nNote: I am now drawing random images for visualization. I am also windowing the image, so that we can see something in the image."},{"metadata":{"trusted":true},"cell_type":"code","source":"def image_resample(image, dicom_header, new_spacing=[1,1]):\n    # Code from https://www.raddq.com/dicom-processing-segmentation-visualization-in-python/\n    # Adapted to work for pixels.\n    spacing = map(float, dicom_header.PixelSpacing)\n    spacing = np.array(list(spacing))\n    resize_factor = spacing / new_spacing\n    new_real_shape = image.shape * resize_factor\n    new_shape = np.round(new_real_shape)\n    real_resize_factor = new_shape / image.shape\n    new_spacing = spacing / real_resize_factor\n    \n    image = scipy.ndimage.interpolation.zoom(image, real_resize_factor)\n    \n    return image","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"tmp = train_csv.iloc[train_csv['Label']['any'].values == 1].iloc[np.random.randint(\n    train_csv.iloc[train_csv['Label']['any'].values == 1].shape[0])].name\n\nhu_img, dicom_header = image_to_hu(image_path, tmp)\nresamp_img = image_resample(hu_img, dicom_header)\n\n# Window images, for visualization\nhu_img = image_windowed(hu_img)\nresamp_img = image_windowed(resamp_img)\n\nplt.figure(figsize=(7.5, 5))\nplt.subplot(121)\nplt.imshow(hu_img, cmap='bone')\nplt.axis('off')\nplt.title(f'Orig shape\\n{hu_img.shape}')\nplt.subplot(122)\nplt.imshow(resamp_img, cmap='bone')\nplt.title(f'New shape\\n{resamp_img.shape}');\nplt.axis('off');","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 5. Segmentation\nAnother pre-processing step, that could help us in the challenge is to extract the brain, and discarding all the other information. I based the segmentation on the code from https://www.raddq.com/dicom-processing-segmentation-visualization-in-python/ . \n\nBut I learned something by now. In the previous versions I used `slic` from `skimage.segmentation`, however I realized that a simple background seperation using the windowing approach is easier and works more realiably. Further, for background seperation we do not need to use some weird criteria.  \n\nIf you have any suggestions, on how to use `skimage.morphology.dilation` or `skimage.morphology.erosion` more efficiently, I would be glad."},{"metadata":{"trusted":true},"cell_type":"code","source":"def image_background_segmentation(image_path, image_id, WW=40, WL=80, display=False):\n    img, dcm_head = image_to_hu(image_path, image_id)\n    img = image_resample(img, dcm_head)\n    img_out = img.copy()\n    # use values outside the window as well, helps with segmentation\n    img = image_windowed(img, custom_center=WW, custom_width=WL, out_side_val=True)\n    \n    # Calculate the outside values by hand (again)\n    lB = WW - WL\n    uB = WW + WL\n    \n    # Keep only values inside of the window\n    background_seperation = np.logical_and(img > lB, img < uB)\n    \n    # Get largest connected component:\n    # From https://github.com/nilearn/nilearn/blob/master/nilearn/_utils/ndimage.py\n    background_seperation = morphology.dilation(background_seperation,  np.ones((5, 5)))\n    labels, label_nb = scipy.ndimage.label(background_seperation)\n    \n    label_count = np.bincount(labels.ravel().astype(np.int))\n    # discard the 0 label\n    label_count[0] = 0\n    mask = labels == label_count.argmax()\n    \n    # Fill holes in the mask\n    mask = morphology.dilation(mask, np.ones((5, 5))) # dilate the mask for less fuzy edges\n    mask = scipy.ndimage.morphology.binary_fill_holes(mask)\n    mask = morphology.dilation(mask, np.ones((3, 3))) # dilate the mask again\n\n    if display:\n        plt.figure(figsize=(15,2.5))\n        plt.subplot(141)\n        plt.imshow(img, cmap='bone')\n        plt.title('Original Images')\n        plt.axis('off')\n\n        plt.subplot(142)\n        plt.imshow(background_seperation)\n        plt.title('Segmentation')\n        plt.axis('off')\n\n        plt.subplot(143)\n        plt.imshow(mask)\n        plt.title('Mask')\n        plt.axis('off')\n\n        plt.subplot(144)\n        plt.imshow(mask * img, cmap='bone')\n        plt.title('Image * Mask')\n        plt.suptitle(image_id)\n        plt.axis('off')\n\n    return mask * img_out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for ii in range(5):\n    tmp = train_csv.iloc[train_csv['Label']['any'].values == 1].iloc[np.random.randint(\n        train_csv.iloc[train_csv['Label']['any'].values == 1].shape[0])].name\n    masked_image = image_background_segmentation(image_path, tmp, display=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 6. Cropping\nCropping the images can now help us to create better or nicer images for a later deep neural network (or what ever)"},{"metadata":{"trusted":true},"cell_type":"code","source":"def image_crop(image):\n    # Based on this stack overflow post: https://stackoverflow.com/questions/26310873/how-do-i-crop-an-image-on-a-white-background-with-python\n    mask = image == 0\n\n    # Find the bounding box of those pixels\n    coords = np.array(np.nonzero(~mask))\n    top_left = np.min(coords, axis=1)\n    bottom_right = np.max(coords, axis=1)\n\n    out = image[top_left[0]:bottom_right[0],\n                top_left[1]:bottom_right[1]]\n    \n    return out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"plt.figure(figsize=(7.5,5))\nfor ii in range(3):\n    tmp = train_csv.iloc[train_csv['Label']['any'].values == 1].iloc[np.random.randint(\n        train_csv.iloc[train_csv['Label']['any'].values == 1].shape[0])].name\n    masked_image = image_background_segmentation(image_path, tmp, False)\n    masked_image = image_windowed(masked_image)\n    cropped_image = image_crop(masked_image)\n    plt.subplot(1, 3, ii + 1)\n    plt.imshow(cropped_image, cmap='bone')\n    plt.title(f'Image Shape:\\n{cropped_image.shape}')\n    plt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 7. Bring images back to equal spacing\n\nPading the images puts the brain in the center and keeps the resampled voxel dimensions. A further thing to test out, might be to resize the images to fill out the whole space. "},{"metadata":{"trusted":true},"cell_type":"code","source":"def image_pad(image, new_height, new_width):\n    # based on https://stackoverflow.com/questions/26310873/how-do-i-crop-an-image-on-a-white-background-with-python\n    height, width = image.shape\n\n    # make canvas\n    im_bg = np.zeros((new_height, new_width))\n\n    # Your work: Compute where it should be\n    pad_left = int( (new_width - width) / 2)\n    pad_top = int( (new_height - height) / 2)\n\n    im_bg[pad_top:pad_top + height,\n          pad_left:pad_left + width] = image\n\n    return im_bg","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"plt.figure(figsize=(7.5, 5))\nfor ii in range(3):\n    tmp = train_csv.iloc[train_csv['Label']['any'].values == 1].iloc[np.random.randint(\n        train_csv.iloc[train_csv['Label']['any'].values == 1].shape[0])].name\n    masked_image = image_background_segmentation(image_path, tmp, False)\n    masked_image = image_windowed(masked_image)\n    cropped_image = image_crop(masked_image)\n    padded_image = image_pad(cropped_image, 256, 256)\n    plt.subplot(1, 3, ii + 1)\n    plt.imshow(padded_image, cmap='bone')\n    plt.title(f'Image Shape:\\n{padded_image.shape}')\n    plt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 8. Rescaling (again)\nFinally we want to rescale the images to either be between 0 and 255 or between 0 and 1, so that the networks can work with it, or to use some pretrained networks, that assume certain value ranges. "},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(7.5, 5))\nfor ii in range(3):\n    tmp = train_csv.iloc[train_csv['Label']['any'].values == 1].iloc[np.random.randint(\n        train_csv.iloc[train_csv['Label']['any'].values == 1].shape[0])].name\n    masked_image = image_background_segmentation(image_path, tmp, False)\n    masked_image = image_windowed(masked_image)\n    cropped_image = image_crop(masked_image)\n    padded_image = image_pad(cropped_image, 256, 256)\n    padded_image = MaxAbsScaler().fit_transform(padded_image.reshape(-1, 1)).reshape([256, 256])\n    plt.subplot(2, 3, ii + 1)\n    plt.imshow(padded_image, cmap='bone')\n    plt.title(f'Image Shape:\\n{padded_image.shape}')\n    plt.axis('off')\n    plt.subplot(2, 3, ii + 4)\n    plt.hist(padded_image.ravel())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 9. Conclusion\nWe create a preprocessing pipeline in the kernel. Which might be of use to some of you, and we learned a bit about interpreting CT images and what kind of data and maybe what kind of struggles we have to expect. \n\nThere are some issues I think with the data, which I observed due to the random sampling of images, I am not sure, whether the pipeline introduced them, or they were there before:\n* In some images, the patient's head is way to big and not completely in the field of view\n* Some images have some kind of artifacts - like weird stripes all over, or deletion\n* There might be empty slices in there\n\nAs I haven't done any serious model fitting, what-so-ever with the data, I am not sure whether these weird images have an effect on the general performance. I mean there are quite a lot of images. But it might be worthwhile to be on the look out. \n"},{"metadata":{},"cell_type":"markdown","source":"# 10. Some ideas\nJust a collection of things, that might be interesting too look at.\n\n### Different spaces\nAs suggested here https://www.kaggle.com/c/rsna-intracranial-hemorrhage-detection/discussion/109365#latest-629434 - using different information about the images might be interesting. Who knows? \n\n### Pixel Values\nThe Houndfield units say something about the tissue. Histograms of the different values might be used to classify the presence of a hemorrhage."},{"metadata":{},"cell_type":"markdown","source":"## 11. Classification based on Histograms\nJust as a short run: Classify hemorrhage presence, using histogram values. "},{"metadata":{"trusted":true},"cell_type":"code","source":"hist_bins = np.array([ 0.,  5.,  10., 15., 20., 25., 30., 35., 40., 45., 50., 55., 60.,\n       65., 70., 75., 80., 85., 90., 95., 100.])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def extract_histogram(image_path, image_id, hist_bins):\n    # hu_img, dicom_header = get_pixels_hu(image_path, image_id)\n    # windowed_img = set_manual_window(hu_img.copy(), custom_center=40, custom_width=80)\n    try:\n        masked_image = image_background_segmentation(image_path, image_id, False)\n        masked_image = image_windowed(masked_image)\n        cropped_image = image_crop(masked_image)\n\n        val, _ = np.histogram(cropped_image.flatten(), bins=hist_bins)\n        tmp = val[1:-1] # Remove the first and last bin, as they are probably noisy\n        tmp = (tmp - np.mean(tmp)) / np.std(tmp) # z-score\n    except:\n        tmp=np.zeros(18)\n    return tmp ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"xTrain = np.zeros((6000, 18))\nyTrain = np.hstack([np.zeros((3000)), np.ones((3000))])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"no_hem = train_csv.iloc[train_csv['Label']['any'].values == 0].index.values\nhem = train_csv.iloc[train_csv['Label']['any'].values == 1].index.values\n\nfor ii, tmp in tqdm_notebook(enumerate(np.random.choice(no_hem, 3000, replace=False))):\n    xTrain[ii, :] = extract_histogram(image_path, tmp, hist_bins)\n\nfor ii, tmp in tqdm_notebook(enumerate(np.random.choice(hem, 3000, replace=False))):\n    xTrain[ii+3000, :] = extract_histogram(image_path, tmp, hist_bins)\n    \nxTrain[np.isnan(xTrain)] = 0 # somehow, there are some nans in there","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"from scipy.stats import ttest_ind\nplt.figure(figsize=(15,10))\nfor n, vec in enumerate(xTrain.T):\n    plt.subplot(3,6, n + 1)\n    sns.distplot(vec[yTrain==0])\n    sns.distplot(vec[yTrain==1])\n    t, p = ttest_ind(vec[yTrain==0], vec[yTrain==1])\n    plt.title(f'HU bin {hist_bins[n+1]:2.0f}, t={t:4.2f}')\n\nplt.axis('tight');","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's have a look at the different distributions. \nLooking at the t-values (of course almost everything is significant ~.~), we find the highest difference in distributions around HU 24 - 32, and 44 to 56. These values roughly correspond to older hematomas and blood. Which we would expect, when looking for hemorrhage. Maybe the image histograms can already help us to classify the presence of an hemorrhage?\n\n### Table from above\n| Substance | | HU|\n|-------------------\t|---------------------\t|------------------\t|\n| Subdural hematoma \t| First hours         \t| +75 to +100   \t|\n|   \t|   After 3 days       \t|        +65 to +85            \t|\n| \t|  After 10-14 days     \t|         +35 to +40           \t|\n| Other blood       \t| Unclotted           \t| +13 to +50 \t|\n|      \t|  Clotted      \t|      +50 to +75            \t| \n\nSource: https://en.wikipedia.org/wiki/Hounsfield_scale\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.linear_model import LogisticRegressionCV\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.model_selection import cross_val_score, StratifiedKFold\n\nSKF = StratifiedKFold(5)\n\nlogReg_score = cross_val_score(LogisticRegressionCV(cv=5), xTrain, yTrain, cv = SKF)\nrfClf_score = cross_val_score(RandomForestClassifier(n_estimators=100), xTrain, yTrain, cv = SKF)\n\nprint(f'Logistic Regression Accuracy: {np.mean(logReg_score):4.3f} +/- {np.std(logReg_score):4.3f}')\nprint(f'Random Forest Accuracy: {np.mean(rfClf_score):4.3f} +/- {np.std(rfClf_score):4.3f}')","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":1}