Breast Cancer Classification Using Python
By: Mugdha Paithankar
Tags: Classification Algorithms, Machine Learning, Hyperparameter Tuning, Recall, Exploratory Data Analysis

Photo by Peter Boccia on Unsplash

Breast cancer (BC) is one of the most common cancers among women in the world today.

Currently, the average risk of a woman in the United States developing breast cancer sometime in her life is about 13%, which means there is a 1 in 8 chance she will develop breast cancer!

An early diagnosis of BC can greatly improve the prognosis and chance of survival for patients. Thus an accurate identification of malignant tumors is of paramount importance.

In this article I will also go over all the steps needed to make a Data Science project complete in itself, and with the use of machine learning algorithms, ultimately build a model which accurately classifies tumors as Benign or Malignant based on the tumor shape and its geometry.

Step 1: Get the data!

I got the dataset from Kaggle. It contains 596 rows and 32 columns of tumor shape and specifications. The tumor is classified as benign or malignant based on its geometry and shape. Features are computed from a digitized image of a fine needle aspirate (FNA) of a breast mass, which is type of biopsy procedure. They describe characteristics of the cell nuclei present in the image.

The features of the dataset include:

tumor radius (mean of distances from center to points on the perimeter) texture (standard deviation of gray-scale values) perimeter area smoothness (local variation in radius lengths) compactness (perimeter² / area — 1.0) concavity (severity of concave portions of the contour) concave points (number of concave portions of the contour) symmetry fractal dimension

The mean, standard error and “worst” or largest (mean of the three largest values) of these features were computed for each image, resulting in 30 features.

Step 2: Exploratory Data Analysis (EDA)

#make a dataframe

df = pd.read_csv(‘data.csv’) #examine the shape of the data

df.shape() #get the column names

df.columns

The dataset has 569 rows and 33 columns. There are two extra columns “id” and “Unnamed: 32”. We drop Unnamed: 32 which has all Nan values.

#Drop the column with all missing values (na, NAN, NaN)

#NOTE: This drops the column Unnamed: 32 column

df = df.dropna(axis=1) #Get a count of the number of 'M' & 'B' cells

df['diagnosis'].value_counts() #Visualize this count

sns.countplot(df['diagnosis'],label="Count")

212 Malignant and 357 Benign tumors

There are now 30 features we can visualize. I decided to plot 10 features at a time. This led to 3 plots containing 10 features each. The means of all the features were plotted together, so were the standard errors and worst dimensions.

Violin plots are like density plots and unlike bar graphs with means and error bars, violin plots contain all data points which make them an excellent tool to visualize samples of small sizes.

I made violin plots and commented, based on their distribution whether that feature will be good for classification. To make violin plots for this dataset, first separate the data labels ‘M’ or ‘B’ (into y) and features (into X). Then visualize 10 features at a time.

# y includes diagnosis column with M or B values

y = df.diagnosis # drop the column 'id' as it is does not convey any useful info

# drop diagnosis since we are separating labels and features

list = [‘id’,’diagnosis’] # X includes our features

X = df.drop(list,axis = 1) # get the first ten features

data_dia = y

data = X

data_std = (data — data.mean()) / (data.std()) # standardization

# get the first 10 features

data = pd.concat([y,data_std.iloc[:,0:10]],axis=1)

data = pd.melt(data,id_vars=”diagnosis”,

var_name=”features”,

value_name=’value’) # make a violin plot

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

sns.violinplot(x=”features”, y=”value”, hue=”diagnosis”, data=data,split=True, inner=”quart”)

plt.xticks(rotation=90)

Violin plot displaying all the mean features

The median of texture_mean for Malignant and Benign looks separated, so it might be a good feature for classification. For fractal_dimension_mean, the medians of the Malignant and Benign groups are very close to each other.

Violin plot displaying all the standard error features

The medians for almost all Malignant or Benign don’t vary much for the standard error features above, except for concave points_se and concavity_se. smoothness_se or symmetry_se have a very similar distribution which could make classification using this feature difficult. The shape of the violin plot for area_se looks warped and the distribution of data points for benign and malignant very different!

Violin plot displaying all the worst dimension features

area_worst look well separated, so it might be easier to use this feature for classification! Variance seems highest for fractal_dimension_worst. concavity_worst and concave_points_worst seem to have a similar data distribution.

In order to check the correlation between the features, I plotted a correlation matrix. It is effective in summarizing a large amount of data where the goal is to see patterns.

#correlation map

f,ax = plt.subplots(figsize=(18, 18))

matrix = np.triu(X.corr())

sns.heatmap(X.corr(), annot=True, linewidths=.5, fmt= ‘.1f’,ax=ax, mask=matrix)

Correlation heatmap of all the features

The means, std errors and worst dimension lengths of compactness, concavity and concave points of tumors are highly correlated amongst each other (correlation > 0.8). The mean, std errors and worst dimensions of radius, perimeter and area of tumors have a correlation of 1! texture_mean and texture_worst have a correlation of 0.9. area_worst and area_mean have a correlation of 1.

By now we have a rough idea that many of the features are highly correlated amongst each other. But what about correlation between the benign and malignant groups for each feature? In order to understand if there is a difference between the data distribution for malignant and benign groups, I visualized some features via box plots and performed a t test to detect statistical significance.

Box plots succinctly compare multiple distributions and are a great way to visualize the IQR.