Machine Learning In Healthcare: Detecting Melanoma
By: Sakshi Butala
Tags: Machine Learning, Data Science, Programming, Health, Data Visualization

Machine Learning In Healthcare: Detecting Melanoma

Using the patient's diagnosis report and skin lesion images to detect whether the lesion is cancerous or non-cancerous by applying several machine learning algorithms.

Photo by National Cancer Institute on Unsplash

Skin cancer is the most common type of cancer. It occurs due to the abnormal growth of skin cells, usually on the areas exposed to sunlight. There are three major types of skin cancer — basal cell carcinoma, squamous cell carcinoma, and melanoma. Melanoma, specifically, is responsible for 75% of skin cancer deaths, despite being the least common skin cancer.

Melanoma is a deadly disease, but if caught early, most melanomas can be cured with minor surgery.

In this article, we shall identify melanoma from the patient’s diagnosis records and images of their skin lesion by applying several machine learning algorithms to classify the lesion as benign or malignant. Better detection of melanoma has the opportunity to positively impact millions of people.

Note: The following code is implemented on a Kaggle kernel using the dataset SIIM-ISIC Melanoma Classification provided by Kaggle. You can find the entire code here.

We shall follow the following steps for implementing the algorithm.

Importing Libraries

Let’s start the implementation by importing the required libraries inside a Kaggle kernel as shown below:

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

import seaborn as sns

import cv2

import pydicom as dicom

import pandas as pd

import numpy as np

from sklearn.metrics import accuracy_score, confusion_matrix

from sklearn.metrics import mean_squared_error, r2_score

The pydicom library imported, is used for working with images provided in the dataset. These images are of type DICOM (Digital Imaging and Communications in Medicine) which is the international standard to transmit, store, retrieve, print, process, and display medical imaging information.

Analyzing Dataset

The next step is to import the dataset SIIM-ISIC Melanoma Classification provided by Kaggle.

df = pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/train.csv')

df.head()

SIIM-ISIC Melanoma Classification Dataset

From the dataset given above, we can infer that classification of melanoma depends upon two things, the patient details and the image of the patient’s skin lesion. The whole process is explained below.

We take the patient’s details and skin lesion images and then apply the machine learning algorithm to detect whether or not the person suffers from cancer.

Image Classification

Let us start by detecting melanoma present in the images provided in the dataset.

Melanoma signs include:

A large brownish spot with darker speckles

A mole that changes in color, size or feel or that bleeds

A small lesion with an irregular border and portions that appear red, pink, white, blue or blue-black

A painful lesion that itches or burns

Dark lesions on your palms, soles, fingertips or toes, or on mucous membranes lining your mouth, nose, vagina or anus

Using these signs, the machine learning algorithm classifies skin lesions as benign or malignant.

Lets us start the implementation by taking a small sample of data from the entire dataset to work on.

s0 = df.target[df.target.eq(0)].sample(50).index

s1 = df.target[df.target.eq(1)].sample(60).index df = df.loc[s0.union(s1)]

df['target'].value_counts()

This is our newly generated dataset which we will use to train our machine learning models.

Lets us now take a look at the images. These images are present in the DICOM format, and therefore we use the dicom.dcmread() function provided by pydicom library to read the images.

image = '/kaggle/input/siim-isic-melanoma-classification/train/' + df['image_name'][1512] +'.dcm' ds = dicom.dcmread(image) plt.imshow(ds.pixel_array)

Picture showing the difference between malignant and benign cancer

The next step is to train our machine learning models. In order to do that, the images should first be represented in a format understood by the models. To do this, we need to convert the images into its pixelized format.

Therefore, for every image in the dataset, we read the image using dicom.dmread() and extract the pixels using ds.pixel_array. These pixels are multidimensional, and hence we convert it to a one-dimensional array using the flatten function. We then append these pixel format images in a list named images.

images = [] for x in df['image_name']:

image = '/kaggle/input/siim-isic-melanoma-classification/train/' + x +'.dcm'

ds = dicom.dcmread(image)

pixels = ds.pixel_array

images.append(pixels.flatten())

Representation of images using pixels

Now, the issue that arises is each image has a different number of pixels and therefore the generated arrays have uneven lengths. To overcome this issue, we use the padding technique that either adds extra values to the array or discards certain values to make the length of the array equal to the max length specified.

import tensorflow as tf

images = tf.keras.preprocessing.sequence.pad_sequences(

images,

maxlen = 720,

dtype = "int32",

padding = "pre",

truncating = "pre",

value = 0

)

We will also be needing a test dataset containing images to test our model. We can generate the test dataset as follows.

test = df.tail(50)

test.head()

Test Dataset

Once we have our dataset ready, we repeat the procedure shown above. That is, we first convert the images into its pixel format and then apply the padding technique so that the images have the same number of pixels.

test_images = []

count = 0 for x in test['image_name']:

image = '/kaggle/input/siim-isic-melanoma-classification/train/' + x +'.dcm'

ds = dicom.dcmread(image)

pixels = ds.pixel_array



test_images.append(pixels.flatten())

count +=1

print(count) test_images = tf.keras.preprocessing.sequence.pad_sequences(

test_images,

maxlen = 720,

dtype = "int32",

padding = "pre",

truncating = "pre",

value = 0

)

Finally, it's time to train our model.

We will be using several machine learning algorithms to train our model and then test it to view the accuracy score.

We will set the value of

X = images (list containing images in pixel format)

y = np.array(df[‘target’]) (values that state whether the lesion in the image is benign or malignant)

1. Logistic Regression

from sklearn.linear_model import LogisticRegression X = images

y = np.array(df['target'])

classifier_lr = LogisticRegression()

classifier_lr.fit(X,y) X_test = test_images

y_test = np.array(test['target'])

y_pred_lr = classifier_lr.predict(X_test) print('Accuracy Score: ',accuracy_score(y_test,y_pred_lr))

print('Confusion Matrix:

',confusion_matrix(y_test,y_pred_lr))

Accuracy given by Logistic Regression Algorithm

2. Support Vector Machine

from sklearn import svm

X = images

y = np.array(df['target'])

classifier_svm = svm.SVC()

classifier_svm.fit(X,y) X_test = test_images

y_test = np.array(test['target'])

y_pred_svm = classifier_svm.predict(X_test) print('Accuracy Score: ',accuracy_score(y_test,y_pred_svm))

print('Confusion Matrix:

',confusion_matrix(y_test,y_pred_svm))

Accuracy given by Support Vector Machine Algorithm

3. Decision Tree

from sklearn.tree import DecisionTreeClassifier

X = images

y = np.array(df['target'])

classifier_dt = DecisionTreeClassifier()

classifier_dt.fit(X,y) X_test = test_images

y_test = np.array(test['target'])

y_pred_dt = classifier_dt.predict(X_test) print('Accuracy Score: ',accuracy_score(y_test,y_pred_dt))

print('Confusion Matrix:

',confusion_matrix(y_test,y_pred_dt))

Accuracy given by Decision Tree Algorithm

4. Random Forest

from sklearn.ensemble import RandomForestClassifier

X = images

y = np.array(df['target'])

classifier_rf = RandomForestClassifier()

classifier_rf.fit(X,y) X_test = test_images

y_test = np.array(test['target'])

y_pred_rf = classifier_rf.predict(X_test) print('Accuracy Score: ',accuracy_score(y_test,y_pred_rf))

print('Confusion Matrix:

',confusion_matrix(y_test,y_pred_rf))

Accuracy given by the Random Forest Algorithm

5. Adaptive Boosting

from sklearn.ensemble import AdaBoostClassifier

X = images

y = np.array(df['target'])

classifier_ab = AdaBoostClassifier()

classifier_ab.fit(X,y) X_test = test_images

y_test = np.array(test['target'])

y_pred_ab = classifier_ab.predict(X_test) print('Accuracy Score: ',accuracy_score(y_test,y_pred_ab))

print('Confusion Matrix:

',confusion_matrix(y_test,y_pred_ab))

Accuracy given by Adaptive Boosting Algorithm

6. Gradient Boosting

from sklearn.ensemble import GradientBoostingClassifier

X = images

y = np.array(df['target'])

classifier_gb = GradientBoostingClassifier()

classifier_gb.fit(X,y) X_test = test_images

y_test = np.array(test['target'])

y_pred_gb = classifier_gb.predict(X_test) print('Accuracy Score: ',accuracy_score(y_test,y_pred_gb))

print('Confusion Matrix:

',confusion_matrix(y_test,y_pred_gb))

Accuracy given by Gradient Boosting Algorithm

After training and testing the images using several machine learning algorithms we get different accuracies. Some algorithms overfit the data while some underfit. Therefore we go forward with the Logistic Regression algorithm since it neither overfits nor underfits the data, giving an accuracy of 96%.

Bar plot showing the accuracy of obtained using the machine learning algorithms

Classification using Patient Records

Lets us start by renaming “anatom_site_general_challenge” to “site” for our convenience.

df = df.rename(columns = {'anatom_site_general_challenge':'site'})

To initiate the training of the data, we first need to understand the data. Let's apply some visualizations and data cleaning techniques to interpret our data better.

First, let us remove all the missing values from the dataset using the following code

df = df.dropna(axis=0, how = 'any')

Considering age_approx and as a factor, we can use the following code to create the graphs shown below.

age = []

for i in range(df.shape[0]):

try:

if df['target'][i] == 1:

age.append(df['age_approx'][i])

except:

pass plt.figure(figsize=(15,5)) plt.subplot(1,2,1)

sns.distplot(age)

plt.title('Distribution of age of people having malignant cancer') plt.subplot(1,2,2)

sns.countplot(y = age)

plt.ylabel('Age')

plt.title('Count plot of age of people having malignant cancer')

Graphs created using age_approx as a factor

The following points can be inferred from the above graphs:

Most patients suffering from malignant cancer fall between the age range of 40 to 80 years

The maximum number of cancer patients have age values greater than 60, followed by people having age values between 55 to 60.

The count of patients suffering from cancer and having an age value below 10 are very less.

Considering site and as a factor, we can use the following code to create the graphs shown below.

site = []

for i in range(df.shape[0]):

try:

if df['target'][i] == 1:

site.append(df['site'][i])

except:

pass sns.countplot(y = site) sns.countplot(y = site,palette="rocket")

plt.title('Graph showing count of patients having cancer and the site it is located in')

plt.ylabel('Site')

Graph created using site as a factor

The following points can be inferred from the above graphs:

Maximum patients have the skin lesion present on their torso

Very few patients have skin lesions present on their palms/sores or oral/genital places.

As you can see, the attributes sex, site and diagnosis contains categorical data. And so, we use pandas.get_dummies() to convert the categorical data into dummy or indicator variables understood by the model.

We also drop the non-required columns, benign_malignant and patient_id.

This can be done as follows:

df = pd.get_dummies(df, columns = ['sex'],drop_first=True) df = pd.get_dummies(df, columns = ['site'],drop_first=True) df = pd.get_dummies(df, columns = ['diagnosis'],drop_first=True)

df = df.drop('diagnosis_unknown', axis = 1) df = df.drop(['benign_malignant', 'patient_id'], axis = 1)

df.head()

Our dataset now contains 16 attributes. The next step is the selection of the right attributes to train our model. We can do this by finding out the correlation between the attributes and the target. To do this, let us generate a heatmap using the following code:

plt.figure(figsize = (10,10))

sns.heatmap(df.corr()[['target']].sort_values('target').tail(16), annot = True)

Heatmap showing the correlation between the attributes and the target

The following points can be inferred from the above heatmap:

diagnosis_melanoma has a direct correlation with the target value. Therefore, if a person is diagnosed with melanoma, he has cancer and if a person is not diagnosed with melanoma, he doesn’t have cancer.

has a direct correlation with the target value. Therefore, if a person is diagnosed with melanoma, he has cancer and if a person is not diagnosed with melanoma, he doesn’t have cancer. age_approx, sex_male and site_upper extremity are positively correlated with the target.

and are positively correlated with the target. diagnos_nevus, site_lower extremity and site_torso are negatively correlated with the target.

This can also be interpreted from the graphs shown below.

Graphs showing the correlation between the attributes and the target

Let us now train our machine learning models. We will be using several machine learning algorithms to train our model and then test it to view the accuracy score.

We start by creating the train and test dataset.

X = df[['diagnosis_melanoma','site_torso','diagnosis_nevus','site_lower extremity','site_upper extremity', 'sex_male', 'age_approx']] y = df['target'] from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 1)

Now we need to apply the classification algorithms which take these attributes and train the model against the target value. This can be done by using the same algorithms and the procedure used above to train the model with skin lesion images.

After successful training of the algorithms, we obtain the following accuracy scores:

As you can see, the Support Vector Machine algorithm doesn’t overfit the data and gives an accuracy of 98% we select it for further processing.

We selected the Logistic Regression algorithm for predicting cancer from images and we selected Support Vector Machine to predict cancer based on the medical details and diagnosis of the patient.

In our next and final step, we test the entire record of the patient and detect whether he or she suffers from cancer.

The patient record is as follows:

image_name = ISIC_0149568

age_approx = 55

sex_male = 0

site_lower extremity = 0

site_torso = 0

site_upper extremity = 1

diagnosis_melanoma = 1

diagnosis_nevus = 0

image_path = '/kaggle/input/siim-isic-melanoma-classification/train/ISIC_0149568.dcm'

details = [[55,0,0,0,1,1,0]]

image_to_test = []

ds = dicom.dcmread(image_path)

pixels = ds.pixel_array

plt.imshow(pixels)

image_to_test.append(pixels.flatten()) image_to_test = tf.keras.preprocessing.sequence.pad_sequences(

image_to_test,

maxlen = 720,

dtype = "int32",

padding = "pre",

truncating = "pre",

value = 0

) print(train2.predict(image_to_test)) if train1.predict(details) == [1]:



result1 = 'Malignant'

else:

result1 = 'Benign' if train2.predict(image_to_test) == [1]:

result2 = 'Malignant'

else:

result2 = 'Benign' print('Result from patient details: ', result1)

print('Result from patient image: ', result2)

image_path stores the path to the image_name

details stores the patients record details

train1 is the model trained using patients records.

train2 is the model trained using images of patients skin lesion.

After executing the code, we get the result as follows:

Output after final testing

As you can see, the algorithm correctly detected that the patient suffers from cancer. And so, we can infer that machine learning algorithms can be effectively used in the healthcare and the medical field.

Find the entire code here.

If you want to know how to classify images using neural networks instead of machine learning algorithms click here.

References