<h1>Table of Contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Introduction" data-toc-modified-id="Introduction-1">Introduction</a></span></li><li><span><a href="#Exploratory-Data-Analysis" data-toc-modified-id="Exploratory-Data-Analysis-2">Exploratory Data Analysis</a></span></li><li><span><a href="#Feature-Scaling" data-toc-modified-id="Feature-Scaling-3">Feature Scaling</a></span></li><li><span><a href="#Principal-Component-Analysis" data-toc-modified-id="Principal-Component-Analysis-4">Principal Component Analysis</a></span><ul class="toc-item"><li><span><a href="#How-many-prinicpal-components?" data-toc-modified-id="How-many-prinicpal-components?-4.1">How many prinicpal components?</a></span></li><li><span><a href="#Compare-variation-with-different-number-of-PCs" data-toc-modified-id="Compare-variation-with-different-number-of-PCs-4.2">Compare variation with different number of PCs</a></span></li></ul></li><li><span><a href="#Principal-component-intuition" data-toc-modified-id="Principal-component-intuition-5">Principal component intuition</a></span></li></ul></div>

# Introduction
I would like to demonstrate how to use principal component analysis to reduce the dimensionality of a dataset, specifically the **breast_cancer** dataset from the scikit-learn package.
This example is inspired from the following course, where it is covered: [Python for Data Science and Machine Learning Bootcamp](https://www.udemy.com/course/python-for-data-science-and-machine-learning-bootcamp/).


```python
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline

from sklearn import datasets
```

# Exploratory Data Analysis


```python
cancer_data = datasets.load_breast_cancer()

print(f"Keys of the cancer dataset are: \n {list(cancer_data.keys())}")
```

    Keys of the cancer dataset are: 
     ['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename']


The input data, or observations of the characteristics of the tumours is found in the dataset using: 
```
> cancer_data['data']
```
Whilst the response variable, if the cancer is malignant (0) or benign (1), can be found in the target variable, found using:
```
> cancer_data['target']
```
Let's inspect the input data:


```python
print(f"Shape of data is: {cancer_data['data'].shape}")
```

    Shape of data is: (569, 30)



```python
print(f"First few observations of the target variable are: \n {cancer_data['target'][:10]}. "
      f"\n \n The unique values are: \n {np.unique(cancer_data['target'])}")
```

    First few observations of the target variable are: 
     [0 0 0 0 0 0 0 0 0 0]. 
     
     The unique values are: 
     [0 1]


Let's inspect the input data:


```python
pd.DataFrame(cancer_data['data'],
             columns=cancer_data['feature_names']).head(3)
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>mean radius</th>
      <th>mean texture</th>
      <th>mean perimeter</th>
      <th>mean area</th>
      <th>mean smoothness</th>
      <th>mean compactness</th>
      <th>mean concavity</th>
      <th>mean concave points</th>
      <th>mean symmetry</th>
      <th>mean fractal dimension</th>
      <th>...</th>
      <th>worst radius</th>
      <th>worst texture</th>
      <th>worst perimeter</th>
      <th>worst area</th>
      <th>worst smoothness</th>
      <th>worst compactness</th>
      <th>worst concavity</th>
      <th>worst concave points</th>
      <th>worst symmetry</th>
      <th>worst fractal dimension</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>17.99</td>
      <td>10.38</td>
      <td>122.8</td>
      <td>1001.0</td>
      <td>0.11840</td>
      <td>0.27760</td>
      <td>0.3001</td>
      <td>0.14710</td>
      <td>0.2419</td>
      <td>0.07871</td>
      <td>...</td>
      <td>25.38</td>
      <td>17.33</td>
      <td>184.6</td>
      <td>2019.0</td>
      <td>0.1622</td>
      <td>0.6656</td>
      <td>0.7119</td>
      <td>0.2654</td>
      <td>0.4601</td>
      <td>0.11890</td>
    </tr>
    <tr>
      <th>1</th>
      <td>20.57</td>
      <td>17.77</td>
      <td>132.9</td>
      <td>1326.0</td>
      <td>0.08474</td>
      <td>0.07864</td>
      <td>0.0869</td>
      <td>0.07017</td>
      <td>0.1812</td>
      <td>0.05667</td>
      <td>...</td>
      <td>24.99</td>
      <td>23.41</td>
      <td>158.8</td>
      <td>1956.0</td>
      <td>0.1238</td>
      <td>0.1866</td>
      <td>0.2416</td>
      <td>0.1860</td>
      <td>0.2750</td>
      <td>0.08902</td>
    </tr>
    <tr>
      <th>2</th>
      <td>19.69</td>
      <td>21.25</td>
      <td>130.0</td>
      <td>1203.0</td>
      <td>0.10960</td>
      <td>0.15990</td>
      <td>0.1974</td>
      <td>0.12790</td>
      <td>0.2069</td>
      <td>0.05999</td>
      <td>...</td>
      <td>23.57</td>
      <td>25.53</td>
      <td>152.5</td>
      <td>1709.0</td>
      <td>0.1444</td>
      <td>0.4245</td>
      <td>0.4504</td>
      <td>0.2430</td>
      <td>0.3613</td>
      <td>0.08758</td>
    </tr>
  </tbody>
</table>
<p>3 rows × 30 columns</p>
</div>



# Feature Scaling
As we can see above, the scales of all of the variables in the data are not similar, therefore we need to carry out feature scaling (also known as normalisation and standardisation). This is crucial to ensure that significant values (such as mean area, when compared to mean smoothness) do  not dominate the model due to their large magnitude.

We will use the scaling tool build into **scikit-learn**, StandardScaler, to scale each feature and ensure it has single unit variance. We will carry out these steps below.


```python
from sklearn.preprocessing import StandardScaler
cancer_input = cancer_data['data']

scaler = StandardScaler()
scaler.fit(cancer_input)
cancer_scaled = scaler.transform(cancer_input)
```

Now we can see the scaled data, and compare it with the original values from above.


```python
pd.DataFrame(data=cancer_scaled, 
             columns=cancer_data['feature_names']).head(3)
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>mean radius</th>
      <th>mean texture</th>
      <th>mean perimeter</th>
      <th>mean area</th>
      <th>mean smoothness</th>
      <th>mean compactness</th>
      <th>mean concavity</th>
      <th>mean concave points</th>
      <th>mean symmetry</th>
      <th>mean fractal dimension</th>
      <th>...</th>
      <th>worst radius</th>
      <th>worst texture</th>
      <th>worst perimeter</th>
      <th>worst area</th>
      <th>worst smoothness</th>
      <th>worst compactness</th>
      <th>worst concavity</th>
      <th>worst concave points</th>
      <th>worst symmetry</th>
      <th>worst fractal dimension</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>1.097064</td>
      <td>-2.073335</td>
      <td>1.269934</td>
      <td>0.984375</td>
      <td>1.568466</td>
      <td>3.283515</td>
      <td>2.652874</td>
      <td>2.532475</td>
      <td>2.217515</td>
      <td>2.255747</td>
      <td>...</td>
      <td>1.886690</td>
      <td>-1.359293</td>
      <td>2.303601</td>
      <td>2.001237</td>
      <td>1.307686</td>
      <td>2.616665</td>
      <td>2.109526</td>
      <td>2.296076</td>
      <td>2.750622</td>
      <td>1.937015</td>
    </tr>
    <tr>
      <th>1</th>
      <td>1.829821</td>
      <td>-0.353632</td>
      <td>1.685955</td>
      <td>1.908708</td>
      <td>-0.826962</td>
      <td>-0.487072</td>
      <td>-0.023846</td>
      <td>0.548144</td>
      <td>0.001392</td>
      <td>-0.868652</td>
      <td>...</td>
      <td>1.805927</td>
      <td>-0.369203</td>
      <td>1.535126</td>
      <td>1.890489</td>
      <td>-0.375612</td>
      <td>-0.430444</td>
      <td>-0.146749</td>
      <td>1.087084</td>
      <td>-0.243890</td>
      <td>0.281190</td>
    </tr>
    <tr>
      <th>2</th>
      <td>1.579888</td>
      <td>0.456187</td>
      <td>1.566503</td>
      <td>1.558884</td>
      <td>0.942210</td>
      <td>1.052926</td>
      <td>1.363478</td>
      <td>2.037231</td>
      <td>0.939685</td>
      <td>-0.398008</td>
      <td>...</td>
      <td>1.511870</td>
      <td>-0.023974</td>
      <td>1.347475</td>
      <td>1.456285</td>
      <td>0.527407</td>
      <td>1.082932</td>
      <td>0.854974</td>
      <td>1.955000</td>
      <td>1.152255</td>
      <td>0.201391</td>
    </tr>
  </tbody>
</table>
<p>3 rows × 30 columns</p>
</div>



To check that the data has unit variance, and mean centred around zero, we can look at the describe method on the dataframe, and confirm the features have been scaled to have a mean of zero, and a standard deviation of 1.


```python
pd.DataFrame(data=cancer_scaled, 
             columns=cancer_data['feature_names']).describe()
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>mean radius</th>
      <th>mean texture</th>
      <th>mean perimeter</th>
      <th>mean area</th>
      <th>mean smoothness</th>
      <th>mean compactness</th>
      <th>mean concavity</th>
      <th>mean concave points</th>
      <th>mean symmetry</th>
      <th>mean fractal dimension</th>
      <th>...</th>
      <th>worst radius</th>
      <th>worst texture</th>
      <th>worst perimeter</th>
      <th>worst area</th>
      <th>worst smoothness</th>
      <th>worst compactness</th>
      <th>worst concavity</th>
      <th>worst concave points</th>
      <th>worst symmetry</th>
      <th>worst fractal dimension</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>count</th>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>...</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
      <td>5.690000e+02</td>
    </tr>
    <tr>
      <th>mean</th>
      <td>-3.162867e-15</td>
      <td>-6.530609e-15</td>
      <td>-7.078891e-16</td>
      <td>-8.799835e-16</td>
      <td>6.132177e-15</td>
      <td>-1.120369e-15</td>
      <td>-4.421380e-16</td>
      <td>9.732500e-16</td>
      <td>-1.971670e-15</td>
      <td>-1.453631e-15</td>
      <td>...</td>
      <td>-2.333224e-15</td>
      <td>1.763674e-15</td>
      <td>-1.198026e-15</td>
      <td>5.049661e-16</td>
      <td>-5.213170e-15</td>
      <td>-2.174788e-15</td>
      <td>6.856456e-16</td>
      <td>-1.412656e-16</td>
      <td>-2.289567e-15</td>
      <td>2.575171e-15</td>
    </tr>
    <tr>
      <th>std</th>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>...</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
      <td>1.000880e+00</td>
    </tr>
    <tr>
      <th>min</th>
      <td>-2.029648e+00</td>
      <td>-2.229249e+00</td>
      <td>-1.984504e+00</td>
      <td>-1.454443e+00</td>
      <td>-3.112085e+00</td>
      <td>-1.610136e+00</td>
      <td>-1.114873e+00</td>
      <td>-1.261820e+00</td>
      <td>-2.744117e+00</td>
      <td>-1.819865e+00</td>
      <td>...</td>
      <td>-1.726901e+00</td>
      <td>-2.223994e+00</td>
      <td>-1.693361e+00</td>
      <td>-1.222423e+00</td>
      <td>-2.682695e+00</td>
      <td>-1.443878e+00</td>
      <td>-1.305831e+00</td>
      <td>-1.745063e+00</td>
      <td>-2.160960e+00</td>
      <td>-1.601839e+00</td>
    </tr>
    <tr>
      <th>25%</th>
      <td>-6.893853e-01</td>
      <td>-7.259631e-01</td>
      <td>-6.919555e-01</td>
      <td>-6.671955e-01</td>
      <td>-7.109628e-01</td>
      <td>-7.470860e-01</td>
      <td>-7.437479e-01</td>
      <td>-7.379438e-01</td>
      <td>-7.032397e-01</td>
      <td>-7.226392e-01</td>
      <td>...</td>
      <td>-6.749213e-01</td>
      <td>-7.486293e-01</td>
      <td>-6.895783e-01</td>
      <td>-6.421359e-01</td>
      <td>-6.912304e-01</td>
      <td>-6.810833e-01</td>
      <td>-7.565142e-01</td>
      <td>-7.563999e-01</td>
      <td>-6.418637e-01</td>
      <td>-6.919118e-01</td>
    </tr>
    <tr>
      <th>50%</th>
      <td>-2.150816e-01</td>
      <td>-1.046362e-01</td>
      <td>-2.359800e-01</td>
      <td>-2.951869e-01</td>
      <td>-3.489108e-02</td>
      <td>-2.219405e-01</td>
      <td>-3.422399e-01</td>
      <td>-3.977212e-01</td>
      <td>-7.162650e-02</td>
      <td>-1.782793e-01</td>
      <td>...</td>
      <td>-2.690395e-01</td>
      <td>-4.351564e-02</td>
      <td>-2.859802e-01</td>
      <td>-3.411812e-01</td>
      <td>-4.684277e-02</td>
      <td>-2.695009e-01</td>
      <td>-2.182321e-01</td>
      <td>-2.234689e-01</td>
      <td>-1.274095e-01</td>
      <td>-2.164441e-01</td>
    </tr>
    <tr>
      <th>75%</th>
      <td>4.693926e-01</td>
      <td>5.841756e-01</td>
      <td>4.996769e-01</td>
      <td>3.635073e-01</td>
      <td>6.361990e-01</td>
      <td>4.938569e-01</td>
      <td>5.260619e-01</td>
      <td>6.469351e-01</td>
      <td>5.307792e-01</td>
      <td>4.709834e-01</td>
      <td>...</td>
      <td>5.220158e-01</td>
      <td>6.583411e-01</td>
      <td>5.402790e-01</td>
      <td>3.575891e-01</td>
      <td>5.975448e-01</td>
      <td>5.396688e-01</td>
      <td>5.311411e-01</td>
      <td>7.125100e-01</td>
      <td>4.501382e-01</td>
      <td>4.507624e-01</td>
    </tr>
    <tr>
      <th>max</th>
      <td>3.971288e+00</td>
      <td>4.651889e+00</td>
      <td>3.976130e+00</td>
      <td>5.250529e+00</td>
      <td>4.770911e+00</td>
      <td>4.568425e+00</td>
      <td>4.243589e+00</td>
      <td>3.927930e+00</td>
      <td>4.484751e+00</td>
      <td>4.910919e+00</td>
      <td>...</td>
      <td>4.094189e+00</td>
      <td>3.885905e+00</td>
      <td>4.287337e+00</td>
      <td>5.930172e+00</td>
      <td>3.955374e+00</td>
      <td>5.112877e+00</td>
      <td>4.700669e+00</td>
      <td>2.685877e+00</td>
      <td>6.046041e+00</td>
      <td>6.846856e+00</td>
    </tr>
  </tbody>
</table>
<p>8 rows × 30 columns</p>
</div>



We can confirm the data has been scaled as reported above.

Furthermore, there are many features in the dataset, and we'd like to get a better intuition for which features are important in determining if a tumour is malignant or benign.

In this case, we will attempt to reduce the dimensionality of the data using principal component analysis whilst still retaining as much of the original variation in the data as possible.

# Principal Component Analysis

Generally it is quite difficult to visualise more than 2, or 3 dimensions. So, with this 30-dimensional dataset, we will attempt to carry out a dimensionality reduction using two principal components. That is, we will be mapping the data from 30-dimensional space, to two dimensions.


```python
from sklearn.decomposition import PCA

pca = PCA(n_components=2)
pca.fit(cancer_scaled)
x_pca = pca.transform(cancer_scaled)
```


```python
plt.style.use('ggplot')
plt.figure(figsize=(10, 7))
plt.scatter(x=x_pca[:,0],
            y=x_pca[:,1],
            marker='o',
            c=cancer_data['target'], # the colouring is according to malignant/benign
            cmap='magma')
plt.xlabel("First Principal Component")
plt.ylabel("Second Principal Component")
plt.suptitle("Principal Component Analysis with n=2 principal components")
plt.show()

```

There is a clear difference between the malignant (white) and benign tumours (black), in terms of the separation between the values of the principal components.

It would appear that using the principal component analysis dimensionality reduction to two principal components gives a clear separation between the malignant and benign tumours. It appears, at first glance, that quite a lot of the variation in the original, 30-dimensional dataset can be explained with two principal components.

## How many prinicpal components?
In order to establish what is a good number of components to choose for principal component analysis, one can see what percentage of the overall variation in the data described by each principal component. For this task, one would look at the eigenvalues of the problem, and these are sorted from the largest to the smallest.

In this case, we have this stored within the PCA object from *sklearn*


```python
pca.explained_variance_ratio_
```




    array([0.44272026, 0.18971182])



Therefore, in this case, we can see that the explained variance by the first two principal components is 44.3% and 19% of the variance. 

Therefore, by compressing the data from 30-dimensions originally to two dimensions, we have kept almost two-thirds of the original variation in the data.

## Compare variation with different number of PCs
Below we will run some code to investigate how the choice of the number of principal components affects the amount of original variation retained in the mapped data.


```python
num_pc_iter = [5, 10, 15, 20, 25, 30]
variation_explained = []

for i, num_pc in enumerate(num_pc_iter, 1): # get enumerate to start at one
    # use PCA on the transformed dataset to reduce dimensions
    print("*"*30)
    print(f"Iteration {i}. \n "
          f"Number of principal components to choose: {num_pc}")
    pca_iter = PCA(n_components=num_pc)
    pca_iter.fit(cancer_scaled)
    # transform the data using the num of principal components
    transformed_data = pca_iter.transform(cancer_scaled)
    transformed_variance = pca_iter.explained_variance_ratio_

    # print(f"The original shape of data was {cancer.shape}. \n"
    #       f"The shape of the new mapped data is {transformed_data.shape} \n")
    variation_explained_i = np.cumsum(transformed_variance)
    variation_explained.append(variation_explained_i[-1])
    print(f"Explained {100 * variation_explained_i[-1]: .2f}% of total variance ")
    

    # map the data back to original space following compression
    cancer_re_mapped = pca_iter.inverse_transform(transformed_data)
    diff_new_old = cancer_re_mapped - cancer_scaled

    print(f"Max sum of differences for features (between newly mapped and original)"
          f" {np.max(np.sum(diff_new_old, axis=0)) :.2E} \n")

```

    ******************************
    Iteration 1. 
     Number of principal components to choose: 5
    Explained  84.73% of total variance 
    Max sum of differences for features (between newly mapped and original) 8.64E-14 
    
    ******************************
    Iteration 2. 
     Number of principal components to choose: 10
    Explained  95.16% of total variance 
    Max sum of differences for features (between newly mapped and original) 7.16E-14 
    
    ******************************
    Iteration 3. 
     Number of principal components to choose: 15
    Explained  98.65% of total variance 
    Max sum of differences for features (between newly mapped and original) 6.85E-14 
    
    ******************************
    Iteration 4. 
     Number of principal components to choose: 20
    Explained  99.56% of total variance 
    Max sum of differences for features (between newly mapped and original) 5.30E-14 
    
    ******************************
    Iteration 5. 
     Number of principal components to choose: 25
    Explained  99.94% of total variance 
    Max sum of differences for features (between newly mapped and original) 4.03E-14 
    
    ******************************
    Iteration 6. 
     Number of principal components to choose: 30
    Explained  100.00% of total variance 
    Max sum of differences for features (between newly mapped and original) 1.12E-14 
    



```python
variation_retention_results = pd.DataFrame(
    index=num_pc_iter,
    data=["{0:.2f}%".format(val * 100) for val in variation_explained]).reset_index()
variation_retention_results.columns = [
    'Number of Principal Components', 'Percentage of original variation retained']

variation_retention_results
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Number of Principal Components</th>
      <th>Percentage of original variation retained</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>5</td>
      <td>84.73%</td>
    </tr>
    <tr>
      <th>1</th>
      <td>10</td>
      <td>95.16%</td>
    </tr>
    <tr>
      <th>2</th>
      <td>15</td>
      <td>98.65%</td>
    </tr>
    <tr>
      <th>3</th>
      <td>20</td>
      <td>99.56%</td>
    </tr>
    <tr>
      <th>4</th>
      <td>25</td>
      <td>99.94%</td>
    </tr>
    <tr>
      <th>5</th>
      <td>30</td>
      <td>100.00%</td>
    </tr>
  </tbody>
</table>
</div>



We can see that using 15 principal components, mapping the original 30-dimensional data to 15 components will still give us almost 99% of the variance of the original dataset, which is very good. Going forward, if we'd like to use this data, one would be tempted to use this 15 dimensional data as it will carry half as much information in size as the original dataset, and therefore calculations can be carried out faster.

Let's view this results in visual format.


```python
plt.figure(figsize=(8,6))
plt.bar(x=num_pc_iter, 
        height=["{0:.0f}%".format(val * 100) for val in variation_explained])
plt.suptitle("Amount of original variation in data retained")
plt.ylabel("Proportion of original variation retained")
plt.xlabel("Number of principal components used")
```

# Principal component intuition
Whilst it is useful to achieve dimensionality reduction using principal component analysis, the intuition of a principal component is not as basic as saying that the first principal component corresponds to the *mean_concavity* feature (how concave in shape the tumour is), for example.

Instead what the components correspond to is a linear combination of the input features. Let's see this below:


```python
components_df = pd.DataFrame(pca.components_, 
                             columns=cancer_data['feature_names'])

components_df.head(3)
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>mean radius</th>
      <th>mean texture</th>
      <th>mean perimeter</th>
      <th>mean area</th>
      <th>mean smoothness</th>
      <th>mean compactness</th>
      <th>mean concavity</th>
      <th>mean concave points</th>
      <th>mean symmetry</th>
      <th>mean fractal dimension</th>
      <th>...</th>
      <th>worst radius</th>
      <th>worst texture</th>
      <th>worst perimeter</th>
      <th>worst area</th>
      <th>worst smoothness</th>
      <th>worst compactness</th>
      <th>worst concavity</th>
      <th>worst concave points</th>
      <th>worst symmetry</th>
      <th>worst fractal dimension</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>0.218902</td>
      <td>0.103725</td>
      <td>0.227537</td>
      <td>0.220995</td>
      <td>0.142590</td>
      <td>0.239285</td>
      <td>0.258400</td>
      <td>0.260854</td>
      <td>0.138167</td>
      <td>0.064363</td>
      <td>...</td>
      <td>0.227997</td>
      <td>0.104469</td>
      <td>0.236640</td>
      <td>0.224871</td>
      <td>0.127953</td>
      <td>0.210096</td>
      <td>0.228768</td>
      <td>0.250886</td>
      <td>0.122905</td>
      <td>0.131784</td>
    </tr>
    <tr>
      <th>1</th>
      <td>-0.233857</td>
      <td>-0.059706</td>
      <td>-0.215181</td>
      <td>-0.231077</td>
      <td>0.186113</td>
      <td>0.151892</td>
      <td>0.060165</td>
      <td>-0.034768</td>
      <td>0.190349</td>
      <td>0.366575</td>
      <td>...</td>
      <td>-0.219866</td>
      <td>-0.045467</td>
      <td>-0.199878</td>
      <td>-0.219352</td>
      <td>0.172304</td>
      <td>0.143593</td>
      <td>0.097964</td>
      <td>-0.008257</td>
      <td>0.141883</td>
      <td>0.275339</td>
    </tr>
  </tbody>
</table>
<p>2 rows × 30 columns</p>
</div>



Above, we see that the first principal component, with the row name *0*, is a combination of the original input components (which have been feature scaled):
\
\begin{align}
    PrincipalComponent_1 = 0.219*x_1 + 0.104*x_2 + 0.228*x_3
\end{align}
\
where $x_1$ is the mean radius, $x_2$ the mean texture, $x_3$ the mean perimeter, and so on...

Below we will plot a heatmap of the first two principal components, the intuition being that the lighter (/darker) colours show higher (/lower) correlation with the specific feature in the columns. 


```python
plt.figure(figsize=(18,15))
sns.heatmap(components_df, cmap='viridis')
```

In this case, for example, we see that the second principal component has a high weighting of **mean fractal dimension** (due to the light yellow colour).

f0c138baf7d2c3a075f71bff8fe7a408b18b7f83
ipynb
Jupyter Notebook
notebook-projects/Breast Cancer - PCA.ipynb
philip-papasavvas/ml_sandbox
e96540f6b03430c7ff3f3691df7fa4900af677ae
MIT
notebook-projects/Breast Cancer - PCA.ipynb
philip-papasavvas/ml_sandbox
e96540f6b03430c7ff3f3691df7fa4900af677ae
MIT
notebook-projects/Breast Cancer - PCA.ipynb
philip-papasavvas/ml_sandbox
e96540f6b03430c7ff3f3691df7fa4900af677ae
MIT
Qwen/Qwen-72B
1. YES
2. YES