Fundamentos pr谩cticos

1

Aplica Platzidoro en este curso y asegura el 茅xito de tu aprendizaje

2

Los fundamentos de machine learning que aprender谩s

3

Introducci贸n a Numpy

4

Introducci贸n y manipulaci贸n de datos con Pandas

5

Introducci贸n a ScikitLearn

6

Comandos b谩sicos de las librer铆as usadas en el curso (Numpy, Pandas y ScikitLearn)

Regresi贸n Lineal y Log铆stica

7

驴Qu茅 es la predicci贸n de datos?

8

Sobreajuste y subajuste en los datos

9

Regresi贸n lineal simple y regresi贸n lineal m煤ltiple

10

Regresi贸n lineal simple con Scikit-Learn: divisi贸n de los datos

11

Regresi贸n lineal simple con Scikit-Learn: creaci贸n del modelo

12

Regresi贸n log铆stica con Scikit-Learn: definici贸n y divisi贸n de datos

13

Regresi贸n log铆stica con Scikit-Learn: evaluaci贸n del modelo

14

Matriz de confusi贸n

15

PlatziDoro C谩psula 1

脕rboles de decisi贸n

16

驴Qu茅 es un 谩rbol de decisi贸n y c贸mo se divide?

17

Comprendiendo nuestro data set para la creaci贸n de un 谩rbol de decisi贸n

18

Creando un clasificador con Scikit-Learn

19

Entrenamiento del modelo de clasificaci贸n

20

Visualizaci贸n del 谩rbol de decisi贸n

K-Means

21

驴Qu茅 es K-Means?

22

Cargando el data set de Iris

23

Construcci贸n y evaluaci贸n del modelo con K-Means

24

Graficaci贸n del modelo

25

PlatziDoro C谩psula 2

Aprendizaje profundo

26

Introducci贸n al aprendizaje profundo

27

Conceptos b谩sicos de Tensor Flow

28

Red neuronal convolucional

29

Conociendo el set de datos para la creaci贸n de la red neuronal

30

Crea y entrena tu primera red neuronal convolucional con Tensor Flow

31

Evaluaci贸n de la red convolucional

32

PlatziDoro C谩psula 3

Despedida

33

Recomendaciones para analizar correctamente tu problema

34

Siguientes pasos para continuar aprendendiendo de Machine Learning

A煤n no tienes acceso a esta clase

Crea una cuenta y contin煤a viendo este curso

Graficaci贸n del modelo

24/34
Recursos

Aportes 38

Preguntas 7

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesi贸n.

Buenas tardes a todos, para aquellos que obtuvieron una precisi贸n del 36-37% (al menos para este caso en particular) es debido a que trabajaron con los datos directamente sin estandarizarlos previamente (estoy seguro que el tema de estandarizaci贸n ser谩 tratado en clases posteriores, as铆 que no teman). Haciendo uso de la estandarizaci贸n pude obtener una precisi贸n de 0.89. A continuaci贸n, dejo mi c贸digo para que puedan observar la estandarizaci贸n de datos.

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
from sklearn import metrics
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler #Necesario para la estandarizacion de los datos

Descarga de los datos de Vinos

vinos = datasets.load_wine()
variables = np.array(vinos.feature_names)
x_vinos = vinos.data
y_vinos = vinos.target

Normalizacion de los valores de 鈥淴鈥

scaler = StandardScaler()
scaler.fit(vinos.data)
x_scaled = scaler.transform(vinos.data)
x = pd.DataFrame(x_scaled, columns=variables, ) #Si deseas trabajar con los datos sin estandarizar, solo cambia x_scaled por x_vinos
y = pd.DataFrame(y_vinos, columns= ["Target"])
x.head(5)

Elaboracion del Modelo y Metodo del Codo

wccs =[]
n = 1
acc = 0
for i in range(1, 11):
    codo = KMeans(n_clusters = i, max_iter = 1000, random_state = 0)
    codo.fit(x)
    y_kmeans = codo.predict(x)
    wccs.append(codo.inertia_)
    accuracy =  round(metrics.adjusted_rand_score(y_vinos, y_kmeans), 4)
    print(f'Cantidad de Centroides: {i} ---  Precision: {accuracy}')
    if accuracy > acc:
        acc = accuracy
        n = i
plt.plot(range(1, 11), wcss)
plt.title('Metodo del Codo')
plt.xlabel('Numero de centroides')
plt.ylabel('WCSS')
plt.show()
print(f"Se recomienda emplear una cantidad de {n} centroides, para asi garantizar una precision de {acc}")


Ejecucion del modelo KMeans con la cantidad de centroides seleccionados

modelo = KMeans(n_clusters = n, max_iter = 1000)
modelo.fit(x)
y_labels = modelo.labels_
y_kmeans = modelo.predict(x)
print('predicciones ', y_kmeans)
y_kmeans_df = pd.DataFrame(y_kmeans, columns = ['Prediction'])

Precision

accuracy =  metrics.adjusted_rand_score(y_vinos, y_kmeans)
print(round(accuracy, 5))

Vizualizacion del modelo

# Concateno el dataset de entrada con el de la prediccion
Z = pd.concat([x, y_kmeans_df], axis = 1)
# Grafico
sns.pairplot(Z, hue = 'Prediction')

En el dataset de vinos, la raz贸n por la que debemos normalizar los datos antes de aplicar el modelo es porque estamos trabajando con datos que miden diferentes cosas, como la intensidad del color, la alcalinidad, el grado de alcohol, etc, estos son valores que no pueden ser comparados entre s铆 (es como sumar peras con manzanas) y por eso se debe estandarizar, es decir, aplicar un proceso estad铆stico que hace que todos los datos se ajusten a una curva de distribuci贸n normal y se situen en una misma escala que permita su comparacion, por eso es que el accuracy aumenta desde un 36-37%, hasta un 89%. Pueden leer m谩s sobre la estandarizaci贸n aqu铆.

Creo que esto nos deja una lecci贸n m谩s de lo importante que es conocer nuestros datos antes empezar a trabajar con ellos

Hola comparto mi c贸digo para el dataset de wine

from sklearn import metrics
from sklearn.cluster import KMeans
from sklearn import datasets
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# Cargamos informacion de wines
wines = datasets.load_wine()

# Separamos nuestra dataset
X_wines = wines.data
Y_wines = wines.target

# Llevo los datos a una estructura de DataFrame
xw = pd.DataFrame(X_wines, columns = ['Alcohol', 'Malic Acid', 'Ash', 'Alcalinity of Ash', 'Magnesium', 
                                      'Total Phenols', 'Flavanoids', 'Nonflavanoid Phenols', 'Proanthocyanins', 
                                      'Colour Intensity', 'Hue', 'OD280/OD315 of diluted wines', 'Proline'])
yw = pd.DataFrame(Y_wines, columns = ['Target'])
xw.head(5)

# Ploteo para encontrar el numero de clusters de acuerdo a 
# metodo del codo
wcss = []
for i in range(1, 11):
    kmeans = KMeans(n_clusters=i, max_iter=1000, random_state=0)
    kmeans.fit(xw)
    yw_kmeans = kmeans.predict(xw)
    wcss.append(kmeans.inertia_)
    accuracy =  metrics.adjusted_rand_score(Y_wines, yw_kmeans)
    print(f'numero de n_clusters: {i} accurracy {accuracy}')
plt.plot(range(1, 11), wcss)
plt.title('ELBOW METHOD')
plt.xlabel('NUMBER OF CLUSTERS')
plt.ylabel('WCSS')
plt.show()
# Aplico el modelo de KMeans
modelw = KMeans(n_clusters = 3, max_iter = 1000)
modelw.fit(xw)
yw_labels = modelw.labels_
yw_kmeans = modelw.predict(xw)
print('predicciones ', yw_kmeans)
yw_kmeans_df = pd.DataFrame(yw_kmeans, columns = ['Prediction'])

# Precisi贸n del modelo
accuracyw =  metrics.adjusted_rand_score(Y_wines, yw_kmeans)
print(accuracyw)

# Concateno el dataset de entrada con el de la prediccion
Z = pd.concat([xw, yw_kmeans_df],axis=1)

# Grafico para ver relaci贸n de las features con respecto a las 
# valores de la predicci贸n, poniendo color seg煤n (0,1,2) 
# considerando las tres clases.
sns.pairplot(Z, hue = 'Prediction')

Para lo que obtengo la siguiente gr谩fica, aqui no se ve depronto muy claro pero en el colab se ve bien:

Aqui se puede ver la relacion interesante que hay entre la feature proline con las clases y las demas features.

Adjunto codigo con los estandarizados, el cual hace pasar el modelo del 37% al 89%

<h1>Ejemplo de Vinos</h1>
from sklearn.cluster import KMeans
from sklearn import datasets
from sklearn import metrics

import pandas as pd
import matplotlib.pyplot as plt

%matplotlib inline

from sklearn.preprocessing import StandardScaler #Necesario para la estandarizacion de los datos

wine = datasets.load_wine()
wine

scaler = StandardScaler()
scaler.fit(wine.data)
x_scaler = scaler.transform(wine.data)

nombre_columnas = wine.feature_names

#x = pd.DataFrame(wine.data, columns=nombre_columnas)
x = pd.DataFrame(x_scaler, columns=nombre_columnas)
y = pd.DataFrame(wine.target, columns=['Target'])

x

El DataFrame generado por pandas tiene un tama帽o de 178 filas por 13 columnas.

x_plot = x['alcohol']
y_plot = x['color_intensity']

plt.scatter(x_plot, y_plot, c='b')
plt.xlabel('Cantidad de Alcohol')
plt.ylabel('Intensidad del Color')

plt.show()

model = KMeans(n_clusters=3, max_iter=1000)
model.fit(x)

y_kmeans = model.predict(x)

precision = metrics.adjusted_rand_score(wine.target, y_kmeans)
precision

  • n_clusters=2 -> 0.3694
  • n_clusters=3 -> 0.3711
  • n_clusters=4 -> 0.3034
  • n_clusters=5 -> 0.3115
  • n_clusters=6 -> 0.2909
  • n_clusters=7 -> 0.2209
  • n_clusters=8 -> 0.1978
  • n_clusters=9 -> 0.1739
x_plot = x['alcohol']
y_plot = x['color_intensity']

plt.scatter(x_plot, y_plot, c=y_kmeans, s=30)
plt.xlabel('Cantidad de Alcohol')
plt.ylabel('Intensidad del Color')

plt.show()

Se concluye que no hay relacion entre la cantidad de alcohol que tiene un vino y la intensidad de su color 馃槮

Si estandarizamos los datos (???) podemos obtener una precision del 89% aproximadamente.

scaler = StandardScaler()
scaler.fit(wine.data)
x_scaler = scaler.transform(wine.data)
### WINE ANALYSIS

wine = datasets.load_wine()
wine

x = pd.DataFrame(wine.data, columns=wine.feature_names)
y = pd.DataFrame(wine.target, columns=["Target"])

corr = x.corr()
corr.style.background_gradient(cmap='coolwarm')

plt.scatter(x['flavanoids'],x['total_phenols'], s=30)
plt.xlabel('flavanoids',fontsize=10)
plt.ylabel('total_phenols',fontsize=10)
plt.show()

model = KMeans(n_clusters=3,max_iter=1000)
model.fit(x)

y_labels = model.labels_

acuracy = metrics.adjusted_rand_score(wine.target, y_labels)
print(acuracy)

##### 0.37111371823084754

new_x = x[["flavanoids","total_phenols","malic_acid","hue","od280/od315_of_diluted_wines"]]
model = KMeans(n_clusters=3,max_iter=1000)
model.fit(new_x)

y_labels = model.labels_

acuracy = metrics.adjusted_rand_score(wine.target, y_labels)
print(acuracy)

###### 0.47627086172451033

plt.scatter(x['flavanoids'],x['total_phenols'], c=y_labels,s=30)
plt.xlabel('flavanoids',fontsize=10)
plt.ylabel('total_phenols',fontsize=10)
plt.show()

Les comparto como resolv铆 el reto.

wines = datasets.load_wine()
x = wines.data
y = wines.target
x = pd.DataFrame(x, columns=wines.feature_names)
WSS = []
for i in range(1,10):
  model = KMeans(n_clusters = i , max_iter = 1000)
  model.fit(x)
  WSS.append(model.inertia_)
  print('Accuracy: ', metrics.adjusted_rand_score(y, model.predict(x)

Mi output fue.

Accuracy:  0.0 WSS: 17592296.383508474
Accuracy:  0.3694075388574537 WSS: 4543749.614531862
Accuracy:  0.37111371823084754 WSS: 2370689.686782968
Accuracy:  0.3196724933068579 WSS: 1337429.7347864588
Accuracy:  0.31158801033176253 WSS: 916379.187153917
Accuracy:  0.29090227688418224 WSS: 647326.0020260847
Accuracy:  0.2209596701158363 WSS: 412303.82825080137
Accuracy:  0.19843744177983885 WSS: 323211.55263465445
Accuracy:  0.17441376056983432 WSS: 271873.0632650521

Con lo que procedi a aplicar el metodo de codo.

plt.figure(facecolor='white')
plt.plot(range(1,10),WSS,'r-',alpha = 0.3)
plt.xlabel('Numero de cluster')
plt.ylabel('WSS')
plt.title('Metodo de Elbow')

Obteniendo.

Asi que la mejor cantidad de clusters era3.

model = KMeans(n_clusters = 3 , max_iter = 1000)
model.fit(x)

Realice la comparacion entre graficas.

plt.figure(facecolor='lightgreen')
plt.scatter(x['alcohol'],x['proanthocyanins'], c=model.predict(x) , s = 30, alpha = 0.4)
plt.xlabel('Petal Length', fontsize = 10)
plt.ylabel('Peta Width', fontsize = 10)
plt.figure(facecolor='lightgreen')
plt.scatter(x['alcohol'],x['proanthocyanins'], c=y , s = 30, alpha = 0.4)
plt.xlabel('Petal Length', fontsize = 10)
plt.ylabel('Peta Width', fontsize = 10)

Me di贸 muy bajo el %, supongo que es porque como no se mucho de vinos no pude escojer los parametros adecuados o cual seria la mejor solucion?


import pandas as pd
from sklearn import datasets
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt

wines = datasets.load_wine()

x_wines = wines.data
y_wines = wines.target

 x = pd.DataFrame(wines.data, columns=wines.feature_names)
 y = pd.DataFrame(wines.target, columns=['Target'])
 x.head()

plt.scatter(x['total_phenols'],x['proline'], c='blue')
plt.xlabel('total_phenols')
plt.ylabel('proline')
plt.show()

model = KMeans(n_clusters=3, max_iter=1000)
model.fit(x)
y_labels = model.labels_

y_kmeans = model.predict(x)

from sklearn import metrics

accuracy = metrics.adjusted_rand_score(y_wines,y_kmeans)

accuracy
#0.37111371823084754

plt.scatter(x['total_phenols'],x['proline'], c=y_kmeans, s=30)
plt.xlabel('total_phenols', fontsize=10)
plt.ylabel('proline', fontsize=10)
plt.show()

ma da una eficiencia de 37.6 % MALISIMO


RETO:

Usando PCA podria mejorar la clusterizacion!

Hola. Intente hacer el reto con datos propios y me genero una duda. Cuando se comenz贸 el modulo de K-Means, Yecely hablo que es un algoritmo no supervisado (sin etiqueta o target) por lo que me genera la duda:
Como puedo yo medir el Accuracy de mi modelo si yo no tengo target?

O estoy encarando el problema de una manera err贸nea?

aqui estan los resultados.



from sklearn.cluster import KMeans
from sklearn import datasets
import pandas as pd

import matplotlib.pyplot as plt

wine = datasets.load_wine() # load_wines
#  wine

X_wine = wine.data
Y_wine = wine.target

x = pd.DataFrame(wine.data, columns =wine.feature_names)
y = pd.DataFrame(wine.target, columns = ['Target'])
x.head(5)

	alcohol 	malic_acid 	ash 	alcalinity_of_ash 	magnesium 	total_phenols 	flavanoids 	nonflavanoid_phenols 	proanthocyanins 	color_intensity 	hue 	od280/od315_of_diluted_wines 	proline
0 	14.23 	1.71 	2.43 	15.6 	127.0 	2.80 	3.06 	0.28 	2.29 	5.64 	1.04 	3.92 	1065.0
1 	13.20 	1.78 	2.14 	11.2 	100.0 	2.65 	2.76 	0.26 	1.28 	4.38 	1.05 	3.40 	1050.0
2 	13.16 	2.36 	2.67 	18.6 	101.0 	2.80 	3.24 	0.30 	2.81 	5.68 	1.03 	3.17 	1185.0
3 	14.37 	1.95 	2.50 	16.8 	113.0 	3.85 	3.49 	0.24 	2.18 	7.80 	0.86 	3.45 	1480.0
4 	13.24 	2.59 	2.87 	21.0 	118.0 	2.80 	2.69 	0.39 	1.82 	4.32 	1.04 	2.93 	735.0

feature2 = 'proline'
feature1 = 'hue'

plt.scatter(x[feature1], x[feature2], c = 'blue')
plt.xlabel(feature1, fontsize = 10)
plt.ylabel(feature2, fontsize = 10)

Text(0, 0.5, 'proline')

#  Construcci贸n y evaluaci贸n del modelo con K-Means
#  unsupervised learning

model = KMeans(n_clusters = 3, max_iter = 1000)
model.fit(x)
y_labels = model.labels_

y_kmeans = model.predict(x)
print('Predicciones', y_kmeans)

Predicciones [1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 1 1 2 2 1 1 2 1 1 1 1 1 1 2 2
 1 1 2 2 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 2 0 2 0 0 2 0 0 2 2 2 0 0 1
 2 0 0 0 2 0 0 2 2 0 0 0 0 0 2 2 0 0 0 0 0 2 2 0 2 0 2 0 0 0 2 0 0 0 0 2 0
 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 2 0 0 2 2 2 2 0 0 0 2 2 0 0 2 2 0 2
 2 0 0 0 0 2 2 2 0 2 2 2 0 2 0 2 2 0 2 2 2 2 0 0 2 2 2 2 2 0]

from sklearn import metrics

accuracy = metrics.adjusted_rand_score(Y_wine, y_kmeans)
print(accuracy)

0.37111371823084754

#  Graficacion del modelo 
plt.scatter(x[feature1], x[feature2], c = y_kmeans, s= 30)
plt.xlabel(feature1, fontsize = 10)
plt.ylabel(feature2, fontsize = 10)

Text(0, 0.5, 'proline')


Solo acotar algo adicional al comentario que hicieron sobre estandarizar o escalar los datos antes de aplicar un modelo.
Hay varios tipos de estandarizaci贸n, puedo mencionar 4 de ellos:

StandarScaler - NO es recomendado cuando tienes outliers
RobustScaler - SI es recomendado cuando tienes outliers
MinMaxScaler - NO es recomendado cuando tienes outliers
MaxAbsScaler - NO es recomendado cuando tienes outliers
La raz贸n de porque uso RobustScaler y porque si es recomendado con outliers, es que este es aplicado usando la mediana, en cambio StandardScaler es usado con la media, si revisamos bien los datos, nos fijaremos que algunos features tienen outliers, y estos podr铆an darnos un mal resultado, en este caso eran pocos, y no afecta mucho al resultado, pero es algo a tener en cuenta cuando vayamos a realizar un trabajo profesional, les dejo mi repositorio por si se desean revisarlo.

Github

Si quieren graficar en seaborn les dejo para que puedan ver como funciono el KMeans

<code> 
sns.scatterplot(data=X  ,x="SepalLengthCm", y="SepalWidthCm", hue=prediction)

HICE EL RETO !!! UN SALUDO DESDE EL SALVADOR, LA CRIPTO NACION

from sklearn.cluster import KMeans
import numpy as np
from sklearn import datasets
import pandas as pd

import matplotlib.pyplot as plt
from sklearn import metrics

DATOS = datasets.load_wine()

DataTarget = DATOS.target

col_list = DATOS.feature_names
DataToTrain = pd.DataFrame(DATOS.data, columns = col_list)
print(col_list)

K_optimo = 0;
Mejor = 0

for K in range(2,8):

# Variamos K
model = KMeans(n_clusters= K, max_iter=1000) 

#Se entrena modelo
model.fit(DataToTrain)  

y_labels = model.labels_ 

#Creamos prediccion
y_kmeans = model.predict(DataToTrain) 

# Revisamos la precicion del modelo
accuracy = metrics.adjusted_rand_score(DataTarget, y_kmeans) 
print(K,' ',accuracy)

if accuracy > Mejor:    
    K_optimo = K
    Mejor = accuracy

print(鈥欌)
print(f鈥橫ax accuracy: {round(Mejor,3)}% \nUsando K: {K_optimo} ')

Salida
[鈥榓lcohol鈥, 鈥榤alic_acid鈥, 鈥榓sh鈥, 鈥榓lcalinity_of_ash鈥, 鈥榤agnesium鈥, 鈥榯otal_phenols鈥, 鈥榝lavanoids鈥, 鈥榥onflavanoid_phenols鈥, 鈥榩roanthocyanins鈥, 鈥榗olor_intensity鈥, 鈥榟ue鈥, 鈥榦d280/od315_of_diluted_wines鈥, 鈥榩roline鈥橾

2 0.3694075388574537
3 0.37111371823084754
4 0.303442531578347
5 0.31158801033176253
6 0.2909022768841822
7 0.22632105878612552

Max accuracy: 0.371%
Usando K: 3

#COMO SABEMOS QUE OPTIMO ES 3
#Aunque su exactitude es muy bajo 37%
#Grafico aleatoriamente variables alcohol y hue

K = 3

model = KMeans(n_clusters= K, max_iter=1000)
model.fit(DataToTrain)

y_labels = model.labels_

#Creamos prediccion
y_means = model.predict(DataToTrain)

plt.scatter(DataToTrain[鈥榓lcohol鈥橾, DataToTrain[鈥榟ue鈥橾, c=y_means, s=30)
plt.xlabel(鈥楢lcohol鈥, fontsize = 10)
plt.ylabel(鈥楬ue鈥, fontsize = 10)

(NO SALE EL GRAFICO)

Justo me hice la misma pregunta, sobre como incrementar el accuracy del modelo. Encontre entre los comentarios el tip de estandarizar los datos antes de entrenar el modelo. Y ya en c贸digo, antes de entrenar el modelo, realice los siguientes pasos que me ayudaron a tener un incremento hasta el .89

import matplotlib.pyplot as plt
import pandas as pd
from sklearn.cluster import KMeans
from sklearn import datasets
from sklearn import metrics
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import StandardScaler

x_cols = wine_data.feature_names
y_cols = wine_data.target_names

scaler = StandardScaler()
x_scaled = scaler.fit_transform(x_wine)

x = pd.DataFrame(x_scaled, columns = x_cols)
y = pd.DataFrame(wine_data.target, columns = ['Target'])

model = KMeans(n_clusters = 3, max_iter = 100000)
model.fit(x)

Y como adicional, encontr茅 en est谩 p谩gina, c贸mo generar un gr谩fico en 3D que nos permite ver el cruce de 3 variables, agrupando con k-means: 3D Scatter

Mi c贸digo qued贸 de la siguiente manera:

fig = plt.figure()
ax = fig.add_subplot(projection='3d')

plt.title('3D Scatter plot with K-Means', fontsize = 18)
ax.set_xlabel('Alcohol', fontsize = 8)
ax.set_ylabel('Malic Acid', fontsize = 8)
ax.set_zlabel('Alcalinity of hash', fontsize = 8)
ax.scatter(x['alcohol'], x['malic_acid'], x['alcalinity_of_ash'], c = y_kmeans, marker='o')

hola! si quieren visualizar los datos les dejo este link super 煤til 馃槂

esta gr谩fica, por ejemplo, indica que la prolina es bastante importante para determinar el tipo de vino

鈥淓st谩s teniendo un sobreajuste porque est谩s tratando de que memorice la informaci贸n, no que aprenda de la informaci贸n鈥

Con esa frase me quedaron claras muchas cosas sobre el aprendizaje pero en el humano, que funciona de forma parecida.

Deben permitirnos analizar grandes casos y abstraerlos.
Y a veces los m茅todos de ciertos profesores no se prestan a un aprendizaje adecuado en sus alumnos

Resultado final 0.87, seguramente algunos obtuvimos un valor menor inicialmente, hay t茅cnicas de normalizaci贸n de datos que pueden aplicarse a estos problemas

dejo mi colab notebook para que puedan consultar el c贸digo:
https://colab.research.google.com/drive/1YtNgGxUdKkKtVcYh_ZmCGnOFgQYBQFQG?usp=sharing

Mi soluci贸n:

from sklearn.cluster import KMeans
from sklearn import datasets
import pandas as pd
import matplotlib.pyplot as plt

wine = datasets.load_wine()
x_wine = wine.data
y_wine = wine.target

wine.feature_names

['alcohol',
 'malic_acid',
 'ash',
 'alcalinity_of_ash',
 'magnesium',
 'total_phenols',
 'flavanoids',
 'nonflavanoid_phenols',
 'proanthocyanins',
 'color_intensity',
 'hue',
 'od280/od315_of_diluted_wines',
 'proline']

x = pd.DataFrame(wine.data, columns= ['alcohol',
 'malic_acid',
 'ash',
 'alcalinity_of_ash',
 'magnesium',
 'total_phenols',
 'flavanoids',
 'nonflavanoid_phenols',
 'proanthocyanins',
 'color_intensity',
 'hue',
 'od280/od315_of_diluted_wines',
 'proline'])
y = pd.DataFrame(wine.target, columns= ['Target'])
print(x.head())
print(y.head())


 alcohol  malic_acid   ash  ...   hue  od280/od315_of_diluted_wines  proline
0    14.23        1.71  2.43  ...  1.04                          3.92   1065.0
1    13.20        1.78  2.14  ...  1.05                          3.40   1050.0
2    13.16        2.36  2.67  ...  1.03                          3.17   1185.0
3    14.37        1.95  2.50  ...  0.86                          3.45   1480.0
4    13.24        2.59  2.87  ...  1.04                          2.93    735.0

[5 rows x 13 columns]
   Target
0       0
1       0
2       0
3       0
4       0

plt.scatter(x['alcohol'], x['color_intensity'], c='blue')
plt.xlabel('Alcohol', fontsize=15)
plt.ylabel('Color intensity', fontsize=15)
![image1kmeans.png](https://static.platzi.com/media/user_upload/image1kmeans-eada8d87-0ff1-4ff7-87c1-01e898cafe2c.jpg)

model = KMeans(n_clusters=3, max_iter=10000)
model.fit(x)
y_labels = model.labels_

y_kmeans = model.predict(x)
print('Predicciones: ', y_kmeans)

accuracy = metrics.adjusted_rand_score(y_wine, y_kmeans)
print('accuracy: ', accuracy)

accuracy: 0.37111371823084754

plt.scatter(x['alcohol'], x['color_intensity'], c=y_kmeans, s=30)
plt.xlabel('Alcohol', fontsize=15)
plt.ylabel('Color Intensity', fontsize=15)

![image1kmeans2.png](https://static.platzi.com/media/user_upload/image1kmeans2-38d0ace9-24c5-4da4-ba7f-62bf6ac694c7.jpg)

Pero si probamos dos caracteristicas diferentes:

plt.scatter(x['total_phenols'], x['proline'], c=y_kmeans, s=30)
plt.xlabel('total_phenols', fontsize=15)
plt.ylabel('proline', fontsize=15)

![image1kmeans3.png](https://static.platzi.com/media/user_upload/image1kmeans3-550ff854-782b-47f3-86d6-d3b1c142999d.jpg)

Les tengo una propuesta sobre el modelo trabajado:

x = x.iloc[:,2:]

Averiguen ustedes que pasa con la precisi贸n y como separa las especies ahora

Parece que hacer clusters por alcohol y acido malico no es muy buena opcion 鈥 馃槂

![](
![](
![](

hola, yo 鈥樷榬esolv铆鈥欌 el reto reciclando el c贸digo que nos mostr贸 en el v铆deo profe, pero no logro que la predicci贸n sea de mas de 36~37 %

el codigo:

from sklearn.cluster import KMeans
from sklearn import datasets
import pandas as pd
import matplotlib.pyplot as plt
dt = datasets.load_wine()
dt.feature_names

[鈥榓lcohol鈥,
鈥榤alic_acid鈥,
鈥榓sh鈥,
鈥榓lcalinity_of_ash鈥,
鈥榤agnesium鈥,
鈥榯otal_phenols鈥,
鈥榝lavanoids鈥,
鈥榥onflavanoid_phenols鈥,
鈥榩roanthocyanins鈥,
鈥榗olor_intensity鈥,
鈥榟ue鈥,
鈥榦d280/od315_of_diluted_wines鈥,
鈥榩roline鈥橾

x_wine = dt.data
y_wine = dt.target
x = pd.DataFrame(x_wine, columns = ['alcohol','malic_acid','ash','alcalinity_of_ash','magnesium','total_phenols','flavanoids','nonflavanoid_phenols','proanthocyanins','color_intensity','hue','od280/od315_of_diluted_wines','proline'])
y = pd.DataFrame(dt.target, columns = ['Target'])
x.head(10)
plt.scatter(x['malic_acid'], x['proline'], c='green')
plt.xlabel('malic_acid', fontsize = 10)
plt.ylabel('proline', fontsize = 10)
model = KMeans(n_clusters= 3, max_iter= 1000)
model.fit(x)
y_labels = model.labels_
y_kmeans = model.predict(x)
print('Predicciones ', y_kmeans)
from sklearn import metrics

accuracy = metrics.adjusted_rand_score(y_iris, y_kmeans)
print(accuracy)
plt.scatter(x['malic_acid'], x['proline'], c=y_kmeans, s= 30)
plt.xlabel('malic_acid', fontsize = 10)
plt.ylabel('proline', fontsize = 10)
![](data:image/png;base64,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%0AAAAASUVORK5CYII=)

Realic茅 el ejercicio y obtuve un Accuracy del 89 - 90% usando las categorias 鈥榗olor_intensity鈥 y 鈥榓lcohol鈥 (prob茅 con varias y con esta obtuve el mejor resultado), la recomendaci贸n de Diego Medina es muy importante y que ciertamente no se ha tocado muy a profundidad hasta este punto; comparto mi c贸digo por si alguno est谩 interesado en checkarlo.

<import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
from sklearn import metrics
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler #Necesario para la estandarizacion de los datos

X_wines = wines.data
Y_wines = wines.target


scaler = StandardScaler()
scaler.fit(wines.data)
x_scaled = scaler.transform(wines.data)

x = pd.DataFrame(wines.data, columns=['alcohol',
  'malic_acid',
  'ash',
  'alcalinity_of_ash',
  'magnesium',
  'total_phenols',
  'flavanoids',
  'nonflavanoid_phenols',
  'proanthocyanins',
  'color_intensity',
  'hue',
  'od280/od315_of_diluted_wines',
  'proline'])

x = pd.DataFrame(x_scaled, columns=['alcohol',
  'malic_acid',
  'ash',
  'alcalinity_of_ash',
  'magnesium',
  'total_phenols',
  'flavanoids',
  'nonflavanoid_phenols',
  'proanthocyanins',
  'color_intensity',
  'hue',
  'od280/od315_of_diluted_wines',
  'proline'])

y = pd.DataFrame(wines.target, columns=['Target'])


plt.scatter(x['color_intensity'], x['alcohol'], c='red')
plt.xlabel('alcohol', fontsize = 10 )
plt.ylabel('color_intensity', fontsize = 10 )

model = KMeans(n_clusters=3, max_iter=10000)
model.fit(x)
y_labels = model.labels_
y_kmeans = model.predict(x)
print('Predicciones', y_kmeans)
accuracy = metrics.adjusted_rand_score(Y_wines, y_kmeans)
print('Accuracy = ', accuracy)

plt.scatter(x['color_intensity'], x['alcohol'], c=y_kmeans)
plt.xlabel('alcohol', fontsize = 10 )
plt.ylabel('color_intensity', fontsize = 10 )





>

En este ejemplo no se ha utilizado una estandarizacion para los par谩metros, por eso la precisi贸n es de tan solo el 37%

<h1>K-Means</h1>

from sklearn.cluster import KMeans
from sklearn import datasets

import pandas as pd
import matplotlib.pyplot as plt

%matplotlib inline

iris = datasets.load_iris()

El dataset iris viene incluido con SciKitLearn

x_iris = iris.data
y_iris = iris.target

x = pd.DataFrame(iris.data, columns=[鈥楽epal Length鈥, 鈥楽epal Width鈥, 鈥楶etal Length鈥, 鈥楶etal, Width鈥橾)
y = pd.DataFrame(iris.target, columns=[鈥楾arget鈥橾)

x.head(5)

plt.scatter(x[鈥楶etal Length鈥橾, x[鈥楶etal, Width鈥橾, c=鈥榖鈥)
plt.xlabel(鈥楶etal Length鈥, fontsize=10)
plt.ylabel(鈥楶etal Width鈥, fontsize=10)

plt.show()

model = KMeans(n_clusters=3, max_iter=1000)
model.fit(x)

y_label = model.labels_

Al inicion se definio a n_cluester=2 como valor inicial para comprobar como funciona el algoritmo kmeans. Luego este valor se reemplazara por su valor verdadero.

  • n_cluester=2 me da una presicion del 0.5399
  • n_cluester=3 me da una presicion del 0.7302
  • n_cluester=4 me da una presicion del 0.6498
  • n_cluester=5 me da una presicion del 0.6078

Siempre se debe utilizar el valor mas cercano a cero.

y_kmeans = model.predict(x)
print('Predicciones: ', y_kmeans)

from sklearn import metrics

accuracy = metrics.adjusted_rand_score(y_iris, y_kmeans)
accuracy

plt.scatter(x[鈥楶etal Length鈥橾, x[鈥楶etal, Width鈥橾, c=y_kmeans, s=30)
plt.xlabel(鈥楶etal Length鈥)
plt.ylabel(鈥楶etal Width鈥)

plt.show()

  • Para graficar correctamente la separacion de los grupos por color es critico el siguiente comando c=y_kmeans.

  • El comando s=30 le indico el tama帽o del punto.

# K-Means
---

from sklearn.cluster import KMeans
from sklearn import datasets

import pandas as pd
import matplotlib.pyplot as plt

%matplotlib inline

iris = datasets.load_iris()

El dataset iris viene incluido con `SciKitLearn`

x_iris = iris.data
y_iris = iris.target

x = pd.DataFrame(iris.data, columns=['Sepal Length', 'Sepal Width', 'Petal Length', 'Petal, Width'])
y = pd.DataFrame(iris.target, columns=['Target'])

x.head(5)

plt.scatter(x['Petal Length'], x['Petal, Width'], c='b')
plt.xlabel('Petal Length', fontsize=10)
plt.ylabel('Petal Width', fontsize=10)

plt.show()

model = KMeans(n_clusters=3, max_iter=1000)
model.fit(x)

y_label = model.labels_

Al inicion se definio a `n_cluester=2` como valor inicial para comprobar como funciona el algoritmo `kmeans`. Luego este valor se reemplazara por su valor verdadero.

* `n_cluester=2` me da una presicion del **0.5399**
* `n_cluester=3` me da una presicion del **0.7302**
* `n_cluester=4` me da una presicion del **0.6498**
* `n_cluester=5` me da una presicion del **0.6078**

Siempre se debe utilizar el valor mas cercano a cero.

y_kmeans = model.predict(x)
print('Predicciones: ', y_kmeans)

from sklearn import metrics

accuracy = metrics.adjusted_rand_score(y_iris, y_kmeans)
accuracy

plt.scatter(x['Petal Length'], x['Petal, Width'], c=y_kmeans, s=30)
plt.xlabel('Petal Length')
plt.ylabel('Petal Width')

plt.show()

* Para graficar correctamente la separacion de los grupos por color es critico el siguiente comando `c=y_kmeans`.

* El comando `s=30` le indico el tama帽o del punto.

Hola comunidad

Dejo las im谩genes de los 3 modelos seg煤n el n煤mero de centroides

Modelo A: 2 Centroides

Modelo B: 3 Centroides

Modelo C: 4 Centroides

como podr铆a graficar en d贸nde queda el o los centroides?

Reto鈥

from sklearn.cluster import KMeans
from sklearn import datasets
from sklearn import metrics
import pandas as pd
import matplotlib.pyplot as plt

wines = datasets.load_wine()

X_wines = wines.data
Y_wines = wines.target
wines.feature_names

x = pd.DataFrame(wines.data, columns = ['alcohol',
 'malic_acid',
 'ash',
 'alcalinity_of_ash',
 'magnesium',
 'total_phenols',
 'flavanoids',
 'nonflavanoid_phenols',
 'proanthocyanins',
 'color_intensity',
 'hue',
 'od280/od315_of_diluted_wines',
 'proline'])
y = pd.DataFrame(wines.target, columns = ['Target'])
x.head(5)

plt.scatter(x['flavanoids'], x['magnesium'], c = 'blue')
plt.xlabel('Flavanoids', fontsize = 10)
plt.ylabel('magnesium', fontsize = 10)

model = KMeans(n_clusters=3, max_iter=1000)
model.fit(x)
y_labels = model.labels_
y_kmeans = model.predict(x)
print("Predicciones ", y_kmeans)

accuracy = metrics.adjusted_rand_score(Y_wines, y_kmeans)
print(accuracy)

plt.scatter(x['flavanoids'], x['magnesium'], c= y_kmeans, s = 30)
plt.xlabel('Flavanoids', fontsize = 10)
plt.ylabel('magnesium', fontsize = 10)

Gr谩fica de alcohol vs magnesio, use 3 clusters, me da un accuracy de 0.37

yo quiero ser mas efciente, como hago?

x = pd.DataFrame(wines.data, columns=['Alcohol','Malic acid','Ash','Alcalinity of ash','Magnesium','Total phenols',
                                   'Flavanoids','Nonflavanoid phenols','Proanthocyanins','Color intensity','Hue',
                                   'OD280/OD315 of diluted wines','Proline'])
y = pd.DataFrame(wines.target, columns=['Target'])

from sklearn.preprocessing import StandardScaler, MinMaxScaler

scaler = StandardScaler().fit(x.values)
#Aplicamos esta funcion con el metodo transform a los features, de este modo
features = scaler.transform(x.values)
x_norm = pd.DataFrame(features, columns=['Alcohol','Malic acid','Ash','Alcalinity of ash','Magnesium','Total phenols',
                                   'Flavanoids','Nonflavanoid phenols','Proanthocyanins','Color intensity','Hue',
                                   'OD280/OD315 of diluted wines','Proline'])

# m茅todo del codo
wcss = []
for i in range(1, 11):
    kmeans = KMeans(n_clusters=i, max_iter=1000, random_state=0)
    kmeans.fit(x_norm)
    y_kmeans = kmeans.predict(x_norm)
    wcss.append(kmeans.inertia_)
    accuracy =  metrics.adjusted_rand_score(y_wines, y_kmeans)
    print(f'numero de n_clusters: {i} accurracy {accuracy}')
plt.plot(range(1, 11), wcss)
plt.title('Metodo Codo')
plt.xlabel('Numeros de Cluster')

plt.show()

Me da un 0.897 de accurracy

wine = datasets.load_wine()
x = wine.data
y = wine.target
print(wine.feature_names)
print('-------------')
print(wine.target)
print(x)
print('-------------')
print(y)

x_df = pd.DataFrame(x, columns=wine.feature_names)
x_df.head()
y_df = pd.DataFrame(y, columns=['target'])
y_df.head()

wine_model = KMeans(n_clusters=3, max_iter=1000)
wine_model.fit(x_df)
y_labels = wine_model.labels_

y_kmeans = wine_model.predict(x_df)
plt.scatter(x_df['alcohol'], x_df['malic_acid'], c=y_kmeans, s=30)
plt.xlabel('alcohol', fontsize=10)
plt.ylabel('malic_acid', fontsize=10)
plt.show()

plt.scatter(x_df['alcohol'], x_df['malic_acid'], c=y_kmeans, s=30)
plt.xlabel('alcohol', fontsize=10)
plt.ylabel('malic_acid', fontsize=10)
plt.show()
names = wine.feature_names
len(names)

for i in range(len(names)-1):
    plt.scatter(x_df[names[i]], x_df[names[i+1]], c=y_kmeans, s=30)
    plt.xlabel(names[i], fontsize=10)
    plt.ylabel(names[i+1], fontsize=10)
    plt.show()

print(metrics.adjusted_rand_score(y, y_kmeans))





Un aspecto a tener en cuenta es que el an谩lisis visual que hicimos en clase se hizo solo con los datos de los p茅talos, pero el algoritmo entren贸 adem谩s con la informaci贸n de los s茅palos. Si pudi茅ramos ver los datos en 4 dimensiones los puntos tienen una distribuci贸n m谩s compleja y ah铆 es donde se vuelve importante K-Means.

Veo muchos comentarios diciendo que hay que escalar los datos para mejor el accuracy, calculado como **metrics.adjusted_rand_score(y_vinos, y_kmeans) **, de 0.37 a 0.87. Pero no se debe interpretar como que el 87% de los casos la predicci贸n el correcta. Recomiendo que siempre vayamos a la documentaci贸n para ver que es lo que realmente significan los m茅todos que usamos para Accuracy.

Para este caso particular, sin escalar los datos se logra predecir correctamente el 18.5% de los datos. Y escalando, se predice correctamente el 34.8% de los datos. A pesar de que el accuracy nos daba 0.87, el ajuste, incluso escalando, es muy malo. Si lo pensamos de otra forma, y como hay 3 tipos de vinos, el modelo escalado es igual que clasificar el vino de una forma aleatoria.

Hola a todos, sobre la precisi贸n del 36 al 37% con los datos de vinos, comentar que como dicen otros compa帽eros se realiza una normalizaci贸n de los datos, esta puede ser como cuando se hace la normalizaci贸n para pasar a una distribuci贸n est谩ndar es estad铆stica, b谩sicamente hay que aplicarle a cada dato (xi - mu) / sigma, siendo:

  • xi: el dato.
  • mu: la media de los datos de la columna.
  • sigma: la desviaci贸n est谩ndar de los datos de la columna.

Entonces lo que hay que hacer es obtener todas las medias y las desviaciones est谩ndar por cada columna y usar la f贸rmula. Esto se hace para que todos los datos queden en una misma escala. Lo anterior es lo que hace por dentro StandardScaler utilizado por el compa帽ero Diego Medina en su c贸digo.
Otra forma de normalizar y estandarizar los datos es (xi - mu) / Rango, siendo:

  • xi: el dato.
  • mu: la media de los datos de la columna.
  • Rango: dato m谩ximo - dato m铆nimo.
    De esta forma hacemos que todos los datos est茅n entre -1 y 1.

Espero les sirva.
Un abrazo!

Dejo mi c贸digo probando ambas t茅cnicas si usar StandardScaler:

from sklearn.cluster import KMeans
from sklearn import datasets
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import metrics
wine = datasets.load_wine()
X_wine = wine.data
Y_wine = wine.target
cols = wine.feature_names
x = pd.DataFrame(X_wine, columns=cols)
y = pd.DataFrame(Y_wine, columns=['Target'])
# Rango
x_norm_ran = (x - x.mean(axis=0)) / (x.max(axis=0) - x.min(axis=0))
# Desviaci贸n est谩ndar
x_norm_std = (x - x.mean(axis=0)) / x.std(axis=0)
model_ran = KMeans(n_clusters=3, max_iter=1000)
model_ran.fit(x_norm_ran)
y_kmeans_ran = model_ran.predict(x_norm_ran)

accuracy = metrics.adjusted_rand_score(Y_wine, y_kmeans_ran)
print(f"La precici贸n para el modelo nomalizado con Rango es : {accuracy}")

La precici贸n para el modelo nomalizado con Rango es : 0.8536602842727953

model_std = KMeans(n_clusters=3, max_iter=1000)
model_std.fit(x_norm_std)
y_kmeans_std = model_std.predict(x_norm_std)

accuracy = metrics.adjusted_rand_score(Y_wine, y_kmeans_std)
print(f"La precici贸n para el modelo nomalizado con desviaci贸n est谩ndar es : {accuracy}")

La precici贸n para el modelo nomalizado con desviaci贸n est谩ndar es : 0.8974949815093207

Esta fue mi soluci贸n para el dataset de wines.

import pandas as pd
import sklearn.datasets as datasets
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
import sklearn.metrics as metrics
wines = datasets.load_wine()
x = pd.DataFrame(wines.data, columns=wines.feature_names)
y = pd.DataFrame(wines.target, columns=['Target'])
y_classes = wines.target
plt.scatter(x['alcohol'], x['color_intensity'], c = y_classes, s=30)
plt.xlabel('Alcohol', fontsize=10)
plt.ylabel('Color intensity', fontsize=10)
# Data normalization
norm = MinMaxScaler().fit(x)
x_norm = norm.transform(x)

#Data standardization
std_scaler = StandardScaler()
data_scaled = x_norm.copy()
data_scaled = pd.DataFrame(data_scaled, columns=wines.feature_names)
model = KMeans(n_clusters=3, max_iter=1000)
model.fit(data_scaled)
y_kmeans = model.predict(data_scaled)
print("Predictions: ", y_kmeans)
accuracy = metrics.adjusted_rand_score(y_classes, y_kmeans)
accuracy

Logr茅 86% de accuracy