Mi-a reprosat un cititor ca sunt haotic in alegerea subiectelor si in modul de prezentare!
Pai, chiar asa este!
Vestea buna e ca nu o sa raman asa, haotic, toata viata!
M-am apucat de curand de ai.musetoiu.ro. Nu dati click, ca inca nu merge!
Dar acela va fi locul in care veti putea gasi, zic eu, cea mai buna colectie de tutoriale de AI in limba romana!
(Ma laud si eu pentru ca, in alta ordine de idei, n-am mai vazut nicaieri in .ro free learning – ca asa sunt romanii, mai zgarciti cu impartasirea cunostintelor si experientelor personale. Iar cand concurezi de unul singur, ai sanse foarte mari sa iesi pe primul loc, nu?).
Oricum, pana sa fie gata, ma mai incurajez singur postand aici diverse chestii, fara pretentia de a fi neaparat utile cuiva – e un fel de teasing amestecat cu o lene cosmica!

Asa ca, azi, hai sa vedem ce-i aia Regresie Logistica, aka Logistic Regresion, una dintre cele mai simple forme de Machine Learning!
Daca vreti sa va delectati cu partea de teorie, intrati AICI si o sa gasiti tot ce va trebuie!
Daca vreti direct hands-on (desi eu va recomand sa incepeti cu teoria), ati nimerit unde trebuie.

Bun!
Sa incepem cu inceputul si sa importam modulele necesare!
In afara de numpy (obligatoriu), alegem si sklearn si nu keras, tensorflow sau alte alea, din doua motive simple: sintaxa intuitiva si afinitati personale!
Si matplotlib, ca sa vedem cate ceva!

In [1]:
import numpy as np
print(np.__version__)
import sklearn
print(sklearn.__version__)
import matplotlib
print(matplotlib.__version__)
1.14.5
0.19.1
2.2.3

Va rog sa remarcati ca am printat si versiunea modulelor, ca sa stiti ce sa verificati daca voua nu va merge!

Primul pas este pre-procesarea datelor.
Sklearn are o librarie care exact asta face: preprocessing!

In [2]:
from sklearn import preprocessing

Ca sa vedem ce poate face aceasta librarie, ne trebuie date care sa fie pre-procesate.
Asa ca definim noi o matrice, cu valori si dimensiuni alese la intamplare, sa vedem ce iese!

In [3]:
matricea_noastra = np.array([[5.1, 4, -6],
                     [2,7,8],
                     [-3.1, 6, -8],
                     [3.9, -9.8, 5.25]])
In [4]:
matricea_noastra.shape
Out[4]:
(4, 3)
In [5]:
matricea_noastra.ndim
Out[5]:
2

Asadar, avem o matrice (un array) in doua dimensiuni, cu patru linii si trei coloane!
Sa incepem cu binarizarea – o pre-procesare foarte des folosita, foarte utila… obligatorie as zice!
Se foloseste atunci cand vrem sa convertim datele la valori bool, aka 1 si 0, aka True si False.
Sa fixam, zic, un prag la valoarea 3.5.
Ce e peste 3.5 va avea valoarea 1. Restul valorilor vor fi 0.
Asta se face intr-o singura linie de cod (v-am zis ca sklearn are mila de noi):

In [6]:
data_binarizata = preprocessing.Binarizer(threshold = 3.5).transform(matricea_noastra)
data_binarizata
Out[6]:
array([[1., 1., 0.],
       [0., 1., 1.],
       [0., 1., 0.],
       [1., 0., 1.]])

Cam asta e binarizarea!
O alta pre-procesare obligatorie este Mean removaleliminarea mediei, insemna inlaturarea valorii medii, in asa fel incat noile valori sa fie grupate in jurul lui 0.
Hai intai sa vedem valorile inainte de transformare, mai precis media si deviatia standard inainte de transformare:

In [7]:
print('Inainte')
print('Media = ', matricea_noastra.mean(axis = 0))
print('Deviatia standard = ', matricea_noastra.std(axis = 0))
Inainte
Media =  [ 1.975   1.8    -0.1875]
Deviatia standard =  [3.13159305 6.78380424 6.91776472]

Hai sa inlaturam valorile medii, aka sa facem mean removal:

In [8]:
matricea_dupa = preprocessing.scale(matricea_noastra)
matricea_dupa
Out[8]:
array([[ 0.99789467,  0.32430181, -0.84022806],
       [ 0.00798316,  0.76653155,  1.18354705],
       [-1.62058094,  0.61912164, -1.12933878],
       [ 0.61470312, -1.709955  ,  0.78601979]])

… si sa vedem media si deviatia standard dupa scalare

In [9]:
print('Dupa')
print('Media = ', matricea_dupa.mean(axis = 0))
print('Deviatia standard = ', matricea_dupa.std(axis = 0))
Dupa
Media =  [ 2.77555756e-17 -5.55111512e-17  5.55111512e-17]
Deviatia standard =  [1. 1. 1.]

Asta a fost mean removal
Scalarea este urmatoarea pre-procesare extrem de utila!
Pe scurt, scalarea asta aduce toate valorile in intervalul 0-1 (sau in ce interval vrem noi).

In [10]:
matrice_scalata = preprocessing.MinMaxScaler(feature_range=(0, 1))
matrice_scalata = matrice_scalata.fit_transform(matricea_noastra)
matrice_scalata
Out[10]:
array([[1.        , 0.82142857, 0.125     ],
       [0.62195122, 1.        , 1.        ],
       [0.        , 0.94047619, 0.        ],
       [0.85365854, 0.        , 0.828125  ]])

Valorile maxime au devenit 1, valorile minime au devenit 0 iar valorile intermediare s-au inghesuit intre!
Cool, nu?

Normalizarea este o alta pre-procesare cool, si este de doua feluri:
L1 – se asigura ca suma valorilor absolute ale fiecarei linii din matrice este 1
L2 – se asigura ca suma patratelor valorilor fiecarei linii din matrice este 1
Cum adica ce-i cool in asta?
Cititi teoria (v-am dat link la inceput) si o sa gasiti acolo raspunsul! Nu fiti lenesi!
Oricum, normalizarea functioneaza cam asa:

In [11]:
matrice_normalizata_l1 = preprocessing.normalize(matricea_noastra, norm='l1')
matrice_normalizata_l2 = preprocessing.normalize(matricea_noastra, norm='l2')
In [12]:
matrice_normalizata_l1
Out[12]:
array([[ 0.33774834,  0.26490066, -0.39735099],
       [ 0.11764706,  0.41176471,  0.47058824],
       [-0.18128655,  0.35087719, -0.46783626],
       [ 0.20580475, -0.5171504 ,  0.27704485]])
In [13]:
matrice_normalizata_l2
Out[13]:
array([[ 0.57742427,  0.45288178, -0.67932268],
       [ 0.18490007,  0.64715023,  0.73960026],
       [-0.29609877,  0.5730944 , -0.76412586],
       [ 0.33101702, -0.83178635,  0.44559983]])

O sa ma intrebati probabil de ce am ales o matrice bidimensionala!
Pai, pentru ca mi-am imaginat ca o sa va jucati cu imagini!
Iar o imagine (alb-negru) chiar asta e: o matrice 2D de numere!
Hai sa va conving!

In [14]:
import skimage
from skimage import io
poza = io.imread('/Users/dan/Desktop/dragnea.jpg', as_grey = True) # daca scrieti as_gray o sa cititi RGB :D
print('Poza este o variabila de tipul {0}, de dimensiunea {1} si de forma {2}'.format(type(poza),poza.ndim,poza.shape))
Poza este o variabila de tipul <class 'numpy.ndarray'>, de dimensiunea 2 si de forma (576, 1024)

Daca tot nu credeti, iata si cum arata matricea:

In [15]:
poza
Out[15]:
array([[0.39721843, 0.39665294, 0.39665294, ..., 0.67907451, 0.67907451,
        0.67907451],
       [0.39273137, 0.39273137, 0.39273137, ..., 0.67907451, 0.67907451,
        0.67907451],
       [0.3888098 , 0.3888098 , 0.39273137, ..., 0.67907451, 0.67907451,
        0.67907451],
       ...,
       [0.30844863, 0.3123702 , 0.31629176, ..., 0.25797765, 0.25797765,
        0.25797765],
       [0.30844863, 0.30844863, 0.3123702 , ..., 0.25797765, 0.25797765,
        0.25797765],
       [0.30452706, 0.30844863, 0.3123702 , ..., 0.25797765, 0.25797765,
        0.25797765]])

…da, stiu, abia asteptati sa vedeti poza, nu niste numere…

In [16]:
io.imshow(poza)
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/skimage/io/_plugins/matplotlib_plugin.py:51: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  out_of_range_float = (np.issubdtype(image.dtype, np.float) and
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/matplotlib/axes/_base.py:1428: MatplotlibDeprecationWarning: The 'box-forced' keyword argument is deprecated since 2.2.
  " since 2.2.", cbook.mplDeprecation)
Out[16]:
<matplotlib.image.AxesImage at 0x112d66588>

Hai totusi sa nu ne tinem de prostii!
Voiam doar sa va zic ca imagine = matrice 2D (sau 3D daca imaginea e color gen RGB sau 4D daca e video)
Ca sa nu va pierdeti in denumiri incercati sa ganditi folosind termenul “tensor”:

  • o lista este un tensor de dimensiunea 1
  • o matrice ca aia de mai sus e un vector, sau un tensor de dimensiunea 2
  • o matrice ca poza de mai sus citita color este un tensor de dimensiunea 3
  • numarul de dimensiuni este cat vreti voi sa fie, cu conditia sa-i ziceti ‘tensor’
  • n-am inventat eu asta, ci google cand s-a hotarat sa elibereze tensorflow spre folosinta publica

Oricum, o sa aveti nevoie si de label encoding – puteti lua asta drept o pre-procesare a labels-urilor 🙂

Uite, sa zicem ca avem urmatoarele etichete:

In [17]:
etichete = ['prost', 'destept', 'mediocru', 'slabanog', 'hot', 'politician']

Pentru ca masina pe care lucrezi stie doar 1 si 0, trebuie sa creezi un codificator care sa faca fix asta: sa transforme etichetele (niste cuvinte) in numere pe care masina stie sa le gestioneze.
Dupa ce l-ai creat, evident, il pui sa-si faca treaba cu comanda “fit”.

In [18]:
codificator = preprocessing.LabelEncoder()
codificator.fit(etichete)
Out[18]:
LabelEncoder()

… si vezi ce-a iesit:

In [19]:
for i, item in enumerate(codificator.classes_):
    print(item, '-->', i)
destept --> 0
hot --> 1
mediocru --> 2
politician --> 3
prost --> 4
slabanog --> 5

Cam asa functioneaza!
In loc sa-i zici ca e hot, ii spui ca-i “numarul 1”! 😀
Ca sa va conving, hai sa facem si un test:

In [20]:
etichete_test = ['hot', 'politician', 'prost']
In [21]:
valori_etichete = codificator.transform(etichete_test)
In [22]:
valori_etichete
Out[22]:
array([1, 3, 4])

Asadar, avem “codurile” 1, 3 si 4.
Hai sa le “decodam” sa vedem daca obtinem etichetele test!

In [23]:
etichete_decodate = codificator.inverse_transform(valori_etichete)
etichete_decodate
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sklearn/preprocessing/label.py:151: DeprecationWarning: The truth value of an empty array is ambiguous. Returning False, but in future this will result in an error. Use `array.size > 0` to check that an array is not empty.
  if diff:
Out[23]:
array(['hot', 'politician', 'prost'], dtype='<U10')

Deci, i-am bunghit la fix!

Cu aceste mici lamuriri, putem aborda chestiuni simple de clasificare!

Clasificarea e un fel de “Hello, world!” al Machine Learning – ceva basic!

Dupa cum v-am promis la inceput, hai sa purcedem cu Logistic Regresion – o tehnica folosita pentru a explica relatia intre variabilele-input si variabilele-output.
Stati linistiti la locurile voastre, ca o sa evit in continuare aritmetica pe cat imi va fi posibil 😀
Hai sa mai importam niste module care ne vor fi de folos:

In [24]:
from sklearn import linear_model

… si sa zicem ca avem urmatorul set de date, X (majuscula) si y (minuscula).
X este o matrice (hai, ca ati inteles ce-i aia!) iar y este o lista care contine labels-urile (etichetele) – evident, codate cu LabelEncoder, ca doar de-aia v-am aratat mai sus cum functioneaza – pentru fiecare valoare din X.
Asta e notatia standard.

In [25]:
X = np.array([[3.1, 7.2], [4, 6.7], [2.9, 8], [5.1, 4.5], [6, 5], [5.6, 5],
              [3.3, 0.4], [3.9, 0.9], [2.8, 1], [0.5, 3.4], [1, 4], [0.6, 4.9]])
y = np.array([0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3])

Chiar daca valorile astea sunt luate la intamplare (dintr-un manual de sklearn :))), ele trebuie sa fie corelate, in sensul ca numarul de labels din y sa fie egal cu numarul de valori (linii) din X

In [26]:
print(X.shape)
print(y.shape)
(12, 2)
(12,)

Pasul urmator este sa construim un ‘clasificator’ – aka un obiect care asta face, clasifica!

In [27]:
clasificator = linear_model.LogisticRegression(solver='liblinear', C=1)

Apoi il antrenam pe X si y definite deja. In sklearn, antrenamentul este invocat cu ‘fit’ (parca am mai zis asta!)

In [28]:
clasificator.fit(X, y)
Out[28]:
LogisticRegression(C=1, class_weight=None, dual=False, fit_intercept=True,
          intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
          penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
          verbose=0, warm_start=False)

Ca sa vedem performantele clasificatorului nostru, mai avem putina treaba!
Hai sa definim o functie, sa-i zicem “vezi_clasificatoru” – asa, fara ‘l’ la sfarsit:

In [29]:
import matplotlib.pyplot as plt
def vezi_clasificatoru(clasificator, X, y):
    # definim valorile maxime pentru X si y
    min_x, max_x = X[:, 0].min() -1.0, X[:, 0].max() + 1.0
    min_y, max_y = X[:, 1].min() - 1.0, X[:, 1].max() + 1.0
    # definim mesh, grid si un step size
    mesh_step_size = 0.01
    x_vals, y_vals = np.meshgrid(np.arange(min_x, max_x, mesh_step_size), np.arange(min_y, max_y, mesh_step_size))
    # punem clasificatorul la treaba in interiorul grid-ului
    rezultat = clasificator.predict(np.c_[x_vals.ravel(), y_vals.ravel()])
    # cred ca o sa fie de nevoie de reshape
    rezultat = rezultat.reshape(x_vals.shape)
    # ... si plotam rezultatul
    plt.figure()
    plt.pcolormesh(x_vals, y_vals, rezultat, cmap=plt.cm.Spectral)
    plt.scatter(X[:, 0], X[:, 1], c=y, s=75, edgecolors='white',linewidth=1, cmap=plt.cm.Paired)
    plt.xlim(x_vals.min(), x_vals.max())
    plt.ylim(y_vals.min(), y_vals.max())
    plt.xticks((np.arange(int(X[:, 0].min() - 1), int(X[:, 0].max() + 1), 1.0)))
    plt.yticks((np.arange(int(X[:, 1].min() - 1), int(X[:, 1].max() + 1), 1.0)))
    plt.show()

Hai ca n-a dat eroare!
Acum putem vedea performantele clasificatorului!

In [30]:
vezi_clasificatoru(clasificator, X, y)

Asadar, cam asta e logistic regresion classification!
Clasificatorul construit de noi a grupat valorile din X in functie de labels-urile din y – si asta se numeste clasificare!

Ca delimitarile sa fie mai vizibile, trebuie sa facem C-ul mai mare! Adica:

In [31]:
clasificator_mai_bun = linear_model.LogisticRegression(solver='liblinear', C=100) # adica in loc de 1 am facut 100
clasificator_mai_bun.fit(X, y)
vezi_clasificatoru(clasificator_mai_bun, X, y)

Se vede cu ochiul liber ca delimitarile sunt mai clare!

Spuneti ce vreti, dar mai explicit de atat nu pot sa fiu!
Ceea ce ati vazut este cea mai simpla forma de inteligenta artificiala.
Un fel de drosofila, amoeba sau dancila.
Fiti cuminti si o sa va mai arat!

 

 

http://musetoiu.ro/wp-content/uploads/2018/09/dragnea-1024x576.jpghttp://musetoiu.ro/wp-content/uploads/2018/09/dragnea-150x150.jpgdan musetoiuMLRevista preseiclassification,logistic regression,sklearn
  Mi-a reprosat un cititor ca sunt haotic in alegerea subiectelor si in modul de prezentare! Pai, chiar asa este! Vestea buna e ca nu o sa raman asa, haotic, toata viata! M-am apucat de curand de ai.musetoiu.ro. Nu dati click, ca inca nu merge! Dar acela va fi locul in care veti putea...