Machine Learning In Healthcare: Detecting Melanoma | by Sakshi Butala | Towards Data Science

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.
Let’s start the implementation by importing the required libraries inside a Kaggle kernel as shown below:
import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsimport cv2import pydicom as dicomimport pandas as pdimport numpy as npfrom sklearn.metrics import accuracy_score, confusion_matrixfrom 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.
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()
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.
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).indexs1 = df.target[df.target.eq(1)].sample(60).indexdf = 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)
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())
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 tfimages = 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()
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 = 0for 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 LogisticRegressionX = imagesy = np.array(df['target'])classifier_lr = LogisticRegression()classifier_lr.fit(X,y)X_test = test_imagesy_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: \n',confusion_matrix(y_test,y_pred_lr))
2. Support Vector Machine
from sklearn import svmX = imagesy = np.array(df['target'])classifier_svm = svm.SVC()classifier_svm.fit(X,y)X_test = test_imagesy_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: \n',confusion_matrix(y_test,y_pred_svm))
3. Decision Tree
from sklearn.tree import DecisionTreeClassifierX = imagesy = np.array(df['target'])classifier_dt = DecisionTreeClassifier()classifier_dt.fit(X,y)X_test = test_imagesy_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: \n',confusion_matrix(y_test,y_pred_dt))
4. Random Forest
from sklearn.ensemble import RandomForestClassifierX = imagesy = np.array(df['target'])classifier_rf = RandomForestClassifier()classifier_rf.fit(X,y)X_test = test_imagesy_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: \n',confusion_matrix(y_test,y_pred_rf))
5. Adaptive Boosting
from sklearn.ensemble import AdaBoostClassifierX = imagesy = np.array(df['target'])classifier_ab = AdaBoostClassifier()classifier_ab.fit(X,y)X_test = test_imagesy_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: \n',confusion_matrix(y_test,y_pred_ab))
6. Gradient Boosting
from sklearn.ensemble import GradientBoostingClassifierX = imagesy = np.array(df['target'])classifier_gb = GradientBoostingClassifier()classifier_gb.fit(X,y)X_test = test_imagesy_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: \n',confusion_matrix(y_test,y_pred_gb))
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%.
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:        passplt.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')
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:        passsns.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')
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)
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.
age_approx, sex_male and site_upper extremity 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.
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_splitX_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_arrayplt.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:
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.