Chapter 04
Python Machine Learning - Code Examples
Python Machine Learning 3rd Edition by Sebastian Raschka, Packt Publishing Ltd. 2019
Code Repository: https://github.com/rasbt/python-machine-learning-book-3rd-edition
Code License: MIT License
Python Machine Learning - Code Examples
Chapter 4 - Building Good Training Datasets – Data Preprocessing
Note that the optional watermark extension is a small IPython notebook plugin that I developed to make the code reproducible. You can just skip the following line(s).
%load_ext watermark
%watermark -a "Sebastian Raschka" -u -d -p numpy,pandas,matplotlib,sklearnOutput
Sebastian Raschka last updated: 2019-12-04 numpy 1.17.4 pandas 0.25.3 matplotlib 3.1.1 sklearn 0.22
The use of watermark is optional. You can install this Jupyter extension via
conda install watermark -c conda-forge or
pip install watermark For more information, please see: https://github.com/rasbt/watermark.
Overview
from IPython.display import Image
%matplotlib inlineDealing with missing data
Identifying missing values in tabular data
import pandas as pd
from io import StringIO
import sys
csv_data = \
'''A,B,C,D
1.0,2.0,3.0,4.0
5.0,6.0,,8.0
10.0,11.0,12.0,'''
# If you are using Python 2.7, you need
# to convert the string to unicode:
if (sys.version_info < (3, 0)):
csv_data = unicode(csv_data)
df = pd.read_csv(StringIO(csv_data))
dfOutput
A B C D 0 1.0 2.0 3.0 4.0 1 5.0 6.0 NaN 8.0 2 10.0 11.0 12.0 NaN
| A | B | C | D | |
|---|---|---|---|---|
| 0 | 1.0 | 2.0 | 3.0 | 4.0 |
| 1 | 5.0 | 6.0 | NaN | 8.0 |
| 2 | 10.0 | 11.0 | 12.0 | NaN |
df.isnull().sum()Output
A 0 B 0 C 1 D 1 dtype: int64
# access the underlying NumPy array
# via the `values` attribute
df.valuesOutput
array([[ 1., 2., 3., 4.],
[ 5., 6., nan, 8.],
[10., 11., 12., nan]])Eliminating training examples or features with missing values
# remove rows that contain missing values
df.dropna(axis=0)Output
A B C D 0 1.0 2.0 3.0 4.0
| A | B | C | D | |
|---|---|---|---|---|
| 0 | 1.0 | 2.0 | 3.0 | 4.0 |
# remove columns that contain missing values
df.dropna(axis=1)Output
A B 0 1.0 2.0 1 5.0 6.0 2 10.0 11.0
| A | B | |
|---|---|---|
| 0 | 1.0 | 2.0 |
| 1 | 5.0 | 6.0 |
| 2 | 10.0 | 11.0 |
# remove columns that contain missing values
df.dropna(axis=1)Output
A B 0 1.0 2.0 1 5.0 6.0 2 10.0 11.0
| A | B | |
|---|---|---|
| 0 | 1.0 | 2.0 |
| 1 | 5.0 | 6.0 |
| 2 | 10.0 | 11.0 |
# only drop rows where all columns are NaN
df.dropna(how='all') Output
A B C D 0 1.0 2.0 3.0 4.0 1 5.0 6.0 NaN 8.0 2 10.0 11.0 12.0 NaN
| A | B | C | D | |
|---|---|---|---|---|
| 0 | 1.0 | 2.0 | 3.0 | 4.0 |
| 1 | 5.0 | 6.0 | NaN | 8.0 |
| 2 | 10.0 | 11.0 | 12.0 | NaN |
# drop rows that have fewer than 3 real values
df.dropna(thresh=4)Output
A B C D 0 1.0 2.0 3.0 4.0
| A | B | C | D | |
|---|---|---|---|---|
| 0 | 1.0 | 2.0 | 3.0 | 4.0 |
# only drop rows where NaN appear in specific columns (here: 'C')
df.dropna(subset=['C'])Output
A B C D 0 1.0 2.0 3.0 4.0 2 10.0 11.0 12.0 NaN
| A | B | C | D | |
|---|---|---|---|---|
| 0 | 1.0 | 2.0 | 3.0 | 4.0 |
| 2 | 10.0 | 11.0 | 12.0 | NaN |
Imputing missing values
# again: our original array
df.valuesOutput
array([[ 1., 2., 3., 4.],
[ 5., 6., nan, 8.],
[10., 11., 12., nan]])# impute missing values via the column mean
from sklearn.impute import SimpleImputer
import numpy as np
imr = SimpleImputer(missing_values=np.nan, strategy='mean')
imr = imr.fit(df.values)
imputed_data = imr.transform(df.values)
imputed_dataOutput
array([[ 1. , 2. , 3. , 4. ],
[ 5. , 6. , 7.5, 8. ],
[10. , 11. , 12. , 6. ]])df.fillna(df.mean())Output
A B C D 0 1.0 2.0 3.0 4.0 1 5.0 6.0 7.5 8.0 2 10.0 11.0 12.0 6.0
| A | B | C | D | |
|---|---|---|---|---|
| 0 | 1.0 | 2.0 | 3.0 | 4.0 |
| 1 | 5.0 | 6.0 | 7.5 | 8.0 |
| 2 | 10.0 | 11.0 | 12.0 | 6.0 |
Understanding the scikit-learn estimator API
Image(filename='images/04_01.png', width=400) Output
<IPython.core.display.Image object>
[省略较大 image/png 输出]
Image(filename='images/04_02.png', width=300) Output
<IPython.core.display.Image object>
[省略较大 image/png 输出]
Handling categorical data
Nominal and ordinal features
import pandas as pd
df = pd.DataFrame([['green', 'M', 10.1, 'class2'],
['red', 'L', 13.5, 'class1'],
['blue', 'XL', 15.3, 'class2']])
df.columns = ['color', 'size', 'price', 'classlabel']
dfOutput
color size price classlabel 0 green M 10.1 class2 1 red L 13.5 class1 2 blue XL 15.3 class2
| color | size | price | classlabel | |
|---|---|---|---|---|
| 0 | green | M | 10.1 | class2 |
| 1 | red | L | 13.5 | class1 |
| 2 | blue | XL | 15.3 | class2 |
Mapping ordinal features
size_mapping = {'XL': 3,
'L': 2,
'M': 1}
df['size'] = df['size'].map(size_mapping)
dfOutput
color size price classlabel 0 green 1 10.1 class2 1 red 2 13.5 class1 2 blue 3 15.3 class2
| color | size | price | classlabel | |
|---|---|---|---|---|
| 0 | green | 1 | 10.1 | class2 |
| 1 | red | 2 | 13.5 | class1 |
| 2 | blue | 3 | 15.3 | class2 |
inv_size_mapping = {v: k for k, v in size_mapping.items()}
df['size'].map(inv_size_mapping)Output
0 M 1 L 2 XL Name: size, dtype: object
Encoding class labels
import numpy as np
# create a mapping dict
# to convert class labels from strings to integers
class_mapping = {label: idx for idx, label in enumerate(np.unique(df['classlabel']))}
class_mappingOutput
{'class1': 0, 'class2': 1}# to convert class labels from strings to integers
df['classlabel'] = df['classlabel'].map(class_mapping)
dfOutput
color size price classlabel 0 green 1 10.1 1 1 red 2 13.5 0 2 blue 3 15.3 1
| color | size | price | classlabel | |
|---|---|---|---|---|
| 0 | green | 1 | 10.1 | 1 |
| 1 | red | 2 | 13.5 | 0 |
| 2 | blue | 3 | 15.3 | 1 |
# reverse the class label mapping
inv_class_mapping = {v: k for k, v in class_mapping.items()}
df['classlabel'] = df['classlabel'].map(inv_class_mapping)
dfOutput
color size price classlabel 0 green 1 10.1 class2 1 red 2 13.5 class1 2 blue 3 15.3 class2
| color | size | price | classlabel | |
|---|---|---|---|---|
| 0 | green | 1 | 10.1 | class2 |
| 1 | red | 2 | 13.5 | class1 |
| 2 | blue | 3 | 15.3 | class2 |
from sklearn.preprocessing import LabelEncoder
# Label encoding with sklearn's LabelEncoder
class_le = LabelEncoder()
y = class_le.fit_transform(df['classlabel'].values)
yOutput
array([1, 0, 1])
# reverse mapping
class_le.inverse_transform(y)Output
array(['class2', 'class1', 'class2'], dtype=object)
Performing one-hot encoding on nominal features
X = df[['color', 'size', 'price']].values
color_le = LabelEncoder()
X[:, 0] = color_le.fit_transform(X[:, 0])
XOutput
array([[1, 1, 10.1],
[2, 2, 13.5],
[0, 3, 15.3]], dtype=object)from sklearn.preprocessing import OneHotEncoder
X = df[['color', 'size', 'price']].values
color_ohe = OneHotEncoder()
color_ohe.fit_transform(X[:, 0].reshape(-1, 1)).toarray()Output
array([[0., 1., 0.],
[0., 0., 1.],
[1., 0., 0.]])from sklearn.compose import ColumnTransformer
X = df[['color', 'size', 'price']].values
c_transf = ColumnTransformer([ ('onehot', OneHotEncoder(), [0]),
('nothing', 'passthrough', [1, 2])])
c_transf.fit_transform(X).astype(float)Output
array([[ 0. , 1. , 0. , 1. , 10.1],
[ 0. , 0. , 1. , 2. , 13.5],
[ 1. , 0. , 0. , 3. , 15.3]])# one-hot encoding via pandas
pd.get_dummies(df[['price', 'color', 'size']])Output
price size color_blue color_green color_red 0 10.1 1 0 1 0 1 13.5 2 0 0 1 2 15.3 3 1 0 0
| price | size | color_blue | color_green | color_red | |
|---|---|---|---|---|---|
| 0 | 10.1 | 1 | 0 | 1 | 0 |
| 1 | 13.5 | 2 | 0 | 0 | 1 |
| 2 | 15.3 | 3 | 1 | 0 | 0 |
# multicollinearity guard in get_dummies
pd.get_dummies(df[['price', 'color', 'size']], drop_first=True)Output
price size color_green color_red 0 10.1 1 1 0 1 13.5 2 0 1 2 15.3 3 0 0
| price | size | color_green | color_red | |
|---|---|---|---|---|
| 0 | 10.1 | 1 | 1 | 0 |
| 1 | 13.5 | 2 | 0 | 1 |
| 2 | 15.3 | 3 | 0 | 0 |
# multicollinearity guard for the OneHotEncoder
color_ohe = OneHotEncoder(categories='auto', drop='first')
c_transf = ColumnTransformer([ ('onehot', color_ohe, [0]),
('nothing', 'passthrough', [1, 2])])
c_transf.fit_transform(X).astype(float)Output
array([[ 1. , 0. , 1. , 10.1],
[ 0. , 1. , 2. , 13.5],
[ 0. , 0. , 3. , 15.3]])Optional: Encoding Ordinal Features
If we are unsure about the numerical differences between the categories of ordinal features, or the difference between two ordinal values is not defined, we can also encode them using a threshold encoding with 0/1 values. For example, we can split the feature "size" with values M, L, and XL into two new features "x > M" and "x > L". Let's consider the original DataFrame:
df = pd.DataFrame([['green', 'M', 10.1, 'class2'],
['red', 'L', 13.5, 'class1'],
['blue', 'XL', 15.3, 'class2']])
df.columns = ['color', 'size', 'price', 'classlabel']
dfOutput
color size price classlabel 0 green M 10.1 class2 1 red L 13.5 class1 2 blue XL 15.3 class2
| color | size | price | classlabel | |
|---|---|---|---|---|
| 0 | green | M | 10.1 | class2 |
| 1 | red | L | 13.5 | class1 |
| 2 | blue | XL | 15.3 | class2 |
We can use the apply method of pandas' DataFrames to write custom lambda expressions in order to encode these variables using the value-threshold approach:
df['x > M'] = df['size'].apply(lambda x: 1 if x in {'L', 'XL'} else 0)
df['x > L'] = df['size'].apply(lambda x: 1 if x == 'XL' else 0)
del df['size']
dfOutput
color price classlabel x > M x > L 0 green 10.1 class2 0 0 1 red 13.5 class1 1 0 2 blue 15.3 class2 1 1
| color | price | classlabel | x > M | x > L | |
|---|---|---|---|---|---|
| 0 | green | 10.1 | class2 | 0 | 0 |
| 1 | red | 13.5 | class1 | 1 | 0 |
| 2 | blue | 15.3 | class2 | 1 | 1 |
Partitioning a dataset into a seperate training and test set
df_wine = pd.read_csv('https://archive.ics.uci.edu/'
'ml/machine-learning-databases/wine/wine.data',
header=None)
# if the Wine dataset is temporarily unavailable from the
# UCI machine learning repository, un-comment the following line
# of code to load the dataset from a local path:
# df_wine = pd.read_csv('wine.data', header=None)
df_wine.columns = ['Class label', 'Alcohol', 'Malic acid', 'Ash',
'Alcalinity of ash', 'Magnesium', 'Total phenols',
'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins',
'Color intensity', 'Hue', 'OD280/OD315 of diluted wines',
'Proline']
print('Class labels', np.unique(df_wine['Class label']))
df_wine.head()Output
Class labels [1 2 3]
Class label Alcohol Malic acid Ash Alcalinity of ash Magnesium \ 0 1 14.23 1.71 2.43 15.6 127 1 1 13.20 1.78 2.14 11.2 100 2 1 13.16 2.36 2.67 18.6 101 3 1 14.37 1.95 2.50 16.8 113 4 1 13.24 2.59 2.87 21.0 118 Total phenols Flavanoids Nonflavanoid phenols Proanthocyanins \ 0 2.80 3.06 0.28 2.29 1 2.65 2.76 0.26 1.28 2 2.80 3.24 0.30 2.81 3 3.85 3.49 0.24 2.18 4 2.80 2.69 0.39 1.82 Color intensity Hue OD280/OD315 of diluted wines Proline 0 5.64 1.04 3.92 1065 1 4.38 1.05 3.40 1050 2 5.68 1.03 3.17 1185 3 7.80 0.86 3.45 1480 4 4.32 1.04 2.93 735
| Class label | Alcohol | Malic acid | Ash | Alcalinity of ash | Magnesium | Total phenols | Flavanoids | Nonflavanoid phenols | Proanthocyanins | Color intensity | Hue | OD280/OD315 of diluted wines | Proline | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 14.23 | 1.71 | 2.43 | 15.6 | 127 | 2.80 | 3.06 | 0.28 | 2.29 | 5.64 | 1.04 | 3.92 | 1065 |
| 1 | 1 | 13.20 | 1.78 | 2.14 | 11.2 | 100 | 2.65 | 2.76 | 0.26 | 1.28 | 4.38 | 1.05 | 3.40 | 1050 |
| 2 | 1 | 13.16 | 2.36 | 2.67 | 18.6 | 101 | 2.80 | 3.24 | 0.30 | 2.81 | 5.68 | 1.03 | 3.17 | 1185 |
| 3 | 1 | 14.37 | 1.95 | 2.50 | 16.8 | 113 | 3.85 | 3.49 | 0.24 | 2.18 | 7.80 | 0.86 | 3.45 | 1480 |
| 4 | 1 | 13.24 | 2.59 | 2.87 | 21.0 | 118 | 2.80 | 2.69 | 0.39 | 1.82 | 4.32 | 1.04 | 2.93 | 735 |
from sklearn.model_selection import train_test_split
X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values
X_train, X_test, y_train, y_test =\
train_test_split(X, y,
test_size=0.3,
random_state=0,
stratify=y)Bringing features onto the same scale
from sklearn.preprocessing import MinMaxScaler
mms = MinMaxScaler()
X_train_norm = mms.fit_transform(X_train)
X_test_norm = mms.transform(X_test)from sklearn.preprocessing import StandardScaler
stdsc = StandardScaler()
X_train_std = stdsc.fit_transform(X_train)
X_test_std = stdsc.transform(X_test)A visual example:
ex = np.array([0, 1, 2, 3, 4, 5])
print('standardized:', (ex - ex.mean()) / ex.std())
# Please note that pandas uses ddof=1 (sample standard deviation)
# by default, whereas NumPy's std method and the StandardScaler
# uses ddof=0 (population standard deviation)
# normalize
print('normalized:', (ex - ex.min()) / (ex.max() - ex.min()))Output
standardized: [-1.46385011 -0.87831007 -0.29277002 0.29277002 0.87831007 1.46385011] normalized: [0. 0.2 0.4 0.6 0.8 1. ]
Selecting meaningful features
...
L1 and L2 regularization as penalties against model complexity
A geometric interpretation of L2 regularization
Image(filename='images/04_04.png', width=500) Output
<IPython.core.display.Image object>
[省略较大 image/png 输出]
Image(filename='images/04_05.png', width=500) Output
<IPython.core.display.Image object>
[省略较大 image/png 输出]
Sparse solutions with L1-regularization
Image(filename='images/04_06.png', width=500) Output
<IPython.core.display.Image object>
[省略较大 image/png 输出]
For regularized models in scikit-learn that support L1 regularization, we can simply set the penalty parameter to 'l1' to obtain a sparse solution:
from sklearn.linear_model import LogisticRegression
LogisticRegression(penalty='l1', solver='liblinear', multi_class='ovr')Output
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, l1_ratio=None, max_iter=100,
multi_class='ovr', n_jobs=None, penalty='l1',
random_state=None, solver='liblinear', tol=0.0001, verbose=0,
warm_start=False)Applied to the standardized Wine data ...
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(penalty='l1', C=1.0, solver='liblinear', multi_class='ovr')
# Note that C=1.0 is the default. You can increase
# or decrease it to make the regulariztion effect
# stronger or weaker, respectively.
lr.fit(X_train_std, y_train)
print('Training accuracy:', lr.score(X_train_std, y_train))
print('Test accuracy:', lr.score(X_test_std, y_test))Output
Training accuracy: 1.0 Test accuracy: 1.0
lr.intercept_Output
array([-1.2633382 , -1.21589578, -2.36999996])
np.set_printoptions(8)lr.coef_[lr.coef_!=0].shapeOutput
(23,)
lr.coef_Output
array([[ 1.24567193, 0.18059252, 0.7436152 , -1.16126524, 0. ,
0. , 1.17058952, 0. , 0. , 0. ,
0. , 0.54691857, 2.51057502],
[-1.53780982, -0.38671917, -0.9952918 , 0.36442868, -0.05924262,
0. , 0.66774065, 0. , 0. , -1.93333009,
1.23525317, 0. , -2.23256458],
[ 0.13537951, 0.16960766, 0.35751869, 0. , 0. ,
0. , -2.43327552, 0. , 0. , 1.56221192,
-0.81849722, -0.49599876, 0. ]])import matplotlib.pyplot as plt
fig = plt.figure()
ax = plt.subplot(111)
colors = ['blue', 'green', 'red', 'cyan',
'magenta', 'yellow', 'black',
'pink', 'lightgreen', 'lightblue',
'gray', 'indigo', 'orange']
weights, params = [], []
for c in np.arange(-4., 6.):
lr = LogisticRegression(penalty='l1', C=10.**c, solver='liblinear',
multi_class='ovr', random_state=0)
lr.fit(X_train_std, y_train)
weights.append(lr.coef_[1])
params.append(10**c)
weights = np.array(weights)
for column, color in zip(range(weights.shape[1]), colors):
plt.plot(params, weights[:, column],
label=df_wine.columns[column + 1],
color=color)
plt.axhline(0, color='black', linestyle='--', linewidth=3)
plt.xlim([10**(-5), 10**5])
plt.ylabel('weight coefficient')
plt.xlabel('C')
plt.xscale('log')
plt.legend(loc='upper left')
ax.legend(loc='upper center',
bbox_to_anchor=(1.38, 1.03),
ncol=1, fancybox=True)
#plt.savefig('images/04_07.png', dpi=300,
# bbox_inches='tight', pad_inches=0.2)
plt.show()Output
<Figure size 432x288 with 1 Axes>
Sequential feature selection algorithms
from sklearn.base import clone
from itertools import combinations
import numpy as np
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
class SBS():
def __init__(self, estimator, k_features, scoring=accuracy_score,
test_size=0.25, random_state=1):
self.scoring = scoring
self.estimator = clone(estimator)
self.k_features = k_features
self.test_size = test_size
self.random_state = random_state
def fit(self, X, y):
X_train, X_test, y_train, y_test = \
train_test_split(X, y, test_size=self.test_size,
random_state=self.random_state)
dim = X_train.shape[1]
self.indices_ = tuple(range(dim))
self.subsets_ = [self.indices_]
score = self._calc_score(X_train, y_train,
X_test, y_test, self.indices_)
self.scores_ = [score]
while dim > self.k_features:
scores = []
subsets = []
for p in combinations(self.indices_, r=dim - 1):
score = self._calc_score(X_train, y_train,
X_test, y_test, p)
scores.append(score)
subsets.append(p)
best = np.argmax(scores)
self.indices_ = subsets[best]
self.subsets_.append(self.indices_)
dim -= 1
self.scores_.append(scores[best])
self.k_score_ = self.scores_[-1]
return self
def transform(self, X):
return X[:, self.indices_]
def _calc_score(self, X_train, y_train, X_test, y_test, indices):
self.estimator.fit(X_train[:, indices], y_train)
y_pred = self.estimator.predict(X_test[:, indices])
score = self.scoring(y_test, y_pred)
return scoreimport matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=5)
# selecting features
sbs = SBS(knn, k_features=1)
sbs.fit(X_train_std, y_train)
# plotting performance of feature subsets
k_feat = [len(k) for k in sbs.subsets_]
plt.plot(k_feat, sbs.scores_, marker='o')
plt.ylim([0.7, 1.02])
plt.ylabel('Accuracy')
plt.xlabel('Number of features')
plt.grid()
plt.tight_layout()
# plt.savefig('images/04_08.png', dpi=300)
plt.show()Output
<Figure size 432x288 with 1 Axes>
k3 = list(sbs.subsets_[10])
print(df_wine.columns[1:][k3])Output
Index(['Alcohol', 'Malic acid', 'OD280/OD315 of diluted wines'], dtype='object')
knn.fit(X_train_std, y_train)
print('Training accuracy:', knn.score(X_train_std, y_train))
print('Test accuracy:', knn.score(X_test_std, y_test))Output
Training accuracy: 0.967741935483871 Test accuracy: 0.9629629629629629
knn.fit(X_train_std[:, k3], y_train)
print('Training accuracy:', knn.score(X_train_std[:, k3], y_train))
print('Test accuracy:', knn.score(X_test_std[:, k3], y_test))Output
Training accuracy: 0.9516129032258065 Test accuracy: 0.9259259259259259
Assessing feature importance with Random Forests
from sklearn.ensemble import RandomForestClassifier
feat_labels = df_wine.columns[1:]
forest = RandomForestClassifier(n_estimators=500,
random_state=1)
forest.fit(X_train, y_train)
importances = forest.feature_importances_
indices = np.argsort(importances)[::-1]
for f in range(X_train.shape[1]):
print("%2d) %-*s %f" % (f + 1, 30,
feat_labels[indices[f]],
importances[indices[f]]))
plt.title('Feature Importance')
plt.bar(range(X_train.shape[1]),
importances[indices],
align='center')
plt.xticks(range(X_train.shape[1]),
feat_labels[indices], rotation=90)
plt.xlim([-1, X_train.shape[1]])
plt.tight_layout()
#plt.savefig('images/04_09.png', dpi=300)
plt.show()Output
1) Proline 0.185453 2) Flavanoids 0.174751 3) Color intensity 0.143920 4) OD280/OD315 of diluted wines 0.136162 5) Alcohol 0.118529 6) Hue 0.058739 7) Total phenols 0.050872 8) Magnesium 0.031357 9) Malic acid 0.025648 10) Proanthocyanins 0.025570 11) Alcalinity of ash 0.022366 12) Nonflavanoid phenols 0.013354 13) Ash 0.013279
<Figure size 432x288 with 1 Axes>
from sklearn.feature_selection import SelectFromModel
sfm = SelectFromModel(forest, threshold=0.1, prefit=True)
X_selected = sfm.transform(X_train)
print('Number of features that meet this threshold criterion:',
X_selected.shape[1])Output
Number of features that meet this threshold criterion: 5
Now, let's print the 3 features that met the threshold criterion for feature selection that we set earlier (note that this code snippet does not appear in the actual book but was added to this notebook later for illustrative purposes):
for f in range(X_selected.shape[1]):
print("%2d) %-*s %f" % (f + 1, 30,
feat_labels[indices[f]],
importances[indices[f]]))Output
1) Proline 0.185453 2) Flavanoids 0.174751 3) Color intensity 0.143920 4) OD280/OD315 of diluted wines 0.136162 5) Alcohol 0.118529
Summary
...
Readers may ignore the next cell.
! python ../.convert_notebook_to_script.py --input ch04.ipynb --output ch04.pyOutput
[NbConvertApp] Converting notebook ch04.ipynb to script [NbConvertApp] Writing 17120 bytes to ch04.py
