Classificação -- Classes não linearmente separáveis

(esta página corresponde ao notebook practice_classification2.ipynb)

Classificação de pontos 2D : classes positiva (1) e negativa (0)

Coloração no gráficos:

$\Huge \cdot$ Positive, classified as positive
$\Huge \cdot$ Negative, classified as negative
$\mathtt{x}$ Positive, classified as negative
$\mathtt{x}$ Negative, classified as positive

A fronteira de decisão resultante ao se aplicar a regressão linear ou logística a um problema de classificação é sempre uma função linear (reta, plano, hiperplano). Fronteiras "tortuosas" não são possíveis.

Aqui vamos examinar a aplicação da regressão logística para a classificação de dados 2D, cuja fronteira de decisão é sabidamente não-linear. Ao final consideramos a criação de features polinomiais.

Gerar dados

In [1]:
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
from funcoes import geraDados2DfronteiraNonLinear

N = 100
X, y, x, fx = geraDados2DfronteiraNonLinear(N)
Shape do X:  (100, 3)
Shape do y:  (100,)

Testar regressão logística

Experimente alterar o valor de alpha e o número de iterações

In [2]:
from funcoes import sigmoid, gradientDescent2, computeCost2

# chutar uns pesos iniciais
w = np.zeros(3)
initialCost = computeCost2(X, y, w)
print('Initial cost: ', initialCost)
R = X.dot(w)

# plotar a fronteira inicial
fig = plt.figure(figsize=(12,5))
plt.subplot(121)
plt.title('Initial fit')
for i in range(N):
    if  y[i]>0 :
        if R[i]>0:
            plt.plot(X[i,1],X[i,2],'bo')  # positivas corretas
        else:
            plt.plot(X[i,1],X[i,2],'bx')  # positivas erradas
    else:
        if R[i]>0:
            plt.plot(X[i,1],X[i,2],'rx')  # negativas erradas
        else:
            plt.plot(X[i,1],X[i,2],'ro')  # negativas corretas
plt.plot(X[:,1], X.dot(w), '-')
plt.xlabel('x')
plt.ylabel('y')

# Some gradient descent settings
iterations = 500
alpha = 0.1

# run gradient descent
w, J_history = gradientDescent2(X, y, w, alpha, iterations)

finalCost = computeCost2(X, y, w)
print('Final cost: ', finalCost)

print("w = ", w)

R = X.dot(w)
#print R

plt.subplot(122)
plt.title('Final fit')
for i in range(N):
    if  y[i]>0 :
        if R[i]>0:
            plt.plot(X[i,1],X[i,2],'bo')  # positivas corretas
        else:
            plt.plot(X[i,1],X[i,2],'rx')  # positivas erradas
    else:
        if R[i]>0:
            plt.plot(X[i,1],X[i,2],'bx')  # negativas erradas
        else:
            plt.plot(X[i,1],X[i,2],'ro')  # negativas corretas

plt.plot(x, fx, lw=2)
xs = np.arange(0, max(X[:,1]), 0.01)
fxs = [(-w[0]-w[1]*p)/w[2] for p in x ]
plt.plot(xs, fxs, lw=2)
plt.xlabel('x1')
plt.ylabel('x2')
plt.show()
Initial cost:  0.125
Final cost:  0.0990969757588
w =  [ 0.76528378  0.66738499 -2.00022026]

Adicionar novos features (polinomiais)

O dado original estendido é da forma $(1,x_1,x_2)$. Vamos criar novas features. Expecificamente, consideraremos $(1,x_1,x_2,x_1^2,x_1x_2, x_2^2)$ e aplicar a regressão logística ao dado "ampliado".

In [3]:
X = np.vstack(zip(np.ones(N),X[:,1], X[:,2], X[:,1]*X[:,1],\
                  X[:,1]*X[:,2], X[:,2]*X[:,2]))
print(X.shape)
print(X[1,:])
(100, 6)
[ 1.          0.56353212  0.6925571   0.31756845  0.39027817  0.47963534]

Experimente variar o peso inicial, o número de iterações e o alpha (learning rate)

In [4]:
# chutar uns pesos iniciais
w = np.zeros(6)
initialCost = computeCost2(X, y, w)
print('Initial cost: ', initialCost)

# Some gradient descent settings
iterations = 500
alpha = 0.5

# run gradient descent
w, J_history = gradientDescent2(X, y, w, alpha, iterations)

finalCost = computeCost2(X, y, w)
print('Final cost: ', finalCost)

print("w = ", w)

R = X.dot(w)
#print R

fig = plt.figure(figsize=(6,5))

for i in range(N):
    if  y[i]>0 :
        if R[i]>0:
            plt.plot(X[i,1],X[i,2],'bo')  # positivas corretas
        else:
            plt.plot(X[i,1],X[i,2],'rx')  # positivas erradas
    else:
        if R[i]>0:
            plt.plot(X[i,1],X[i,2],'bx')  # negativas erradas
        else:
            plt.plot(X[i,1],X[i,2],'ro')  # negativas corretas

plt.plot(x, fx, lw=2)
plt.xlabel('x1')
plt.ylabel('x2')
plt.show()
Initial cost:  0.125
Final cost:  0.0818281005199
w =  [ 1.33312166 -1.46865074 -1.9871587   3.54717882 -0.34561928 -1.64274611]