522 lines
30 KiB
HTML
522 lines
30 KiB
HTML
<!--
|
|
Automatically generated HTML file from DocOnce source
|
|
(https://github.com/hplgit/doconce/)
|
|
-->
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<meta name="generator" content="DocOnce: https://github.com/hplgit/doconce/" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<meta name="description" content="Data Analysis and Machine Learning: Preprocessing and Dimensionality Reduction">
|
|
|
|
<title>Data Analysis and Machine Learning: Preprocessing and Dimensionality Reduction</title>
|
|
|
|
|
|
<link href="https://cdn.rawgit.com/hplgit/doconce/master/bundled/html_styles/style_solarized_box/css/solarized_light_code.css" rel="stylesheet" type="text/css" title="light"/>
|
|
<script src="https://cdn.rawgit.com/hplgit/doconce/master/bundled/html_styles/style_solarized_box/js/highlight.pack.js"></script>
|
|
<script>hljs.initHighlightingOnLoad();</script>
|
|
|
|
<link href="https://thomasf.github.io/solarized-css/solarized-light.min.css" rel="stylesheet">
|
|
<style type="text/css">
|
|
h1 {color: #b58900;} /* yellow */
|
|
/* h1 {color: #cb4b16;} orange */
|
|
/* h1 {color: #d33682;} magenta, the original choice of thomasf */
|
|
code { padding: 0px; background-color: inherit; }
|
|
pre {
|
|
border: 0pt solid #93a1a1;
|
|
box-shadow: none;
|
|
}
|
|
.alert-text-small { font-size: 80%; }
|
|
.alert-text-large { font-size: 130%; }
|
|
.alert-text-normal { font-size: 90%; }
|
|
.alert {
|
|
padding:8px 35px 8px 14px; margin-bottom:18px;
|
|
text-shadow:0 1px 0 rgba(255,255,255,0.5);
|
|
border:1px solid #93a1a1;
|
|
border-radius: 4px;
|
|
-webkit-border-radius: 4px;
|
|
-moz-border-radius: 4px;
|
|
color: #555;
|
|
background-color: #eee8d5;
|
|
background-position: 10px 5px;
|
|
background-repeat: no-repeat;
|
|
background-size: 38px;
|
|
padding-left: 55px;
|
|
width: 75%;
|
|
}
|
|
.alert-block {padding-top:14px; padding-bottom:14px}
|
|
.alert-block > p, .alert-block > ul {margin-bottom:1em}
|
|
.alert li {margin-top: 1em}
|
|
.alert-block p+p {margin-top:5px}
|
|
.alert-notice { background-image: url(https://cdn.rawgit.com/hplgit/doconce/master/bundled/html_images/small_yellow_notice.png); }
|
|
.alert-summary { background-image:url(https://cdn.rawgit.com/hplgit/doconce/master/bundled/html_images/small_yellow_summary.png); }
|
|
.alert-warning { background-image: url(https://cdn.rawgit.com/hplgit/doconce/master/bundled/html_images/small_yellow_warning.png); }
|
|
.alert-question {background-image:url(https://cdn.rawgit.com/hplgit/doconce/master/bundled/html_images/small_yellow_question.png); }
|
|
|
|
div { text-align: justify; text-justify: inter-word; }
|
|
</style>
|
|
|
|
|
|
</head>
|
|
|
|
<!-- tocinfo
|
|
{'highest level': 2,
|
|
'sections': [('Reducing the number of degrees of freedom, overarching view',
|
|
2,
|
|
None,
|
|
'___sec0'),
|
|
('Preprocessing our data', 2, None, '___sec1'),
|
|
('Simple preprocessing examples, Franke function and regression',
|
|
2,
|
|
None,
|
|
'___sec2'),
|
|
('Simple preprocessing examples, breast cancer data and '
|
|
'classification',
|
|
2,
|
|
None,
|
|
'___sec3'),
|
|
('Principal Component Analysis', 2, None, '___sec4'),
|
|
('PCA and scikit-learn', 2, None, '___sec5'),
|
|
('More on the PCA', 2, None, '___sec6'),
|
|
('Incremental PCA', 2, None, '___sec7'),
|
|
('Randomized PCA', 2, None, '___sec8'),
|
|
('Kernel PCA', 2, None, '___sec9'),
|
|
('LLE', 2, None, '___sec10'),
|
|
('Other techniques', 2, None, '___sec11')]}
|
|
end of tocinfo -->
|
|
|
|
<body>
|
|
|
|
|
|
|
|
<script type="text/x-mathjax-config">
|
|
MathJax.Hub.Config({
|
|
TeX: {
|
|
equationNumbers: { autoNumber: "AMS" },
|
|
extensions: ["AMSmath.js", "AMSsymbols.js", "autobold.js", "color.js"]
|
|
}
|
|
});
|
|
</script>
|
|
<script type="text/javascript" async
|
|
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<!-- ------------------- main content ---------------------- -->
|
|
|
|
|
|
|
|
<center><h1>Data Analysis and Machine Learning: Preprocessing and Dimensionality Reduction</h1></center> <!-- document title -->
|
|
|
|
<p>
|
|
<!-- author(s): Morten Hjorth-Jensen -->
|
|
|
|
<center>
|
|
<b>Morten Hjorth-Jensen</b> [1, 2]
|
|
</center>
|
|
|
|
<p>
|
|
<!-- institution(s) -->
|
|
|
|
<center>[1] <b>Department of Physics, University of Oslo</b></center>
|
|
<center>[2] <b>Department of Physics and Astronomy and National Superconducting Cyclotron Laboratory, Michigan State University</b></center>
|
|
<br>
|
|
<p>
|
|
<center><h4>Oct 14, 2019</h4></center> <!-- date -->
|
|
<br>
|
|
<p>
|
|
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
|
|
|
|
<h2 id="___sec0">Reducing the number of degrees of freedom, overarching view </h2>
|
|
<div class="alert alert-block alert-block alert-text-normal">
|
|
<b></b>
|
|
<p>
|
|
|
|
<p>
|
|
Many Machine Learning problems involve thousands or even millions of features for each training
|
|
instance. Not only does this make training extremely slow, it can also make it much harder to find a good
|
|
solution, as we will see. This problem is often referred to as the curse of dimensionality.
|
|
Fortunately, in real-world problems, it is often possible to reduce the number of features considerably,
|
|
turning an intractable problem into a tractable one.
|
|
|
|
<p>
|
|
Here we will discuss some of the most popular dimensionality
|
|
reduction techniques: the principal component analysis PCA, Kernel PCA, and Locally Linear Embedding (LLE).
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p>
|
|
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
|
|
|
|
<h2 id="___sec1">Preprocessing our data </h2>
|
|
<div class="alert alert-block alert-block alert-text-normal">
|
|
<b></b>
|
|
<p>
|
|
|
|
<p>
|
|
Before we proceed however, we will discuss how to preprocess our
|
|
data. Till now and in connection with our previous examples we have not met so many cases
|
|
where we are too sensitive to the scaling of our data. Normally the
|
|
data may need a rescaling and/or may be sensitive to extreme
|
|
values. Scaling the data renders our inputs much more suitable for the
|
|
algorithms we want to employ.
|
|
|
|
<p>
|
|
<b>Scikit-Learn</b> has several functions which allow us to rescale the data, normally resulting in much better results in terms of various accuracy scores. The <b>StandardScaler</b> function in <b>Scikit-Learn</b> ensures that for each feature/predictor we study the mean value is zero and the variance is zero (every column in the design/feature matrix).
|
|
This scaling has the drawback that it does not ensure that we have a particular maximum or minumum in our data set. Another function included in <b>Scikit-Learn</b> is the <b>MinMaxScaler</b> which ensures that all features are exactly between \( 0 \) and \( 1 \). The <b>Normalizer</b> function scales each column of the design matrix by its Euclidean norm.
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p>
|
|
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
|
|
|
|
<h2 id="___sec2">Simple preprocessing examples, Franke function and regression </h2>
|
|
|
|
<p>
|
|
|
|
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
|
|
<div class="highlight" style="background: #eeeedd"><pre style="line-height: 125%"><span></span><span style="color: #228B22"># Common imports</span>
|
|
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">os</span>
|
|
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">numpy</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">np</span>
|
|
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">pandas</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">pd</span>
|
|
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">matplotlib.pyplot</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">plt</span>
|
|
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">sklearn.linear_model</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">skl</span>
|
|
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.metrics</span> <span style="color: #8B008B; font-weight: bold">import</span> mean_squared_error
|
|
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.model_selection</span> <span style="color: #8B008B; font-weight: bold">import</span> train_test_split
|
|
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.preprocessing</span> <span style="color: #8B008B; font-weight: bold">import</span> MinMaxScaler, StandardScaler, Normalizer
|
|
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.svm</span> <span style="color: #8B008B; font-weight: bold">import</span> SVR
|
|
|
|
<span style="color: #228B22"># Where to save the figures and data files</span>
|
|
PROJECT_ROOT_DIR = <span style="color: #CD5555">"Results"</span>
|
|
FIGURE_ID = <span style="color: #CD5555">"Results/FigureFiles"</span>
|
|
DATA_ID = <span style="color: #CD5555">"DataFiles/"</span>
|
|
|
|
<span style="color: #8B008B; font-weight: bold">if</span> <span style="color: #8B008B">not</span> os.path.exists(PROJECT_ROOT_DIR):
|
|
os.mkdir(PROJECT_ROOT_DIR)
|
|
|
|
<span style="color: #8B008B; font-weight: bold">if</span> <span style="color: #8B008B">not</span> os.path.exists(FIGURE_ID):
|
|
os.makedirs(FIGURE_ID)
|
|
|
|
<span style="color: #8B008B; font-weight: bold">if</span> <span style="color: #8B008B">not</span> os.path.exists(DATA_ID):
|
|
os.makedirs(DATA_ID)
|
|
|
|
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">image_path</span>(fig_id):
|
|
<span style="color: #8B008B; font-weight: bold">return</span> os.path.join(FIGURE_ID, fig_id)
|
|
|
|
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">data_path</span>(dat_id):
|
|
<span style="color: #8B008B; font-weight: bold">return</span> os.path.join(DATA_ID, dat_id)
|
|
|
|
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">save_fig</span>(fig_id):
|
|
plt.savefig(image_path(fig_id) + <span style="color: #CD5555">".png"</span>, format=<span style="color: #CD5555">'png'</span>)
|
|
|
|
|
|
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">FrankeFunction</span>(x,y):
|
|
term1 = <span style="color: #B452CD">0.75</span>*np.exp(-(<span style="color: #B452CD">0.25</span>*(<span style="color: #B452CD">9</span>*x-<span style="color: #B452CD">2</span>)**<span style="color: #B452CD">2</span>) - <span style="color: #B452CD">0.25</span>*((<span style="color: #B452CD">9</span>*y-<span style="color: #B452CD">2</span>)**<span style="color: #B452CD">2</span>))
|
|
term2 = <span style="color: #B452CD">0.75</span>*np.exp(-((<span style="color: #B452CD">9</span>*x+<span style="color: #B452CD">1</span>)**<span style="color: #B452CD">2</span>)/<span style="color: #B452CD">49.0</span> - <span style="color: #B452CD">0.1</span>*(<span style="color: #B452CD">9</span>*y+<span style="color: #B452CD">1</span>))
|
|
term3 = <span style="color: #B452CD">0.5</span>*np.exp(-(<span style="color: #B452CD">9</span>*x-<span style="color: #B452CD">7</span>)**<span style="color: #B452CD">2</span>/<span style="color: #B452CD">4.0</span> - <span style="color: #B452CD">0.25</span>*((<span style="color: #B452CD">9</span>*y-<span style="color: #B452CD">3</span>)**<span style="color: #B452CD">2</span>))
|
|
term4 = -<span style="color: #B452CD">0.2</span>*np.exp(-(<span style="color: #B452CD">9</span>*x-<span style="color: #B452CD">4</span>)**<span style="color: #B452CD">2</span> - (<span style="color: #B452CD">9</span>*y-<span style="color: #B452CD">7</span>)**<span style="color: #B452CD">2</span>)
|
|
<span style="color: #8B008B; font-weight: bold">return</span> term1 + term2 + term3 + term4
|
|
|
|
|
|
<span style="color: #8B008B; font-weight: bold">def</span> <span style="color: #008b45">create_X</span>(x, y, n ):
|
|
<span style="color: #8B008B; font-weight: bold">if</span> <span style="color: #658b00">len</span>(x.shape) > <span style="color: #B452CD">1</span>:
|
|
x = np.ravel(x)
|
|
y = np.ravel(y)
|
|
|
|
N = <span style="color: #658b00">len</span>(x)
|
|
l = <span style="color: #658b00">int</span>((n+<span style="color: #B452CD">1</span>)*(n+<span style="color: #B452CD">2</span>)/<span style="color: #B452CD">2</span>) <span style="color: #228B22"># Number of elements in beta</span>
|
|
X = np.ones((N,l))
|
|
|
|
<span style="color: #8B008B; font-weight: bold">for</span> i <span style="color: #8B008B">in</span> <span style="color: #658b00">range</span>(<span style="color: #B452CD">1</span>,n+<span style="color: #B452CD">1</span>):
|
|
q = <span style="color: #658b00">int</span>((i)*(i+<span style="color: #B452CD">1</span>)/<span style="color: #B452CD">2</span>)
|
|
<span style="color: #8B008B; font-weight: bold">for</span> k <span style="color: #8B008B">in</span> <span style="color: #658b00">range</span>(i+<span style="color: #B452CD">1</span>):
|
|
X[:,q+k] = (x**(i-k))*(y**k)
|
|
|
|
<span style="color: #8B008B; font-weight: bold">return</span> X
|
|
|
|
|
|
<span style="color: #228B22"># Making meshgrid of datapoints and compute Franke's function</span>
|
|
n = <span style="color: #B452CD">5</span>
|
|
N = <span style="color: #B452CD">1000</span>
|
|
x = np.sort(np.random.uniform(<span style="color: #B452CD">0</span>, <span style="color: #B452CD">1</span>, N))
|
|
y = np.sort(np.random.uniform(<span style="color: #B452CD">0</span>, <span style="color: #B452CD">1</span>, N))
|
|
z = FrankeFunction(x, y)
|
|
X = create_X(x, y, n=n)
|
|
<span style="color: #228B22"># split in training and test data</span>
|
|
X_train, X_test, y_train, y_test = train_test_split(X,z,test_size=<span style="color: #B452CD">0.2</span>)
|
|
|
|
|
|
svm = SVR(gamma=<span style="color: #CD5555">'auto'</span>,C=<span style="color: #B452CD">10.0</span>)
|
|
svm.fit(X_train, y_train)
|
|
|
|
<span style="color: #228B22"># The mean squared error and R2 score</span>
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"MSE before scaling: {:.2f}"</span>.format(mean_squared_error(svm.predict(X_test), y_test)))
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"R2 score before scaling {:.2f}"</span>.format(svm.score(X_test,y_test)))
|
|
|
|
scaler = StandardScaler()
|
|
scaler.fit(X_train)
|
|
X_train_scaled = scaler.transform(X_train)
|
|
X_test_scaled = scaler.transform(X_test)
|
|
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"Feature min values before scaling:\n {}"</span>.format(X_train.min(axis=<span style="color: #B452CD">0</span>)))
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"Feature max values before scaling:\n {}"</span>.format(X_train.max(axis=<span style="color: #B452CD">0</span>)))
|
|
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"Feature min values after scaling:\n {}"</span>.format(X_train_scaled.min(axis=<span style="color: #B452CD">0</span>)))
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"Feature max values after scaling:\n {}"</span>.format(X_train_scaled.max(axis=<span style="color: #B452CD">0</span>)))
|
|
|
|
svm = SVR(gamma=<span style="color: #CD5555">'auto'</span>,C=<span style="color: #B452CD">10.0</span>)
|
|
svm.fit(X_train_scaled, y_train)
|
|
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"MSE after scaling: {:.2f}"</span>.format(mean_squared_error(svm.predict(X_test_scaled), y_test)))
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"R2 score for scaled data: {:.2f}"</span>.format(svm.score(X_test_scaled,y_test)))
|
|
</pre></div>
|
|
<p>
|
|
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
|
|
|
|
<h2 id="___sec3">Simple preprocessing examples, breast cancer data and classification </h2>
|
|
|
|
<p>
|
|
We show here how we can use a simple regression case on the breast cancer data using support vector machine as algorithm for classification
|
|
|
|
<p>
|
|
|
|
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
|
|
<div class="highlight" style="background: #eeeedd"><pre style="line-height: 125%"><span></span><span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">matplotlib.pyplot</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">plt</span>
|
|
<span style="color: #8B008B; font-weight: bold">import</span> <span style="color: #008b45; text-decoration: underline">numpy</span> <span style="color: #8B008B; font-weight: bold">as</span> <span style="color: #008b45; text-decoration: underline">np</span>
|
|
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.model_selection</span> <span style="color: #8B008B; font-weight: bold">import</span> train_test_split
|
|
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.datasets</span> <span style="color: #8B008B; font-weight: bold">import</span> load_breast_cancer
|
|
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.svm</span> <span style="color: #8B008B; font-weight: bold">import</span> SVC
|
|
cancer = load_breast_cancer()
|
|
|
|
X_train, X_test, y_train, y_test = train_test_split(cancer.data,cancer.target,random_state=<span style="color: #B452CD">0</span>)
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(X_train.shape)
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(X_test.shape)
|
|
|
|
svm = SVC(C=<span style="color: #B452CD">100</span>)
|
|
svm.fit(X_train, y_train)
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"Test set accuracy: {:.2f}"</span>.format(svm.score(X_test,y_test)))
|
|
|
|
<span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.preprocessing</span> <span style="color: #8B008B; font-weight: bold">import</span> MinMaxScaler, StandardScaler
|
|
|
|
scaler = MinMaxScaler()
|
|
scaler.fit(X_train)
|
|
X_train_scaled = scaler.transform(X_train)
|
|
X_test_scaled = scaler.transform(X_test)
|
|
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"Feature min values before scaling:\n {}"</span>.format(X_train.min(axis=<span style="color: #B452CD">0</span>)))
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"Feature max values before scaling:\n {}"</span>.format(X_train.max(axis=<span style="color: #B452CD">0</span>)))
|
|
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"Feature min values before scaling:\n {}"</span>.format(X_train_scaled.min(axis=<span style="color: #B452CD">0</span>)))
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"Feature max values before scaling:\n {}"</span>.format(X_train_scaled.max(axis=<span style="color: #B452CD">0</span>)))
|
|
|
|
|
|
svm.fit(X_train_scaled, y_train)
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"Test set accuracy scaled data: {:.2f}"</span>.format(svm.score(X_test_scaled,y_test)))
|
|
|
|
scaler = StandardScaler()
|
|
scaler.fit(X_train)
|
|
X_train_scaled = scaler.transform(X_train)
|
|
X_test_scaled = scaler.transform(X_test)
|
|
|
|
svm.fit(X_train_scaled, y_train)
|
|
<span style="color: #8B008B; font-weight: bold">print</span>(<span style="color: #CD5555">"Test set accuracy scaled data: {:.2f}"</span>.format(svm.score(X_test_scaled,y_test)))
|
|
</pre></div>
|
|
<p>
|
|
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
|
|
|
|
<h2 id="___sec4">Principal Component Analysis </h2>
|
|
<div class="alert alert-block alert-block alert-text-normal">
|
|
<b></b>
|
|
<p>
|
|
Principal Component Analysis (PCA) is by far the most popular dimensionality reduction algorithm.
|
|
First it identifies the hyperplane that lies closest to the data, and then it projects the data onto it.
|
|
|
|
<p>
|
|
The following Python code uses NumPy’s <b>svd()</b> function to obtain all the principal components of the
|
|
training set, then extracts the first two principal components
|
|
<p>
|
|
|
|
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
|
|
<div class="highlight" style="background: #eee8d5"><pre style="line-height: 125%"><span></span>X_centered = X - X.mean(axis=<span style="color: #B452CD">0</span>)
|
|
U, s, V = np.linalg.svd(X_centered)
|
|
c1 = V.T[:, <span style="color: #B452CD">0</span>]
|
|
c2 = V.T[:, <span style="color: #B452CD">1</span>]
|
|
</pre></div>
|
|
<p>
|
|
PCA assumes that the dataset is centered around the origin. Scikit-Learn’s PCA classes take care of centering
|
|
the data for you. However, if you implement PCA yourself (as in the preceding example), or if you use other libraries, don’t
|
|
forget to center the data first.
|
|
|
|
<p>
|
|
Once you have identified all the principal components, you can reduce the dimensionality of the dataset
|
|
down to \( d \) dimensions by projecting it onto the hyperplane defined by the first \( d \) principal components.
|
|
Selecting this hyperplane ensures that the projection will preserve as much variance as possible.
|
|
<p>
|
|
|
|
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
|
|
<div class="highlight" style="background: #eee8d5"><pre style="line-height: 125%"><span></span>W2 = V.T[:, :<span style="color: #B452CD">2</span>]
|
|
X2D = X_centered.dot(W2)
|
|
</pre></div>
|
|
<p>
|
|
<!-- !split -->
|
|
|
|
<h2 id="___sec5">PCA and scikit-learn </h2>
|
|
|
|
<p>
|
|
Scikit-Learn’s PCA class implements PCA using SVD decomposition just like we did before. The
|
|
following code applies PCA to reduce the dimensionality of the dataset down to two dimensions (note
|
|
that it automatically takes care of centering the data):
|
|
<p>
|
|
|
|
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
|
|
<div class="highlight" style="background: #eee8d5"><pre style="line-height: 125%"><span></span><span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.decomposition</span> <span style="color: #8B008B; font-weight: bold">import</span> PCA
|
|
pca = PCA(n_components = <span style="color: #B452CD">2</span>)
|
|
X2D = pca.fit_transform(X)
|
|
</pre></div>
|
|
<p>
|
|
After fitting the PCA transformer to the dataset, you can access the principal components using the
|
|
components variable (note that it contains the PCs as horizontal vectors, so, for example, the first
|
|
principal component is equal to
|
|
<p>
|
|
|
|
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
|
|
<div class="highlight" style="background: #eee8d5"><pre style="line-height: 125%"><span></span>pca.components_.T[:, <span style="color: #B452CD">0</span>]).
|
|
</pre></div>
|
|
<p>
|
|
Another very useful piece of information is the explained variance ratio of each principal component,
|
|
available via the \( explained\_variance\_ratio \) variable. It indicates the proportion of the dataset’s
|
|
variance that lies along the axis of each principal component.
|
|
More material to come here.
|
|
|
|
<p>
|
|
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
|
|
|
|
<h2 id="___sec6">More on the PCA </h2>
|
|
Instead of arbitrarily choosing the number of dimensions to reduce down to, it is generally preferable to
|
|
choose the number of dimensions that add up to a sufficiently large portion of the variance (e.g., 95%).
|
|
Unless, of course, you are reducing dimensionality for data visualization — in that case you will
|
|
generally want to reduce the dimensionality down to 2 or 3.
|
|
The following code computes PCA without reducing dimensionality, then computes the minimum number
|
|
of dimensions required to preserve 95% of the training set’s variance:
|
|
<p>
|
|
|
|
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
|
|
<div class="highlight" style="background: #eee8d5"><pre style="line-height: 125%"><span></span>pca = PCA()
|
|
pca.fit(X)
|
|
cumsum = np.cumsum(pca.explained_variance_ratio_)
|
|
d = np.argmax(cumsum >= <span style="color: #B452CD">0.95</span>) + <span style="color: #B452CD">1</span>
|
|
</pre></div>
|
|
<p>
|
|
You could then set \( n\_components=d \) and run PCA again. However, there is a much better option: instead
|
|
of specifying the number of principal components you want to preserve, you can set \( n\_components \) to be
|
|
a float between 0.0 and 1.0, indicating the ratio of variance you wish to preserve:
|
|
<p>
|
|
|
|
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
|
|
<div class="highlight" style="background: #eee8d5"><pre style="line-height: 125%"><span></span>pca = PCA(n_components=<span style="color: #B452CD">0.95</span>)
|
|
X_reduced = pca.fit_transform(X)
|
|
</pre></div>
|
|
<p>
|
|
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
|
|
|
|
<h2 id="___sec7">Incremental PCA </h2>
|
|
One problem with the preceding implementation of PCA is that it requires the whole training set to fit in
|
|
memory in order for the SVD algorithm to run. Fortunately, Incremental PCA (IPCA) algorithms have
|
|
been developed: you can split the training set into mini-batches and feed an IPCA algorithm one minibatch
|
|
at a time. This is useful for large training sets, and also to apply PCA online (i.e., on the fly, as new
|
|
instances arrive).
|
|
|
|
<p>
|
|
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
|
|
|
|
<h2 id="___sec8">Randomized PCA </h2>
|
|
|
|
<p>
|
|
Scikit-Learn offers yet another option to perform PCA, called Randomized PCA. This is a stochastic
|
|
algorithm that quickly finds an approximation of the first d principal components. Its computational
|
|
complexity is \( O(m \times d^2)+O(d^3) \), instead of \( O(m \times n^2) + O(n^3) \), so it is dramatically faster than the
|
|
previous algorithms when \( d \) is much smaller than \( n \).
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p>
|
|
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
|
|
|
|
<h2 id="___sec9">Kernel PCA </h2>
|
|
<div class="alert alert-block alert-block alert-text-normal">
|
|
<b></b>
|
|
<p>
|
|
|
|
<p>
|
|
The kernel trick is a mathematical technique that implicitly maps instances into a
|
|
very high-dimensional space (called the feature space), enabling nonlinear classification and regression
|
|
with Support Vector Machines. Recall that a linear decision boundary in the high-dimensional feature
|
|
space corresponds to a complex nonlinear decision boundary in the original space.
|
|
It turns out that the same trick can be applied to PCA, making it possible to perform complex nonlinear
|
|
projections for dimensionality reduction. This is called Kernel PCA (kPCA). It is often good at
|
|
preserving clusters of instances after projection, or sometimes even unrolling datasets that lie close to a
|
|
twisted manifold.
|
|
For example, the following code uses Scikit-Learn’s KernelPCA class to perform kPCA with an
|
|
<p>
|
|
|
|
<!-- code=python (!bc pycod) typeset with pygments style "perldoc" -->
|
|
<div class="highlight" style="background: #eee8d5"><pre style="line-height: 125%"><span></span><span style="color: #8B008B; font-weight: bold">from</span> <span style="color: #008b45; text-decoration: underline">sklearn.decomposition</span> <span style="color: #8B008B; font-weight: bold">import</span> KernelPCA
|
|
rbf_pca = KernelPCA(n_components = <span style="color: #B452CD">2</span>, kernel=<span style="color: #CD5555">"rbf"</span>, gamma=<span style="color: #B452CD">0.04</span>)
|
|
X_reduced = rbf_pca.fit_transform(X)
|
|
</pre></div>
|
|
|
|
</div>
|
|
|
|
|
|
<p>
|
|
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
|
|
|
|
<h2 id="___sec10">LLE </h2>
|
|
|
|
<p>
|
|
Locally Linear Embedding (LLE) is another very powerful nonlinear dimensionality reduction
|
|
(NLDR) technique. It is a Manifold Learning technique that does not rely on projections like the previous
|
|
algorithms. In a nutshell, LLE works by first measuring how each training instance linearly relates to its
|
|
closest neighbors (c.n.), and then looking for a low-dimensional representation of the training set where
|
|
these local relationships are best preserved (more details shortly).
|
|
|
|
<p>
|
|
<!-- !split --><br><br><br><br><br><br><br><br><br><br>
|
|
|
|
<h2 id="___sec11">Other techniques </h2>
|
|
|
|
<p>
|
|
There are many other dimensionality reduction techniques, several of which are available in Scikit-Learn.
|
|
|
|
<p>
|
|
Here are some of the most popular:
|
|
|
|
<ul>
|
|
<li> <b>Multidimensional Scaling (MDS)</b> reduces dimensionality while trying to preserve the distances between the instances.</li>
|
|
<li> <b>Isomap</b> creates a graph by connecting each instance to its nearest neighbors, then reduces dimensionality while trying to preserve the geodesic distances between the instances.</li>
|
|
<li> <b>t-Distributed Stochastic Neighbor Embedding</b> (t-SNE) reduces dimensionality while trying to keep similar instances close and dissimilar instances apart. It is mostly used for visualization, in particular to visualize clusters of instances in high-dimensional space (e.g., to visualize the MNIST images in 2D).</li>
|
|
<li> Linear Discriminant Analysis (LDA) is actually a classification algorithm, but during training it learns the most discriminative axes between the classes, and these axes can then be used to define a hyperplane onto which to project the data. The benefit is that the projection will keep classes as far apart as possible, so LDA is a good technique to reduce dimensionality before running another classification algorithm such as a Support Vector Machine (SVM) classifier discussed in the SVM lectures.</li>
|
|
</ul>
|
|
|
|
|
|
<!-- ------------------- end of main content --------------- -->
|
|
|
|
|
|
<center style="font-size:80%">
|
|
<!-- copyright --> © 1999-2019, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license
|
|
</center>
|
|
|
|
|
|
</body>
|
|
</html>
|
|
|
|
|