The goal of this tutorial is to introduce you to the scikit libraries for classification. We will also cover feature selection, and evaluation.
import numpy as np
import scipy.sparse as sp_sparse
import matplotlib.pyplot as plt
import sklearn as sk
import sklearn.datasets as sk_data
import sklearn.metrics as metrics
import seaborn as sns
%matplotlib inline
Feature selection is about finding the best features for your classifier. This may be important if you do not have enough training data. The idea is to find metrics that either characterize the features by themselves, or with respect to the class we want to predict, or with respect to other features.
http://scikit-learn.org/stable/modules/feature_selection.html
The VarianceThreshold selection drops features whose variance is below some threshold. If we have binary features we can estimate the treshold exactly so as to guarantee a specific ratio of 0's and 1's
from sklearn.feature_selection import VarianceThreshold
X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
print(np.array(X))
sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
sel.fit_transform(X)
[[0 0 1] [0 1 0] [1 0 0] [0 1 1] [0 1 0] [0 1 1]]
array([[0, 1], [1, 0], [0, 0], [1, 1], [1, 0], [1, 1]])
import sklearn.datasets as sk_data
iris = sk_data.load_iris()
X = iris.data
print(X[1:10,:])
print(X.var(axis = 0))
sel = VarianceThreshold(threshold=0.2)
sel.fit_transform(X)[1:10]
[[4.9 3. 1.4 0.2] [4.7 3.2 1.3 0.2] [4.6 3.1 1.5 0.2] [5. 3.6 1.4 0.2] [5.4 3.9 1.7 0.4] [4.6 3.4 1.4 0.3] [5. 3.4 1.5 0.2] [4.4 2.9 1.4 0.2] [4.9 3.1 1.5 0.1]] [0.68112222 0.18871289 3.09550267 0.57713289]
array([[4.9, 1.4, 0.2], [4.7, 1.3, 0.2], [4.6, 1.5, 0.2], [5. , 1.4, 0.2], [5.4, 1.7, 0.4], [4.6, 1.4, 0.3], [5. , 1.5, 0.2], [4.4, 1.4, 0.2], [4.9, 1.5, 0.1]])
A more sophisticated feature selection technique uses test to determine if a feature and the class label are independent. An example of such a test is the chi-square test (there are more)
In this case we keep the features with high chi-square score and low p-value.
The features with the lowest scores and highest values are rejected.
The chi-square test is usually applied on categorical data.
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
iris = sk_data.load_iris()
X, y = iris.data, iris.target
print(X.shape)
print('Features:')
print(X[1:10,:])
print('Labels:')
print(y[1:10])
sel = SelectKBest(chi2, k=2)
X_new = sel.fit_transform(X, y)
print('Selected Features:')
print(X_new[1:10])
(150, 4) Features: [[4.9 3. 1.4 0.2] [4.7 3.2 1.3 0.2] [4.6 3.1 1.5 0.2] [5. 3.6 1.4 0.2] [5.4 3.9 1.7 0.4] [4.6 3.4 1.4 0.3] [5. 3.4 1.5 0.2] [4.4 2.9 1.4 0.2] [4.9 3.1 1.5 0.1]] Labels: [0 0 0 0 0 0 0 0 0] Selected Features: [[1.4 0.2] [1.3 0.2] [1.5 0.2] [1.4 0.2] [1.7 0.4] [1.4 0.3] [1.5 0.2] [1.4 0.2] [1.5 0.1]]
The chi-square values and the p-values between features and target variable (X columns and y)
print('Chi2 values')
print(sel.scores_)
c,p = sk.feature_selection.chi2(X, y)
print('Chi2 values')
print(c) #The chi-square value between X columns and y
print('p-values')
print(p) #The p-value for the test
Chi2 values [ 10.81782088 3.7107283 116.31261309 67.0483602 ] Chi2 values [ 10.81782088 3.7107283 116.31261309 67.0483602 ] p-values [4.47651499e-03 1.56395980e-01 5.53397228e-26 2.75824965e-15]
Python has several classes and objects for implementing different supervised learning techniques such as Regression and Classification.
Regardless of the model being implemented, the following methods are implemented:
The method fit() takes the training data and labels/values, and trains the model
The method predict() takes as input the test data and applies the model.
To perform classification we first need to prepare the data into train and test datasets.
from sklearn.datasets import load_iris
import sklearn.utils as utils
iris = load_iris()
print("sample of data")
print(iris.data[:5,:])
print("the class labels vector")
print(iris.target)
print("the names of the classes:",iris.target_names)
print(iris.feature_names)
sample of data [[5.1 3.5 1.4 0.2] [4.9 3. 1.4 0.2] [4.7 3.2 1.3 0.2] [4.6 3.1 1.5 0.2] [5. 3.6 1.4 0.2]] the class labels vector [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2] the names of the classes: ['setosa' 'versicolor' 'virginica'] ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
Randomly shuffle the data. This is useful to know that the data is in random order
X, y = utils.shuffle(iris.data, iris.target, random_state=1) #shuffle the data
print(X.shape)
print(y.shape)
print(y)
(150, 4) (150,) [0 1 1 0 2 1 2 0 0 2 1 0 2 1 1 0 1 1 0 0 1 1 1 0 2 1 0 0 1 2 1 2 1 2 2 0 1 0 1 2 2 0 2 2 1 2 0 0 0 1 0 0 2 2 2 2 2 1 2 1 0 2 2 0 0 2 0 2 2 1 1 2 2 0 1 1 2 1 2 1 0 0 0 2 0 1 2 2 0 0 1 0 2 1 2 2 1 2 2 1 0 1 0 1 1 0 1 0 0 2 2 2 0 0 1 0 2 0 2 2 0 2 0 1 0 1 1 0 0 1 0 1 1 0 1 1 1 1 2 0 0 2 1 2 1 2 2 1 2 0]
Select a subset for training and a subset for testing
train_set_size = 100
X_train = X[:train_set_size] # selects first 100 rows (examples) for train set
y_train = y[:train_set_size]
X_test = X[train_set_size:] # selects from row 100 until the last one for test set
y_test = y[train_set_size:]
print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)
(100, 4) (100,) (50, 4) (50,)
We can also use the train_test_split function of python for splitting the data into train and test sets. In this case you do not need the random shuffling (but it does not hurt).
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0)
http://scikit-learn.org/stable/supervised_learning.html#supervised-learning
Python has classes and objects that implement the different classification techniques that we described in class.
http://scikit-learn.org/stable/modules/tree.html
Train and apply a decision tree classifier. The default score computed in the classifier object is the accuracy. Decision trees can also give us probabilities
from sklearn import tree
dtree = tree.DecisionTreeClassifier()
dtree = dtree.fit(X_train, y_train)
print("classifier accuracy:",dtree.score(X_test,y_test))
y_pred = dtree.predict(X_test)
y_prob = dtree.predict_proba(X_test)
print("classifier predictions:",y_pred[:10])
print("ground truth labels :",y_test[:10])
print(y_prob[:10])
classifier accuracy: 0.9 classifier predictions: [0 1 0 1 1 0 1 0 0 2] ground truth labels : [0 1 0 1 1 0 1 0 0 2] [[1. 0. 0.] [0. 1. 0.] [1. 0. 0.] [0. 1. 0.] [0. 1. 0.] [1. 0. 0.] [0. 1. 0.] [1. 0. 0.] [1. 0. 0.] [0. 0. 1.]]
Compute some more metrics
print("accuracy:",metrics.accuracy_score(y_test,y_pred))
print("\nConfusion matrix")
print(metrics.confusion_matrix(y_test,y_pred))
print("\nPrecision Score per class")
print(metrics.precision_score(y_test,y_pred,average=None))
print("\nAverage Precision Score")
print(metrics.precision_score(y_test,y_pred,average='weighted'))
print("\nRecall Score per class")
print(metrics.recall_score(y_test,y_pred,average=None))
print("\nAverage Recall Score")
print(metrics.recall_score(y_test,y_pred,average='weighted'))
print("\nF1-score Score per class")
print(metrics.f1_score(y_test,y_pred,average=None))
print("\nAverage F1 Score")
print(metrics.f1_score(y_test,y_pred,average='weighted'))
accuracy: 0.9 Confusion matrix [[19 0 0] [ 0 17 1] [ 0 4 9]] Precision Score per class [1. 0.80952381 0.9 ] Average Precision Score 0.9054285714285715 Recall Score per class [1. 0.94444444 0.69230769] Average Recall Score 0.9 F1-score Score per class [1. 0.87179487 0.7826087 ] Average F1 Score 0.897324414715719
Visualize the decision tree.
For this you will need to install the package python-graphviz
#conda install python-graphviz
import graphviz
print(iris.feature_names)
dot_data = tree.export_graphviz(dtree,out_file=None)
graph = graphviz.Source(dot_data)
graph
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
dtree2 = tree.DecisionTreeClassifier(max_depth=2)
dtree2 = dtree2.fit(X_train, y_train)
print(dtree2.score(X_test,y_test))
dot_data2 = tree.export_graphviz(dtree2,out_file=None)
graph2 = graphviz.Source(dot_data2)
graph2
0.9
https://scikit-learn.org/stable/modules/neighbors.html#classification
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train,y_train)
print("classifier score:", knn.score(X_test,y_test))
y_pred = knn.predict(X_test)
print("\naccuracy:",metrics.accuracy_score(y_test,y_pred))
print("\nConfusion matrix")
print(metrics.confusion_matrix(y_test,y_pred))
print("\nPrecision Score per class")
print(metrics.precision_score(y_test,y_pred,average=None))
print("\nAverage Precision Score")
print(metrics.precision_score(y_test,y_pred,average='weighted'))
print("\nRecall Score per class")
print(metrics.recall_score(y_test,y_pred,average=None))
print("\nAverage Recall Score")
print(metrics.recall_score(y_test,y_pred,average='weighted'))
print("\nF1-score Score per class")
print(metrics.f1_score(y_test,y_pred,average=None))
print("\nAverage F1 Score")
print(metrics.f1_score(y_test,y_pred,average='weighted'))
classifier score: 0.94 accuracy: 0.94 Confusion matrix [[19 0 0] [ 0 16 2] [ 0 1 12]] Precision Score per class [1. 0.94117647 0.85714286] Average Precision Score 0.9416806722689074 Recall Score per class [1. 0.88888889 0.92307692] Average Recall Score 0.94 F1-score Score per class [1. 0.91428571 0.88888889] Average F1 Score 0.9402539682539682
from sklearn import svm
#svm_clf = svm.LinearSVC()
#svm_clf = svm.SVC(kernel = 'poly')
svm_clf = svm.SVC()
svm_clf.fit(X_train,y_train)
print("classifier score:",svm_clf.score(X_test,y_test))
y_pred = svm_clf.predict(X_test)
print("\naccuracy:",metrics.accuracy_score(y_test,y_pred))
print("\nConfusion matrix")
print(metrics.confusion_matrix(y_test,y_pred))
print("\nPrecision Score per class")
print(metrics.precision_score(y_test,y_pred,average=None))
print("\nAverage Precision Score")
print(metrics.precision_score(y_test,y_pred,average='weighted'))
print("\nRecall Score per class")
print(metrics.recall_score(y_test,y_pred,average=None))
print("\nAverage Recall Score")
print(metrics.recall_score(y_test,y_pred,average='weighted'))
print("\nF1-score Score per class")
print(metrics.f1_score(y_test,y_pred,average=None))
print("\nAverage F1 Score")
print(metrics.f1_score(y_test,y_pred,average='weighted'))
classifier score: 0.98 accuracy: 0.98 Confusion matrix [[19 0 0] [ 0 18 0] [ 0 1 12]] Precision Score per class [1. 0.94736842 1. ] Average Precision Score 0.9810526315789474 Recall Score per class [1. 1. 0.92307692] Average Recall Score 0.98 F1-score Score per class [1. 0.97297297 0.96 ] Average F1 Score 0.9798702702702704
import sklearn.linear_model as linear_model
lr_clf = linear_model.LogisticRegression(solver='lbfgs')
lr_clf.fit(X_train, y_train)
print("classifier score:",lr_clf.score(X_test,y_test))
y_pred = lr_clf.predict(X_test)
print("\naccuracy:",metrics.accuracy_score(y_test,y_pred))
print("\nConfusion matrix")
print(metrics.confusion_matrix(y_test,y_pred))
print("\nPrecision Score per class")
print(metrics.precision_score(y_test,y_pred,average=None))
print("\nAverage Precision Score")
print(metrics.precision_score(y_test,y_pred,average='weighted'))
print("\nRecall Score per class")
print(metrics.recall_score(y_test,y_pred,average=None))
print("\nAverage Recall Score")
print(metrics.recall_score(y_test,y_pred,average='weighted'))
print("\nF1-score Score per class")
print(metrics.f1_score(y_test,y_pred,average=None))
print("\nAverage F1 Score")
print(metrics.f1_score(y_test,y_pred,average='weighted'))
classifier score: 0.96 accuracy: 0.96 Confusion matrix [[19 0 0] [ 0 17 1] [ 0 1 12]] Precision Score per class [1. 0.94444444 0.92307692] Average Precision Score 0.96 Recall Score per class [1. 0.94444444 0.92307692] Average Recall Score 0.96 F1-score Score per class [1. 0.94444444 0.92307692] Average F1 Score 0.96
For Logistic Regression we can also obtain the probabilities for the different classes
probs = lr_clf.predict_proba(X_test)
print("Class Probabilities (first 10):")
print (probs[:10])
print(probs.argmax(axis = 1)[:10])
print(probs.max(axis = 1)[:10])
Class Probabilities (first 10): [[9.83119371e-01 1.68804538e-02 1.75315569e-07] [4.02273980e-02 9.32025580e-01 2.77470222e-02] [9.41679973e-01 5.83196830e-02 3.44441536e-07] [4.23957279e-02 9.40670050e-01 1.69342220e-02] [2.44208893e-03 5.61707800e-01 4.35850111e-01] [9.56398788e-01 4.36006210e-02 5.90547605e-07] [2.74758774e-03 6.67193724e-01 3.30058688e-01] [9.59965982e-01 4.00331184e-02 8.99426873e-07] [9.27989281e-01 7.20096431e-02 1.07638094e-06] [4.80727038e-05 2.97373890e-02 9.70214538e-01]] [0 1 0 1 1 0 1 0 0 2] [0.98311937 0.93202558 0.94167997 0.94067005 0.5617078 0.95639879 0.66719372 0.95996598 0.92798928 0.97021454]
And the coeffients of the logistic regression model
print(lr_clf.coef_)
[[-0.41315006 0.80862115 -2.20080165 -0.95080628] [ 0.07433106 -0.29229165 -0.03285585 -0.84578588] [ 0.338819 -0.5163295 2.2336575 1.79659216]]
Linear Regression is implemented in the library sklearn.linear_model.LinearRegression: https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html
from sklearn.linear_model import LinearRegression
X_reg = np.array([[1, 1], [1, 2], [2, 2], [2, 3]])
# y = 1 * x_0 + 2 * x_1 + 3
y_reg = np.dot(X_reg, np.array([1, 2])) + 3
reg = LinearRegression().fit(X_reg, y_reg)
#Obtain the function coefficients
print(reg.coef_)
#and the intercept
print(reg.intercept_)
[1. 2.] 3.000000000000001
The $R^2$ score computes the "explained variance"
$R^2 = 1-\frac{\sum_i (y_i -\hat y_i)^2}{\sum_i (y_i -\bar y)^2}$
where $\hat y_i$ is the prediction for point $x_i$ and $\bar y$ is the mean value of the target variable
print(reg.score(X_reg, y_reg))
1.0
#Predict for a new point
reg.predict(np.array([[3, 5]]))
array([16.])
A more complex example with the diabetes dataset
diabetes_X, diabetes_y = sk_data.load_diabetes(return_X_y=True)
# Shuffle the data
diabetes_X, diabetes_y = utils.shuffle(diabetes_X, diabetes_y, random_state=1)
# Split the data into training/testing sets
diabetes_X_train = diabetes_X[:-20]
diabetes_X_test = diabetes_X[-20:]
# Split the targets into training/testing sets
diabetes_y_train = diabetes_y[:-20]
diabetes_y_test = diabetes_y[-20:]
# Create linear regression object
regr = linear_model.LinearRegression()
# Train the model using the training sets
regr.fit(diabetes_X_train, diabetes_y_train)
# Make predictions using the testing set
diabetes_y_pred = regr.predict(diabetes_X_test)
# The coefficients
print('Coefficients: \n', regr.coef_)
# The mean squared error
print('Mean squared error: %.2f'
% metrics.mean_squared_error(diabetes_y_test, diabetes_y_pred))
# The coefficient of determination: 1 is perfect prediction
# Computed over the *test* data
print('Coefficient of determination: %.2f'
% metrics.r2_score(diabetes_y_test, diabetes_y_pred))
print('Predictions:')
print(diabetes_y_pred)
print('True values:')
print(diabetes_y_test)
Coefficients: [ -8.80343059 -238.68845774 515.45209151 329.26528155 -878.18276219 530.03363161 126.03912568 213.28475276 734.46021416 67.32526032] Mean squared error: 2304.97 Coefficient of determination: 0.68 Predictions: [149.75303117 199.7656287 248.11294766 182.95040528 98.34540804 96.66271486 248.59757565 64.84343648 234.52373522 209.30957394 179.26665684 85.95716856 70.54292903 197.93453267 100.34630781 116.81521079 134.97372936 64.08572743 178.32873088 155.32247369] True values: [168. 221. 310. 283. 81. 94. 277. 72. 270. 268. 174. 96. 83. 222. 69. 153. 202. 43. 124. 276.]
p,r,f,s = metrics.precision_recall_fscore_support(y_test,y_pred)
print(p)
print(r)
print(f)
print(s)
[1. 0.94444444 0.90909091] [1. 0.89473684 0.95238095] [1. 0.91891892 0.93023256] [20 19 21]
report = metrics.classification_report(y_test,y_pred)
print(report)
precision recall f1-score support 0 1.00 1.00 1.00 20 1 0.94 0.89 0.92 19 2 0.91 0.95 0.93 21 accuracy 0.95 60 macro avg 0.95 0.95 0.95 60 weighted avg 0.95 0.95 0.95 60
cancer_data = sk_data.load_breast_cancer()
X_cancer,y_cancer = utils.shuffle(cancer_data.data, cancer_data.target, random_state=1)
X_cancer_train = X_cancer[:500]
y_cancer_train = y_cancer[:500]
X_cancer_test = X_cancer[500:]
y_cancer_test = y_cancer[500:]
lr_clf.fit(X_cancer_train, y_cancer_train)
print("classifier score:",lr_clf.score(X_cancer_test,y_cancer_test))
classifier score: 0.9565217391304348
C:\ProgramData\Anaconda3\lib\site-packages\sklearn\linear_model\_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1): STOP: TOTAL NO. of ITERATIONS REACHED LIMIT. Increase the number of iterations (max_iter) or scale the data as shown in: https://scikit-learn.org/stable/modules/preprocessing.html Please also refer to the documentation for alternative solver options: https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression n_iter_i = _check_optimize_result(
y_cancer_pred = lr_clf.predict(X_cancer_test)
cancer_probs = lr_clf.predict_proba(X_cancer_test)
print("Class Probabilities (first 10):")
print (cancer_probs[:10])
y_cancer_scores = cancer_probs[:,1]
precision, recall, thresholds = metrics.precision_recall_curve(y_cancer_test,y_cancer_scores)
#plt.scatter(recall,precision)
plt.plot(recall,precision, color='darkorange',lw=2)
print(recall)
print(precision)
print(thresholds)
Class Probabilities (first 10): [[5.83623551e-01 4.16376449e-01] [8.12467632e-03 9.91875324e-01] [9.99982549e-01 1.74507561e-05] [9.99865722e-01 1.34278348e-04] [2.34747296e-02 9.76525270e-01] [9.99977911e-01 2.20892708e-05] [4.76418230e-03 9.95235818e-01] [1.58051254e-03 9.98419487e-01] [1.92164273e-03 9.98078357e-01] [6.68784558e-02 9.33121544e-01]] [1. 0.97619048 0.97619048 0.97619048 0.95238095 0.92857143 0.9047619 0.88095238 0.85714286 0.83333333 0.80952381 0.78571429 0.76190476 0.76190476 0.73809524 0.71428571 0.69047619 0.66666667 0.64285714 0.61904762 0.5952381 0.57142857 0.54761905 0.52380952 0.5 0.47619048 0.45238095 0.42857143 0.4047619 0.38095238 0.35714286 0.33333333 0.30952381 0.28571429 0.26190476 0.23809524 0.21428571 0.19047619 0.16666667 0.14285714 0.11904762 0.0952381 0.07142857 0.04761905 0.02380952 0. ] [0.93333333 0.93181818 0.95348837 0.97619048 0.97560976 0.975 0.97435897 0.97368421 0.97297297 0.97222222 0.97142857 0.97058824 0.96969697 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. ] [0.41637645 0.45961289 0.64904253 0.76657569 0.8447832 0.84825656 0.85098092 0.9294684 0.93139622 0.93312154 0.93363838 0.94123622 0.94572607 0.95397177 0.96059207 0.97652527 0.97880602 0.98474267 0.98859163 0.98905238 0.99076026 0.99187532 0.99268795 0.99280117 0.99284629 0.99335073 0.99495779 0.99523582 0.99535911 0.99536585 0.996111 0.99721763 0.99738661 0.99802571 0.99807836 0.99841949 0.99923125 0.99935453 0.99947798 0.99958699 0.99970989 0.99973228 0.99978195 0.99979392 0.99986458]
fpr, tpr, ths = metrics.roc_curve(y_cancer_test,y_cancer_scores)
plt.plot(fpr,tpr,color='darkorange',lw=2)
print(metrics.roc_auc_score(y_cancer_test,y_cancer_scores))
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()
No artists with labels found to put in legend. Note that artists whose label start with an underscore are ignored when legend() is called with no argument.
0.9894179894179893
(Xtoy,y_toy)=sk_data.make_classification(n_samples=10000)
Xttrain = Xtoy[:8000,:]
Xttest = Xtoy[8000:,:]
yttrain = y_toy[:8000]
yttest = y_toy[8000:]
lr_clf.fit(Xttrain, yttrain)
#print(lr_clf.score(Xttest,yttest))
#y_tpred = lr_clf.predict(X_test)
tprobs = lr_clf.predict_proba(Xttest)
print (tprobs[:10])
y_tscores = tprobs[:,1]
precision, recall, thresholds = metrics.precision_recall_curve(yttest,y_tscores)
plt.plot(recall,precision)
[[3.20037592e-01 6.79962408e-01] [2.41985792e-01 7.58014208e-01] [5.75281926e-04 9.99424718e-01] [1.15252186e-01 8.84747814e-01] [2.67997941e-03 9.97320021e-01] [9.81477901e-01 1.85220986e-02] [9.96589111e-01 3.41088910e-03] [1.56750808e-02 9.84324919e-01] [9.13521526e-01 8.64784739e-02] [2.78398414e-01 7.21601586e-01]]
[<matplotlib.lines.Line2D at 0x285cad19d00>]
In k-fold cross validation the data is split into k equal parts, the k-1 are used for training and the last one for testing. k models are trained, each time leaving a different part for testing
https://scikit-learn.org/stable/modules/cross_validation.html
There are two methods for implementing k-fold cross-validation, under the library model selection: cross_val_score, and cross validate. The latter allows multiple metrics to be considered together.
import sklearn.model_selection as model_selection
scores = model_selection.cross_val_score(#lr_clf,
#svm_clf,
#knn,
dtree,
X,
y,
scoring='f1_weighted',
cv=5)
print (scores)
print (scores.mean())
[1. 0.93333333 0.96658312 0.96658312 0.93265993] 0.9598319029897977
scores = model_selection.cross_validate(#lr_clf,
#svm_clf,
#knn,
dtree,
X,
y,
scoring=['precision_weighted','recall_weighted'],
cv=3)
print (scores)
print (scores['test_precision_weighted'].mean(),scores['test_recall_weighted'].mean())
{'fit_time': array([0.00199866, 0.00099945, 0.00099945]), 'score_time': array([0.00300002, 0.0039959 , 0.00399733]), 'test_precision_weighted': array([0.96 , 0.98111111, 0.88308772]), 'test_recall_weighted': array([0.96, 0.98, 0.88])} 0.9413996101364522 0.94
If the same steps are often repeated, you can create a pipeline to perform them all at once:
We will use the 20 newsgroups to do a text classification example
from sklearn.datasets import fetch_20newsgroups
categories = ['sci.space','rec.sport.baseball']
#categories = ['alt.atheism', 'rec.sport.baseball']
news_train = sk_data.fetch_20newsgroups(subset='train',
remove=('headers', 'footers', 'quotes'),
categories=categories)
print (len(news_train.target))
X_news_train_data = news_train.data
y_news_train = news_train.target
news_test = sk_data.fetch_20newsgroups(subset='test',
remove=('headers', 'footers', 'quotes'),
categories=categories)
print (len(news_test.target))
X_news_test_data = news_test.data
y_news_test = news_test.target
1190 791
from sklearn.linear_model import LinearRegression
import sklearn.linear_model as linear_model
import sklearn.feature_extraction.text as sk_text
vectorizer = sk_text.TfidfVectorizer(stop_words='english',
#max_features = 1000,
min_df=4, max_df=0.8)
X_news_train = vectorizer.fit_transform(X_news_train_data)
lr_clf = linear_model.LogisticRegression(solver='lbfgs')
lr_clf.fit(X_news_train, y_news_train)
LogisticRegression()
X_news_test = vectorizer.transform(X_news_test_data)
print("classifier score:",lr_clf.score(X_news_test,y_news_test))
classifier score: 0.9216182048040455
We will now see how we can train and use word embeddings. We will also see the NLTK library.
The NLTK libary allows for sohpisticated text processing. It can do stemming, create a parse tree, do PoS (Part-of-Speech) tagging, find Noun Phrases, entities,
import nltk
from nltk.tokenize import sent_tokenize, word_tokenize
nltk.download('punkt')
[nltk_data] Downloading package punkt to [nltk_data] C:\Users\tsap\AppData\Roaming\nltk_data... [nltk_data] Package punkt is already up-to-date!
True
from nltk.corpus import stopwords
nltk.download('stopwords')
[nltk_data] Downloading package stopwords to [nltk_data] C:\Users\tsap\AppData\Roaming\nltk_data... [nltk_data] Package stopwords is already up-to-date!
True
english_stop_words = set(stopwords.words('english'))
import string as string
X_news_train_nltk = []
y_news_train_nltk = []
for x,y in zip(X_news_train_data,y_news_train):
wt = word_tokenize(x.lower())
doc = [w for w in wt if (w not in string.punctuation)] #keep stopwords to maintain realistic windows
if len(doc) == 0: continue
X_news_train_nltk.append(doc)
y_news_train_nltk.append(y)
X_news_test_nltk = []
y_news_test_nltk = []
for x,y in zip(X_news_test_data,y_news_test):
wt = word_tokenize(x.lower())
doc = [w for w in wt if (w not in english_stop_words) and (w not in string.punctuation)]
if len(doc) == 0: continue
X_news_test_nltk.append(doc)
y_news_test_nltk.append(y)
The Gensim library has several NLP models.
You can use existing modules to train a word2vec model: https://radimrehurek.com/gensim/models/word2vec.html
import gensim
from gensim.models import Word2Vec
Train a CBOW embedding on the training data corpus
embedding_size = 100
cbow_model = gensim.models.Word2Vec(X_news_train_nltk, min_count = 1,size = embedding_size, window = 50)
cbow_model.wv['space']
array([ 1.3626347e+00, -9.1802186e-01, -1.2189058e+00, 1.5490552e+00, 1.7962173e-01, -1.8228947e-01, 7.4095041e-01, -8.6752933e-01, 1.3819387e+00, 2.0274465e+00, 1.5030596e+00, -2.3670770e-01, -1.2707617e+00, -4.9571109e+00, -1.6571654e+00, -1.3996867e+00, -1.7083026e+00, 3.5763342e+00, -2.5275729e+00, -2.5971494e+00, 3.9501324e-01, 1.7998517e+00, 5.9064204e-01, -1.9885430e+00, -8.9505285e-01, -8.8297492e-01, -5.8066773e-01, 7.0249361e-01, -2.8329668e+00, 2.7226403e-02, 2.1891525e+00, -3.5315511e+00, -3.0630670e+00, -1.1466244e+00, 3.7846091e+00, 2.0086968e+00, 1.9489932e+00, -1.6308918e+00, -1.1899316e+00, 4.3927424e-02, 2.0978633e-01, 1.5178644e-02, -6.9894773e-01, 1.9074910e+00, 2.2619994e+00, -7.9161793e-01, -4.6662375e-01, -9.8577952e-01, -2.4329665e+00, 1.4078501e+00, 1.1600374e+00, -2.3742394e+00, -9.3097404e-02, 6.5130818e-01, -1.2857968e+00, -5.8206248e-01, 3.7721002e-01, -2.0370612e+00, -1.6875947e+00, 8.9556985e-02, -1.2133864e+00, 1.4314138e+00, 1.0795940e+00, 2.3002479e+00, -5.1381910e-01, -1.7463471e+00, -1.6618823e+00, 1.0985827e+00, 3.5473592e+00, 3.2078640e+00, -4.4867676e-01, 1.1440036e+00, -1.1076572e+00, -4.0362340e-01, -2.7313380e+00, -2.1890466e+00, 1.9209883e+00, 1.2227294e+00, 4.0881285e-01, 1.1249651e+00, 4.1052680e+00, 2.2416701e+00, 1.3895382e+00, 2.2879393e+00, 6.7056608e-01, -2.0860527e+00, 2.4072058e-03, -6.8389457e-01, -2.4418426e+00, -2.1619756e+00, -4.3392124e+00, -3.3873751e+00, 3.1392505e+00, -3.9485118e+00, 6.2412542e-01, -1.4656785e+00, -2.8676972e+00, 3.8035398e+00, 1.0140551e-01, 1.9707490e+00], dtype=float32)
Transform the train and test data
X_news_train_cbow = []
for x in X_news_train_nltk:
vx = np.zeros(embedding_size)
x = [w for w in x if w not in english_stop_words] # we could remove stopwords
for w in x:
vx += cbow_model.wv[w]
if len(x) >0: vx /= len(x)
X_news_train_cbow.append(vx)
X_news_test_cbow = []
for x in X_news_test_nltk:
vx = np.zeros(embedding_size)
length = 0;
for w in x:
if (w not in cbow_model.wv): continue
length += 1
vx += cbow_model.wv[w]
if length != 0: vx /= length
X_news_test_cbow.append(vx)
Train a classifier on the emebddings
lr_clf.fit(np.array(X_news_train_cbow), np.array(y_news_train_nltk))
LogisticRegression()
lr_clf.score(np.array(X_news_test_cbow),y_news_test_nltk)
0.8302631578947368
Train a SkipGram embedding on the training data corpus
embedding_size = 100
skipgram_model = gensim.models.Word2Vec(X_news_train_nltk, min_count = 1,size = embedding_size, window = 50, sg = 1)
Transform the train and test data
X_news_train_skipgram = []
for x in X_news_train_nltk:
vx = np.zeros(embedding_size)
for w in x:
vx += skipgram_model.wv[w]
vx /= len(x)
X_news_train_skipgram.append(vx)
X_news_test_skipgram = []
for x in X_news_test_nltk:
vx = np.zeros(embedding_size)
length = 0
for w in x:
if (w not in skipgram_model.wv): continue
length += 1
vx += skipgram_model.wv[w]
if length!= 0: vx /= length
X_news_test_skipgram.append(vx)
Train a classifier on the emebddings
lr_clf.fit(np.array(X_news_train_skipgram), np.array(y_news_train_nltk))
lr_clf.score(np.array(X_news_test_skipgram),y_news_test_nltk)
0.9355263157894737
You can also download the Google word2vec model trained over millions of documents
import gensim.downloader as api
path = api.load("word2vec-google-news-300", return_path=True)
print(path)
[==================================================] 100.0% 1662.8/1662.8MB downloaded C:\Users\tsap/gensim-data\word2vec-google-news-300\word2vec-google-news-300.gz
#path = 'C:\\Users\\tsapa/gensim-data\word2vec-google-news-300\word2vec-google-news-300.gz'
g_model = gensim.models.KeyedVectors.load_word2vec_format(path, binary=True)
print(len(g_model['hello']))
print(g_model['hello'])
300 [-0.05419922 0.01708984 -0.00527954 0.33203125 -0.25 -0.01397705 -0.15039062 -0.265625 0.01647949 0.3828125 -0.03295898 -0.09716797 -0.16308594 -0.04443359 0.00946045 0.18457031 0.03637695 0.16601562 0.36328125 -0.25585938 0.375 0.171875 0.21386719 -0.19921875 0.13085938 -0.07275391 -0.02819824 0.11621094 0.15332031 0.09082031 0.06787109 -0.0300293 -0.16894531 -0.20800781 -0.03710938 -0.22753906 0.26367188 0.012146 0.18359375 0.31054688 -0.10791016 -0.19140625 0.21582031 0.13183594 -0.03515625 0.18554688 -0.30859375 0.04785156 -0.10986328 0.14355469 -0.43554688 -0.0378418 0.10839844 0.140625 -0.10595703 0.26171875 -0.17089844 0.39453125 0.12597656 -0.27734375 -0.28125 0.14746094 -0.20996094 0.02355957 0.18457031 0.00445557 -0.27929688 -0.03637695 -0.29296875 0.19628906 0.20703125 0.2890625 -0.20507812 0.06787109 -0.43164062 -0.10986328 -0.2578125 -0.02331543 0.11328125 0.23144531 -0.04418945 0.10839844 -0.2890625 -0.09521484 -0.10351562 -0.0324707 0.07763672 -0.13378906 0.22949219 0.06298828 0.08349609 0.02929688 -0.11474609 0.00534058 -0.12988281 0.02514648 0.08789062 0.24511719 -0.11474609 -0.296875 -0.59375 -0.29492188 -0.13378906 0.27734375 -0.04174805 0.11621094 0.28320312 0.00241089 0.13867188 -0.00683594 -0.30078125 0.16210938 0.01171875 -0.13867188 0.48828125 0.02880859 0.02416992 0.04736328 0.05859375 -0.23828125 0.02758789 0.05981445 -0.03857422 0.06933594 0.14941406 -0.10888672 -0.07324219 0.08789062 0.27148438 0.06591797 -0.37890625 -0.26171875 -0.13183594 0.09570312 -0.3125 0.10205078 0.03063965 0.23632812 0.00582886 0.27734375 0.20507812 -0.17871094 -0.31445312 -0.01586914 0.13964844 0.13574219 0.0390625 -0.29296875 0.234375 -0.33984375 -0.11816406 0.10644531 -0.18457031 -0.02099609 0.02563477 0.25390625 0.07275391 0.13574219 -0.00138092 -0.2578125 -0.2890625 0.10107422 0.19238281 -0.04882812 0.27929688 -0.3359375 -0.07373047 0.01879883 -0.10986328 -0.04614258 0.15722656 0.06689453 -0.03417969 0.16308594 0.08642578 0.44726562 0.02026367 -0.01977539 0.07958984 0.17773438 -0.04370117 -0.00952148 0.16503906 0.17285156 0.23144531 -0.04272461 0.02355957 0.18359375 -0.41601562 -0.01745605 0.16796875 0.04736328 0.14257812 0.08496094 0.33984375 0.1484375 -0.34375 -0.14160156 -0.06835938 -0.14648438 -0.02844238 0.07421875 -0.07666016 0.12695312 0.05859375 -0.07568359 -0.03344727 0.23632812 -0.16308594 0.16503906 0.1484375 -0.2421875 -0.3515625 -0.30664062 0.00491333 0.17675781 0.46289062 0.14257812 -0.25 -0.25976562 0.04370117 0.34960938 0.05957031 0.07617188 -0.02868652 -0.09667969 -0.01281738 0.05859375 -0.22949219 -0.1953125 -0.12207031 0.20117188 -0.42382812 0.06005859 0.50390625 0.20898438 0.11230469 -0.06054688 0.33203125 0.07421875 -0.05786133 0.11083984 -0.06494141 0.05639648 0.01757812 0.08398438 0.13769531 0.2578125 0.16796875 -0.16894531 0.01794434 0.16015625 0.26171875 0.31640625 -0.24804688 0.05371094 -0.0859375 0.17089844 -0.39453125 -0.00156403 -0.07324219 -0.04614258 -0.16210938 -0.15722656 0.21289062 -0.15820312 0.04394531 0.28515625 0.01196289 -0.26953125 -0.04370117 0.37109375 0.04663086 -0.19726562 0.3046875 -0.36523438 -0.23632812 0.08056641 -0.04248047 -0.14648438 -0.06225586 -0.0534668 -0.05664062 0.18945312 0.37109375 -0.22070312 0.04638672 0.02612305 -0.11474609 0.265625 -0.02453613 0.11083984 -0.02514648 -0.12060547 0.05297852 0.07128906 0.00063705 -0.36523438 -0.13769531 -0.12890625]
Transform the train and test data
X_news_train_gmodel = []
for x in X_news_train_nltk:
vx = np.zeros(300)
length = 0
for w in x:
if w in g_model:
length += 1
vx += g_model[w]
if length != 0: vx /= length
X_news_train_gmodel.append(vx)
X_news_test_gmodel = []
for x in X_news_test_nltk:
vx = np.zeros(300)
length = 0
for w in x:
if (w not in g_model): continue
length += 1
vx += g_model[w]
if length != 0: vx /= length
X_news_test_gmodel.append(vx)
Train a classifier on the emebddings
lr_clf.fit(X_news_train_gmodel, np.array(y_news_train_nltk))
LogisticRegression()
lr_clf.score(np.array(X_news_test_gmodel),y_news_test_nltk)
0.9447368421052632