{"cells":[{"metadata":{},"cell_type":"markdown","source":"# SIIM-ISIC Melanoma Classification\n\nIn this competition, we have been tasked with identifying melanoma in images of skin lesions. In particular, images within the same patient can be used to determine which are likely to represent a melanoma. Using patient-level contextual information may help the development of image analysis tools, which could better support clinical dermatologists.\n\nMelanoma is a deadly disease, but if caught early, most melanomas can be cured with minor surgery. Image analysis tools that automate the diagnosis of melanoma will improve dermatologists' diagnostic accuracy. Better detection of melanoma has the opportunity to positively impact millions of people.\n","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Exploratory Data Analysis","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport pydicom\nfrom skimage.transform import resize\nimport random\nimport os\n\nprint(\"List of directories:\")\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    print(dirname)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"test_dir = '/kaggle/input/siim-isic-melanoma-classification/test'\ntrain_dir = '/kaggle/input/siim-isic-melanoma-classification/train'\ntest_images = []\ntrain_images = []\nfor dirname, _, filenames in os.walk(test_dir):\n    for filename in filenames:\n        test_images.append(filename)\nfor dirname, _, filenames in os.walk(train_dir):\n    for filename in filenames:\n        train_images.append(filename)\nprint(f\"The number of train images are: {len(train_images)}\")\nprint(f\"The number of test images are: {len(test_images)}\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Visualizing DICOM images\n\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Checking the metadata of one DICOM image from the training set\nimage_number = random.randint(0, len(train_images))\nimage_dcm = pydicom.dcmread(os.path.join(train_dir, train_images[image_number]))\nimage_dcm","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Example image from training set\nimage_example = image_dcm.pixel_array\nprint(f\"Shape of image: {image_example.shape}\")\nplt.imshow(image_example, interpolation='nearest')\nplt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Train images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Let's look at multiple images from the training set resized to represent what will be input to a model e.g. ResNet50\nIMG_SIZE = 224\nselected_images = random.sample(range(len(train_images)), 16)\nfig, ax = plt.subplots(4, 4, figsize=(20, 16))\nax = ax.flatten()\nfor a, i in zip(range(16), selected_images):\n    dcm = pydicom.dcmread(os.path.join(train_dir, train_images[i]))\n    image = dcm.pixel_array\n    resized_img = resize(image, (IMG_SIZE, IMG_SIZE), anti_aliasing=True)\n    ax[a].imshow(resized_img, interpolation='nearest')\n    ax[a].axis('off')\n    ax[a].set_title('Image #{}'.format(i))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# The intensity distributions for these images\nfig, ax = plt.subplots(4, 4, figsize=(20, 16))\nax = ax.flatten()\nfor a, i in zip(range(16), selected_images):\n    dcm = pydicom.dcmread(os.path.join(train_dir, train_images[i]))\n    image = dcm.pixel_array\n    resized_img = resize(image, (IMG_SIZE, IMG_SIZE), anti_aliasing=True)\n    ax[a].hist(resized_img[:,:,0].ravel(), bins=50, color='red', alpha=0.3)\n    ax[a].hist(resized_img[:,:,1].ravel(), bins=50, color='green', alpha=0.3)\n    ax[a].hist(resized_img[:,:,2].ravel(), bins=50, color='blue', alpha=0.3)\n    ax[a].set_xlim((0,1))\n    ax[a].set_title('Image #{}'.format(i))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Test images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = 224\nselected_images = random.sample(range(len(test_images)), 16)\nfig, ax = plt.subplots(4, 4, figsize=(20, 16))\nax = ax.flatten()\nfor a, i in zip(range(16), selected_images):\n    dcm = pydicom.dcmread(os.path.join(test_dir, test_images[i]))\n    image = dcm.pixel_array\n    resized_img = resize(image, (IMG_SIZE, IMG_SIZE), anti_aliasing=True)\n    ax[a].imshow(resized_img, interpolation='nearest')\n    ax[a].axis('off')\n    ax[a].set_title('Image #{}'.format(i))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# The intensity distributions for these images\nfig, ax = plt.subplots(4, 4, figsize=(20, 16))\nax = ax.flatten()\nfor a, i in zip(range(16), selected_images):\n    dcm = pydicom.dcmread(os.path.join(test_dir, test_images[i]))\n    image = dcm.pixel_array\n    resized_img = resize(image, (IMG_SIZE, IMG_SIZE), anti_aliasing=True) \n    ax[a].hist(resized_img[:,:,0].ravel(), bins=50, color='red', alpha=0.5)\n    ax[a].hist(resized_img[:,:,1].ravel(), bins=50, color='green', alpha=0.5)\n    ax[a].hist(resized_img[:,:,2].ravel(), bins=50, color='blue', alpha=0.5)\n    ax[a].set_xlim((0,1))\n    ax[a].set_title('Image #{}'.format(i))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Analyzing train and set datasets","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/train.csv')\ntest = pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/test.csv')\nprint(f\"Train data: {train.shape}\\nTest data: {test.shape}\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Training dataset","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.patient_id.nunique()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"So, there are 33126 images for 2056 patients.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train.sex.value_counts())\nprint(train.sex.value_counts(normalize=True))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train['images_per_patient'] = train.groupby('patient_id')['patient_id'].transform('count')\nprint(f\"The number of images per patient is in the range {train.images_per_patient.min()}:{train.images_per_patient.max()}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(12,6))\ntrain['age_approx'].value_counts().sort_index().plot(kind='bar')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train['diagnosis'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train['benign_malignant'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(pd.crosstab(train['benign_malignant'], train['sex']))\nprint(\"\\n\")\nprint(pd.crosstab(train['benign_malignant'], train['sex'], normalize='columns'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"age_mal = train['age_approx'][train.benign_malignant==\"malignant\"].value_counts().sort_index()\nage_mal_prop = train['age_approx'][train.benign_malignant==\"malignant\"].value_counts(normalize=True).sort_index()\nfig, ax = plt.subplots(1, 2, figsize=(16, 6))\nax[0].bar(age_mal.index,age_mal.values, width=3)\nax[0].set_xlabel('Approx age of patients')\nax[0].set_ylabel('Number of malignancies')\nax[1].bar(age_mal_prop.index,age_mal_prop.values, width=3)\nax[1].set_xlabel('Approx age of patients')\nax[1].set_ylabel('Proportion of malignancies')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(pd.crosstab(train['benign_malignant'], train['age_approx'], normalize='columns'))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"For patients above the age of 60 there is at least a 2% chance that the image contains a malignant diagnosis.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train.anatom_site_general_challenge.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(pd.crosstab(train['benign_malignant'], train['anatom_site_general_challenge'], normalize='columns'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pos_mal = train['anatom_site_general_challenge'][train.benign_malignant==\"malignant\"].value_counts()\npos_mal_prop = train['anatom_site_general_challenge'][train.benign_malignant==\"malignant\"].value_counts(normalize=True)\nfig, ax = plt.subplots(1, 2, figsize=(20, 6))\nax[0].bar(pos_mal.index,pos_mal.values)\nax[0].set_xlabel('Anatomical location')\nax[0].set_ylabel('Number of malignancies')\nax[1].bar(pos_mal_prop.index,pos_mal_prop.values)\nax[1].set_xlabel('Anatomical location')\nax[1].set_ylabel('Proportion of malignancies')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"new_cols = ['unknown', 'nevus', 'melanoma', 'seborrheic keratosis', 'lentigo NOS', 'lichenoid keratosis', 'solar lentigo', 'cafe-au-lait macule', \n            'atypical melanocytic proliferation']\nfor col in new_cols:\n    train[col] = np.where(train['diagnosis']==col, 1, 0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.tail(10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.melanoma.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train['conditions_per_patient'] = 0\nfor i, pid in enumerate(train.patient_id.unique()):\n    cond = 0\n    for col in new_cols[1:]:\n        cond += np.where(train.loc[train['patient_id'] == pid, col].sum(axis=0) == 0, 0, 1)\n    train.loc[train['patient_id'] == pid, 'conditions_per_patient'] = cond","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.groupby('patient_id').first()['conditions_per_patient'].value_counts().sort_index().plot(kind='bar')\nplt.xlabel('Number of conditions')\nplt.ylabel('Number of patients')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.groupby('patient_id').first()['conditions_per_patient'].value_counts().sort_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mel = [image_name + '.jpg' for image_name in train[train.melanoma==1].image_name]\nnonmel = [image_name + '.jpg' for image_name in train[train.melanoma==0].image_name]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"jpg_dir = '/kaggle/input/siim-isic-melanoma-classification/jpeg/train'\njpg_dir_test = '/kaggle/input/siim-isic-melanoma-classification/jpeg/test'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Random image\nnum = random.randint(0, len(mel))\nimage_jpg = plt.imread(os.path.join(jpg_dir, mel[num]))\nplt.imshow(image_jpg, interpolation='nearest')\nplt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Random images selected for melanoma and without melanoma\nnum_images = 4\nmel_images = random.sample(range(len(mel)), num_images)\nnonmel_images = random.sample(range(len(mel)), num_images)\nfig, ax = plt.subplots(2, 4, figsize=(16, 9))\nax = ax.flatten()\nfor i in range(num_images):\n    img = plt.imread(os.path.join(jpg_dir, mel[mel_images[i]]))\n    img = resize(img, (IMG_SIZE, IMG_SIZE), anti_aliasing=True)\n    ax[i].imshow(img, interpolation='nearest')\n    ax[i].axis('off')\n    ax[i].set_title('Melanoma = 1')\nfor i in range(num_images):\n    img = plt.imread(os.path.join(jpg_dir, nonmel[nonmel_images[i]]))\n    img = resize(img, (IMG_SIZE, IMG_SIZE), anti_aliasing=True)\n    ax[i+4].imshow(img, interpolation='nearest')\n    ax[i+4].axis('off')\n    ax[i+4].set_title('Melanoma = 0')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, ax = plt.subplots(2, 4, figsize=(20, 12))\nax = ax.flatten()\nfor i in range(num_images):\n    img = plt.imread(os.path.join(jpg_dir, mel[mel_images[i]]))\n    img = resize(img, (IMG_SIZE, IMG_SIZE), anti_aliasing=True)\n    ax[i].hist(img[:,:,0].ravel(), bins=50, color='red', alpha=0.3)\n    ax[i].hist(img[:,:,1].ravel(), bins=50, color='green', alpha=0.3)\n    ax[i].hist(img[:,:,2].ravel(), bins=50, color='blue', alpha=0.3)\n    ax[i].set_xlim((0,1))\n    ax[i].set_title('Melanoma = 1')\nfor i in range(num_images):\n    img = plt.imread(os.path.join(jpg_dir, nonmel[nonmel_images[i]]))\n    img = resize(img, (IMG_SIZE, IMG_SIZE), anti_aliasing=True)\n    ax[i+4].hist(img[:,:,0].ravel(), bins=50, color='red', alpha=0.3)\n    ax[i+4].hist(img[:,:,1].ravel(), bins=50, color='green', alpha=0.3)\n    ax[i+4].hist(img[:,:,2].ravel(), bins=50, color='blue', alpha=0.3)\n    ax[i+4].set_xlim((0,1))\n    ax[i+4].set_title('Melanoma = 0')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Test dataset","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"test.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test.patient_id.nunique()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There are 10982 images for 690 patients in the test set","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print(test.sex.value_counts())\nprint(test.sex.value_counts(normalize=True))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test['images_per_patient'] = test.groupby('patient_id')['patient_id'].transform('count')\nprint(f\"The number of images per patient is in the range {test.images_per_patient.min()}:{test.images_per_patient.max()}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(12,6))\ntest['age_approx'].value_counts().sort_index().plot(kind='bar')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(8,6))\ntest.anatom_site_general_challenge.value_counts().plot(kind='bar')\nplt.ylabel('Number of images')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Let's look at a small sample of test images with their intensity distributions\nimg_test = [image_name + '.jpg' for image_name in test.image_name]\njpg_test_images = random.sample(range(len(test_images)), num_images)\nfig, ax = plt.subplots(2, 4, figsize=(20, 10))\nax = ax.flatten()\nfor a, i in zip(range(num_images), jpg_test_images):\n    img = plt.imread(os.path.join(jpg_dir_test, img_test[i]))\n    resized_img = resize(img, (IMG_SIZE, IMG_SIZE), anti_aliasing=True)\n    ax[a].imshow(resized_img, interpolation='nearest')\n    ax[a].axis('off')\n    ax[a].set_title('Image #{}'.format(i))\nfor a, i in zip(range(num_images), jpg_test_images):\n    img = plt.imread(os.path.join(jpg_dir_test, img_test[i]))\n    resized_img = resize(img, (IMG_SIZE, IMG_SIZE), anti_aliasing=True)\n    ax[a+4].hist(resized_img[:,:,0].ravel(), bins=50, color='red', alpha=0.3)\n    ax[a+4].hist(resized_img[:,:,1].ravel(), bins=50, color='green', alpha=0.3)\n    ax[a+4].hist(resized_img[:,:,2].ravel(), bins=50, color='blue', alpha=0.3)\n    ax[a+4].set_title('Image #{}'.format(i))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* The gender ratio is different in the test set (57:43) compared to the train set (52:48)\n* The age distribution appears to be similar\n* The anatomical site has the same sequence when sorted\n* On the whole, the test set has similar distributions of variables as in the train set","execution_count":null}],"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":4}