Category Archives: Python

Linear Decision Boundary of Logistic Regression

Now, we will study the concept of a decision boundary for a binary classification problem. We use synthetic data to create a clear example of how the decision boundary of logistic regression looks in comparison to the training samples. We start by generating two features, X1 and X2, at random. Since there are two features, we can say that the data for this problem are two-dimensional. This makes it easy to visualize. The concepts we illustrate here generalize to cases of more than two features, such as the real-world datasets you’re likely to see in your work; however, the decision boundary is harder to visualize in higher-dimensional spaces.

Perform the following steps:

  1. Generate the features using the following code:
np.random.seed(seed=6)
X_1_pos = np.random.uniform(low=1, high=7, size=(20,1))
print(X_1_pos[0:3])
X_1_neg = np.random.uniform(low=3, high=10, size=(20,1))
print(X_1_neg[0:3])
X_2_pos = np.random.uniform(low=1, high=7, size=(20,1))
print(X_1_pos[0:3])
X_2_neg = np.random.uniform(low=3, high=10, size=(20,1))
print(X_1_neg[0:3])

You don’t need to worry too much about why we selected the values we did; the plotting we do later should make it clear. Notice, however, that we are also going to assign the true class at the same time. The result of this is that we have 20 samples each in the positive and negative classes, for a total of 40 samples, and that we have two features for each sample. We show the first three values of each feature for both positive and negative classes.

The output should be the following:

IMG0

Generating synthetic data for a binary classification problem

  1. Plot these data, coloring the positive samples in red and the negative samples in blue. The plotting code is as follows:
plt.scatter(X_1_pos, X_2_pos, color='red', marker='x')
plt.scatter(X_1_neg, X_2_neg, color='blue', marker='x')
plt.xlabel('$X_1$')
plt.ylabel('$X_2$')
plt.legend(['Positive class', 'Negative class'])

The result should look like this:

 IMG1

Generating synthetic data for a binary classification problem

In order to use our synthetic features with scikit-learn, we need to assemble them into a matrix. We use NumPy’s block function for this to create a 40 by 2 matrix. There will be 40 rows because there are 40 total samples, and 2 columns because there are 2 features. We will arrange things so that the features for the positive samples come in the first 20 rows, and those for the negative samples after that.

  1. Create a 40 by 2 matrix and then show the shape and the first 3 rows:
X = np.block([[X_1_pos, X_2_pos], [X_1_neg, X_2_neg]])
print(X.shape)
print(X[0:3])

The output should be:

 IMG2

Combining synthetic features in to a matrix

We also need a response variable to go with these features. We know how we defined them, but we need an array of y values to let scikit-learn know.

  1. Create a vertical stack (vstack) of 20 1s and then 20 0s to match our arrangement of the features and reshape to the way that scikit-learn expects. Here is the code:
y = np.vstack((np.ones((20,1)), np.zeros((20,1)))).reshape(40,)
print(y[0:5])
print(y[-5:])

You will obtain the following output:

 IMG3

Create the response variable for the synthetic data

At this point, we are ready to fit a logistic regression model to these data with scikit-learn. We will use all of the data as training data and examine how well a linear model is able to fit the data.

  1. First, import the model class using the following code:
from sklearn.linear_model import LogisticRegression
  1. Now instantiate, indicating the liblinear solver, and show the model object using the following code:
example_lr = LogisticRegression(solver='liblinear')
example_lr

The output should be as follows:

 IMG3BIS

Fit a logistic regression model to the synthetic data in scikit-learn

  1. Now train the model on the synthetic data:
example_lr.fit(X, y)

How do the predictions from our fitted model look?

We first need to obtain these predictions, by using the trained model’s .predict method on the same samples we used for model training. Then, in order to add these predictions to the plot, using the color scheme of red = positive class and blue = negative class, we will create two lists of indices to use with the arrays, according to whether the prediction is 1 or 0. See whether you can understand how we’ve used a list comprehension, including an if statement, to accomplish this.

  1. Use this code to get predictions and separate them into indices of positive and negative class predictions. Show the indices of positive class predictions as a check:
y_pred = example_lr.predict(X)
positive_indices = [counter for counter in range(len(y_pred)) if y_pred[counter]==1]
negative_indices = [counter for counter in range(len(y_pred)) if y_pred[counter]==0]
positive_indices

The output should be:

IMG4

Positive class prediction indices

  1. Here is the plotting code:
plt.scatter(X_1_pos, X_2_pos, color='red', marker='x')
plt.scatter(X_1_neg, X_2_neg, color='blue', marker='x')
plt.scatter(X[positive_indices,0], X[positive_indices,1], s=150, marker='o',
edgecolors='red', facecolors='none')
plt.scatter(X[negative_indices,0], X[negative_indices,1], s=150, marker='o',
edgecolors='blue', facecolors='none')
plt.xlabel('$X_1$')
plt.ylabel('$X_2$')
plt.legend(['Positive class', 'Negative class', 'Positive predictions', 'Negative predictions'])

The plot should appear as follows:

 IMG5

Predictions and true classes plotted together

From the plot, it’s apparent that the classifier struggles with data points that are close to where you may imagine the linear decision boundary to be; some of these may end up on the wrong side of that boundary. Use this code to get the coefficients from the fitted model and print them:

theta_1 = example_lr.coef_[0][0]
theta_2 = example_lr.coef_[0][1]
print(theta_1, theta_2)

The output should look like this:

IMG6

Coefficients from the fitted model

  1. Use this code to get the intercept:
theta_0 = example_lr.intercept_

Now use the coefficients and intercept to define the linear decision boundary. This captures the dividing line of the inequality, X2 ≥ -(1/2)X1 – (0/2):

X_1_decision_boundary = np.array([0, 10])
X_2_decision_boundary = -(theta_1/theta_2)*X_1_decision_boundary - (theta_0/theta_2)

To summarize the last few steps, after using the .coef_ and .intercept_ methods to retrieve the model coefficients 12 and the intercept 0, we then used these to create a line defined by two points, according to the equation we described for the decision boundary.

  1. Plot the decision boundary using the following code, with some adjustments to assign the correct labels for the legend, and to move the legend to a location (loc) outside a plot that is getting crowded:
pos_true = plt.scatter(X_1_pos, X_2_pos, color='red', marker='x', label='Positive class')
neg_true = plt.scatter(X_1_neg, X_2_neg, color='blue', marker='x', label='Negative class')
pos_pred = plt.scatter(X[positive_indices,0], X[positive_indices,1], s=150, marker='o',
edgecolors='red', facecolors='none', label='Positive predictions')
neg_pred = plt.scatter(X[negative_indices,0], X[negative_indices,1], s=150, marker='o',
edgecolors='blue', facecolors='none', label='Negative predictions')
dec = plt.plot(X_1_decision_boundary, X_2_decision_boundary, 'k-', label='Decision boundary')
plt.xlabel('$X_1$')
plt.ylabel('$X_2$')
plt.legend(loc=[0.25, 1.05])

You will obtain the following plot:

 IMG7

True classes, predicted classes, and the decision boundary of a logistic regression

In this post, we discuss the basics of logistic regression along with various other methods for examining the relationship between features and a response variable.  To know, how to install the required packages to set up a data science coding environment, read the book Data Science Projects with Python on Packt Publishing.

Why is Logistic Regression Considered a Linear Model?

A model is considered linear if the transformation of features that is used to calculate the prediction is a linear combination of the features. The possibilities for a linear combination are that each feature can be multiplied by a numerical constant, these terms can be added together, and an additional constant can be added. For example, in a simple model with two features, X1 and X2, a linear combination would take the form:

FOR1

Linear combination of X1 and X2

The constants i, can be any number, positive, negative, or zero, for i = 0, 1, and 2 (although if a coefficient is 0, this removes a feature from the linear combination). A familiar example of a linear transformation of one variable is a straight line with the equation y = mx + b. In this case, o = b and 1 = mo is called the intercept of a linear combination, which should make sense when thinking about the equation of a straight line in slope-intercept form like this.

However, while these transformations are not part of the basic formulation of a linear combination, they could be added to a linear model by engineering features, for example defining a new feature, X3 = X12.

Predictions of logistic regression, which take the form of probabilities, are made using the sigmoid function. This function is clearly non-linear and is given by the following:

 FOR2

Non-linear sigmoid function

Why, then, is logistic regression considered a linear model? It turns out that the answer to this question lies in a different formulation of the sigmoid equation, called the logit function. We can derive the logic function by solving the sigmoid function for X; in other words, finding the inverse of the sigmoid function. First, we set the sigmoid equal to p, the probability of observing the positive class, then solve for X as shown in the following:

 FOR3

Solving for X

Here, we’ve used some laws of exponents and logs to solve for X. You may also see the logit expressed as:

 FOR4

Logit function

The probability of failure, q, is expressed in terms of the probability of successp: q = 1 – p, because probabilities sum to 1. Even though in our case, credit default would probably be considered a failure in the sense of real-world outcomes, the positive outcome (response variable = 1 in a binary problem) is conventionally considered “success” in mathematical terminology. The logit function is also called the log odds, because it is the natural logarithm of the odds ratiop/q. Odds ratios may be familiar from the world of gambling, via phrases such as “the odds are 2 to 1 that team a defeats team b.”

In general, what we’ve called capital X in these manipulations can stand for a linear combination of all the features. For example, this would be X = o + 1X1 + 2X2 in our simple case of two features. Logistic regression is considered a linear model because the features included in X are, in fact, only subject to a linear combination when the response variable is considered to be the log odds. This is an alternative way of formulating the problem, as compared to the sigmoid equation.

In summary, the features X1X2,…, Xj look like this in the sigmoid equation version of logistic regression:

 FOR5

Sigmoid version of logistic regression

But they look like this in the log odds version, which is why logistic regression is called a linear model:

 FOR6

Log odds version of logistic regression

Because of this way of looking at logistic regression, ideally the features of a logistic regression model would be linear in the log odds of the response variable.

This post is taken from the book Data Science Projects with Python by Packt Publishing written by Stephen Klosterman. The book explains descriptive analyses for future operations using predictive models.

Packt Humble Bundle package

I am pleased to announce that my title, Python Machine Learning Cookbook, is part of the Packt Humble Bundle package, currently on sale on the Humble Bundle website until May 27, 2019.

PMLC

Humble Bundle is a distribution platform that sells games, ebooks, software, and other digital content. Since their inception in 2010, their mission has been to support charities (“Humble”) while providing awesome content to customers at great prices (“Bundle”). So far they helped to raise of $140m for a number of featured charities.

www.humblebundle.com

Inizializzazione delle variabili in Python

python

L’inizializzazione delle variabili in Python rappresenta una buona pratica di programmazione che ci mette al riparo da situazioni impreviste. Questo perchè è possibile che nel codice che abbiamo realizzato si possano generare degli errori dovuti all’utilizzo di variabili che non risultano iniliazzate.

Ricordiamo allora che per inizializzazione delle variabili in Python s’intende l’operazione di creazione della variabile con l’attribuzione ad essa di un valore valido; vediamone allora un esempio banale:
a = 1
in tale istruzione è stato utilizzato l’operatore di assegnazione (segno di uguale =), con il significato di assegnare appunto alla locazione di memoria individuata dal nome a il valore 1. Il tipo attribuito alla variabile viene stabilito in fase di inizializzazione; sarà allora che si deciderà se assegnare ad essa una stringa di testo, un valore booleano (true e false), un numero decimale etc.

LINK DI APPROFONDIMENTO PER L’ARGOMENTO:

Nomi di variabili in Python

python

I nomi delle variabili in Python rispettano le regole già viste per gli identificatori Python, ricordiamo poi che Python è case sensitive, nel senso che le lettere maiuscole e minuscole rappresentano entità differenti. Allora i nomi Luigi, luigi e LUIGI si riferiscono a tre variabili diverse. Infine è opportuno segnalare che le parole riservate non possono essere utilizzate come nomi di variabile in Python.

Lista delle parole riservate in Python

and continue else for import not raise
assert def except from in or return
break del exec global is pass try
class elif finally if lambda print while

Per la maggior parte dei compilatori, un nome di variabile può contenere fino a 31 caratteri, in modo da poter adottare per una variabile un nome sufficientemente descrittivo, in Python tale limite non viene indicato. La scelta del nome assume un’importanza fondamentale al fine di rendere leggibile il codice; questo perché un codice leggibile sarà facilmente mantenibile anche da persone diverse dal programmatore che lo ha creato.

LINK DI APPROFONDIMENTO PER L’ARGOMENTO:

Il namespace in Python

python

Con la parola namespace in Python, che tradotto suonerebbe come spazio dei nomi, si intende un dizionario Python che contiene i nomi delle variabili (chiavi) ed i valori di tali variabili (valori) in modo da tenere traccia delle variabili utilizzate in quel particolare contesto.

In generale, uno spazio dei nomi (a volte chiamato anche contesto) è un sistema di denominazione per creare dei nomi univoci onde evitare ambiguità. Tutti noi utilizziamo nella vita quotidiana un sistema del tipo namespace, vale a dire l’identificazione di persone attraverso nome cognome. Un altro esempio è relativo alle reti: ogni dispositivo di rete (workstation, server di stampa, …) ha bisogno di un nome e di un indirizzo univoco. Ancora un altro esempio è la struttura delle directory del file system. Lo stesso nome file può essere utilizzato in diverse directory, i file sono accessibili unicamente attraverso dei percorsi.
Molti linguaggi di programmazione usano spazi dei nomi o contesti per gli identificatori. Un identificatore definito in un namespace è associato a quel namespace. In questo modo, lo stesso identificatore può essere definito indipendentemente in più domini. (Come gli stessi nomi di file in directory nei differenti linguaggi di programmazione), che supportano spazi dei nomi, possono avere regole diverse che determinano a quale spazio dei nomi un identificatore appartiene.

Alcuni spazi dei nomi in Python (namespace in Python) sono:

  • global names
  • local names
  • built-in names

Ed allora ogni blocco di un programma Python, dispone dei suoi namespace, ad esempio una funzione ha il suo namespace, denominato namespace locale, che contiene i riferimenti a tutte le variabili utilizzate dalla funzione, ed i suoi argomenti. Così come un modulo ha il suo namespace, denominato questa volta namespace globale, in quanto contiene i riferimenti alle variabili del modulo, alle funzioni, alle classi, ed infine ai moduli importati. C’è poi il namespace built-in, accessibile da ogni modulo, che contiene le funzioni built-in e le eccezioni.

LINK DI APPROFONDIMENTO PER L’ARGOMENTO:

Le variabili in Python

python

Con il termine variabile ci si riferisce ad un tipo di dato il cui valore è variabile nel corso dell’esecuzione del programma, in questo articolo ci occuperemo delle variabili in Python. È però possibile assegnarne un valore iniziale, si parlerà allora di inizializzazione della variabile. La fase di inizializzazione, assume un importanza fondamentale in quanto rappresenta il momento in cui la variabile viene creata, tale momento coincide con quello in cui ad essa viene associato un dato valore. A differenza dei linguaggi cosiddetti compilativi tale procedura può essere inserita in qualunque punto dello script, anche se i significati possono assumere valori differenti.

Con il termine variabile ci si riferisce ad un tipo di dato il cui valore è variabile nel corso dell’esecuzione del programma. È però possibile assegnarne un valore iniziale, si parlerà allora di inizializzazione della variabile. La fase di inizializzazione, assume un importanza fondamentale in quanto rappresenta il momento in cui la variabile viene creata, tale momento coincide con quello in cui ad essa viene associato un dato valore. A differenza dei linguaggi cosiddetti compilativi tale procedura può essere inserita in qualunque punto dello script, anche se i significati possono assumere valori differenti.

Le variabili in Python possono essere di due tipi di variabili:

  1. variabili globali;
  2. variabili locali;

Come si può intuire, le variabili globali risultano accessibili a livello globale all’interno del programma, le variabili locali invece assumono significato solo ed esclusivamente nel settore di appartenenza, risultando visibili solo all’interno del metodo in cui vengono inizializzate.

Python utilizza due funzioni built-in: locals e globals per specificare i diversi tipi di variabili; tali funzioni forniscono un accesso basato sui dizionari alle variabili locali e globali. 

LINK DI APPROFONDIMENTO PER L’ARGOMENTO:

 

Identificatori in Python

python

Un identificatore in Python  è il nome con cui sono rappresentate costanti, variabili, metodi, classi e moduli. Un identificatore in Python  può essere costituito da una lettera maiuscola, minuscola o dal simbolo underscore seguito da altri caratteri, che a loro volta possono essere una qualsiasi combinazione di lettere maiuscole e minuscole, underscore e cifre. I caratteri minuscoli corrispondono alle lettere minuscole dell’alfabeto dalla a alla z, compreso il simbolo underscore, mentre i caratteri maiuscoli corrispondono alle lettere maiuscole dell’alfabeto dalla A alla Z e le cifre da 0 al 9. Il numero di caratteri che compongono il nome non è limitato.

Un identificatore in Python può essere scelto applicando le seguenti regole:

  • Un identificatore non può contenere degli spazi vuoti.
  • I nomi delle classi iniziano con una lettera maiuscola e tutti gli altri identificatori con una lettera minuscola.
  • Se il nome inizia con un underscore ciò indica per convenzione che l’identificatore è destinato ad essere privato.
  • Se invece l’identificatore inizia con due caratteri di sottolineatura ciò indica un identificatore fortemente privato.
  • Se l’identificatore, inoltre, termina con due simboli di sottolineatura, l’identificatore è un nome definito speciale.

C’è da precisare che non possono essere usate come nomi degli identificatori alcune parole, che sono quindi riservate ad opportuni impieghi dall’interprete.

Parole riservate in Python

Parole riservate in Python

LINK DI APPROFONDIMENTO PER L’ARGOMENTO:

Indentazione del codice in Python

python

Un caratteristica essenziale del linguaggio di programmazione Python è il metodo che utilizza per delimitare i blocchi di programma, e cioè l’indentazione del codice.

Per indentazione del codice in Python, si intende quella tecnica utilizzata nella programmazione attraverso la quale si evidenziano dei blocchi di programma con l’inserimento di una certa quantità di spazio vuoto all’inizio di una riga di testo allo scopo di aumentarne la leggibilità. Così ogni riga viene indentata di un certo numero di spazi che dipende dalla sua posizione all’interno della struttura logica del programma.

Nell’indentazione del codice in Python, si utilizzano gli spazi bianchi, che vengono ignorati dall’interprete, allo scopo di separare più chiaramente le istruzioni ed in modo di rappresentare esplicitamente le relazioni di annidamento. La tecnica consiste nell’anteporre a ogni istruzione una quantità di spazio bianco proporzionale al numero di strutture di controllo o blocchi a cui tale istruzione appartiene.

indentazione del codice in Python

Indentazione del codice in Python

Allora Python, invece di usare parentesi o parole chiave, usa l’indentazione stessa per indicare i blocchi nidificati; a tal proposito si possono usare sia una tabulazione, sia un numero arbitrario di spazi bianchi, ma lo standard Python prevede  4 spazi bianchi. La cosa da ricordare è che la indentazione in Python non è facoltativa ma è una regola, nel senso che se si omette l’indentazione in una struttura condizionale, ad esempio, che rappresenta di norma una struttura nidificata, allora l’interprete ci restituirà un messaggio di errore.

Nell’utilizzo di tale tecnica è necessario ricordare delle semplici regole:

  • il numero di spazi da utilizzare è variabile;
  • tutte le istruzioni del blocco di programma devono presentare lo stesso numero di spazi di indentazione.

LINK DI APPROFONDIMENTO PER L’ARGOMENTO:

Opzioni da linea di comando in Python

python

In questo post impareremo a lanciare dei comandi Python attraverso l’utilizzo di una finestra di terminale. La prima cosa che risulta utile sapere è come impartire i comandi Python all’interprete; per fare questo possiamo utilizzare il seguente formato:

Python [option] [ nomefile | -c command | -m module | - ]          [arg]

dove:

  • option – rappresenta l’opzione che può essere passata all’interprete per eseguire una particolare azione;
  • nomefile – rappresenta il nome dello script Python che si vuole eseguire;
  • -c command – specifica un comando Python da eseguire;
  • -m module – lancia un modulo contenuto nella libreria a corredo dell’interprete: sarà allora ricercato il modulo nel sys.path, ed una volta individuato sarà lanciato come top-level file;
  • arg – indica che nient’altro sarà passato all’interprete python.

LINK DI APPROFONDIMENTO PER L’ARGOMENTO:

Documentazione ActivePython

python

ActivePython Documentation rappresenta una nutrita collezione di documentazione che viene fornita a corredo della IDE già dettagliatamente descritta nelle pagine precedenti.

Si tratta di una raccolta davvero completa che ci fornirà tutti gli argomenti necessari per apprendere le caratteristiche di base del linguaggio di programmazione Python se siamo dei principianti, mentre ci permetterà di arricchire le nostre competenze se siamo già pratici della sintassi di questo potente ma snello strumento per la programmazione ad oggetti.

Documentazione Python

Documentazione Python

Il sommario che si apre quando richiamiamo la documentazione Python ci offre i seguenti argomenti:

  • Active Python User Guide
  • What’s New
  • Python Documentation
  • Helpful Resources
  • PyWin 32 Documentation

 Come è possibile verificare, la documentazione a corredo del pacchetto ci permette di accedere ad una Guida all’uso di Active Python, alle novità introdotte dalla nuova versione, ad una raccolta di documenti su Python, alle risorse di aiuto ed infine alla documentazione su PyWin 32.

LINK DI APPROFONDIMENTO PER L’ARGOMENTO: