Python Data Science
Python Data Science
Release 0.1
Jake Teo
1 General Notes 3
1.1 Virtual Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Modeling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2 In-Built Datasets 9
3 Exploratory Analysis 11
3.1 Univariate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2 Multi-Variate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4 Feature Preprocessing 19
4.1 Missing Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.2 Outliers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.3 Encoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.4 Coordinates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
5 Feature Normalization 25
5.1 Scaling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
5.2 Pipeline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
5.3 Persistance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
6 Feature Engineering 29
6.1 Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
6.2 Auto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
7 Class Imbalance 35
7.1 Over-Sampling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
7.2 Under-Sampling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
7.3 Under/Over-Sampling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
7.4 Cost Sensitive Classification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
8 Data Leakage 37
8.1 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
8.2 Types of Leakages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
8.3 Detecting Leakages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
8.4 Minimising Leakages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
9 Supervised Learning 41
i
9.1 Classification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
9.2 Regression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
10 Unsupervised Learning 69
10.1 Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
10.2 Clustering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
10.3 One-Class Classification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
10.4 Distance Metrics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
11 Active Learning 99
11.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
11.2 Sampling Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
11.3 Query Strategies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
11.4 Stop Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
11.5 Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
14 Evaluation 127
14.1 Classification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
14.2 Regression . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
14.3 K-fold Cross-Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
14.4 Hyperparameters Tuning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
15 Explainability 147
15.1 Feature Importance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
15.2 Permutation Importance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
15.3 Partial Dependence Plots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
15.4 SHAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
16 Utilities 153
16.1 Persistance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
16.2 Memory Reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
16.3 Parallel Pandas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
16.4 Jupyter Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
17 Docker 157
17.1 Creating Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
17.2 Docker Compose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
17.3 Docker Swarm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
17.4 Networking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
17.5 Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
18 Ethics 163
ii
18.1 Types of Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
18.2 Hidden Biases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
18.3 Is it Better than a Human? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
18.4 Model used for Unintended Purposes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
18.5 Keeping Data Confidential . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
19 Resources 165
iii
iv
Data Science Documentation, Release 0.1
This documentation summarises various machine learning techniques in Python. A lot of the content are compiled
from various resources, so please cite them appropriately if you are using.
Contents 1
Data Science Documentation, Release 0.1
2 Contents
CHAPTER 1
General Notes
Every project has a different set of requirements and different set of python packages to support it. The versions of
each package can differ or break with each python or dependent packages update, so it is important to isolate every
project within an enclosed virtual environment. Anaconda provides a straight forward way to manage this.
# create environment
conda create -n yourenvname
# activate environment
source activate yourenvname
# install package
conda install -n yourenvname [package]
# deactivate environment
conda deactivate
# delete environment
conda env remove -n yourenvname -all
Alternatively, we can create a fixed environment file and execute using conda env create -f
3
Data Science Documentation, Release 0.1
environment.yml. This will create an environment with the name and packages specified within the folder.
Channels specify where the packages are installed from.
name: environment_name
channels:
- conda-forge
- defaults
dependencies:
- python=3.7
- bokeh=0.9.2
- numpy=1.9.*
- pip:
- baytune==0.3.1
1.2 Modeling
A parsimonious model is a the model that accomplishes the desired level of prediction with as few predictor variables
as possible.
1.2.1 Variables
The type of data is essential as it determines what kind of tests can be applied to it.
Continuous: Also known as quantitative. Unlimited number of values
Categorical: Also known as discrete or qualitative. Fixed number of values or categories
The best predictive algorithm is one that has good Generalization Ability. With that, it will be able to give accurate
predictions to new and previously unseen data.
High Bias results from Underfitting the model. This usually results from erroneous assumptions, and cause the model
to be too general.
High Variance results from Overfitting the model, and it will predict the training dataset very accurately, but not with
unseen new datasets. This is because it will fit even the slightless noise in the dataset.
The best model with the highest accuarcy is the middle ground between the two.
1. Remove features that have too many NAN or fill NAN with another value
2. Remove features that will introduce data leakage
1.2. Modeling 5
Data Science Documentation, Release 0.1
With the exception of Tree models and Naive Bayes, other machine learning techniques like Neural Networks, KNN,
SVM should have their features scaled.
Split the dataset into Train and Test datasets. By default, sklearn assigns 75% to train & 25% to test randomly. A
random state (seed) can be selected to fixed the randomisation
Create Model
clf = DecisionTreeClassifier()
Fit Model
Test Model
Test the model by predicting identity of unseen data using the testing dataset.
y_predict = model.predict(X_test)
Score Model
Cross Validation
When all code is working fine, remove the train-test portion and use Grid Search Cross Validation to compute the best
parameters with cross validation.
Final Model
Finally, rebuild the model using the full dataset, and the chosen parameters tested.
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
# models to test
svml = LinearSVC()
svm = SVC()
rf = RandomForestClassifier()
xg = XGBClassifier()
xr = ExtraTreesClassifier()
# iterations
classifiers = [svml, svm, rf, xr, xg]
names = ['Linear SVM', 'RBF SVM', 'Random Forest', 'Extremely Randomized Trees',
˓→'XGBoost']
results = []
# train-test split
X = df[df.columns[:-1]]
# normalise data for SVM
X = StandardScaler().fit(X).transform(X)
(continues on next page)
1.2. Modeling 7
Data Science Documentation, Release 0.1
In-Built Datasets
There are in-built datasets provided in both statsmodels and sklearn packages.
Statsmodels
In statsmodels, many R datasets can be obtained from the function sm.datasets.get_rdataset(). To view
each dataset’s description, use print(duncan_prestige.__doc__).
import statsmodels.api as sm
prestige = sm.datasets.get_rdataset("Duncan", "car", cache=True).data
print prestige.head()
Sklearn
There are five common toy datasets here. For others, view http://scikit-learn.org/stable/datasets/index.html. To view
each dataset’s description, use print boston['DESCR'].
9
Data Science Documentation, Release 0.1
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)
0 5.1 3.5 1.4 0.2
1 4.9 3.0 1.4 0.2
2 4.7 3.2 1.3 0.2
3 4.6 3.1 1.5 0.2
4 5.0 3.6 1.4 0.2
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)
0 5.1 3.5 1.4 0.2
1 4.9 3.0 1.4 0.2
2 4.7 3.2 1.3 0.2
3 4.6 3.1 1.5 0.2
4 5.0 3.6 1.4 0.2
0 setosa
1 setosa
2 setosa
3 setosa
4 setosa
Name: species, dtype: category
Categories (3, object): [setosa, versicolor, virginica]
Exploratory Analysis
Exploratory data analysis (EDA) is an essential step to understand the data better; in order to engineer and select
features before modelling. This often requires skills in visualisation to better interpret the data.
3.1 Univariate
When plotting distributions, it is important to compare the distribution of both train and test sets. If the test set very
specific to certain features, the model will underfit and have a low accuarcy.
import seaborn as sns
import matplotlib.pyplot as plt
%config InlineBackend.figure_format = 'retina'
%matplotlib inline
for i in X.columns:
plt.figure(figsize=(15,5))
sns.distplot(X[i])
sns.distplot(pred[i])
For categorical features, you may want to see if they have enough sample size for each category.
import seaborn as sns
import matplotlib.pyplot as plt
%config InlineBackend.figure_format = 'retina'
%matplotlib inline
df['Wildnerness'].value_counts()
(continues on next page)
11
Data Science Documentation, Release 0.1
cmap = sns.color_palette("Set2")
sns.countplot(x='Wildnerness',data=df, palette=cmap);
plt.xticks(rotation=45);
To check for possible relationships with the target, place the feature under hue.
plt.figure(figsize=(12,6))
sns.countplot(x='Cover_Type',data=wild, hue='Wilderness');
plt.xticks(rotation=45);
Multiple Plots
fig, axes = plt.subplots(ncols=3, nrows=1, figsize=(15, 5)) # note only for 1 row or
˓→1 col, else need to flatten nested list in axes
col = ['Winner','Second','Third']
for ax in fig.axes:
plt.sca(ax)
plt.xticks(rotation=90)
Using the 50 percentile to compare among different classes, it is easy to find feature that can have high prediction
importance if they do not overlap. Also can be use for outlier detection. Features have to be continuous.
From different dataframes, displaying the same feature.
df.boxplot(figsize=(10,5));
3.1. Univariate 13
Data Science Documentation, Release 0.1
plt.figure(figsize=(7, 5))
cmap = sns.color_palette("Set3")
sns.boxplot(x='Cover_Type', y='Elevation', data=df, palette=cmap);
plt.xticks(rotation=45);
Multiple Plots
cmap = sns.color_palette("Set2")
3.1. Univariate 15
Data Science Documentation, Release 0.1
3.2 Multi-Variate
Using seaborn
plt.figure(figsize=(15, 8))
sns.heatmap(corr, cmap=sns.color_palette("RdBu_r", 20));
3.2. Multi-Variate 17
Data Science Documentation, Release 0.1
Feature Preprocessing
Machine learning models cannot accept null/NaN values. We will need to either remove them or fill them with a
logical value. To investigate how many nulls in each column:
def null_analysis(df):
'''
desc: get nulls for each column in counts & percentages
arg: dataframe
return: dataframe
'''
null_cnt = df.isnull().sum() # calculate null counts
null_cnt = null_cnt[null_cnt!=0] # remove non-null cols
null_percent = null_cnt / len(df) * 100 # calculate null percentages
null_table = pd.concat([pd.DataFrame(null_cnt), pd.DataFrame(null_percent)], axis=1)
null_table.columns = ['counts', 'percentage']
null_table.sort_values('counts', ascending=False, inplace=True)
return null_table
It makes no sense to fill in the null values if there are too many of them. We can set a threshold to delete the entire
column if there are too many nulls.
def null_threshold(df, threshold=25):
'''
desc: delete columns based on a null percentage threshold
arg: df=dataframe; threshold=percentage of nulls in column
return: dataframe
'''
(continues on next page)
19
Data Science Documentation, Release 0.1
We can change missing values for the entire dataframe into their individual column means or medians.
import pandas as pd
import numpy as np
from sklearn.impute import SimpleImputer
We can also use interpolation via pandas default function to fill in the missing values. https://pandas.pydata.org/
pandas-docs/stable/reference/api/pandas.Series.interpolate.html
import pandas as pd
4.2 Outliers
Especially sensitive in linear models. They can be (1) removed manually by defining the lower and upper bound limit,
or (2) grouping the features into ranks.
4.3 Encoding
# Test data
df = DataFrame(['A', 'B', 'B', 'C'], columns=['Col'])
df['Fact'] = pd.factorize(df['Col'])[0]
le = preprocessing.LabelEncoder()
df['Lab'] = le.fit_transform(df['Col'])
print(df)
# Col Fact Lab
# 0 A 0 0
(continues on next page)
4.2. Outliers 21
Data Science Documentation, Release 0.1
One-Hot Encoding: We could use an integer encoding directly, rescaled where needed. This may work for problems
where there is a natural ordinal relationship between the categories, and in turn the integer values, such as labels for
temperature ‘cold’, warm’, and ‘hot’. There may be problems when there is no ordinal relationship and allowing the
representation to lean on any such relationship might be damaging to learning to solve the problem. An example might
be the labels ‘dog’ and ‘cat’.
Each category is one binary field of 1 & 0. Not good if too many categories in a feature. Need to store in sparse matrix.
• Dummies: pd.get_dummies, this converts a string into binary, and splits the columns according to n
categories
• sklearn: sklearn.preprocessing.OneHotEncoder, string has to be converted into numeric, then
stored in a sparse matrix.
Feature Interactions: interactions btw categorical features
• Linear Models & KNN
4.4 Coordinates
It is necessary to define a projection for a coordinate reference system if there is a classification in space, eg k-means
clustering. This basically change the coordinates from a spherical component to a flat surface.
Also take note of spatial auto-correlation.
4.4. Coordinates 23
Data Science Documentation, Release 0.1
Feature Normalization
Normalisation is another important concept needed to change all features to the same scale. This allows for faster
convergence on learning, and more uniform influence for all weights. More on sklearn website:
• http://scikit-learn.org/stable/modules/preprocessing.html
Tree-based models is not dependent on scaling, but non-tree models models, very often are hugely dependent on it.
Outliers can affect certain scalers, and it is important to either remove them or choose a scalar that is robust towards
them.
• https://scikit-learn.org/stable/auto_examples/preprocessing/plot_all_scaling.html
• http://benalexkeen.com/feature-scaling-with-scikit-learn/
5.1 Scaling
It standardize features by removing the mean and scaling to unit variance The standard score of a sample x is calculated
as:
z = (x - u) / s
import pandas pd
from sklearn.preprocessing import StandardScaler
X_test_scaled = scaler.transform(X_test)
25
Data Science Documentation, Release 0.1
Another way to normalise is to use the Min Max Scaler, which changes all features to be between 0 and 1, as defined
below:
import pandas pd
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
5.1.3 RobustScaler
Works similarly to standard scaler except that it uses median and quartiles, instead of mean and variance. Good as it
ignores data points that are outliers.
5.1.4 Normalizer
Scales each data point such that the feature vector has a Euclidean length of 1. Often used when the direction of the
data matters, not the length of the feature vector.
5.2 Pipeline
Scaling have a chance of leaking the part of the test data in train-test split into the training data. This is especially
inevitable when using cross-validation.
We can scale the train and test datasets separately to avoid this. However, a more convenient way is to use the pipeline
function in sklearn, which wraps the scaler and classifier together, and scale them separately during cross validation.
Any other functions can also be input here, e.g., rolling window feature extraction, which also have the potential to
have data leakage.
# "scaler" & "svm" can be any name. But they must be placed in the correct order of
˓→processing
pipe.fit(X_train, y_train)
Pipeline(steps=[('scaler', MinMaxScaler(copy=True, feature_range=(0, 1))), ('svm',
˓→SVC(C=1.0, cac
pipe.score(X_test, y_test)
0.95104895104895104
5.3 Persistance
To save the fitted scaler to normalize new datasets, we can save it using pickle or joblib for reusing in the future.
5.2. Pipeline 27
Data Science Documentation, Release 0.1
Feature Engineering
Feature Engineering is one of the most important part of model building. Collecting and creating of relevant features
from existing ones are most often the determinant of a high prediction value.
They can be classified broadly as:
• Aggregations
– Rolling/sliding Window (overlapping)
– Tumbling Window (non-overlapping)
• Transformations
• Decompositions
• Interactions
6.1 Manual
6.1.1 Decomposition
Datetime Breakdown
Very often, various dates and times of the day have strong interactions with your predictors. Here’s a script to pull
those values out.
def extract_time(df):
df['timestamp'] = pd.to_datetime(df['timestamp'])
df['hour'] = df['timestamp'].dt.hour
df['mth'] = df['timestamp'].dt.month
df['day'] = df['timestamp'].dt.day
df['dayofweek'] = df['timestamp'].dt.dayofweek
return df
29
Data Science Documentation, Release 0.1
import holidays
train['holiday'] = train['timestamp'].apply(lambda x: 0 if holidays.US().get(x) is
˓→None else 1)
Time-Series
Decomposing a time-series into trend (long-term), seaonality (short-term), residuals (noise). There are two methods
to decompose:
• Additive—The component is present and is added to the other components to create the overall forecast value.
• Multiplicative—The component is present and is multiplied by the other components to create the overall fore-
cast value
Usually an additive time-series will be used if there are no seasonal variations over time.
import statsmodels.api as sm
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
Fourier Transformation
The Fourier transform (FT) decomposes a function of time (a signal) into its constituent frequencies, i.e., converts
amplitudes into frequencies.
Wavelet Transform
Wavelet transforms are time-frequency transforms employing wavelets. They are similar to Fourier transforms, the
difference being that Fourier transforms are localized only in frequency instead of in time and frequency. There are
various considerations for wavelet transform, including:
• Which wavelet transform will you use, CWT or DWT?
• Which wavelet family will you use?
• Up to which level of decomposition will you go?
• Number of coefficients (vanishing moments)
• What is the right range of scales to use?
• http://ataspinar.com/2018/12/21/a-guide-for-using-the-wavelet-transform-in-machine-learning/
• https://www.kaggle.com/jackvial/dwt-signal-denoising
• https://www.kaggle.com/tarunpaparaju/lanl-earthquake-prediction-signal-denoising
import pywt
6.2 Auto
Automatic generation of new features from existing ones are starting to gain popularity, as it can save a lot of time.
6.2. Auto 31
Data Science Documentation, Release 0.1
6.2.1 Tsfresh
tsfresh is a feature extraction package for time-series. It can extract more than 1200 different features, and filter out
features that are deemed relevant. In essence, it is a univariate feature extractor.
https://tsfresh.readthedocs.io/en/latest/
Extract all possible features
def list_union_df(fault_list):
'''
Description
------------
Convert list of faults with a single signal value into a dataframe with an id for
˓→each fault sample
df = pd.concat(dflist)
return df
df = list_union_df(fault_list)
# tsfresh
extracted_features = extract_features(df, column_id='id')
# delete columns which only have one value for all rows
for i in extracted_features.columns:
col = extracted_features[i]
if len(col.unique()) == 1:
del extracted_features[i]
features_filtered_direct = extract_relevant_features(timeseries, y,
column_id='id',
column_sort='time_steps',
fdr_level=0.05)
6.2.2 FeatureTools
FeatureTools is extremely useful if you have datasets with a base data, with other tables that have relationships to it.
We first create an EntitySet, which is like a database. Then we create entities, i.e., individual tables with a unique id
for each table, and showing their relationships between each other.
https://github.com/Featuretools/featuretools
import featuretools as ft
def make_entityset(data):
es = ft.EntitySet('Dataset')
es.entity_from_dataframe(dataframe=data,
entity_id='recordings',
index='index',
time_index='time')
es.normalize_entity(base_entity_id='recordings',
new_entity_id='engines',
index='engine_no')
es.normalize_entity(base_entity_id='recordings',
new_entity_id='cycles',
index='time_in_cycles')
return es
es = make_entityset(data)
es
We then use something called Deep Feature Synthesis (dfs) to generate features automatically.
Primitives are the type of new features to be extracted from the datasets. They can be aggregations (data is combined)
or transformation (data is changed via a function) type of extractors. The list can be found via ft.primitives.
list_primitives(). External primitives like tsfresh, or custom calculations can also be input into FeatureTools.
FeatureTools appears to be a very powerful auto-feature extractor. Some resources to read further are as follows:
• https://brendanhasz.github.io/2018/11/11/featuretools
• https://towardsdatascience.com/automated-feature-engineering-in-python-99baf11cc219
• https://medium.com/@rrfd/simple-automatic-feature-engineering-using-featuretools-in-python-for-classification-b1308040e183
6.2. Auto 33
Data Science Documentation, Release 0.1
Class Imbalance
In domains like predictive maintenance, machine failures are usually rare occurrences in the lifetime of the assets com-
pared to normal operation. This causes an imbalance in the label distribution which usually causes poor performance
as algorithms tend to classify majority class examples better at the expense of minority class examples as the total
misclassification error is much improved when majority class is labeled correctly. Techniques are available to correct
for this.
The imbalance-learn package provides an excellent range of algorithms for adjusting for imbalanced
data. Install with pip install -U imbalanced-learn or conda install -c conda-forge
imbalanced-learn.
An important thing to note is that resampling must be done AFTER the train-test split, so as to prevent data leakage.
7.1 Over-Sampling
SMOTE (synthetic minority over-sampling technique) is a common and popular up-sampling technique.
smote = SMOTE()
X_resampled, y_resampled = smote.fit_sample(X_train, y_train)
clf = LogisticRegression()
clf.fit(X_resampled, y_resampled)
ada = ADASYN()
X_resampled, y_resampled = ada.fit_sample(X_train, y_train)
clf = LogisticRegression()
clf.fit(X_resampled, y_resampled)
35
Data Science Documentation, Release 0.1
7.2 Under-Sampling
rus = RandomUnderSampler()
X_resampled, y_resampled = rus.fit_sample(X_train, y_train)
clf = LogisticRegression()
clf.fit(X_resampled, y_resampled)
7.3 Under/Over-Sampling
SMOTEENN combines SMOTE with Edited Nearest Neighbours, which is used to pare down and centralise the
negative cases.
smo = SMOTEENN()
X_resampled, y_resampled = smo.fit_sample(X_train, y_train)
clf = LogisticRegression()
clf.fit(X_resampled, y_resampled)
One can also make the classifier aware of the imbalanced data by incorporating the weights of the classes into a cost
function. Intuitively, we want to give higher weight to minority class and lower weight to majority class.
http://albahnsen.github.io/CostSensitiveClassification/index.html
Data Leakage
Data leakage is a serious bane in machine learning, which usually results in overly optimistic model results.
8.1 Examples
37
Data Science Documentation, Release 0.1
Supervised Learning
9.1 Classification
Fig. 1: www.mathworks.com
Note:
1. Distance Metric: Eclidean Distance (default). In sklearn it is known as (Minkowski with p = 2)
2. How many nearest neighbour: k=1 very specific, k=5 more general model. Use nearest k data points to
determine classification
3. Weighting function on neighbours: (optional)
4. How to aggregate class of neighbour points: Simple majority (default)
41
Data Science Documentation, Release 0.1
Uses gini index (default) or entropy to split the data at binary level.
Strengths: Can select a large number of features that best determine the targets.
Weakness: Tends to overfit the data as it will split till the end. Pruning can be done to remove the leaves to prevent
overfitting but that is not available in sklearn. Small changes in data can lead to different splits. Not very reproducible
for future data (see random forest).
More more tuning parameters https://medium.com/@mohtedibf/indepth-parameter-tuning-for-decision-tree-6753118a03c3
###### IMPORT MODULES #######
import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeClassifier
print test_predictor.shape
print train_predictor.shape
(38, 4)
(112, 4)
print sklearn.metrics.confusion_matrix(test_target,predictions)
print sklearn.metrics.accuracy_score(test_target, predictions)*100, '%'
[[14 0 0]
[ 0 13 0]
[ 0 1 10]]
97.3684210526 %
Viewing the decision tree requires installing of the two packages conda install graphviz & conda install pydotplus.
9.1. Classification 43
Data Science Documentation, Release 0.1
Parameters to tune decision trees include maxdepth & min sample leaf.
9.1. Classification 45
Data Science Documentation, Release 0.1
is, allowing for the possibility of picking the same row again at each selection. You repeat this random
selection process N times. The resulting bootstrap sample has N rows just like the original training set but
with possibly some rows from the original dataset missing and others occurring multiple times just due to
the nature of the random selection with replacement. This process is repeated to generate n samples, using
the parameter n_estimators, which will eventually generate n number decision trees.
• Splitting Features: When picking the best split for a node, instead of finding the best split across all
possible features (decision tree), a random subset of features is chosen and the best split is found within
that smaller subset of features. The number of features in the subset that are randomly considered at each
stage is controlled by the max_features parameter.
This randomness in selecting the bootstrap sample to train an individual tree in a forest ensemble, combined with the
fact that splitting a node in the tree is restricted to random subsets of the features of the split, virtually guarantees that
all of the decision trees and the random forest will be different.
print train_feature.shape
print test_feature.shape
(404, 13)
(102, 13)
9.1. Classification 47
Data Science Documentation, Release 0.1
accuracy
82.3529411765 %
confusion matrix
[[21 0 3]
[ 0 21 4]
[ 8 3 42]]
RM 0.225612
LSTAT 0.192478
CRIM 0.108510
DIS 0.088056
AGE 0.074202
NOX 0.067718
B 0.057706
PTRATIO 0.051702
TAX 0.047568
INDUS 0.037871
RAD 0.026538
ZN 0.012635
CHAS 0.009405
# see how many decision trees are minimally required make the accuarcy consistent
import numpy as np
import matplotlib.pylab as plt
import seaborn as sns
%matplotlib inline
trees=range(100)
accuracy=np.zeros(100)
for i in range(len(trees)):
clf=RandomForestClassifier(n_estimators= i+1)
model=clf.fit(train_feature, train_target)
predictions=model.predict(test_feature)
accuracy[i]=sklearn.metrics.accuracy_score(test_target, predictions)
plt.plot(trees,accuracy)
# well, seems like more than 10 trees will have a consistent accuracy of 0.82.
# Guess there's no need to have an ensemble of 100 trees!
Gradient Boosted Decision Trees (GBDT) builds a series of small decision trees, with each tree attempting to correct
errors from previous stage. Here’s a good video on it, which describes AdaBoost, but gives a good overview of tree
boosting models.
Typically, gradient boosted tree ensembles use lots of shallow trees known in machine learning as weak learners. Built
in a nonrandom way, to create a model that makes fewer and fewer mistakes as more trees are added. Once the model
is built, making predictions with a gradient boosted tree models is fast and doesn’t use a lot of memory.
learning_rate parameter controls how hard each tree tries to correct mistakes from previous round. High learning
rate, more complex trees.
Key parameters, n_estimators, learning_rate, max_depth.
9.1. Classification 49
Data Science Documentation, Release 0.1
# Default Parameters
clf = GradientBoostingClassifier(random_state = 0)
clf.fit(X_train, y_train)
clf.fit(X_train, y_train)
# Results
Breast cancer dataset (learning_rate=0.1, max_depth=3)
Accuracy of GBDT classifier on training set: 1.00
Accuracy of GBDT classifier on test set: 0.96
9.1.6 XGBoost
XGBoost or eXtreme Gradient Boosting, is a form of gradient boosted decision trees is that designed to be highly effi-
cient, flexible and portable. It is one of the highly dominative classifier in competitive machine learning competitions.
https://www.analyticsvidhya.com/blog/2016/03/complete-guide-parameter-tuning-xgboost-with-codes-python/#
# evaluate predictions
(continues on next page)
9.1.7 LightGBM
LightGBM (Light Gradient Boosting) is a lightweight version of gradient boosting developed by Microsoft. It has
similar performance to XGBoost but can run much faster than it.
https://lightgbm.readthedocs.io/en/latest/index.html
import lightgbm
parameters = {
'application': 'binary',
'objective': 'binary',
'metric': 'auc',
'is_unbalance': 'true',
'boosting': 'gbdt',
'num_leaves': 31,
'feature_fraction': 0.5,
'bagging_fraction': 0.5,
'bagging_freq': 20,
'learning_rate': 0.05,
'verbose': 0
}
model = lightgbm.train(parameters,
train_data,
valid_sets=test_data,
num_boost_round=5000,
early_stopping_rounds=100)
9.1.8 CatBoost
Category Boosting has high performance compared to other popular models, and does not require conversion of
categorical values into numbers. It is said to be even faster than LighGBM, and allows model to be ran using GPU.
For easy use, run in Colab & switch runtime to GPU.
More:
• https://catboost.ai
• https://github.com/catboost/tutorials/blob/master/classification/classification_tutorial.ipynb
9.1. Classification 51
Data Science Documentation, Release 0.1
# Model Fitting
# verbose, gives output every n iteration
model.fit(X_train, y_train,
cat_features=cat_features,
eval_set=(X_test, y_test),
verbose=5,
task_type='GPU')
# Get Parameters
model.get_all_params
# Evaluation
model.get_feature_importance(prettified=True)
We can also use k-fold cross validation for better scoring evaluation. There is no need to specify
CatBoostRegressor or CatBoostClassifier, just input the correct eval_metric. One of the folds will
be used as a validation set.
More: https://catboost.ai/docs/concepts/python-reference_cv.html
# CV scores
scores = catboost.cv(cv_dataset, params, fold_count=5)
scores
Naive Bayes is a probabilistic model. Features are assumed to be independent of each other in a given class. This
makes the math very easy. E.g., words that are unrelated multiply together to form the final probability.
Prior Probability: Pr(y). Probability that a class (y) occurred in entire training dataset
Liklihood: Pr(y|xi) Probability of a class (y) occuring given all the features (xi).
There are 3 types of Naive Bayes:
Sklearn allows partial fitting, i.e., fit the model incrementally if dataset is too large for memory.
Naive Bayes model only have one smoothing parameter called alpha (default 0.1). It adds a virtual data point that
have positive values for all features. This is necessary considering that if there are no positive feature, the entire
probability will be 0 (since it is a multiplicative model). More alpha means more smoothing, and more generalisation
(less complex) model.
from sklearn.naive_bayes import GaussianNB
from adspy_shared_utilities import plot_class_regions_for_classifier
9.1. Classification 53
Data Science Documentation, Release 0.1
Binary output or y value. Functions are available in both statsmodels and sklearn packages.
Lower CI Upper CI OR
depth 61.625434 80.209893 70.306255
layers_YESNO 0.112824 0.130223 0.121212
h = 6
w = 8
print('A fruit with height {} and width {} is predicted to be: {}'
.format(h,w, ['not an apple', 'an apple'][clf.predict([[h,w]])[0]]))
h = 10
w = 7
print('A fruit with height {} and width {} is predicted to be: {}'
.format(h,w, ['not an apple', 'an apple'][clf.predict([[h,w]])[0]]))
subaxes.set_xlabel('height')
subaxes.set_ylabel('width')
9.1. Classification 55
Data Science Documentation, Release 0.1
Support Vector Machines (SVM) involves locating the support vectors of two boundaries to find a maximum tolerance
hyperplane. Side note: linear kernels work best for text classification.
We can directly call a linear SVC by directly importing the LinearSVC function
from sklearn.svm import LinearSVC
X_train, X_test, y_train, y_test = train_test_split(X_cancer, y_cancer, random_state
˓→= 0)
Multi-Class Classification, i.e., having more than 2 target values, is also possible. With the results, it is possible to
compare one class versus all other classes.
9.1. Classification 57
Data Science Documentation, Release 0.1
visualising in a graph. . .
plt.figure(figsize=(6,6))
colors = ['r', 'g', 'b', 'y']
cmap_fruits = ListedColormap(['#FF0000', '#00FF00', '#0000FF','#FFFF00'])
plt.scatter(X_fruits_2d[['height']], X_fruits_2d[['width']],
c=y_fruits_2d, cmap=cmap_fruits, edgecolor = 'black', alpha=.7)
# and the decision boundary is defined as being all points with y = 0, to plot x_
˓→1 as a
# function of x_0 we just solve w_0 x_0 + w_1 x_1 + b = 0 for x_1:
plt.plot(x_0_range, -(x_0_range * w[0] + b) / w[1], c=color, alpha=.8)
plt.legend(target_names_fruits)
plt.xlabel('height')
plt.ylabel('width')
plt.xlim(-2, 12)
plt.ylim(-2, 15)
plt.show()
Full tuning in Support Vector Machines, using normalisation, kernel tuning, and regularisation.
Parameters include
• hidden_layer_sizes which is the number of hidden layers, with no. units in each layer (default
100).
• solvers is the algorithm usedthat does the numerical work of finding the optimal weights. default adam
used for large datasets, lbfgs is used for smaller datasets.
• alpha: L2 regularisation, default is 0.0001,
• activation: non-linear function used for activation function which include relu (default),
logistic, tanh
One Hidden Layer
from sklearn.neural_network import MLPClassifier
from adspy_shared_utilities import plot_class_regions_for_classifier_subplot
9.1. Classification 59
Data Science Documentation, Release 0.1
Fig. 10: Activation Function. University of Michigan: Coursera Data Science in Python
scaler = MinMaxScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# RESULTS
Breast cancer dataset
Accuracy of NN classifier on training set: 0.98
Accuracy of NN classifier on test set: 0.97
9.1. Classification 61
Data Science Documentation, Release 0.1
9.2 Regression
Ordinary Least Squares Regression or OLS Regression is the most basic form and fundamental of regression. Best
fit line ŷ = a + bx is drawn based on the ordinary least squares method. i.e., least total area of squares (sum of
squares) with length from each x,y point to regresson line.
OLS can be conducted using statsmodel package.
Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly
˓→specified.
reg = linear_model.LinearRegression()
model = reg.fit ([[0, 0], [1, 1], [2, 2]], [0, 1, 2])
model
(continues on next page)
# R2 scores
r2_trains = model.score(X_train, y_train)
r2_tests = model.score(X_test, y_test)
Regularisaton is an important concept used in Ridge Regression as well as the next LASSO regression. Ridge
regression uses regularisation which adds a penalty parameter to a variable when it has a large variation. Regularisation
prevents overfitting by restricting the model, thus lowering its complexity.
• Uses L2 regularisation, which reduces the sum of squares of the parameters
• The influence of L2 is controlled by an alpha parameter. Default is 1.
• High alpha means more regularisation and a simpler model.
• More in https://www.analyticsvidhya.com/blog/2016/01/complete-tutorial-ridge-lasso-regression-python/
print('Crime dataset')
print('ridge regression linear model intercept: {}'
.format(linridge.intercept_))
print('ridge regression linear model coeff:\n{}'
.format(linridge.coef_))
print('R-squared score (training): {:.3f}'
.format(linridge.score(X_train_scaled, y_train)))
print('R-squared score (test): {:.3f}'
.format(linridge.score(X_test_scaled, y_test)))
print('Number of non-zero features: {}'
.format(np.sum(linridge.coef_ != 0)))
9.2. Regression 63
Data Science Documentation, Release 0.1
Note:
• Many variables with small/medium effects: Ridge
• Only a few variables with medium/large effects: LASSO
LASSO refers to Least Absolute Shrinkage and Selection Operator Regression. Like Ridge Regression this also has a
regularisation property.
• Uses L1 regularisation, which reduces sum of the absolute values of coefficients, that change unimportant fea-
tures (their regression coefficients) into 0
• This is known as a sparse solution, or a kind of feature selection, since some variables were removed in the
process
• The influence of L1 is controlled by an alpha parameter. Default is 1.
• High alpha means more regularisation and a simpler model. When alpha = 0, then it is a normal OLS regression.
a. Bias increase & variability decreases when alpha increases.
b. Useful when there are many features (explanatory variables).
c. Have to standardize all features so that they have mean 0 and std error 1.
d. Have several algorithms: LAR (Least Angle Regression). Starts w 0 predictors & add each predictor that is most
correlated at each step.
print train_feature.shape
print test_feature.shape
(404, 13)
(102, 13)
df2=pd.DataFrame(model.coef_, index=feature.columns)
df2.sort_values(by=0,ascending=False)
RM 3.050843
RAD 2.040252
ZN 1.004318
B 0.629933
CHAS 0.317948
INDUS 0.225688
AGE 0.000000
CRIM -0.770291
NOX -1.617137
TAX -1.731576
PTRATIO -1.923485
DIS -2.733660
LSTAT -3.878356
9.2. Regression 65
Data Science Documentation, Release 0.1
# Polynomial Regression
poly = PolynomialFeatures(degree=2)
(continues on next page)
9.2. Regression 67
Data Science Documentation, Release 0.1
Unsupervised Learning
10.1 Transformations
69
Data Science Documentation, Release 0.1
PCA summarises multiple fields of data into principal components, usually just 2 so that it is easier to visualise in
a 2-dimensional plot. The 1st component will show the most variance of the entire dataset in the hyperplane, while
the 2nd shows the 2nd shows the most variance at a right angle to the 1st. Because of the strong variance between
data points, patterns tend to be teased out from a high dimension to even when there’s just two dimensions. These 2
components can serve as new features for a supervised analysis.
In short, PCA finds the best possible characteristics, that summarises the classes of a feature. Two excellent sites
elaborate more: setosa, quora. The most challenging part of PCA is interpreting the components.
cancer = load_breast_cancer()
df = pd.DataFrame(cancer['data'],columns=cancer['feature_names'])
# Before applying PCA, each feature should be centered (zero mean) and with unit
˓→variance
scaled_data = StandardScaler().fit(df).transform(df)
x_pca = pca.transform(scaled_data)
print(df.shape, x_pca.shape)
# RESULTS
(569, 30) (569, 2)
percent = pca.explained_variance_ratio_
print(percent)
print(sum(percent))
Plotting the PCA-transformed version of the breast cancer dataset. We can see that malignant and benign cells cluster
between two groups and can apply a linear classifier to this two dimensional representation of the dataset.
plt.figure(figsize=(8,6))
plt.scatter(x_pca[:,0], x_pca[:,1], c=cancer['target'], cmap='plasma', alpha=0.4,
˓→edgecolors='black', s=65);
Plotting the magnitude of each feature value for the first two principal components. This gives the best explanation for
the components for each field.
plt.gca().set_xticks(np.arange(-.5, len(feature_names)));
plt.gca().set_yticks(np.arange(0.5, 2));
plt.gca().set_xticklabels(feature_names, rotation=90, ha='left', fontsize=12);
plt.gca().set_yticklabels(['First PC', 'Second PC'], va='bottom', fontsize=12);
10.1. Transformations 71
Data Science Documentation, Release 0.1
We can also plot the feature magnitudes in the scatterplot like in R into two separate axes, also known as a biplot. This
shows the relationship of each feature’s magnitude clearer in a 2D space.
# put feature values into dataframe
components = pd.DataFrame(pca.components_.T, index=df.columns, columns=['PCA1','PCA2
˓→'])
# main scatterplot
plt.scatter(x_pca[:,0], x_pca[:,1], c=cancer['target'], cmap='plasma', alpha=0.4,
˓→edgecolors='black', s=40);
# reference lines
ax2.hlines(0,-0.5,0.5, linestyles='dotted', colors='grey')
ax2.vlines(0,-0.5,0.5, linestyles='dotted', colors='grey')
Lastly, we can specify the percentage explained variance, and let PCA decide on the number components.
Multi-Dimensional Scaling
Multi-Dimensional Scaling (MDS) is a type of manifold learning algorithm that to visualize a high dimensional dataset
and project it onto a lower dimensional space - in most cases, a two-dimensional page. PCA is weak in this aspect.
sklearn gives a good overview of various manifold techniques. https://scikit-learn.org/stable/modules/manifold.html
# each feature should be centered (zero mean) and with unit variance
X_fruits_normalized = StandardScaler().fit(X_fruits).transform(X_fruits)
mds = MDS(n_components = 2)
10.1. Transformations 73
Data Science Documentation, Release 0.1
t-SNE
t-Distributed Stochastic Neighbor Embedding (t-SNE) is a powerful manifold learning algorithm for visualizing clus-
ters. It finds a two-dimensional representation of your data, such that the distances between points in the 2D scatterplot
match as closely as possible the distances between the same points in the original high dimensional dataset. In partic-
ular, t-SNE gives much more weight to preserving information about distances between points that are neighbors.
More information here.
from sklearn.manifold import TSNE
tsne = TSNE(random_state = 0)
X_tsne = tsne.fit_transform(X_fruits_normalized)
plot_labelled_scatter(X_tsne, y_fruits,
(continues on next page)
10.1. Transformations 75
Data Science Documentation, Release 0.1
Fig. 2: You can see how some dimensionality reduction methods may be less successful on some datasets. Here, it
doesn’t work as well at finding structure in the small fruits dataset, compared to other methods like MDS.
LDA
Latent Dirichlet Allocation is another dimension reduction method, but unlike PCA, it is a supervised method. It
attempts to find a feature subspace or decision boundary that maximizes class separability. It then projects the data
points to new dimensions in a way that the clusters are as separate from each other as possible and the individual
elements within a cluster are as close to the centroid of the cluster as possible.
Differences of PCA & LDA, from:
• https://sebastianraschka.com/Articles/2014_python_lda.html
• https://stackabuse.com/implementing-lda-in-python-with-scikit-learn/
# from sklearn documentation
from sklearn.decomposition import LatentDirichletAllocation
from sklearn.datasets import make_multilabel_classification
Self-Organzing Maps
SOM is a special type of neural network that is trained using unsupervised learning to produce a two-dimensional map.
Each row of data is assigned to its Best Matching Unit (BMU) neuron. Neighbourhood effect to create a topographic
map
They differ from other artificial neural networks as:
1. they apply competitive learning as opposed to error-correction learning (such as backpropagation with
gradient descent)
2. in the sense that they use a neighborhood function to preserve the topological properties of the input space.
3. Consist of only one visible output layer
Requires scaling or normalization of all features first.
https://github.com/JustGlowing/minisom
We first need to calculate the number of neurons and how many of them making up each side. The ratio of the side
lengths of the map is approximately the ratio of the two largest eigenvalues of the training data’s covariance matrix.
10.1. Transformations 77
Data Science Documentation, Release 0.1
# calculate eigen_values
normal_cov = np.cov(data_normal)
eigen_values = np.linalg.eigvals(normal_cov)
# 2 largest eigenvalues
result = sorted([i.real for i in eigen_values])[-2:]
ratio_2_largest_eigen = result[1]/result[0]
side = total_neurons/ratio_2_largest_eigen
# two sides
print(total_neurons)
print('1st side', side)
print('2nd side', ratio_2_largest_eigen)
Quantization error is the distance between each vector and the BMU.
som.quantization_error(array)
10.2 Clustering
Find groups in data & assign every point in the dataset to one of the groups.
10.2.1 K-Means
Need to specify K number of clusters. It is also important to scale the features before applying K-means, unless the
fields are not meant to be scaled, like distances. Categorical data is not appropriate as clustering calculated using
euclidean distance (means). For long distances over an lat/long coordinates, they need to be projected to a flat surface.
One aspect of k means is that different random starting points for the cluster centers often result in very different
clustering solutions. So typically, the k-means algorithm is run in scikit-learn with ten different random initializations
and the solution occurring the most number of times is chosen.
Downsides
• Very sensitive to outliers. Have to remove before running the model
• Might need to reduce dimensions if very high no. of features or the distance separation might not be
obvious
Methodology
1. Specify number of clusters (3)
2. 3 random data points are randomly selected as cluster centers
3. Each data point is assigned to the cluster center it is cloest to
4. Cluster centers are updated to the mean of the assigned points
5. Steps 3-4 are repeated, till cluster centers remain unchanged
Example 1
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
from adspy_shared_utilities import plot_labelled_scatter
from sklearn.preprocessing import MinMaxScaler
fruits = pd.read_table('fruit_data_with_colors.txt')
X_fruits = fruits[['mass','width','height', 'color_score']].as_matrix()
y_fruits = fruits[['fruit_label']] - 1
X_fruits_normalized = MinMaxScaler().fit(X_fruits).transform(X_fruits)
10.2. Clustering 79
Data Science Documentation, Release 0.1
Example 2
df.describe()
print train_feature.shape
print test_feature.shape
(120, 4)
(30, 4)
10.2. Clustering 81
Data Science Documentation, Release 0.1
/ train_feature.shape[0])
plt.plot(clusters, meandist)
plt.xlabel('Number of clusters')
plt.ylabel('Average distance')
plt.title('Selecting k with the Elbow Method')
We can visualise the clusters by reducing the dimensions into 2 using PCA. They are separate by theissen polygons,
though at a multi-dimensional space.
plt.figure(figsize=(8,8))
plt.scatter(pd.DataFrame(pca)[0],pd.DataFrame(pca)[1], c=labels, cmap='plasma',
˓→alpha=0.5);
10.2. Clustering 83
Data Science Documentation, Release 0.1
Sometimes we need to find the cluster centres so that we can get an absolute distance measure of centroids to new
data. Each feature will have a defined centre for each cluster.
If we have labels or y, and want to determine which y belongs to which cluster for an evaluation score, we can use a
groupby to find the most number of labels that fall in a cluster and manually label them as such.
df = concat.groupby(['label','cluster'])['cluster'].count()
If we want to know what is the distance of each datapoint’s assign cluster distance to their centroid, we can do a
fit_transform to get all distance from all cluster centroids and process from there.
GMM is, in essence a density estimation model but can function like clustering. It has a probabilistic model under the
hood so it returns a matrix of probabilities belonging to each cluster for each data point. More: https://jakevdp.github.
io/PythonDataScienceHandbook/05.12-gaussian-mixtures.html
We can input the covariance_type argument such that it can choose between diag (the default, ellipse constrained to
the axes), spherical (like k-means), or full (ellipse without a specific orientation).
BIC or AIC are used to determine the optimal number of clusters using the elbow diagram, the former usually recom-
mends a simpler model. Note that number of clusters or components measures how well GMM works as a density
estimator, not as a clustering algorithm.
input_gmm = normal.values
bic_list = []
aic_list = []
ranges = range(1,30)
for i in ranges:
gmm = GaussianMixture(n_components=i).fit(input_gmm)
(continues on next page)
10.2. Clustering 85
Data Science Documentation, Release 0.1
plt.figure(figsize=(10, 5))
plt.plot(ranges, bic_list, label='BIC');
plt.plot(ranges, aic_list, label='AIC');
plt.legend(loc='best');
Agglomerative Clustering is a type of hierarchical clustering technique used to build clusters from bottom up. Divisive
Clustering is the opposite method of building clusters from top down, which is not available in sklearn.
Methods of linking clusters together.
AgglomerativeClustering method in sklearn allows clustering to be choosen by the no. clusters or distance
threshold.
from sklearn.datasets import make_blobs
from sklearn.cluster import AgglomerativeClustering
X, y = make_blobs(random_state = 10)
cls_assignment = cls.fit_predict(X)
10.2. Clustering 87
Data Science Documentation, Release 0.1
One of the benfits of this clustering is that a hierarchy can be built via a dendrogram. We have to recompute the
clustering using the ward function.
# BUILD DENDROGRAM
from scipy.cluster.hierarchy import ward, dendrogram
Z = ward(X)
plt.figure(figsize=(10,5));
dendrogram(Z, orientation='left', leaf_font_size=8))
plt.show()
More: https://joernhees.de/blog/2015/08/26/scipy-hierarchical-clustering-and-dendrogram-tutorial/
In essence, we can also use the 3-step method above to compute agglomerative clustering.
# 1. clustering
Z = linkage(X, method='ward', metric='euclidean')
# 2. draw dendrogram
plt.figure(figsize=(10,5));
dendrogram(Z, orientation='left', leaf_font_size=8)
plt.show()
# 3. flatten cluster
distance_threshold = 10
y = fcluster(Z, distance_threshold, criterion='distance')
sklearn agglomerative clustering is very slow, and an alternative fastcluster library performs much faster as it is
a C++ library with a python interface.
More: https://pypi.org/project/fastcluster/
import fastcluster
from scipy.cluster.hierarchy import dendrogram, fcluster
# 1. clustering
Z = fastcluster.linkage_vector(X, method='ward', metric='euclidean')
Z_df = pd.DataFrame(data=Z, columns=['clusterOne','clusterTwo','distance',
˓→'newClusterSize'])
# 2. draw dendrogram
plt.figure(figsize=(10, 5))
dendrogram(Z, orientation='left', leaf_font_size=8)
plt.show();
# 3. flatten cluster
distance_threshold = 2000
clusters = fcluster(Z, distance_threshold, criterion='distance')
10.2. Clustering 89
Data Science Documentation, Release 0.1
Then we select the distance threshold to cut the dendrogram to obtain the selected clustering level. The output is the
cluster labelled for each row of data. As expected from the dendrogram, a cut at 2000 gives us 5 clusters.
This link gives an excellent tutorial on prettifying the dendrogram. http://datanongrata.com/2019/04/27/67/
10.2.4 DBSCAN
Density-Based Spatial Clustering of Applications with Noise (DBSCAN). Need to scale/normalise data. DBSCAN
works by identifying crowded regions referred to as dense regions.
Key parameters are eps and min_samples. If there are at least min_samples many data points within a distance of
eps to a given data point, that point will be classified as a core sample. Core samples that are closer to each other than
the distance eps are put into the same cluster by DBSCAN.
There is recently a new method called HDBSCAN (H = Hierarchical). https://hdbscan.readthedocs.io/en/latest/index.
html
Methodology
1. Pick an arbitrary point to start
2. Find all points with distance eps or less from that point
3. If points are more than min_samples within distance of esp, point is labelled as a core sample, and assigned
a new cluster label
4. Then all neighbours within eps of the point are visited
5. If they are core samples their neighbours are visited in turn and so on
6. The cluster thus grows till there are no more core samples within distance eps of the cluster
7. Then, another point that has not been visited is picked, and step 1-6 is repeated
8. 3 kinds of points are generated in the end, core points, boundary points, and noise
9. Boundary points are core clusters but not within distance of esp
10.2. Clustering 91
Data Science Documentation, Release 0.1
cls = dbscan.fit_predict(X)
print("Cluster membership values:\n{}".format(cls))
Cluster membership values:
[ 0 1 0 2 0 0 0 2 2 -1 1 2 0 0 -1 0 0 1 -1 1 1 2 2 2 1]
# -1 indicates noise or outliers
plot_labelled_scatter(X, cls + 1,
['Noise', 'Cluster 0', 'Cluster 1', 'Cluster 2'])
These requires the training of a normal state(s), allows outliers to be detected when they lie outside trained state.
One-class SVM is an unsupervised algorithm that learns a decision function for outlier detection: classifying new data
as similar or different to the training set.
Besides the kernel, two other parameters are impt: The nu parameter should be the proportion of outliers you expect
to observe (in our case around 2%), the gamma parameter determines the smoothing of the contour lines.
from sklearn.svm import OneClassSVM
clf.fit(X_train)
y_pred_test = clf.predict(X_test)
# -1 are outliers
y_pred_test
# array([ 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1])
We can also get the average anomaly scores. The lower, the more abnormal. Negative scores represent outliers,
positive scores represent inliers.
clf.decision_function(X_test)
array([ 0.14528263, 0.14528263, -0.08450298, 0.14528263, 0.14528263,
0.14528263, 0.14528263, 0.14528263, 0.14528263, -0.14279962,
0.14528263, 0.14528263, -0.05483886, -0.10086102, 0.14528263,
0.14528263])
Euclidean distance is the straight line distance between points, while cosine distance is the cosine of the angle between
these two points.
euclidean([1,2],[1,3])
# 1
cosine([1,2],[1,3])
# 0.010050506338833642
Mahalonobis distance is the distance between a point and a distribution, not between two distinct points. Therefore, it
is effectively a multivariate equivalent of the Euclidean distance.
https://www.machinelearningplus.com/statistics/mahalanobis-distance/
• x: is the vector of the observation (row in a dataset),
• m: is the vector of mean values of independent variables (mean of each column),
import pandas as pd
import numpy as np
from scipy.spatial.distance import mahalanobis
return distanceMD
If two time series are identical, but one is shifted slightly along the time axis, then Euclidean distance may consider
them to be very different from each other. DTW was introduced to overcome this limitation and give intuitive distance
measurements between time series by ignoring both global and local shifts in the time dimension.
DTW is a technique that finds the optimal alignment between two time series, if one time series may be “warped” non-
linearly by stretching or shrinking it along its time axis. Dynamic time warping is often used in speech recognition
to determine if two waveforms represent the same spoken phrase. In a speech waveform, the duration of each spoken
sound and the interval between sounds are permitted to vary, but the overall speech waveforms must be similar.
From the creators of FastDTW, it produces an accurate minimum-distance warp path between two time series than is
nearly optimal (standard DTW is optimal, but has a quadratic time and space complexity).
Output: Identical = 0, Difference > 0
import numpy as np
from scipy.spatial.distance import euclidean
from fastdtw import fastdtw
# 2.8284271247461903
SAX, developed in 2007, compares the similarity of two time-series patterns by slicing them into horizontal & vertical
regions, and comparing between each of them. This can be easily explained by 4 charts provided by https://jmotif.
github.io/sax-vsm_site/morea/algorithm/SAX.html.
There are obvious benefits using such an algorithm, for one, it will be very fast as pattern matching is aggregated.
However, the biggest downside is that both time-series signals have to be of same time-length.
Then normalised.
The chart is then sliced by various timeframes, Piecewise Aggregate Approximation, and each slice is compared
between the two signals independently.
Each signal value, i.e., y-axis is then sliced horizontally into regions, and assigned an alphabet.
Lastly, we use a distance scoring metric, through a fixed lookup table to easily calculate the total scores between each
pair of PAA.
E.g., if the PAA fall in a region or its immediate adjacent one, we assume they are the same, i.e., distance = 0. Else, a
distance value is assigned. The total distance is then computed to derice a distance metric.
For this instance:
• SAX transform of ts1 into string through 9-points PAA: “abddccbaa”
• SAX transform of ts2 into string through 9-points PAA: “abbccddba”
• SAX distance: 0 + 0 + 0.67 + 0 + 0 + 0 + 0.67 + 0 + 0 = 1.34
This is the code from the package saxpy. Unfortunately, it does not have the option of calculating of the sax distance.
import numpy as np
from saxpy.znorm import znorm
from saxpy.paa import paa
(continues on next page)
sig1a = saxpy_sax(sig1)
sig2a = saxpy_sax(sig2)
Another more mature package is tslearn. It enables the calculation of sax distance, but the sax alphabets are set as
integers instead.
sax_data = sax.fit_transform([sig1_n,sig2_n])
# distance measure
distance = sax.distance_sax(sax_data[0],sax_data[1])
# [[[0]
# [3]
# [3]
# [1]]
# [[0]
# [1]
# [2]
# [3]]]
# 1.8471662549420924
https://github.com/target/matrixprofile-ts
Active Learning
11.1 Introduction
Getting labeled data is a huge and often prohibitive cost for a lot of machine learning projects. Active Learning is
a methodology that can sometimes greatly reduce the amount of labeled data required to train a model with higher
accuracy if it is allowed to choose which data to label. It does this by prioritizing the labeling work for the experts
(oracles).
Active Learning prioritizes which data the model is most confused about and requests labels for just those. This helps
the model learn faster, and lets the experts skip labeling data that wouldn’t be very helpful to the model.
Fig. 1: Training samples near the decision boundary allows a more accurate hyperplane being drawn.
99
Data Science Documentation, Release 0.1
to change.
3. Pool-Based Sampling: This is similar to stream-based, except that it starts a large pool of unlabelled data.
The main difference between stream-based and pool-based active learning is that the former scans through the data
sequentially and makes query decisions individually, whereas the latter evaluates and ranks the entire collection before
selecting the best query.
1. Uncertainiy Sampling: Learner will choose instances which it is least certain how to label. There are 3 methods
in this sampling, i.e., Least Confidence, Margin Sampling, and Entropy Sampling, with the latter being the best
among the 3 due to its consideration of utilizing all the possible label probabilities for the selection process.
2. Query by Committee: Using an ensemble of models to vote on which candidates to label.
We can use a performance metric, e.g. accuracy to determine when to stop further querying. Ideally it should be
when any further labelling and retraining of the model does not improve the performance metric significantly, i.e., the
performance has reached plateau. This means that the slope of the graph (y2-y1/x2-x1) per time-step has neared 0.
Of course, plateauing is determined on a good query strategy together with an appropriate model.
https://modal-python.readthedocs.io/en/latest/index.html
11.5 Resources
Deep Learning
Deep Learning falls under the broad class of Articial Intelligence > Machine Learning. It is a Machine Learning tech-
nique that uses multiple internal layers (hidden layers) of non-linear processing units (neurons) to conduct supervised
or unsupervised learning from data.
12.1 Introduction
12.1.1 GPU
Tensorflow is able to run faster and more effeciently using Nivida’s GPU pip install tensorflow-gpu.
12.1.2 Preprocessing
Keras accepts numpy input, so we have to convert. Also, for multi-class classification, we need to
convert them into binary values; i.e., using one-hot encoding. For the latter, we can in-place use
sparse_categorical_crossentropy for the loss function which will can process the multi-class label with-
out converting to one-hot encoding.
# convert to numpy arrays
X = np.array(X)
# OR
X = X.values
It is important to scale or normalise the dataset before putting in the neural network.
from sklearn.preprocessing import StandardScaler
101
Data Science Documentation, Release 0.1
model.summary()
12.1.3 Evaluation
The model compiled has a history method (model.history.history) that gives the accuracy and loss for both
train & test sets for each time step. We can plot it out for a better visualization. Alternatively we can also use
TensorBoard, which is installed together with TensorFlow package. It will also draw the model architecture.
def plot_validate(model, loss_acc):
'''Plot model accuracy or loss for both train and test validation per epoch
(continues on next page)
if loss_acc == 'loss':
axis_title = 'loss'
title = 'Loss'
epoch = len(history['loss'])
elif loss_acc == 'acc':
axis_title = 'acc'
title = 'Accuracy'
epoch = len(history['loss'])
plt.figure(figsize=(15,4))
plt.plot(history[axis_title])
plt.plot(history['val_' + axis_title])
plt.title('Model ' + title)
plt.ylabel(title)
plt.xlabel('Epoch')
plt.grid(b=True, which='major')
plt.minorticks_on()
plt.grid(b=True, which='minor', alpha=0.2)
plt.legend(['Train', 'Test'])
plt.show()
12.1.4 Auto-Tuning
Unlike grid-search we can use Bayesian optimization for a faster hyperparameter tuning.
https://www.dlology.com/blog/how-to-do-hyperparameter-search-with-baysian-optimization-for-keras-model/ https:
//medium.com/@crawftv/parameter-hyperparameter-tuning-with-bayesian-optimization-7acf42d348e1
ReLu (Rectified Linear units) is very popular compared to the now mostly obsolete sigmoid & tanh functions because
it avoids vanishing gradient problem and has faster convergence. However, ReLu can only be used in hidden layers.
Also, some gradients can be fragile during training and can die. It can cause a weight update which will makes it never
activate on any data point again. Simply saying that ReLu could result in Dead Neurons.
To fix this problem another modification was introduced called Leaky ReLu to fix the problem of dying neurons. It
introduces a small slope to keep the updates alive. We then have another variant made form both ReLu and Leaky
ReLu called Maxout function .
Output Layer
Activation function
• Binary Classification: Sigmoid
• Multi-Class Classification: Softmax
• Regression: Linear
Fig. 3: https://towardsdatascience.com/activation-functions-and-its-types-which-is-better-a9a5310cc8f
Backpropagation, short for “backward propagation of errors,” is an algorithm for supervised learning of artificial neural
networks using gradient descent.
• Optimizer is a learning algorithm called gradient descent, refers to the calculation of an error gradient or slope
of error and “descent” refers to the moving down along that slope towards some minimum level of error.
• Batch Size is a hyperparameter of gradient descent that controls the number of training samples to work through
before the model’s internal parameters are updated.
• Epoch is a hyperparameter of gradient descent that controls the number of complete passes through the training
dataset.
Optimizers is used to find the minimium value of the cost function to perform backward propagation. There are more
advanced adaptive optimizers, like AdaGrad/RMSprop/Adam, that allow the learning rate to adapt to the size of the
gradient. The hyperparameters are essential to get the model to perform well.
Fig. 4: From Udemy, Zero to Hero Deep Learning with Python & Keras
Assume you have a dataset with 200 samples (rows of data) and you choose a batch size of 5 and 1,000 epochs. This
means that the dataset will be divided into 40 batches, each with 5 samples. The model weights will be updated after
each batch of 5 samples. This also means that one epoch will involve 40 batches or 40 updates to the model.
More here:
• https://machinelearningmastery.com/difference-between-a-batch-and-an-epoch/.
• https://machinelearningmastery.com/gentle-introduction-mini-batch-gradient-descent-configure-batch-size/
• https://blog.usejournal.com/stock-market-prediction-by-recurrent-neural-network-on-lstm-model-56de700bff68
12.3 ANN
12.3.1 Theory
An artifical neural network is the most basic form of neural network. It consists of an input layer, hidden layers, and
an output layer. This writeup by Berkeley gave an excellent introduction to the theory. Most of the diagrams are taken
from the site.
Zooming in at a single perceptron, the input layer consists of every individual features, each with an assigned weight
feeding to the hidden layer. An activation function tells the perception what outcome it is.
Activation functions consists of ReLU, Tanh, Linear, Sigmoid, Softmax and many others. Sigmoid is used for binary
classifications, while softmax is used for multi-class classifications.
The backward propagation algorithm works in such that the slopes of gradient descent is calculated by working back-
wards from the output layer back to the input layer. The weights are readjusted to reduce the loss and improve the
accuracy of the model.
A summary is as follows
1. Randomly initialize the weights for all the nodes.
2. For every training example, perform a forward pass using the current weights, and calculate the output of each
node going from left to right. The final output is the value of the last node.
3. Compare the final output with the actual target in the training data, and measure the error using a loss function.
4. Perform a backwards pass from right to left and propagate the error to every individual node using backprop-
agation. Calculate each weight’s contribution to the error, and adjust the weights accordingly using gradient
descent. Propagate the error gradients back starting from the last layer.
Before training, the model needs to be compiled with the learning hyperparameters of optimizer, loss, and metric
functions.
def create_model():
model = Sequential()
model.add(Dense(6, input_dim=4, kernel_initializer='normal', activation='relu'))
#model.add(Dense(4, kernel_initializer='normal', activation='relu'))
model.add(Dense(1, kernel_initializer='normal', activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
# convert the 0-9 labels into "one-hot" format, as we did for TensorFlow.
train_labels = keras.utils.to_categorical(mnist_train_labels, 10)
test_labels = keras.utils.to_categorical(mnist_test_labels, 10)
model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(784,)))
model.add(Dense(10, activation='softmax'))
model.summary()
model.compile(loss='categorical_crossentropy',
optimizer=RMSprop(),
metrics=['accuracy'])
model = Sequential()
model.compile(loss='sparse_categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
model.fit(X_train, y_train,
batch_size=batch,
epochs= epoch,
verbose=verbose,
validation_data=(X_test, y_test))
return model
iris = load_iris()
X = pd.DataFrame(iris['data'], columns=iris['feature_names'])
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X,y,random_state=0)
12.4 CNN
Convolutional Neural Network (CNN) is suitable for unstructured data like image classification, machine translation,
sentence classification, and sentiment analysis.
12.4.1 Theory
This article from medium gives a good introduction of CNN. The steps goes something like this:
1. Provide input image into convolution layer
2. Choose parameters, apply filters with strides, padding if requires. Perform convolution on the image and apply
ReLU activation to the matrix.
There are many topologies, or CNN architecture to build on as the hyperparameters, layers etc. are endless. Some
specialized architecture includes LeNet-5 (handwriting recognition), AlexNet (deeper than LeNet, image classifica-
tion), GoogLeNet (deeper than AlexNet, includes inception modules, or groups of convolution), ResNet (even deeper,
maintains performance using skip connections). This article1 gives a good summary of each architecture.
import tensorflow
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Conv2D, MaxPooling2D, Flatten
from tensorflow.keras.optimizers import RMSprop
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=input_shape))
# 64 3x3 kernels
model.add(Conv2D(64, (3, 3), activation='relu'))
# Reduce by taking the max of each 2x2 block
model.add(MaxPooling2D(pool_size=(2, 2)))
# Dropout to avoid overfitting
model.add(Dropout(0.25))
# Flatten the results to one dimension for passing into our final layer
model.add(Flatten())
# A hidden layer to learn with
model.add(Dense(128, activation='relu'))
# Another dropout
model.add(Dropout(0.5))
# Final categorization from 0-9 with softmax
model.add(Dense(10, activation='softmax'))
model.summary()
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
12.5 RNN
Recurrent Neural Network (RNN). A typical RNN looks like below, where X(t) is input, h(t) is output and A is the
neural network which gains information from the previous step in a loop. The output of one unit goes into the next
one and the information is passed.
12.5.1 Theory
Long Short Term Memory (LSTM) is a special kind of Recurrent Neural Networks (RNN) with the capability of
learning long-term dependencies. The intricacies lie within the cell, where 3 internal mechanisms called gates regulate
the flow of information. This consists of 4 activation functions, 3 sigmoid and 1 tanh, instead of the typical 1 activation
function. This medium from article gives a good description of it. An alternative, or simplified form of LSTM is Gated
Recurrent Unit (GRU).
LSTM requires input needs to be of shape (num_sample, time_steps, num_features) if using tensorflow
backend. This can be processed using keras’s TimeseriesGenerator.
X = [1,2,3,4,5,6,7,8,9,10]
y = [5,6,7,8,9,1,2,3,4,5]
data = TimeseriesGenerator(X, y,
length=time_steps,
stride=stride,
batch_size=num_sample)
(continues on next page)
# (array([[1, 2, 3, 4, 5, 6],
# [2, 3, 4, 5, 6, 7],
# [3, 4, 5, 6, 7, 8],
# [4, 5, 6, 7, 8, 9]]), array([2, 3, 4, 5]))
# note that y-label is the next time step away
time_steps = 6
stride = 1
num_sample = 4
data = TimeseriesGenerator(X, y,
length=time_steps,
stride=stride,
batch_size=num_sample)
X = data[0][0]
y = data[0][1]
The code below uses LSTM for sentiment analysis in IMDB movie reviews.
from tensorflow.keras.preprocessing import sequence
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Embedding
from tensorflow.keras.layers import LSTM
from tensorflow.keras.datasets import imdb
# embedding layer converts input data into dense vectors of fixed size of 20k words &
˓→128 hidden neurons, better suited for neural network
model = Sequential()
model.add(Embedding(20000, 128)) #for nlp
model.add(LSTM(128, dropout=0.2, recurrent_dropout=0.2)) #128 memory cells
model.add(Dense(1, activation='sigmoid')) #1 class classification, sigmoid for binary
˓→classification
model.compile(loss='binary_crossentropy',
optimizer='adam',
metrics=['accuracy'])
model.fit(x_train, y_train,
(continues on next page)
def lstm(X_train, y_train, X_test, y_test, classes, epoch, batch, verbose, dropout)
model = Sequential()
# return sequences refer to all the outputs of the memory cells, True if next
˓→layer is LSTM
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy',
optimizer='adam',
metrics=['accuracy'])
model.fit(X, y,
batch_size=batch,
epochs= epoch,
verbose=verbose,
validation_data=(X_test, y_test))
return model
df = stock('S68', 10)
# train-test split-------------
df1 = df[:2400]
df2 = df[2400:]
X_train = df1[['High','Low','Open','Close','Volume']].values
y_train = df1['change'].values
X_test = df2[['High','Low','Open','Close','Volume']].values
y_test = df2['change'].values
# normalisation-------------
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
data = TimeseriesGenerator(X, y,
length=time_steps,
sampling_rate=sampling_rate,
batch_size=num_sample)
X_train = data[0][0]
y_train = data[0][1]
# model validation-------------
classes = 1
epoch = 2000
batch = 200
verbose = 0
dropout = 0.2
From Keras documentation, it is not recommended to save the model in a pickle format. Keras allows saving in a
HDF5 format. This saves the entire model architecture, weights and optimizers.
Reinforcement Learning
Reinforcement learning is an area of machine learning concerned with how software agents ought to take actions in
an environment so as to maximize some notion of cumulative reward.
13.1 Concepts
Basic Elements
Term Description
Agent A model/algorithm that is taked with learning to accomplish a task
Environment The world where agent acts in.
Action A decision the agent makes in an environment
Reward Signal A scalar indication of how well the agent is performing a task
State A description of the environment that can be perceived by the agent
Terminal State A state at which no further actions can be made by an agent
Fig. 1: https://www.kdnuggets.com/2018/03/5-things-reinforcement-learning.html
121
Data Science Documentation, Release 0.1
Term Description
Policy (𝜋) Function that outputs decisions the agent makes. In simple terms, it instructs what the agent should
do at each state.
Value Function that describes how good or bad a state is. It is the total amount of reward an agent is
Function predicted to accumulate over the future, starting from a state.
Model of Predicts how the environment will reac tto the agent’s actions. In given a state & action, what is the
Environ- next state and reward. Such an approach is called a model-based method, in contrast with model-free
ment methods.
Reinforcement learning helps to solve Markov Decision Process (MDP). The core problem of MDPs is to find a
“policy” for the decision maker: a function 𝜋 that specifies the action 𝜋(s) that the decision maker will choose when
in state s. The diagram illustrate the Markov Decision Process.
13.2 Q-Learning
Q-Learning is an example of model-free reinforcement learning to solve the Markov Decision Process. It derives the
policy by directly looking at the data instead of developing a model.
We first build a Q-table with each column as the type of action possible, and then each row as the number of possible
states. And initialise the table with all zeros.
Updating the function Q uses the following Bellman equation. Algorithms using such equation as an iterative update
are called value iteration algorithms.
Learning Hyperparameters
• Learning Rate (𝛼): how quickly a network abandons the former value for the new. If the learning rate is 1, the
new estimate will be the new Q-value.
• Discount Rate (𝛾): how much to discount the future reward. The idea is that the later a reward comes, the less
valuable it becomes. Think inflation of money in the real world.
Exploration vs Exploitation
A central dilemma of reinforcement learning is to exploit what it has already experienced in order to obtain a reward.
But in order to do that, it has to explore in order to make better actions in the future.
This is known as the epsilon greedy strategy. In the beginning, the epsilon rates will be higher. The bot will explore
the environment and randomly choose actions. The logic behind this is that the bot does not know anything about the
environment. However the more the bot explores the environment, the more the epsilon rate will decreases and the bot
starts to exploit the environment.
There are other algothrims to manage the exploration vs exploiation problem, like softmax.
Definitions
• argmax(x): position where the first max value occurs
Code
Start the environment and training parameters for frozen lake in AI gym.
import numpy as np
import gym
import random
env = gym.make("FrozenLake-v0")
action_size = env.action_space.n
state_size = env.observation_space.n
# Exploration parameters
epsilon = 1.0 # Exploration rate
max_epsilon = 1.0 # Exploration probability at start
min_epsilon = 0.01 # Minimum exploration probability
decay_rate = 0.005 # Exponential decay rate for exploration prob
## If this number > greater than epsilon --> exploitation (taking the biggest
˓→ Q value for this state)
if exp_exp_tradeoff > epsilon:
action = np.argmax(qtable[state,:])
# Take the action (a) and observe the outcome state(s') and reward (r)
new_state, reward, done, info = env.step(action)
total_rewards += reward
# Take the action (index) that have the maximum expected future reward given
˓→ that state
action = np.argmax(qtable[state,:])
if done:
# Here, we decide to only print the last state (to see if our agent is on
˓→the goal or fall into an hole)
env.render()
13.3 Resources
• https://towardsdatascience.com/reinforcement-learning-implement-grid-world-from-scratch-c5963765ebff
• https://medium.com/swlh/introduction-to-reinforcement-learning-coding-q-learning-part-3-9778366a41c0
• https://medium.com/@m.alzantot/deep-reinforcement-learning-demysitifed-episode-2-policy-iteration-value-iteration-and-q-978
• https://medium.com/emergent-future/simple-reinforcement-learning-with-tensorflow-part-0-q-learning-with-tables-and-neural-n
Evaluation
Sklearn provides a good list of evaluation metrics for classification, regression and clustering problems.
http://scikit-learn.org/stable/modules/model_evaluation.html
In addition, it is also essential to know how to analyse the features and adjusting hyperparameters based on different
evalution metrics.
14.1 Classification
Fig. 1: Wikipedia
Recall|Sensitivity: (True Positive / True Positive + False Negative) High recall means to get all positives (i.e., True
Positive + False Negative) despite having some false positives. Search & extraction in legal cases, Tumour detection.
Often need humans to filter false positives.
127
Data Science Documentation, Release 0.1
Fig. 2: Wikipedia
Fig. 3: https://www.youtube.com/watch?v=21Igj5Pr6u4
Precision: (True Positive / True Positive + False Positive) High precision means it is important to filter off the any
false positives. Search query suggestion, Document classification, customer-facing tasks.
F1-Score: is the harmonic mean of precision and sensitivity, ie., 2*((precision * recall) / (precision + recall))
1. Confusion Matrix
Plain vanilla matrix. Not very useful as does not show the labels. However, the matrix can be used to build a heatmap
using plotly directly.
print (sklearn.metrics.confusion_matrix(test_target,predictions))
array([[288, 64, 1, 0, 7, 3, 31],
[104, 268, 11, 0, 43, 15, 5],
[ 0, 5, 367, 15, 6, 46, 0],
[ 0, 0, 11, 416, 0, 4, 0],
[ 1, 13, 5, 0, 424, 4, 0],
[ 0, 5, 75, 22, 4, 337, 0],
[ 20, 0, 0, 0, 0, 0, 404]])
# this gives the values of each cell, but api unable to change the layout size
import plotly.figure_factory as ff
layout = go.Layout(width=800, height=500)
data = ff.create_annotated_heatmap(z=x,x=title,y=title)
iplot(data)
With pandas crosstab. Convert encoding into labels and put the two pandas series into a crosstab.
def forest(x):
if x==1:
return 'Spruce/Fir'
elif x==2:
return 'Lodgepole Pine'
elif x==3:
return 'Ponderosa Pine'
elif x==4:
return 'Cottonwood/Willow'
elif x==5:
return 'Aspen'
elif x==6:
return 'Douglas-fir'
elif x==7:
return 'Krummholz'
Using a heatmap.
2. Evaluation Metrics
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
Accuracy: 0.95
Precision: 0.79
Recall: 0.60
F1: 0.68
There are many other evaluation metrics, a list can be found here:
from sklearn.metrics.scorer import SCORERS
for i in sorted(list(SCORERS.keys())):
print i
accuracy
adjusted_rand_score
average_precision
f1
f1_macro
(continues on next page)
3. Classification Report
Classification report shows the details of precision, recall & f1-scores. It might be misleading to just print out a binary
classification as their determination of True Positive, False Positive might differ from us. The report will tease out the
details as shown below. We can also set average=None & compute the mean when printing out each individual
scoring.
print('accuracy:\t', accuracy)
print('\nf1:\t\t',f1)
print('recall\t\t',recall)
(continues on next page)
print('\nf1_avg:\t\t',f1_avg)
print('recall_avg\t',recall_avg)
print('precision_avg\t',precision_avg)
print('\nConfusion Matrix')
print(confusion)
print('\n',classification_report(y_test, y_predict))
4. Decision Function
X_train, X_test, y_train, y_test = train_test_split(X, y_binary_imbalanced, random_
˓→state=0)
[(0, -23.176682692580048),
(0, -13.541079101203881),
(0, -21.722576315155052),
(0, -18.90752748077151),
(0, -19.735941639551616),
(0, -9.7494967330877031),
(1, 5.2346395208185506),
(0, -19.307366394398947),
(continues on next page)
5. Probability Function
X_train, X_test, y_train, y_test = train_test_split(X, y_binary_imbalanced, random_
˓→state=0)
# note that the first column of array indicates probability of predicting negative
˓→class,
[(0, 8.5999236926158807e-11),
(0, 1.31578065170999e-06),
(0, 3.6813318939966053e-10),
(0, 6.1456121155693793e-09),
(0, 2.6840428788564424e-09),
(0, 5.8320607398268079e-05),
(1, 0.99469949997393026),
(0, 4.1201906576825675e-09),
(0, 1.2553305740618937e-11),
(0, 3.3162918920398805e-10),
(0, 3.2460530855408745e-11),
(0, 3.1472051953481208e-09),
(0, 1.5699022391384567e-10),
(0, 1.9921654858205874e-05),
(0, 6.7057057309326073e-06),
(0, 1.704597440356912e-05),
(1, 0.99998640688336282),
(0, 9.8530840165646881e-13),
(0, 2.6020404794341749e-06),
(0, 5.9441185633886803e-12)]
If your problem involves kind of searching a needle in the haystack; the positive class samples are very rare compared
to the negative classes, use a precision recall curve.
from sklearn.metrics import precision_recall_curve
plt.figure()
plt.xlim([0.0, 1.01])
plt.ylim([0.0, 1.01])
plt.plot(precision, recall, label='Precision-Recall Curve')
plt.plot(closest_zero_p, closest_zero_r, 'o', markersize = 12, fillstyle = 'none', c=
˓→'r', mew=3)
plt.xlabel('Precision', fontsize=16)
plt.ylabel('Recall', fontsize=16)
plt.axes().set_aspect('equal')
plt.show()
Receiver Operating Characteristic (ROC) is used to show the performance of a binary classifier. Y-axis is True Positive
Rate (Recall) & X-axis is False Positive Rate (Fall-Out). Area Under Curve (AUC) of a ROC is used. Higher AUC
better.
The term came about in WWII where this metrics is used to determined a receiver operator’s ability to distinguish
false positive and true postive correctly in the radar signals.
Some classifiers have a decision_function method while others have a probability prediction method, and some have
both. Whichever one is available works fine for an ROC curve.
from sklearn.metrics import roc_curve, auc
plt.figure()
plt.xlim([-0.01, 1.00])
plt.ylim([-0.01, 1.01])
plt.plot(fpr_lr, tpr_lr, lw=3, label='LogRegr ROC curve (area = {:0.2f})'.format(roc_
˓→auc_lr))
Logarithmic Loss, or Log Loss is a popular Kaggle evaluation metric, which measures the performance of a classifi-
cation model where the prediction input is a probability value between 0 and 1
Log Loss quantifies the accuracy of a classifier by penalising false classifications; the catch is that Log Loss ramps up
very rapidly as the predicted probability approaches 0. This article from datawookie gives a very good explanation.
14.2 Regression
For regression problems, where the response or y is a continuous value, it is common to use R-Squared and RMSE, or
MAE as evaluation metrics. This website gives an excellent description on all the variants of errors metrics.
R-squared: Percentage of variability of dataset that can be explained by the model.
MSE. Mean squared error. Squaring then getting the mean of all errors (so change negatives into positives).
RMSE: Squared root of MSE so that it gives back the error at the same scale (as it was initially squared).
MAE: Mean Absolute Error. For negative errors, convert them to positive and obtain all error means.
The RMSE result will always be larger or equal to the MAE. If all of the errors have the same magnitude, then
RMSE=MAE. Since the errors are squared before they are averaged, the RMSE gives a relatively high weight to large
errors. This means the RMSE should be more useful when large errors are particularly undesirable.
# R2
r2_full = fullmodel.score(predictor, target)
r2_trains = model3.score(X_train, y_train)
r2_tests = model3.score(X_test, y_test)
print('\nr2 full:', r2_full)
print('r2 train:', r2_trains)
print('r2 test:', r2_tests)
# get predictions
y_predicted_total = model3.predict(predictor)
y_predicted_train = model3.predict(X_train)
y_predicted_test = model3.predict(X_test)
# get MSE
MSE_total = mean_squared_error(target, y_predicted_total)
MSE_train = mean_squared_error(y_train, y_predicted_train)
MSE_test = mean_squared_error(y_test, y_predicted_test)
# get MAE
MAE_total = mean_absolute_error(target, y_predicted_total)
MAE_train = mean_absolute_error(y_train, y_predicted_train)
MAE_test = mean_absolute_error(y_test, y_predicted_test)
RMSLE Root Mean Square Log Error is a very popular evaluation metric in data science competition now. It helps to
reduce the effects of outliers compared to RMSE.
More: https://medium.com/analytics-vidhya/root-mean-square-log-error-rmse-vs-rmlse-935c6cc1802a
Takes more time and computation to use k-fold, but well worth the cost. By default, sklearn uses stratified k-fold cross
validation. Another type is ‘leave one out’ cross-validation.
The mean of the final scores among each k model is the most generalised output. This output can be compared to
different model results for comparison.
More here.
cross_val_score is a compact function to obtain the all scoring values using kfold in one line.
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
X = df[df.columns[1:-1]]
y = df['Cover_Type']
For greater control, like to define our own evaluation metrics etc., we can use KFold to obtain the train & test indexes
for each fold iteration.
from sklearn.model_selection import KFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import f1_score
model = RandomForestClassifier()
kfold_custom(X, y, model, f1score)
There are generally 3 methods of hyperparameters tuning, i.e., Grid-Search, Random-Search, or the more automated
Bayesian tuning.
14.4.1 Grid-Search
From Stackoverflow: Systematically working through multiple combinations of parameter tunes, cross validate each
and determine which one gives the best performance. You can work through many combination only changing param-
eters a bit.
Print out the best_params_ and rebuild the model with these optimal parameters.
Simple example.
model = RandomForestClassifier()
grid_values = {'n_estimators':[150,175,200,225]}
grid = GridSearchCV(model, param_grid = grid_values, cv=5)
grid.fit(predictor, target)
print(grid.best_params_)
print(grid.best_score_)
# {'n_estimators': 200}
# 0.786044973545
Others.
dataset = load_digits()
X, y = dataset.data, dataset.target == 1
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# choose a classifier
clf = SVC(kernel='rbf')
grid_clf_acc.fit(X_train, y_train)
y_decision_fn_scores_acc = grid_clf_acc.decision_function(X_test)
grid_clf_auc.fit(X_train, y_train)
y_decision_fn_scores_auc = grid_clf_auc.decision_function(X_test)
# results 1
('Grid best parameter (max. accuracy): ', {'gamma': 0.001})
('Grid best score (accuracy): ', 0.99628804751299183)
# results 2
('Test set AUC: ', 0.99982858122393004)
('Grid best parameter (max. AUC): ', {'gamma': 0.001})
('Grid best score (AUC): ', 0.99987412783021423)
14.4.2 Auto-Tuning
Bayesian Optimization as the name implies uses Bayesian optimization with Gaussian processes for autotuning. It is
one of the most popular package now for auto-tuning. pip install bayesian-optimization
More: https://github.com/fmfn/BayesianOptimization
# CV scores
scores = catboost.cv(cv_dataset, params, fold_count=3)
# 4) Start optimizing
# init_points: no. steps of random exploration. Helps to diversify random space
# n_iter: no. steps for bayesian optimization. Helps to exploit learnt parameters
optimizer.maximize(init_points=2, n_iter=3)
model = RandomForestRegressor(**params)
model.fit(X_train, y_train)
y_predict = model.predict(X_test)
score = rmsle(y_test, y_predict)
return -score
# Search space
pbounds = {'n_estimators': (1, 5),
'max_depth': (10,50)}
Bayesian Tuning and Bandits (BTB) is a package used for auto-tuning ML models hyperparameters. It similarly
uses Gaussian Process to do this, though there is an option for Uniform. It was born from a Master thesis by Laura
Gustafson in 2018. Because it is lower level than the above package, it has better flexibility, e.g., defining a k-fold
cross-validation.
https://github.com/HDI-Project/BTB
from btb.tuning import GP
from btb import HyperParameter, ParamTypes
score_list = []
param_list = []
for i in range(epoch):
# ** unpacks dict in a argument
model = RandomForestClassifier(**parameters, n_jobs=-1)
model.fit(X_train, y_train)
y_predict = model.predict(X_test)
score = accuracy_score(y_test, y_predict)
if verbose==0:
pass
elif verbose==1:
print('epoch: {}, accuracy: {}'.format(i+1,score))
elif verbose==2:
print('epoch: {}, accuracy: {}, param: {}'.format(i+1,score,parameters))
best_s = tuner._best_score
best_score_index = score_list.index(best_s)
best_param = param_list[best_score_index]
print('\nbest accuracy: {}'.format(best_s))
print('best parameters: {}'.format(best_param))
return best_param
For regression models, we have to make some slight modifications, since the optimization of hyperparameters is tuned
towards a higher evaluation score.
score_list = []
param_list = []
for i in range(epoch):
model = RandomForestRegressor(**parameters, n_jobs=10, verbose=3)
model.fit(X_train, y_train)
y_predict = model.predict(X_test)
score = np.sqrt(mean_squared_error(y_test, y_predict))
if verbose==0:
pass
elif verbose==1:
print('epoch: {}, rmse: {}, param: {}'.format(i+1,score,parameters))
score = -score
best_s = tuner._best_score
best_score_index = score_list.index(best_s)
best_param = param_list[best_score_index]
print('\nbest rmse: {}'.format(best_s))
print('best parameters: {}'.format(best_param))
return best_param
Auto-Sklearn is another auto-ml package that automatically selects both the model and its hyperparameters.
https://automl.github.io/auto-sklearn/master/
import autosklearn.classification
import sklearn.model_selection
import sklearn.datasets
import sklearn.metrics
X, y = sklearn.datasets.load_digits(return_X_y=True)
X_train, X_test, y_train, y_test = sklearn.model_selection.train_test_split(X, y,
˓→random_state=1)
automl = autosklearn.classification.AutoSklearnClassifier()
automl.fit(X_train, y_train)
Auto Keras uses neural network for training. Similar to Google’s AutoML approach.
import autokeras as ak
clf = ak.ImageClassifier()
clf.fit(x_train, y_train)
results = clf.predict(x_test)
Explainability
While sklearn’s supervised models are black boxes, we can derive certain plots and metrics to interprete the outcome
and model better.
Decision trees and other tree ensemble models, by default, allow us to obtain the importance of features.
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier()
model = rf.fit(X_train, y_train)
147
Data Science Documentation, Release 0.1
return f_impt
f_impt = feature_impt(model)
Feature importance is a useful metric to find the strength of each feature that contribute to a model. However,
this is only available by default in sklean tree models. This Kaggle article provides a good clear explanation of an
alternative feature importance, called permutation importance, which can be used for any model. This is a third party
library that needs to be installed via pip install eli5.
How it works is the shuffling of individual features and see how it affects model accuarcy. If a feature is important,
the model accuarcy will be reduced more. If not important, the accuarcy should be affected a lot less.
import eli5
from eli5.sklearn import PermutationImportance
The output is as below. +/- refers to the randomness that shuffling resulted in. The higher the weight, the more
important the feature is. Negative values are possible, but actually refer to 0; though random chance caused the
predictions on shuffled data to be more accurate.
While feature importance shows what variables most affect predictions, partial dependence plots show how a feature
affects predictions. Using the fitted model to predict our outcome, and by repeatedly alter the value of just one
variable, we can trace the predicted outcomes in a plot to show its dependence on the variable and when it plateaus.
https://www.kaggle.com/dansbecker/partial-plots
# plot it
pdp.pdp_plot(pdp_goals, 'Goal Scored')
plt.show()
2D Partial Dependence Plots are also useful for interactions between features.
pdp.pdp_interact_plot(pdp_interact_out=inter1,
feature_names=features_to_plot,
plot_type='contour')
plt.show()
15.4 SHAP
SHapley Additive exPlanations (SHAP) break down a prediction to show the impact of each feature.
https://www.kaggle.com/dansbecker/shap-values
Utilities
This page lists some useful functions and tips to make your datascience journey smoother.
16.1 Persistance
Data, models and scalers are examples of objects that can benefit greatly from pickling. For the former, it allows
multiples faster loading compared to other sources since it is saved in a python format. For others, there are no other
ways of saving as they are natively python objects.
Saving dataframes.
import pandas as pd
df.to_pickle('df.pkl')
df = pd.read_pickle('df.pkl')
import pickle
From sklearn’s documentation, it is said that in the specific case of scikit-learn, it may be better to use joblib’s replace-
ment of pickle (dump & load), which is more efficient on objects that carry large numpy arrays internally as is often
the case for fitted scikit-learn estimators, but can only pickle to the disk and not to a string.
More: https://scikit-learn.org/stable/modules/model_persistence.html
import joblib
joblib.dump(clf, 'model.joblib')
joblib.load('model.joblib')
153
Data Science Documentation, Release 0.1
If the dataset is huge, it can be a problem storing the dataframe in memory. However, we can reduce the dataset size
significantly by analysing the data values for each column, and change the datatype to the smallest that can fit the
range of values. Below is a function created by arjanso in Kaggle that can be plug and play.
import pandas as pd
import numpy as np
def reduce_mem_usage(df):
'''
Source: https://www.kaggle.com/arjanso/reducing-dataframe-memory-size-by-65
Reduce size of dataframe significantly using the following process
1. Iterate over every column
2. Determine if the column is numeric
3. Determine if the column can be represented by an integer
4. Find the min and the max value
5. Determine and apply the smallest datatype that can fit the range of values
'''
start_mem_usg = df.memory_usage().sum() / 1024**2
print("Memory usage of properties dataframe is :",start_mem_usg," MB")
NAlist = [] # Keeps track of columns that have missing values filled in.
for col in df.columns:
if df[col].dtype != object: # Exclude strings
# Print current column type
print("******************************")
print("Column: ",col)
print("dtype before: ",df[col].dtype)
# make variables for Int, max and min
IsInt = False
mx = df[col].max()
mn = df[col].min()
print("min for this col: ",mn)
print("max for this col: ",mx)
# Integer does not support NA, therefore, NA needs to be filled
if not np.isfinite(df[col]).all():
NAlist.append(col)
df[col].fillna(mn-1,inplace=True)
Pandas is fast but that is dependent on the dataset too. We can use multiprocessing to make processing in pandas
multitudes faster by
• splitting a column into partitions
• spin off processes to run a specific function in parallel
• union the partitions together back into a Pandas dataframe
Note that this only works for huge datasets, as it also takes time to spin off processes, and union back partitions
together.
# from http://blog.adeel.io/2016/11/06/parallelize-pandas-map-or-apply/
import numpy as np
import multiprocessing as mp
def func(x):
return x * 10
Jupyter Notebook is the go-to IDE for data science. However, it can be further enhanced using jupyter extensions. pip
install jupyter_contrib_nbextensions && jupyter contrib nbextension install
Some of my favourite extensions are:
• Table of Contents*: Sidebar showing TOC based on
• ExecuteTime: Time to execute script for each cell
• Variable Inspector: Overview of all variables saved in memory. Allow deletion of variables to save mem-
ory.
More: https://towardsdatascience.com/jupyter-notebook-extensions-517fa69d2231
Docker
Containers allow a developer to package up an application with all of the parts it needs, such as libraries and other
dependencies, and ship it all out as one package. They allow a modular construction of an application, or microservice
in short. Docker is a popular tool designed to make it easier to create, deploy, and run applications by using containers.
Preprocessing scripts and models can be created as a docker image snapshot, and launched as a container in production.
For models that require to be consistently updated, we need to use volume mapping such that it is not removed when
the container stops running.
To start of a new project, create a new folder. This should only contain your docker file and related python files.
17.1.1 Dockerfile
A Dockerfile named as such, is a file without extension type. It contains commands to tell docker what are the
steps to do to create an image. It consists of instructions & arguments.
The commands run sequentially when building the image, also known as a layered architecture. Each layer is cached,
such that when any layer fails and is fixed, rebuilding it will start from the last built layer.
• FROM tells Docker which image you base your image on (eg, Python 3 or continuumio/miniconda3).
• RUN tells Docker which additional commands to execute.
• CMD tells Docker to execute the command when the image loads.
157
Data Science Documentation, Release 0.1
To pass environment variables from docker run to the python code, we can use os.environ.get.
import os
color = os.environ.get('APP_COLOR')
docker build -t image-name . –(-t = tag the image as) build and name image, “.” as current directory to
look for Dockerfile
Dockerhub is similar to Github whereby it is a repository for your images to be shared with the community. Note that
Dockerhub can only allow a single image to be made private for the free account.
docker login –login into dockerhub, before you can push your image to the server
docker push account/image_name –account refers to your dockerhub account name, this tag needs to cre-
ated during docker build command when building the image
In a production environment, a docker compose file can be used to run all separate docker containers (which interact
with each other) together. It consists of all necessary configurations that a docker run command provides in a yaml
file.
Below is an example using wordpress blog, where both the wordpress and mysql database are needed to get it working.
Docker Swarm allows management of multiple docker containers as clones in a cluster to ensure high availability in
case of failure. This is similar to Apache Spark whereby there is a Cluster Manager (Swarm Manager), and worker
nodes.
web:
image: "webapp"
deploy:
replicas: 5
database:
image: "mysql"
Use the command docker stack deploy -c docker_compose.yml to launch the swarm.
17.4 Networking
The Bridge Network is a private internal network created by Docker. All containers are attached to this network by
default and they get an IP of 172.17.xxx. They are thus able to communicate with each other internally. However, to
access these networks from the outside world, we need to
• map ports of these containers to the docker host.
• or associate the containers to the network host, meaning the container use the same port as the host network
If we want to separate the internal bridge networks, we can create our own internal bridge networks.
17.5 Commands
Help
Create Image
docker build -t (-t = tag the image as) build and name image, “.” is the location of the
image_name . dockerfile
docker run Ubuntu:17.04 semicolon specifies the version (known as tags as listed in Docker-
hub), else will pull the latest
docker run ubuntu vs docker run the first is an official image, the 2nd with the “/” is created by the
mmumshad/ubuntu community
docker run -d image_name (-d = detach) docker runs in background, and you can continue typ-
ing other commands in the bash. Else need to open another termi-
nal.
docker run -v /local/storage/ (-v = volume mapping) all data will be destroyed if container is
folder:/image/data/folder stopped
mysql
Fig. 5: running docker with a command. each container has a unique container ID, container name, and their base
image name
Start/Stop Containers
Remove Containers/Images
Ethics
Accuarcy does not always tell the whole story. Think about the ramifications of different types of errors (Type I & II)
from the model, and tune accordingly.
Biases based on past data will be reflected in the model. Eg., job applicant being hired could be done based on gender,
race, age.
Do not oversell the model capabilities. Eg. A model can predict cancer from a mammogram, but a doctor should
always be there to verify the result. You never know when you need to tune the model again because of some new
features that were not included in the training sample.
The user might end up using your model for other purposes that might be unethical or wrong.
While data science has the potential to help businesses and humanity in general, there are many issues in confidentially
as personal data can be collected. An internet restricted environment should be conducted where such data is being
extracted for analysis, or if not all sensitive data should be hashed.
163
Data Science Documentation, Release 0.1
Then, the question comes again, should we even collect personal data in the first place? Lets say it is mandatory to
collect data from patients with mental issues, we should probably prevent collecting their identity as doing so will
prevent patients from seeking help in the first place. Having high assurance of their confidentially might be the way
to reduce and control their illness from escalating, and this is more important than collecting their data for analysis.
After all, that is the purpose of data analysis right?
Resources
165
Data Science Documentation, Release 0.1
167