GUIA DE LAS PRACTICAS DE PL DE AA2

En este documento estará recogida todas las prácticas enumeradas con solución para hacer un ctrl + F en el PDF para que sea más fácil de buscar las estructuras del código

Tema 1 Sesión 1

Apartado A

""" Tema 1 : Introducción a Problemas Complejos de Aprendizaje Supervisado Sesión 1 : Datos Multi-etiqueta Bloque A : Ejemplo sencillo mediante aprendizaje mono-etiqueta """ # %% 0 Generación de datos import random from sklearn.svm import SVC import numpy as np from sklearn.metrics import accuracy_score import matplotlib.pyplot as plt def plotME(X,xA,yA,LValues,LNames='Etiqueta'): """ Dibuja los ejemplos de un conjunto multietiqueta sobre los atributos xA,yA. Para cada etiqueta se colorearán los ejemplos con valor 1 """ nL=len(LValues) X=np.array(X) LValues=np.array(LValues) s=3 fig,axs=plt.subplots(1,nL,sharey=True,figsize=[nL*s,1*s]) for il in range(nL): if il==0: axs[il].set_ylabel('Atributo {}'.format(yA)) colors=list(map(lambda l:'blue' if l==1 else 'grey',LValues[il,:])) axs[il].scatter(X[:,xA],X[:,yA],c=colors) axs[il].set_title('{} {}'.format(LNames,il) if type(LNames)==str else LNames[il]) axs[il].set_xlabel('Atributo {}'.format(xA)) # fig.savefig('DistEtiSencillo.pdf',dpi=300,bbox_inches='tight') def genSencillo(RG,e,a): """ Crea un dataset con e ejemplos, a atributos y con 3 etiquetas: Y0, Y1, Y2 Creamos la X con valores de una distribución uniforme en [0;1) para cada valor Y0 será 1 si la suma del primer y segundo atributo son menores de tr, si no 0 Y1 será 1 si la suma del primer y segundo atributo son mayores de (2-tr), si no 0 Y2 será 1 si se cumple la condición de Y0 o la de Y1, si no 0 Parámetros: - RG : random.Random() instancia - e : número de ejemplos - a : número de atributos Retorna: [X,[Y0,Y1,Y2]] : - X : matriz de atributos : - Yx: vector de la etiqueta x """ X =np.zeros([e,a]) Y0=np.zeros(e) Y1=np.zeros(e) Y2=np.zeros(e) th=0.75 for ie in range(e): for ia in range(a): X[ie][ia]=RG.random() Y0[ie]=1 if X[ie][0]+X[ie][1]<th else 0 Y1[ie]=1 if X[ie][0]+X[ie][1]>(2-th) else 0 Y2[ie]=1 if X[ie][0]+X[ie][1]<th or X[ie][0]+X[ie][1]>(2-th) else 0 return [X,[Y0,Y1,Y2]] def calculaAccuracy(MLS,XTr,YTr,XTe,YTe): """ Dado un sistema de aprendizaje (Machine Learning System) un conjunto de entrenamiento y otro de test, realiza un proceso de aprendizaje sobre el entrenamiento, evalúa el test y calcula la accuracy Parámetros: - MLS : Sistema de Aprendizaje de clasificación - [XTr,YTr] : Conjunto de entrenamiento - [XTe,YTe] : Conjunto de test Retorna: [acc,pred]: - acc : valor de la accuracy en test - pred: predicción para cada ejemplo de test """ MLS.fit(XTr,YTr) # Entrenamiento pred=MLS.predict(XTe) # Predicción acc=accuracy_score(pred,YTe) return [acc,pred] # Se va a crear un conjunto de datos mediante la función genSencillo eTr=200 # Número de ejemplos de train eTe=200 # Número de ejemplos de test a=4 # Número de atributos # Generador de números aleatorios RG=random.Random() # Semilla para conseguir repetibilidad RG.seed(1) # Se generan datasets train,test de tipo 'sencillo' [XTr,YTr]=genSencillo(RG,eTr,a) [XTe,YTe]=genSencillo(RG,eTe,a) # Pintar las categorías en función de los atributos 0 y 1 plotME(XTr,0,1,YTr) #%% Clasificador lineal por etiqueta # Acierto si se aprendiera con un sistema de clasificación lineal # Se guardan las predicciones en preds MLS=SVC(kernel='linear',C=1) preds=[] for l in range(len(YTr)): [acc,pred]=calculaAccuracy(MLS,XTr,YTr[l],XTe,YTe[l]) preds.append(pred) print('Etiqueta {} accuracy={}'.format(l,acc)) #%% Utilizar las 2 etiquetas primeras para apremnder la tercera # ¿Se puede aprender mejor la tercera etiqueta usando la información de las dos #primeras? TrY0Y1=np.column_stack([YTr[0],YTr[1]]) TeY0Y1=np.column_stack([YTe[0],YTe[1]]) [acc,pred]=calculaAccuracy(MLS,TrY0Y1,YTr[2],TeY0Y1,YTe[2]) print('\nEtiqueta 2 aprendiendo de las etiquetas 0 y 1 y evaluando las etiquetas 0 y 1 del test:\n accuracy={}'.format(acc)) # Pero esto es trampa (cheating), los valores de todas las categorías de test #son desconocidas durante el train. # Pero sí se pueden utilizar las predicciones TeP0P1=np.column_stack([preds[0],preds[1]]) [acc,pred]=calculaAccuracy(MLS,TrY0Y1,YTr[2],TeP0P1,YTe[2]) print('\nEtiqueta 2 aprendiendo de las etiquetas 0 y 1 y evaluando las predicciones 0 y 1 del test:\n accuracy={}'.format(acc)) #%% Ejercicio 1 # Realiza un aprendizaje de la etiqueta 2 usando tanto las X como las otras 2 etiquetas. # Calcula e imprime el acierto en test. #¿Cómo de útil es añadir la matriz X para aprender la etiqueta 2? #<TODO BEGIN Ejercicio 1> XTrY0Y1=np.column_stack([XTr,YTr[0],YTr[1]]) XTeP0P1=np.column_stack([XTe,preds[0],preds[1]]) [acc,pred]=calculaAccuracy(MLS,XTrY0Y1,YTr[2],XTeP0P1,YTe[2]) print('\nEtiqueta 2 aprendiendo de las X y etiquetas 0 y 1 y evaluando las X y predicciones 0 y 1 del test:\n accuracy={}'.format(acc)) #<TODO END Ejercicio 1>

Apartado B

""" Tema 1 : Introducción a Problemas Complejos de Aprendizaje Supervisado Sesión 1 : Datos Multi-etiqueta Bloque B : Características de Datos multi-etiqueta """ # Los datasets multi-etiqueta tienen como particularidad que la categoría es un # array de valores 0|1. # Ejemplo: dataset de e ejemplos, a atributos y l etiquetas con valores #aleatorios import numpy as np import random e=10 # Ejemplos a=3 # Atributos l=5 # Etiquetas # Generador de números aleatorios RG=random.Random() # Fijar semilla para conseguir repetibilidad RG.seed(1) th=0.5 X=np.zeros([e,a]) Y=np.zeros([e,l]) for ie in range(e): for ia in range(a): X[ie][ia]=RG.uniform(0,1) for il in range(l): v=RG.uniform(0,1) Y[ie][il]=0 if v <th else 1 print('Y: ejemplos={} etiquetas={}\n{}'.format(e,l,Y)) #%% Medidas categoría # Vamos a calcular dos medidas de la categoría: # Cardinalidad(ca): la media del número de unos en cada ejemplo cardi=Y.sum(1).mean() # NOTA: el '1' indica el eje por el que hace la media (por ejemplos) print('Cardinalidad={}'.format(cardi)) #%% Ejercicio 1 #Calcula la densidad(De), que es la media de la proporción de unos en cada ejemplo # Ver "Estadísticas sobre los datos" en "TransparenciasTema1-1.pdf" # https://www.campusvirtual.uniovi.es/mod/resource/view.php?id=275838 #<TODO BEGIN Ejercicio 1> densi=Y.mean(1).mean() print('Densidad ={}'.format(densi)) #<TODO END Ejercicio 1> # No hace falta calcular las 2 medidas, solo hace falta una y la otra se calcula #mediante la ecuación: Ca=De*l #%% Ejercicio 2 # Calcula el número de combinaciones de etiquetas distintas (Dis) que hay en Y. # NOTA: puedes utilizar str para convertir cada ejemplo/fila de Y en una cadena #y luego puedes usar np.unique para obtener el conjunto de éstas sin repeticiones #<TODO BEGIN Ejercicio 1> dis=len(np.unique(list(map(str,Y)))) print('Distintas ={}'.format(dis)) #<TODO END Ejercicio 2>

Apartado C

""" Tema 1 : Introducción a Problemas Complejos de Aprendizaje Supervisado Sesión 1 : Datos Multi-etiqueta Bloque C : Características de Datos multi-regresión """ # Los datasets multi-regresión tienen como particularidad que la categoría es un # array de valores numéricos. # Ejemplo: dataset de e ejemplos, a atributos y r categorías numéricas con valores #aleatorios import numpy as np import random e=10 # Ejemplos a=3 # Atributos r=4 # Categorías numéricas # Generador de números aleatorios RG=random.Random() # Fijar semilla para conseguir repetibilidad RG.seed(1) X=np.zeros([e,a]) Y=np.zeros([e,r]) for ie in range(e): for ia in range(a): X[ie][ia]=RG.uniform(0,1) for ir in range(r): Y[ie][ir]=RG.uniform(0,1) print('Y: ejemplos={} categorías numéricas={}\n{}'.format(e,r,Y)) #%% Información de categorías # Unos valores típicos a calcular son la media, mínimo y máximo de cada categoría: for ir in range(r): print('Categoría:{} media={:0.4f} min={:0.4f} max={:0.4f}'.format(ir,np.mean(Y[:,ir]), np.min(Y[:,ir]), np.max(Y[:,ir]))) #%% Ejercicio 1 # Calcular la distancia(Error) media de cada categoría numérica con su media #<TODO BEGIN Ejercicio 1> for ir in range(r): med=np.mean(Y[:,ir]) # Media de la categoría print('Categoría:{} media={:0.4f} distancia media a la media={:0.4f}'. format(ir,med,np.mean(abs(Y[:,ir]-med)))) #<TODO END Ejercicio 1>

Apartado D

""" Tema 1 : Introducción a Problemas Complejos de Aprendizaje Supervisado Sesión 1 : Datos Multi-etiqueta Bloque D : Lectura de datos multi-etiqueta """ import numpy as np from scipy.io import arff import re def loadarff_denso_numerico(nombre_fichero,l,eaf=True): """ Esta función lee ficheros .arff con las siguientes condiciones: - denso : ha de tener valor para todos los atributos (*1) - numerico: todos los valores han de ser numéricos (*2) (*1) No lee ficheros con representación dispersa. Esta restricción viene data por la función scipy.io.arff.loadarff() (*2) También leería correctamente atributos nominales representados por '0' o '1' Parámetros: - nombre_fichero : cadena, nombre del fichero (con extensión .arff) - l : entero, número de etiquetas. Si None las lee del fichero .arff suponiendo formato MEKA - eaf : booleano, etiquetas al final si True si no, etiquetas al principio Retorna: -[X,Y] : X atributos e Y etiquetas del conjunto de datos como np.array """ f=open(nombre_fichero) data, meta = arff.loadarff(f) if l==None: # Lee l de @relation -C <l> (Meka .arff files) f.seek(0) rel=f.readline() sl=rel[rel.find('-C')+3:] l=int(re.search('[0-9]+',sl)[0]) f.close() data=data.tolist() X=[None]*len(data) Y=[None]*len(data) a=len(data[0])-l # Número de atributos for ie in range(len(data)): if eaf: # Si etiquetas al final X[ie]=list(map(float,data[ie][:a])) Y[ie]=list(map(float,data[ie][a:])) else: # Etiquetas al principio X[ie]=list(map(float,data[ie][l:])) Y[ie]=list(map(float,data[ie][:l])) return [np.array(X),np.array(Y)] #%% Librería MULAN # La librería MULAN (https://sourceforge.net/projects/mulan/) tiene # varios conjuntos de datos: multilabel (https://mulan.sourceforge.net/datasets-mlc.html). # Están en formato .arff, en este formato van seguidos los atributos y las etiquetas. # En MULAN las etiquetas van al final (después de los atributos) # La función loadarff_denso_numerico permite la lectura de algunos ficheros .arff #usando la función scipy.io.arff.loadarff. Hay que indicarle el número de etiquetas #que hay en ese conjunto de datos. # Mira la descripción de la función y el ejemplo de uso que hay a continuación. #%% Ejemplo 1 # El fichero emotions.arff se ha descargado de MULAN nombre_fichero='MultiLabelDatasets/emotions.arff' numero_etiquetas=6 [X,Y]=loadarff_denso_numerico(nombre_fichero,numero_etiquetas) # Imprimamos el número de ejemplos, cardinalizad y densidad # Podemos compararlos con los de la web de descarga print('\nInformación de: {}'.format(nombre_fichero)) print('Núm: ejemplos:{} atributos:{} etiquetas:{}'.format(len(X),len(X[0]),len(Y[0]))) print('Cardinalidad ={:5.3f}'.format(Y.sum(1).mean())) print('Densidad ={:5.3f}'.format(Y.mean(1).mean())) print('Distintos ={}'.format(len(np.unique(list(map(str,Y)))))) #%% Ejercicio 1 # Obtiene de la web de MULAN CAL500.arff # Léelo, calcula e impreme la cardinalidad, densidad y el número de combinaciones #distintas. ¿Coinciden con los de la WEB? (¡Debería!) #<TODO BEGIN Ejercicio 1> nombre_fichero='MultiLabelDatasets/CAL500.arff' numero_etiquetas=174 [X,Y]=loadarff_denso_numerico(nombre_fichero,numero_etiquetas) # Imprimamos el número de ejemplos, cardinalizad y densidad # Podemos compararlos con los de la web de descarga print('\nInformación de: {}'.format(nombre_fichero)) print('Núm: ejemplos:{} atributos:{} etiquetas:{}'.format(len(X),len(X[0]),len(Y[0]))) print('Cardinalidad ={:5.3f}'.format(Y.sum(1).mean())) print('Densidad ={:5.3f}'.format(Y.mean(1).mean())) print('Distintas ={}'.format(len(np.unique(list(map(str,Y)))))) #<TODO END Ejercicio 1> #%% Librería MEKA # La librería MEKA también tiene datasets multi-etiqueta en formato .arff, pero #en este caso las etiquetas van al principio y en la linea marcada por '@ relation' #a contiuación de '-C ' está el número de etiquetas. # Se puede obtener información más detallada en el capítulo 3 del tutorial: # https://master.dl.sourceforge.net/project/meka/meka-1.9.1/Tutorial.pdf # Librería: http://waikato.github.io/meka # Conjunto de datos: https://sourceforge.net/projects/meka/files/Datasets/ #%% Ejercicio 2 # Descargar de MEKA Music.arff, léelo usando loadarff_denso_numerico con los parámetros #adecuados. Calcula e impreme la cardinalidad, densidad y el número de combinaciones # Es el conjunto de datos emotions de MULAN que en MEKA se llama music. Comprueba #que las características son las mismas. #<TODO BEGIN Ejercicio 2> nombre_fichero='MultiLabelDatasets/Music.arff' [X,Y]=loadarff_denso_numerico(nombre_fichero,l=None,eaf=False) l=len(Y[0]) print('\nInformación de: {}'.format(nombre_fichero)) print('Núm: ejemplos:{} atributos:{} etiquetas:{}'.format(len(X),len(X[0]),len(Y[0]))) print('Cardinalidad ={:5.3f}'.format(Y.sum(1).mean())) print('Densidad ={:5.3f}'.format(Y.mean(1).mean())) print('Distintas ={}'.format(len(np.unique(list(map(str,Y)))))) #<TODO END Ejercicio 2> #%% Ejercicio 3 # Descargar de MEKA movielens.arff, está en 'Other Datasets'/'MovieLens' # Tiene como indicar de etiquetas '-C 943' pues parece que está tratando de #aprender los gustos de los usuarios a partir del tipo de película, pero lo #vamos a hacer al revés, vamos a aprender el tipo de película en función de los #gustos de los usuarios. # Lee movielens tomando como etiquetas los 19 últimos atributos. # Elmina el último atributo de las X (movieID), es un identificador único. # Binariza los atributos. Tienen un valor ordinal [0..5] y desconocido (-1). # Se pretende que un valor desconocido se represente por un array de ceros. # Asigna a la variable X01 el nuevo conjunto de atributos # PISTA: Usa adecuadamente sklearn.preprocessing.OneHotEncoder #<TODO BEGIN Ejercicio 3> from sklearn.preprocessing import OneHotEncoder nombre_fichero='MultiLabelDatasets/movielens.arff' [X,Y]=loadarff_denso_numerico(nombre_fichero,l=19) X=X[:,0:(len(X[0])-1)] enc = OneHotEncoder(handle_unknown='ignore',sparse=False, categories=list([0,1,2,3,4,5] for i in range(len(X[0])))) enc.fit(X) X01=enc.transform(X) #<TODO END Ejercicio 3> # Tras ejecutar este código se imprime el valor del original y binarizado # para el primer ejemplo ejemplo, atributos 1 y 2 nombres_enc=enc.get_feature_names_out() for at in [1,2]: print('\nPrimer ejemplo, atributo {}: {:1.0f}'.format(at,X[0][at])) print('Primer ejemplo, atributo {} binarizado:'.format(at)) for i in range(len(nombres_enc)): if nombres_enc[i].find('x{}_'.format(at))>=0: print(' {}={:1.0f}'.format(nombres_enc[i],X01[0][i]))

Apartado E

""" Tema 1 : Introducción a Problemas Complejos de Aprendizaje Supervisado Sesión 1 : Datos Multi-etiqueta Bloque E : Lectura de datos multi-regresión """ import numpy as np # Se han dejado en MultiRegressionDatasets dos ficheros multi-regresion. # Mira el contenido en un editor de texto # Para cargar ficheros .arff se puede utilizar la función loadarff_denso_numerico #que se ha visto en el bloque anterior y que se ha incluído en el pacage lectores from lectores.loadarff_denso_numerico import loadarff_denso_numerico #%% Ejemplo 1 # Leer el fichero rf1.arff que indica en @relation el número de etiquetas y estas #están al final de los atributos. # Obtener la media de cada categoría. nombre_fichero='MultiRegressionDatasets/rf1.arff' [X,Y]=loadarff_denso_numerico(nombre_fichero,l=None,eaf=True) r=len(Y[0]) print('fichero: {} ejemplos:{} categorías:{}'.format(nombre_fichero,len(X),r)) for ir in range(r): print('Categoría:{:2} media={:8.4f}'.format(ir,np.mean(Y[:,ir]))) #%% Ejercicio 1 # Leer waterqual.arff que tiene como categorías los 16 primeros atributos # Imprimir el nombre del fichero, el número de ejemplos y de cagtegorías # Para cada categoría imprimir su media y la distancia media de los ejemplos a su media #<TODO BEGIN Ejercicio 1> nombre_fichero='MultiRegressionDatasets/waterqual.arff' [X,Y]=loadarff_denso_numerico(nombre_fichero,l=16,eaf=False) r=len(Y[0]) print('fichero: {} ejemplos:{} categorías:{}'.format(nombre_fichero,len(X),r)) for ir in range(r): med=np.mean(Y[:,ir]) print('Categoría:{:2} media={:8.4f} distancia media a la media={:0.4f}'.format(ir,med,np.mean(abs(Y[:,ir]-med)))) #<TODO END Ejercicio 1>

Tema 1 Sesion 2

Apartado A

""" Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 2 : Multi-salida Bloque A : Aprendizaje multi-etiqueta """ from sklearn.multioutput import MultiOutputClassifier from sklearn.svm import SVC import random import numpy as np # Una manera trivial de aprender a partir de un conjunto multietiqueta es #aprender etiqueta a etiqueta, a esto se llama: Binary Relevance (BR) # En sklearn la clase que lo implementa es MultiOutputClassifier # https://scikit-learn.org/stable/modules/generated/sklearn.multioutput.MultiOutputClassifier.html # El problema multietiqueta se transforma en uno por cada etiqueta donde #con los mismos atributos se aprende de manera independiente cada etiqueta. # Para aprender ese problema monoetiqueta necesita un sistema de aprendeizaje apropiado. #%% Ejemplo 1 # A partir del conjunto de datos emotions crear un modelo #MultiOutputClassifier tomando como sistema monoetiqueta SVC lineal con C=1 from lectores.loadarff_denso_numerico import loadarff_denso_numerico [X,Y]=loadarff_denso_numerico('MultiLabelDatasets/emotions.arff',6) BR=MultiOutputClassifier(SVC(kernel='linear',C=1)) BR.fit(X,Y) # Otra manera de realizar un aprendendizaje multietiqueta es mediante una #cadena de clasifciadores (CC). # En sklearn la clase que lo implementa es ClassifierChain # https://scikit-learn.org/stable/modules/generated/sklearn.multioutput.ClassifierChain.html #%% Ejercicio 1 # A partir del conjunto de datos emotions crear un modelo #ClassifierChain tomando como sistema monoetiqueta SVC lineal con C=1 # Realiza una predicción en reescritura #Imprimir el número de fallos (valores de las etiquetas diferentes entre Y (real) y # la predicción) en la predicción (preds). # # PISTA: abs(Y-preds) genera una matriz donde hay un 1 donde hay un fallo #<TODO BEGIN Ejercicio 1> from sklearn.multioutput import ClassifierChain CC=ClassifierChain(base_estimator=SVC(kernel='linear',C=1)) CC.fit(X,Y) preds=CC.predict(X) print('Orden CC: original: Fallos={}'.format(int(np.sum(abs(Y-preds))))) #<TODO END Ejercicio 1> #%% Ejercicio 2 # Repetir el experimento del ejercicio 1 pero cambiando el orden las etiquetas en CC # Para lo cual dar valor al parámetro 'order'. # Para generar órdenes aleatorios se puede utilizar: # RG=random.Random() # RG.seed(1) # orden=list(range(l)) # l es el número de etiquetas # RG.shuffle(orden) # Repetir 5 veces la última instrucción e imprimir en cada iteración el orden #y el número de fallos en la predicción #<TODO BEGIN Ejercicio 2> # [X,Y]=loadarff_denso_numerico('MultiLabelDatasets/emotions.arff',6) RG=random.Random() seed=1 RG.seed(seed) l=6 orden=list(range(l)) for i in range(5): RG.shuffle(orden) CC=ClassifierChain(SVC(kernel='linear',C=1),order=orden) CC.fit(X,Y) preds=CC.predict(X) print('Orden CC:{} Fallos={}'.format(orden,int(np.sum(abs(Y-preds))))) #<TODO END Ejercicio 2> #%% LabelPowerset # Otra estrategia es aprender bloques de etiquetas de manera conjunta en vez de una a una. # Funciona especialmente bien cuando hay pocas combinaciones diferentes de etiquetas # El sistema LabelPowerset (LPS) realiza esta aproximación utilizando todas las #combinaciones de etiquetas del entrenamiento. Solo funciona correctamente si #esperamos encontrar las mismas combinaciones en el test. # http://scikit.ml/api/skmultilearn.problem_transform.lp.html # Podemos encontrar este y otros sistemas de aprendizaje en Scikit-multilearn # http://scikit.ml/ #%% Ejemplo 2 # A partir del conjunto de datos emotions crear un modelo #LabelPowerset tomando como sistema monoetiqueta RandomForestClassifier # Realiza una predicción en reescritura from skmultilearn.problem_transform import LabelPowerset from sklearn.ensemble import RandomForestClassifier [X,Y]=loadarff_denso_numerico('MultiLabelDatasets/emotions.arff',6) LPS=LabelPowerset(RandomForestClassifier()) LPS.fit(X,Y) pred=LPS.predict(X).toarray() # .toarray() pasa de sparse a dense # El sistema RAkEL realiza un proceso LPS pero sobre subconjuntos de etiquetas # Los subconjuntos pueden formar una partición (RakelD) http://scikit.ml/api/skmultilearn.ensemble.rakeld.html#skmultilearn.ensemble.RakelD #o pueden tener superposición (RakelO) http://scikit.ml/api/skmultilearn.ensemble.rakelo.html#skmultilearn.ensemble.RakelO #%% Ejemplo 3 # A partir del conjunto de datos emotions crear un modelo #RakelO y otro RakelD tomando como sistema monoetiqueta #RandomForestClassifier(min_samples_split=0.1) # Realiza una predicción en reescritura para cada sistema y contar los ejemplos #en los que hay alguna diferencia en la predicción #NOTA 1: RakelO puede fallar/no terminar si no se indica expresamente el # parámetro 'model_count'. El valor recomendado es el doble de etiquetas. #NOTA 2: Fíjate una manera de comprobar si una predicción en su conjunto # (para todas las etiquetas es igual a otra) from multilearnNew.RakelNew import RakelONew,RakelDNew l=6 [X,Y]=loadarff_denso_numerico('MultiLabelDatasets/emotions.arff',l) RaO=RakelONew(base_classifier=RandomForestClassifier(min_samples_split=0.1),model_count=l*2) # Instancia el modelo RAKEL Overlapping. En esta variante, los subconjuntos de etiquetas se eligen de forma aleatoria y pueden solaparse (una misma etiqueta puede aparecer en varios subproblemas). RaD=RakelDNew(base_classifier=RandomForestClassifier(min_samples_split=0.1)) #Instancia el modelo RAKEL Disjoint. A diferencia del anterior, esta variante divide el total de etiquetas en subgrupos que no se solapan entre sí ( RaO.fit(X,Y) predRaO=RaO.predict(X).toarray() #Realiza las predicciones sobre el mismo conjunto X con el modelo RakelO. Dado que las salidas multietiqueta de estas librerías suelen devolverse como matrices dispersas (sparse matrices), .toarray() las convierte en una matriz densa estándar de NumPy para poder operar fácilmente con ella. RaD.fit(X,Y) predRaD=RaD.predict(X).toarray() EDif=0 # Ejemplos diferentes for ie in range(len(X)): if sum(abs(predRaO[ie]-predRaD[ie]))>0: #Resta elemento a elemento. Si son iguales da 0. Si difieren da 1 o -1. EDif=EDif+1 print('Ejemplos con predicción diferente entre RakelO y RakelD={}'.format(EDif)) #%% Random Forest # Hay otros sistemas de aprendizaje multietiqueta que no necesitan de un sistema #monoetiqueta, por ejemplo RandomForestClassifier (RFC) # https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html # Este sistema puede usarse para aprendizaje mono-etiqueta, como se ha hecho en #este bloque, o puede usarse directamente como sistema multi-etiqueta #%% Ejercicio 3 # Repetir el experimento del ejercicio 1 para el sistema RFC en vez del ClassifierChains. #No necesita sistema monoetiqueta. No dar valor a ningún parámetro. # ¿Cómo interpretas el resultado? ¿Este resultado indica que es mejor que CC? #<TODO BEGIN Ejercicio 3> RFC=RandomForestClassifier() RFC.fit(X,Y) preds=RFC.predict(X) print('RFC: Fallos={}'.format(int(np.sum(abs(Y-preds))))) #<TODO END Ejercicio 3>

Apartado B

""" Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 2 : Multi-salida Bloque B : Aprendizaje multi-regresión """ from sklearn.multioutput import MultiOutputRegressor from sklearn.multioutput import RegressorChain from sklearn.ensemble import RandomForestRegressor # De manera análoga a la clasificación se puede realizar la regresión multi-salida. # El sistema MultiOutputRegressor realiza un aprendizaje de cada salida de manera #independiente #%% Ejercicio 1. # Lee en MultiRegressoinDatsets rf1.arff. Crea un modelo MultiOutputRegressor y #otro RegressorChain de manera que ambos tengan como sistema monoetiqueta el #del vecino más cercano (regresión). También para el sistema RandomForestRegressor #(Este no tiene sistema mono-etiqeuta asociado) # Calcula el ejemplo media (para cada atributo su valor medio) e imprime su # evaluación para cada sistema # # PISTA: En el siguiente enlace encontrarás una implementación del vecino más # cercano para regresión # https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsRegressor.html # # PISTA: Para evaluar un ejemplo hay que crear un conjunto de datos de un ejemplo # de la forma [ [v1, ... ,vn] ] , donde v1 ... vn son los valores de los # atributos del ejemplo. Un conjunto de datos con un ejemplo con 2 atributos # con valores 3 y 4 sería: [[3,4]] from lectores.loadarff_denso_numerico import loadarff_denso_numerico # Leer el conjunto de datos [X,Y]=loadarff_denso_numerico('MultiRegressionDatasets/rf1.arff',l=None) #<TODO BEGIN Ejercicio 1> from sklearn.neighbors import KNeighborsRegressor # Crear el modelo MultiOutputRegressor MOR=MultiOutputRegressor(KNeighborsRegressor()) MOR.fit(X,Y) # Crear el modelo RegressorChain RC=RegressorChain(KNeighborsRegressor()) RC.fit(X,Y) # Crear el modelo RandomForestRegressor RFR=RandomForestRegressor() RFR.fit(X,Y) # Calcular el ejemplo media EMed=X.mean(axis=0) # Crear un dataset con ese ejemplo DMed=[EMed] # Evaluar el ejemplo media para MultiOutputRegressor y RegressorChain PMOR=MOR.predict(DMed) PRC=RC.predict(DMed) PRFR=RFR.predict(DMed) print('Predicción del ejemplo media:') print(' MultiOutputRegressor : {}'.format(PMOR)) print(' RegressorChain : {}'.format(PRC)) print(' RandomForestRegressor : {}'.format(PRFR)) #<TODO END Ejercicio 1>

Apartado C

""" Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 2 : Multi-salida Bloque C : Medias de calidad """ import numpy as np # Como en clasificación multi-etiqueta la categoría de un ejemplo está formado #por una secuencia de 0,1 y su predicción también, es necesario establecer #medias de calidad diferentes de las de clasificación mono-etiqueta. # En sklearn hay información sobre las medias de calidad en: #https://scikit-learn.org/stable/modules/model_evaluation.html # Se utilizará este ejemplo muy sencillo para comprobar como funcionan las #diferentes medidas Y=[[1,0,0,0,0], [1,1,0,0,0], [0,1,1,0,1], [0,0,0,1,0], [1,0,1,1,0]] Y=np.array(Y) P=[[1,0,0,1,0], [1,0,0,0,0], [0,1,1,0,1], [0,0,1,0,0], [0,0,1,1,0] ] P=np.array(P) print('Y=\n{}\n'.format(Y)) print('P=\n{}\n'.format(P)) # accuracy_score funciona igual que en clasificación mono-etiqueta: #proporción de predicciones correctas. Una predicción es correcta si es correcta #para todas las etiquetas. # La medida zero_one_loss es la opuesta: proporción de predicciones nal clasificadas. #Una predicción está mal clasificada si hay, al menos, una etiqueta mal clasificada. # La medida hamming_loss retorna la proporción de etiquetas mas clasificadas. # accuracy_score(y_true=[[0,0,1]],y_pred=[[0,0,1]]) # Out[4]: 1.0 # accuracy_score(y_true=[[0,0,1]],y_pred=[[0,0,0]]) # Out[5]: 0.0 # zero_one_loss(y_true=[[0,0,1]],y_pred=[[0,0,0]]) # Out[6]: 1.0 # hamming_loss(y_true=[[0,0,1]],y_pred=[[0,0,0]]) # Out[7]: 0.3333333333333333 #%% Ejemplo 1: # Calcula accuracy_score para (Y,P) from sklearn.metrics import accuracy_score print('accuracy_score(P,Y) ={:<6.4g}'.format(accuracy_score(P,Y))) # Las medias f1, recall, precision y jaccard se utilizarán en multi-etiqueta #con la opción average='samples', lo que indica que se calcula ese valor para cada #ejemplo, comparando su categoría con la predicción, y luego se calcula la #media de ese valor para todos sus ejemplos. from sklearn.metrics import f1_score,recall_score,precision_score,jaccard_score print('{:32}={:<6.4g}'.format('f1(Y,P,average=\'samples\')', f1_score(Y,P,average='samples'))) print('{:32}={:<6.4g}'.format('recall(Y,P,average=\'samples\')', recall_score(Y,P,average='samples'))) print('{:32}={:<6.4g}'.format('precision(Y,P,average=\'samples\')',precision_score(Y,P,average='samples'))) print('{:32}={:<6.4g}'.format('jaccard(Y,P,average=\'samples\')', jaccard_score(Y,P,average='samples'))) #%% Ejercicio 1 # Calcular e imprimir el valor de f1 de cada ejemplo. # Calcular e imprimir la media de los valores de f1 anteriores. # ¿Conincide con el valor f1_samples? #<TODO BEGIN Ejercicio 1> print('') f1s=[] for ie in range(len(Y)): Yie=[Y[ie]] # Conjunto de valores reales que contiene solo el valor Y[ie] Pie=[P[ie]] # Conjunto de predicciones que contiene solo la predicción P[ie] af1=f1_score(Yie,Pie,average='samples') f1s.append(af1) print('Ejemplo {} Y={} P={} f1={:<6.4g}'.format(ie,Y[ie],P[ie],af1)) print('f1 medio = {:<6.4g}'.format(np.mean(f1s))) #<TODO END Ejercicio 1> #%% Medidas de calidad multi-regresión # Las medidas de calidad mono-regresión se pueden usar como multi-regresión, #sin embargo, su uso ha de estar restringido al caso en que las magnitudes de #las diferentes salidas sean las mismas. # Si no es así, habría que hacer un proceso previo para lograrlo, por ejemplo #usando StandardScaler # Creación del conjunto de datos de escala diferente para cada salida import random from sklearn.preprocessing import StandardScaler ne=5 # Número de ejemplos ns=3 # Número de salidas no=0.1 # Proporción de ruido RG=random.Random() RG.seed(1) Y=[None]*ne P=[None]*ne Escala=[None]*ns for osa in range(ns): Escala[osa]=RG.uniform(1,10) for ie in range(ne): YRow=[None]*ns PRow=[None]*ns for isa in range(ns): v=RG.gauss(0,1)*Escala[isa]+Escala[isa] YRow[isa]=v PRow[isa]=v+RG.gauss(0,1)*no Y[ie]=YRow P[ie]=PRow Y=np.array(Y) P=np.array(P) print('Y=\n{}\n'.format(Y)) print('P=\n{}\n'.format(P)) # Estandarizar SS=StandardScaler() SS.fit(Y) ssY=SS.transform(Y) ssP=SS.transform(P) # Calcular medidas de calidad from sklearn.metrics import mean_absolute_error,mean_squared_error print('mean_absolute_error(ssY,ssP)={:<6.4f}'.format(mean_absolute_error(ssY,ssP))) print('mean_squared_error(ssY,ssP) ={:<6.4f}'.format(mean_squared_error(ssY,ssP))) #%% Medidas de calidad relativas # También se suelen utilizar medidas relativas, son las que la medida se divide #entre la medida de calidad que proporcionaría el sistema media (el que predice #siempre la media) # Se puede utilizar sin necesidad de ningún tipo de ajuste de magnitudes siempre #que se realice el proceso salida a salida. # Después de calcular la medida realtiva de cada salida, se calculará la media #de todas ellas # Para calcular el error de cada salida se puede utilizar multioutput=‘raw_values' #%% Ejemplo 2: # Calcular el error cuadrático medio de cada salida del problema del ejemplo anterior #sin realizar ningún cambio de escala # Imprimir los resultados ECMsalidas=mean_squared_error(Y,P,multioutput='raw_values') print('mean_squared_error(Y,P) ={}'.format(ECMsalidas)) #%% Ejercicio 2: # Calcular el error relativo cuadrático medio del problema del ejemplo anterior #suponiendo que la predicción del sistema Media para cada salida es lo almacenado #en el array Escala #<TODO BEGIN Ejercicio 2> # Calcular el Erorr Cuadrático Medio del sistema Media # La predicción es Escala por cada ejemplo de test PMedia=[Escala]*ne # Cálculo del Error Cuadrático Medio del sistema Media # (Obtener los valores individuales de cada salida, no la media) ECMMedia=mean_squared_error(Y,PMedia,multioutput='raw_values') # Divido, en cada salida, el Error Cuadrático medio entre el Error Cuadrático #Medio del sistema Media ERCMsalidas=ECMsalidas/ECMMedia # La media de lo anterior es el valor buscado ERCM=np.mean(ERCMsalidas) print('Error relativo cuadrático medio={:<6.4f}'.format(ERCM)) #<TODO END Ejercicio 2>

Apartado D

""" Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 2 : Multi-salida Bloque D : Estimación de la Calidad """ from lectores.loadarff_denso_numerico import loadarff_denso_numerico from sklearn.metrics import f1_score,recall_score,precision_score,jaccard_score from sklearn.metrics import make_scorer from sklearn.metrics import mean_squared_error,mean_absolute_error from sklearn.multioutput import MultiOutputClassifier from sklearn.svm import SVC from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import cross_val_score from sklearn.model_selection import cross_validate from sklearn.preprocessing import StandardScaler from sklearn.dummy import DummyRegressor # La manera típica de estimar la calidad de un proceso de aprendizaje es mediante #validación cruzada: cross_val_score y cross_validate realizan este proceso # La principal diferencia es que cross_validate permite calcular varias medidas #a la vez #%% Ejemplo 1 # Para el conjunto de datos MultiLabelDatasets/emotions.arr estimar f1 del # sistema SVC con kernel lineal y C=1: # a) Mediante rescritura # b) Mediante cross_val_score # c) Mediante cross_validate calculando además, la precisión y la cobertura # FÍJATE: en el parámetro scoring y como obtener los valores de las medidas en CVEvals [X,Y]=loadarff_denso_numerico('MultiLabelDatasets/emotions.arff',6) BR=MultiOutputClassifier(SVC(kernel='linear',C=1)) print('SVC, emotions:') # a) Reescritura BR.fit(X,Y) P=BR.predict(X) print('Reescritura f1 ={:<6.4g}'.format(f1_score(Y,P,average='samples'))) # b) cross_val_score CVS=cross_val_score(BR,X,Y,scoring=make_scorer(f1_score,average='samples'),cv=3) print('cross_val_score') print(' CV f1 ={:<6.4g}'.format(CVS.mean())) # c) cross_validate # Conjunto de medidas a calcular scoring={'precision':make_scorer(precision_score,average='samples',zero_division=0), 'cobertura':make_scorer(recall_score,average='samples'), 'f1' :make_scorer(f1_score,average='samples')} CVEvals=cross_validate(BR,X,Y,scoring=scoring,cv=3) print('cross_validate') for scorName in scoring.keys(): print(' Measure {:11}={:<6.4g}'.format(scorName,CVEvals['test_{}'.format(scorName)].mean())) # Para regresión se pueden utilizar las medidas mono-etiqueta, pero hay que #realizar una estandarización de las categorías #%% Ejemplo 2 # Para el conjunto de datos MultiRegressionDatasets/waterqual.arr que tiene 16 #salidas que están al principio estimar: # a) En reescritura: Error Relativo Cuadrático Medio (ERCM) # b) Usando cross_val_score: ERCM # c) Usando cross_validate: ERCM y Error Relativo Absoluto Medio (ERAM) # FÍJATE: - El uso de StandardScaler para estandarizar todas las categorías y # poder combinar medidas calcualdas en cada categoría. # - El uso de DummyRegressor para calcular el error del sistema media. [X,Y]=loadarff_denso_numerico('MultiRegressionDatasets/waterqual.arff',16,eaf=False) print('\nRFR, waterqual:') # Estandarizar las cagetorías SS=StandardScaler() SS.fit(Y) Y=SS.transform(Y) Media=DummyRegressor() # a) Reescritura # RFR RFR=RandomForestRegressor(random_state=1) RFR.fit(X,Y) P=RFR.predict(X) # Media Media.fit(X,Y) PM=Media.predict(X) ReesERCM=mean_squared_error(Y,P)/mean_squared_error(Y,PM) print('Reescritura ERCM ={:<6.4g}'.format(ReesERCM.mean())) # b) cross_val_score # RFR RFR=RandomForestRegressor(random_state=1) CVS=cross_val_score(RFR,X,Y,scoring=make_scorer(mean_squared_error),cv=3) #Media CVSM=cross_val_score(Media,X,Y,scoring=make_scorer(mean_squared_error),cv=3) print('cross_val_score') print(' ERCM ={:<6.4g}'.format((CVS/CVSM).mean())) # c) cross_validate RFR=RandomForestRegressor(random_state=1) # Conjunto de medidas a calcular scoring={'ECM':make_scorer(mean_squared_error), 'EAM':make_scorer(mean_absolute_error)} CVEvals=cross_validate(RFR,X,Y,scoring=scoring,cv=3) CVEvalsM=cross_validate(Media,X,Y,scoring=scoring,cv=3) print('cross_validate') # ERCM sCVRFR=CVEvals['test_ECM'] sCVRFRM=CVEvalsM['test_ECM'] print(' ERCM ={:<6.4g}'.format((sCVRFR/sCVRFRM).mean())) # ERAM sCVRFR=CVEvals['test_EAM'] sCVRFRM=CVEvalsM['test_EAM'] print(' ERAM ={:<6.4g}'.format((sCVRFR/sCVRFRM).mean())) #%% Ejercicio 1 # Del sistema RegressorChain , con sistema mono-categoría KNeighborsRegressor #estimar el error para el conjunto de datos del ejemplo anterior mediante la #medida definina por la función ASError # Variar el parámetro n_neighbors desde 1 hasta 10 y obtener una estimación de #la calidad para cada uno de los valores # Salida: # n_neighbors= 1 ASError=1.5960 # n_neighbors= 2 ASError=1.2959 # n_neighbors= 3 ASError=1.2187 # n_neighbors= 4 ASError=1.1687 # n_neighbors= 5 ASError=1.1308 # n_neighbors= 6 ASError=1.1141 # n_neighbors= 7 ASError=1.1062 # n_neighbors= 8 ASError=1.0980 # n_neighbors= 9 ASError=1.0883 # n_neighbors=10 ASError=1.0834 import numpy as np def ASError(Y,P): """ Medida de calidad que calcula dada la diferencia de 2 valores si esa diferencia es menor de 1 utiliza esa diferencia en valor absoluto y si no utiliza la diferencia al cuadrado. - Parametros: Y : matrix exjemplos x salidas con los valores reales P : matrix exjemplos x salidas con los valores predichos - Retorna: La media de las medidas de calidad de cada par real/predicho """ AS=0 for r in range(len(Y)): for c in range(len(Y[r])): vy=Y[r][c] vp=P[r][c] d=np.abs(vy-vp) if d<1: AS=AS+d else: AS=AS+d*d return AS/(len(Y)*len(Y[0])) # <TODO BEGIN Ejerccio 1> from sklearn.neighbors import KNeighborsRegressor from sklearn.multioutput import RegressorChain for k in range(1,10+1): Reg=KNeighborsRegressor(n_neighbors=k) RC=RegressorChain(Reg) CVEvals=cross_validate(RC,X,Y,scoring={'ASError':make_scorer(ASError)},cv=3) print('n_neighbors={:2} ASError={:6.4f}'.format(k,np.mean(CVEvals['test_ASError']))) # <TODO END Ejerccio 1>

Apartado E

""" Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 2 : Multi-salida Bloque E : Ajuste de hiper-parámetros """ from lectores.loadarff_denso_numerico import loadarff_denso_numerico from sklearn.metrics import f1_score,recall_score,precision_score,jaccard_score from sklearn.metrics import make_scorer from sklearn.model_selection import GridSearchCV from sklearn.metrics import mean_squared_error from sklearn.svm import SVR from sklearn.ensemble import RandomForestClassifier from sklearn.multioutput import RegressorChain from sklearn.model_selection import cross_validate,cross_val_score # Para ajuste hiper-parámetros de los sistemas multi-salida que no utilizan otro #sistema de aprendizaje mono-salida se utilizan las mismas herramientas que #en el aprendizaje mono-salida: por ejemplo GridSearchCV #%% Ejemplo 1 # Para el conjunto de datos MultiLabelDatasets/emotions.arrf estimar f1, #precisión y cobertura usando validación cruzada y el sistema RandomForestClassifier #ajustando mediante GridSearch: # min_samples_split entre [0.01,0.05,0.1] # max_features entre [sqrt', 'log2', None] [X,Y]=loadarff_denso_numerico('MultiLabelDatasets/emotions.arff',6) RFC=RandomForestClassifier(random_state=1) RFC_HP={'min_samples_split':[0.01,0.05,0.1], 'max_features':['sqrt', 'log2', None] } GSRFC=GridSearchCV(RFC,RFC_HP,cv=2,scoring=make_scorer(f1_score,average='samples')) scoring={'precision':make_scorer(precision_score,average='samples',zero_division=0), 'cobertura':make_scorer(recall_score,average='samples'), 'f1' :make_scorer(f1_score,average='samples')} CVEvals=cross_validate(GSRFC,X,Y,cv=3,scoring=scoring) print('emotions validación cruzada RFC()') for scorName in scoring.keys(): print(' Measure {:11}={:<6.4g}'.format(scorName,CVEvals['test_{}'.format(scorName)].mean())) # Para los sistemas multi-salida que utilizan otros sistemas mono-salida #los parámetros de estos últimos se ajustan independientemente, pues si se trataran #de ajustar de manera global tendríamos un problema de orden exponencial. #%% Ejemplo 2 # Para el conjunto de datos MultiRegressionDatasets/waterqual.arff # a) estimar el error cuadrático medio en validación cruzada de 3 folds para el # sistema RegressorChain que utiliza sistema de regresión mono-salida SVR con # kernel rbf donde se ajustan por GridSearch con una validación cruzada de 2 folds # y tratando de mejorar el error cuadrático medio los siguientes hyper-parámetros: # C entre [10**-2,1,10**2] # gamma entre [2**-2,1,2**2] # b) Crear el modelo del que se estimó el error (del punto a)) # c) Evaluar el primer ejemplo # PISTA: Hay que estandarizar las salidas (Y) por que están en escalas diferentes # PISTA: GridSearchCV necesita greater_is_better=False porque # mean_squared_error es mejor cuanto más pequeña. # Sin embargo para cross_val_score no es necesario porque este proceso # solo obtiene el valor de la métrica, no la compara con otra. from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline [X,Y]=loadarff_denso_numerico('MultiRegressionDatasets/waterqual.arff',16,eaf=False) # a) Estimar el error print('Medias y std de cada salida:') for i in range(len(Y[0])): print('Y salida {} media={:5.2f} std={:5.2f}'.format(i,Y[:,i].mean(),Y[:,i].std())) # Estandarizar las salidas SS=StandardScaler() YSS=SS.fit_transform(Y) # Crear el objeto regresor Reg=SVR(kernel='rbf') # Hiper-parámetros y sus posibles valores SVR_HP={'C' :[10**-2,1,10**2], 'gamma':[ 2**-2,1, 2**2]} # Grid-Search sobre el regresor GSReg=GridSearchCV(Reg,SVR_HP,cv=2, scoring=make_scorer(mean_squared_error,greater_is_better=False)) # Cadena que utiliza como regresor el GridSearch anterior RC=RegressorChain(GSReg) # Validación cruzada sobre la cadena CVEvals=cross_val_score(RC,X,YSS, # OJO: Salidas estandarizadas cv=3, scoring=make_scorer(mean_squared_error)) print('waterqual validación cruzada RC(SVR):') print(' error cuadrático medio={:<6.4g}'.format(CVEvals.mean())) # b) Generar el Modelo RC.fit(X,YSS) # c) Predecir el ejemplo 0 PSS=RC.predict([X[0]]) print('Predicción estandarizada:',PSS[0]) P=SS.inverse_transform(PSS) print('Predicción original:',P[0]) #%% Ejercicio 1 # Repetir la experimentación del Ejemplo 1 pero usando clasificador de cadenas #que utiliza como sistema mono-salida SVC con kernel lineal donde el #hyper-parámetro C es optimizado mediante grid-search entre #[0.001,0.01,0.1,1,10,100,1000] tratando de optimizar el error de clasificación # Utilizar el conjunto emotions # Obtener e imprimir: precision, cobertura, f1 [X,Y]=loadarff_denso_numerico('MultiLabelDatasets/emotions.arff',6) #<TODO BEGIN Ejerccio 1> from sklearn.multioutput import ClassifierChain from sklearn.svm import SVC from sklearn.metrics import accuracy_score # Crear el objeto clasificador Cla=SVC(kernel='linear') # Hiper-parámetros y sus posibles valores SVC_HP={'C':[0.001,0.01,0.1,1,10,100,1000]} # Grid-Search sobre el regresor GSSVC=GridSearchCV(Cla,SVC_HP,cv=2,scoring=make_scorer(accuracy_score)) # Cadena que utiliza como clasificador el GridSearch anterior CC=ClassifierChain(GSSVC) # Métricas a utilizar scoring={'precision':make_scorer(precision_score,average='samples',zero_division=0), 'cobertura':make_scorer(recall_score,average='samples'), 'f1' :make_scorer(f1_score,average='samples')} # Validación cruzada sobre la cadena CVEvals=cross_validate(CC,X,Y,cv=3,scoring=scoring) # Imprimir los valores de las métricas print('emotions validación cruzada CC(SVC)') for scorName in scoring.keys(): print(' Measures {:11}={:<6.4g}'.format(scorName,CVEvals['test_{}'.format(scorName)].mean())) #<TODO END Ejerccio 1>

Actividad 1

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 2 : Multi-salida Actividad 1 """ # Actividad 1 # Copia este fichero al proyecto T1_S2... # Utilizar el dataset Yeast: (https://mulan.sourceforge.net/datasets-mlc.html) # Que se encuentra en MultiLabelDatasets/yeast.arff # Mirar el fichero yeast.xml para averiguar cuantas etiquetas tiene # Quedarse con 500 ejemplos de manera aleatoria # Para el sistema RakelO, con sistema monoetiqueta SVC con C=1 y kernel lineal, #modificar el parámetro labelset_size desde 2 hasta el número de etiquetas. # Para cada uno de estos valores de número de etiquetas #estimar utilzando validación cruzadda con 3 folds # a) el valor de f1 # b) la proporción de ejemplos para los que falla al menos una etiqueta # Poner los comentarios apropiados para explicar lo que se hace y porqué # PISTA: seleccionar 500 ejemplos aleatorios: # RG=random.Random() # RG.seed(1) # orden=list(range(len(X))) # random.shuffle(orden) # selecc=orden[:500] # X=X[selecc,:] # Y=Y[selecc,:] # PISTA: b) la proporción de ejemplos para los que falla al menos una etiqueta # Fíjate en los apuntes de teoría: Funciones de pérdida basadas en ejemplos # ¿Hay alguna medida de pérdida (loss) que retorne 1 si hay almenos una etiqeuta #mal y 0 si todas las etiquetas están bien? # Ejemplo de salida # RakelO es un algoritmo con acciones aleatorias que no usa sem¡illa, por tanto #en diferentes ejecuciones podrían obtenerse diferentes salidas # labelset_size: 2 f1=0.6147 Falla al menos una etiqueta=0.852 # labelset_size: 3 f1=0.6179 Falla al menos una etiqueta=0.848 # labelset_size: 4 f1=0.6288 Falla al menos una etiqueta=0.824 # labelset_size: 5 f1=0.6301 Falla al menos una etiqueta=0.8121 # labelset_size: 6 f1=0.6223 Falla al menos una etiqueta=0.822 # labelset_size: 7 f1=0.6251 Falla al menos una etiqueta=0.804 # labelset_size: 8 f1=0.6137 Falla al menos una etiqueta=0.808 # labelset_size: 9 f1=0.6042 Falla al menos una etiqueta=0.806 # labelset_size:10 f1=0.6039 Falla al menos una etiqueta=0.788 # labelset_size:11 f1=0.5951 Falla al menos una etiqueta=0.8 # labelset_size:12 f1=0.5915 Falla al menos una etiqueta=0.788 # labelset_size:13 f1=0.5873 Falla al menos una etiqueta=0.786 # labelset_size:14 f1=0.5873 Falla al menos una etiqueta=0.786 # NOTA User la siguiente implementación de Rakel from multilearnNew.RakelNew import RakelONew #<TODO BEGIN Actividad 1> #<TODO END Actividad 1>

Actividad2

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 2 : Multi-salida Actividad 2 """ # Actividad 2 # Utilizar el dataset MultiRegressionDatasets/rf1.arff # No hace falta indicar el número de etiquetas, está indicado en el fichero #en la primera línea # Utilizar 100 ejemplos aleatorios # Imprimir la estimación del MAE y MSE en validación cruzada con 3 folds de #los sistemas 1.1, 1.2, 2.1 y 2.2: # 1) Random Forest como regresor multisalida ajustando los hyper-parámetros: # min_samples_leaf entre [0.01,0.05,0.1] # max_depth entre [5,10,50] # 1.1) mediante un GridSearch tomando el de mejor error absoluto # 1.2) mediante un GridSearch tomando el de mejor error cuadrático # # 2) Regresor de cadenas tomando como regresor mono-salida un Random Forest # ajustando los hyper-parámetros: # min_samples_leaf entre [0.01,0.05,0.1] # max_depth entre [5,10,50] # 2.1) mediante un GridSearch tomando el de mejor error absoluto # 2.2) mediante un GridSearch tomando el de mejor error cuadrático # # Además imprimir el tiempo total que tarda en aprender (fit) en la validación #cruzada para cada sistema # NOTAS: MAE : Mean Absolute Error # MSE : Mean Squared Error # Utilizar un validación cruzada de 2 folds para la estimación de la medida # en GridSearch # PISTA: El resultado de una validación cruzada (CV) incluye el tiempo de entrenamiento. # Al evaluar lo retornado por una CV en el intérprete de comandos se muestran # los diferentes elementos que contiene. # Ejemplo de salida # 1.1): MAE=7.54896 MSE=219.46257 Tiempo fit= 4.98 # 1.2): MAE=7.61465 MSE=220.41069 Tiempo fit= 4.89 # 2.1): MAE=6.68225 MSE=192.23341 Tiempo fit=40.04 # 2.2): MAE=6.81427 MSE=194.17516 Tiempo fit=39.13 #<TODO BEGIN Actividad 2> #<TODO END Actividad 2>

Tema 1 Sesion 3

Clase Rank

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ @author: quevedo """ import numpy as np from sklearn.svm import LinearSVC from sklearn.base import BaseEstimator from sklearn.metrics import roc_auc_score #%% linearRank class class linearRank(BaseEstimator): """ Class that learns a linear model that generates a global ranking from batchs of partial ranks. """ def __init__(self,LinealClass=None,verbose=0): """ Params: LinealClass : sklearn linear classificator. Method LinealClass.decision_function must be defined Default=sklearn.svm.LinearSVC(C=1,fit_intercept=False) verbose : integer. if 0 no verbosity. """ if LinealClass!=None: self.LinealClass=LinealClass else: self.LinealClass=LinearSVC(C=1,fit_intercept=False) self.verbose=verbose def fit(self,X,Y): """ Learns a linear model using the partial ranks of X defined by Y. Params: X : list of examples. An example is a list of values. Y : if Y is a list of values: These values are used to compare examples. The examples with the same value are not compared. if Y is a list of lists of two values. The first value is used to campare examples in the batch. The second value is the batchId. All examples with the same bathcId own to the same batch. Each example will be only compared to the examples of their batch. """ # Calculate batchs Indices [batchs,oneBatch]=_getBatchsInd(Y) if self.verbose>=1: print('There are {} batchs of length:'.format(len(batchs)),end='') for b in batchs: print(' {}'.format(len(b)),end='') if self.verbose>=2: print('(indices:',end='') for bi in b: print(' {}'.format(bi),end='') print(')',end='') print() # Generate comparisons cX=[] cY=[] for bInd in batchs: # for each batch if self.verbose>=3: print('Batch indices:',end='') for b in bInd: print(' {}'.format(b)) print('') for i in range(len(bInd)-1): # for each pair (i,j) of examples in batch xi=X[i] yi=Y[i] if oneBatch else Y[i][0] for j in range(i,len(bInd)): xj=X[j] yj=Y[j] if oneBatch else Y[j][0] if yi!=yj: # There is a comparation cX.append(np.subtract(xi,xj)) cY.append(np.sign(yi-yj)) cX.append(np.subtract(xj,xi)) cY.append(np.sign(yj-yi)) if self.verbose>=3: print(' Generated pair (Y[{}]={},Y[{}]={}' .format()) if self.verbose>=1: print('Generated {} pairs of comparisons'.format(int(len(cX)/2))) # Learn the model self.LinealClass.fit(cX,cY) if self.verbose>=1: print('Model learned from {} examples.'.format(len(cX)),end='') if self.verbose>=2: print(' W=',end='') for wv in self.LinealClass.coef_[0]: print(' {:6.4f}'.format(wv),end='') print() return self def predict(self,X): """ Predicts X using the learned model in fit. Params: X : list of examples. An example is a list of values. Returns: P : list of predictions. Each prediction is a numeric value. If example A has a prediction greater than example B then A is preferred to (ordered before than) B. """ P=self.LinealClass.decision_function(X) if self.verbose>=1: print('Predicted {} examples'.format(len(X))) return P #%% multiBatchAUC def multiBatchAUC(Y,P): """ Calculates an AUC measure for each batch in Y. Params Y : see linearRank.fit, Y param P : list of values, predictions. Returns average of each Batch's AUC """ [batchs,oneBatch]=_getBatchsInd(Y) if not oneBatch: Y=list(map(lambda x:x[0],Y))# Take the ranker values AUC=0 for bInd in batchs: # Get the batch's Y and P bY=[Y[i] for i in bInd] bP=[P[i] for i in bInd] bAUC=roc_auc_score(bY,bP) AUC=AUC+bAUC AUC=AUC/len(batchs) return AUC #%% CIndex(Y,P) def CIndex(Y,P): """ Calculates a C-index (concordance index) measure C-index is calculated as the proportion of corrected ordered pair of examples https://proceedings.neurips.cc/paper/2007/file/33e8075e9970de0cfea955afd4644bb2-Paper.pdf Params Y : list of values, real values. P : list of values, predictions. Returns C-Index value. The proportion of all ordered pairs in Y that concordance (same order) in P If Y is void or all values or Y are the same (no ordered pairs) None is returned """ E=len(Y) # number of examples Ci=0 nPairs=0 for i in range(E-1): for j in range(i,E): if Y[i]!=Y[j]: # There is a pair that is ordered nPairs=nPairs+1 if P[i]==P[j]: # If tie Ci=Ci+0.5 # half sucess (0.5 of 1) elif np.sign(P[i]-P[j])==np.sign(Y[i]-Y[j]): # Same order Ci=Ci+1 # Full sucess (1 of 1) if nPairs==0: return None else: return Ci/nPairs #%% multiBatchCIndex def multiBatchCIndex(Y,P): """ Calculates a C-index (concordance index) measure for each batch in Y. Params Y : see linearRank.fit, Y param P : list of values, predictions. Returns Average of each Batch's C-index. If a C-Index is None it will not be used in the avarage If all batchs have a None C-Index None is returned """ [batchs,oneBatch]=_getBatchsInd(Y) if not oneBatch: Y=list(map(lambda x:x[0],Y))# Take the ranker values Ci=0 validBatchs=0 for bInd in batchs: # Get the batch's Y and P bY=[Y[i] for i in bInd] bP=[P[i] for i in bInd] bCi=CIndex(bY,bP) if bCi!=None: Ci=Ci+bCi validBatchs=validBatchs+1 if validBatchs>0: return Ci/validBatchs else: return None #%% _getBatchsInd function def _getBatchsInd(Y): if type(Y[0]) not in (list,np.ndarray): # There are no batch Ids batchs=[list(range(len(Y)))] # There are only one batch oneBatch=True return [batchs,oneBatch] # There are batch Ids Bn=np.array(list(map(lambda p:p[1],Y))) # Batchs numbers B=np.unique(Bn) # Different batchs batchs=[] for b in B: batchs.append(np.where(Bn==b)[0].tolist()) oneBatch=False return [batchs,oneBatch] #%% Example of use # X=[[1,2],[3,4],[5,4],[8,9],[4,7]] # Y=[1,1,0,1,0] # Y=[[1,0],[1,0],[0,1],[1,1],[0,0]] # Ranker=linearRank(verbose=2) # Ranker.fit(X,Y) # P=Ranker.predict(X) # print('AUC={:6.4f}'.format(multiBatchAUC(Y,P)))

Apartado A

# -*- coding: utf-8 -*- """ Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 3 : Ranking Bloque A : Conjunto de datos de ranking """ #%% # Los conjuntos de datos de ranking están formados por lotes. # Cada lote tiene varios ejemplos con un valor numérico cada uno # El valor numérico (suele ser un entero) solo sirve para establecer preferencias #entre los ejemplos, de manera que dados dos ejemplos, si el ejemplo A tiene un valor #numérico mayor el ejemplo B, esto indica que se prefiere el A al B. # Si el valor numérico es el mismo, no hay indicación de preferencia entre ellos. # Estas preferencias solo son aplicables dentro de un bloque, nunca se pueden #establecer preferencias entre ejemplos de diferentes bloques. # En esta práctica se indicará que un ejemplo A se prefiere a otro B de la #siguiente manera: A>~B. Si no se establecen preferencias se indica A=~B. # La estructura de datos propuesta para guardar la información anterior consiste #en que la categoría de cada ejemplo sea una lista con dos valores: #Y=[[RankVal1,Lote1],[RankVal2,Lote2],...] # Donde RankVal es el valor de ranking, el que se compara para establecer preferencias #y Lote es el identificador del lote (generalmente un entero) #Cuando hay un solo lote la categoría puede ser una lista de RankVal #%% Ejemplo 1. Un lote # En una competicción de robots se ha logrado la siguiente clasificación: # R1 > ~R3 >~ R4 >~ R2 #Donde cada robot está definido como: # R1 : [1, 34] # R2 : [3, 25] # R3 : [2, 14] # R4 : [2, 45] # Crear la estructura de datos que almacene la información de esas preferencias # Robots: R1=[1, 34] R2=[3, 25] R3=[2, 14] R4=[2, 45] # Orden (solo un lote) X=[R1,R3,R4,R2] Y=[4 ,3 ,2 ,1 ] #%% Ejemplo 2. Varios Lotes # Hay varios críticos que han realizado las siguientes preferencias de restaurantes: # R2 >~ R1, # R2 >~ R4 =~ R3 >~ R1 # R2 >~ R3 >~ R4 >~ R1 # Los atributos que definen cada restaurante son: # R1 : [9.4, 5.0] # R2 : [0.5, -1] # R3 : [3.5, 0] # R4 : [7.5, 2.3] # Crear la estructura de datos que almacene la información de esas preferencias # Restaurantes R1=[9.4, 5.0] R2=[0.5, -1] R3=[3.5, 0] R4=[7.5, 2.3] X=[R2 ,R1 ,R2 ,R4 ,R3 ,R1 ,R2 ,R3 ,R4 ,R1] Y=[[2,1] ,[1,1] ,[3,2] ,[2,2] ,[2,2] ,[1,2] ,[4,3] ,[3,3] ,[2,3] ,[1,3]] #%% Ejercicio 1 # En un laboratorio de pruebas se hacen pruebas a muestras de acero. # Las muestras de aceros vienen determinadas por la composición química siguiente: # A1 : Fe=99.50%, C=0.5% # A2 : Fe=98% , C=0.5%, Cd=1.5% # A3 : Fe=99% , Cd=1% # Se han realizado tres pruebas: # P1 : A1 >~ A2 # P2 : A2 >~ A1 >~ A3 # P3 : A1 >~ A3 # Crear la estructura de datos que almacene la información de esas preferencias #<TODO BEGIN Ejerccio 1> A1=[99.50,0.5,0] A2=[98 ,0.5,1.5] A3=[99 ,0 ,1] X=[A1 ,A2 ,A2 ,A1 ,A3 ,A1 ,A3] Y=[[2,1] ,[1,1] ,[3,2] ,[2,2] ,[1,2] ,[2,3] ,[1,3]] #<TODO END Ejerccio 1>

Apartado B

# -*- coding: utf-8 -*- """ Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 3 : Ranking Bloque B : Aprendizaje a partir de ranking bipartito en un solo lote """ #%% # El objetivo del aprendizaje automático de rankings es crear un modelo que dado #un ejemplo le otorgue un valor numérico de manera que si este valor es mayor #que el dado a otro ejemplo indica que se prefiere el primero al segundo. # Estamos en la situación que el valor de ranking (la categoría) solo tiene dos #valores se llamarán positivo y negativo. # En esta práctica se trabajará solo con un lote. # El objetivo es el ordenar los ejemplos del test de manera que los positivos #estén antes que los negativos. # La clase linearRank realiza el proceso de aprendizaje de un modelo lineal #%% conjunto de datos aleatorio import random import numpy as np from Rank import linearRank from sklearn.metrics import roc_auc_score from sklearn.metrics import RocCurveDisplay def genXY(RG,w,nEje,ruido=0): X=[None]*nEje Y=[None]*nEje at=len(w) for e in range(nEje): x=list(RG.gauss(0,1) for i in range(at)) X[e]=x vRuido=RG.uniform(1,2)*RG.choice([-1,+1])*ruido # Uniform distribution in (-2*ruido;-1] U [+1;+2*ruido) vx=np.dot(x,w)# Producto escalar v=vx+vRuido # Valor 1 si positivo, 0 si negativo if v>0: Y[e]=1 else: Y[e]=0 return [X,Y] nAtt=10 # Atributos RG=random.Random() # Generador de aletoriedad RG.seed(1) w=list(RG.gauss(0,1) for i in range(nAtt)) # Pesos de la función lineal que dará las evaluaciones nEjeTr=100 # Ejemplos de entrenamiento nEjeTe=100 # Ejemplos de test ruido=1 # Ruido. 0 no hay ruido, cuanto mayor, más ruido [XTr,YTr]=genXY(RG,w,nEjeTr,ruido) [XTe,YTe]=genXY(RG,w,nEjeTe,ruido) print('Generado entranamiento({} ejemplos) test({} ejemplos)'.format(len(XTr),len(XTe))) #%% Realizar un entrenamiento y obtener una evaluación del test # Clasificador, lineal y sin término independiente. # Genera como salida la evaluación de la función lineal lRank=linearRank() print('Generando modelos a partir del train y evaluando el test') Model=lRank.fit(XTr,YTr) Eval=Model.predict(XTe) #%% Evaluar la calidad de los modelos de ranking # La calidad de los modelos de ranking bipartitos se mide usando AUC #La medida roc_auc_score realiza este cálculo print('Evaluando la calidad de los modelos de ranking') AUC=roc_auc_score(YTe,Eval) print('AUC={:6.4f}'.format(AUC)) RocCurveDisplay.from_predictions(YTe,Eval) #%% Ejercicio 1 # Variar el ruido desde 0 hasta 10. Para cada nivel de ruido generar un conjunto #de datos con ese ruido. Crear un modelo de ranking con el entrenamiento y #calcular el AUC del test. Imprimir el AUC. # EXTRA: Hacer una gráfica en la que vea como varía el AUC en función del ruido AUCs=[]# Se almacenarán los AUC en esta lista ruidos=list(range(10+1)) # Ruidos de 0 a 10 #<TODO BEGIN Ejerccio 1> # Cálculo del AUC por cada nivel de ruido for ruido in ruidos: # Generación del conjunto de ejemplos [XTr,YTr]=genXY(RG,w,nEjeTr,ruido) [XTe,YTe]=genXY(RG,w,nEjeTe,ruido) # Aprendizaje / evaluación Model=lRank.fit(XTr,YTr) Eval=Model.predict(XTe) # Cálculo del AUC AUC=roc_auc_score(YTe,Eval) # Almnacenar el AUC en AUCs AUCs.append(AUC) # Imprimir print('ruido={:2} AUC={:6.4f}'.format(ruido,AUC)) #<TODO END Ejerccio 1> # Gráfica de AUC en función del ruido import matplotlib.pyplot as plt plt.figure() plt.title('Ejercicio 1 (Extra). AUC en función del ruido') plt.xlabel('Ruido') plt.xticks(ruidos) plt.ylabel('AUC') plt.grid() plt.plot(ruidos,AUCs)

Apartado C

# -*- coding: utf-8 -*- """ Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 2 : Ranking Bloque C : Aprendizaje de ranking multipartito de un solo lote """ #%% # Estamos en la situación que el valor de ranking (la categoría) tiene #diferentes valores numéricos, puden ser valores discretos o en coma flotante. # En esta práctica se trabajará solo con un lote. # El objetivo es el ordenar los ejemplos del test de manera que los ejemplos #con valores mayores estén antes que los ejemplos con valores menores. # La métrica CIndex (Concordance index) calcula la proporción de pares #correctamente ordenados #%% Leer qsar_aquatic_toxicity.csv # Leer datos de datasets/qsar_aquatic_toxicity.csv #https://archive.ics.uci.edu/ml/datasets/QSAR+aquatic+toxicity # La última columna es la categoría (calidad del agua), es un valor en coma flotante #pero nos interesa solo el valor entero, así que se aplicará la función round # El resto de columnas (toas menos la última) será los atributos # Crear valiables X,Y donde se guarden los datos de este conjunto # Se tomarán solo los 100 primeros ejemplos (por razones de eficiencia) import csv X=[] Y=[] with open('datasets/qsar_aquatic_toxicity.csv') as csvfile: Reader=csv.reader(csvfile,delimiter=';',quoting=csv.QUOTE_NONNUMERIC) for row in Reader: X.append(row[:len(row)-1]) Y.append(round(row[len(row)-1])) X=X[:100] Y=Y[:100] #%% Estimación de CIndex # Realizar una validación cruzada con 3 folds del sistema linearRank con el #conjuto de datos anterior. Estimar CIndex from Rank import linearRank,CIndex from sklearn.model_selection import cross_validate from sklearn.metrics import make_scorer Ranker=linearRank(verbose=1) cv=cross_validate(Ranker,X,Y,scoring=make_scorer(CIndex),cv=3) print('CIndex={:6.4f}'.format(cv['test_score'].mean())) #%% Ejercicio 1 # Los valores de la Y son enteros en [0;10], pero solo interesa la calidad del #agua según los siguientes criterios: # Mala : [0; 4] # Regular : [5; 7] # Buena : [8:10] # Modifica los valores de la Y de manera que las aguas con el mismo criterio tengan #un mismo valor y sea acorde a Buena>~Regular>~Mala # Repite el experimento anterior y calcula la estimación del CIndex para este caso # El CIndex, ¿Ha mejorado o empeorado? #<TODO BEGIN Ejerccio 1> # Generando Y3 donde Mala->0, Regular->1, Buena->2 Y3=[] for v in Y: if v <=4: c=0 elif v<=7: c=1 else: c=2 Y3.append(c) # Experimentación cv=cross_validate(Ranker,X,Y3,scoring=make_scorer(CIndex),cv=3) print('Y3: CIndex={:6.4f}'.format(cv['test_score'].mean())) #<TODO END Ejerccio 1>

Apartado D

# -*- coding: utf-8 -*- """ Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 3 : Ranking Bloque D : Aprendizaje de ranking con varios lotes """ #%% # Como se indicó en el bloque A, los conjuntos de ejemplos de ranking están agrupados #por lotes. Solo los objetos del mismo lote formarán pares (preferencias) #%% Ejemplo restaurantes # Datos del bloque A # Restaurantes R1=[9.4, 5.0] R2=[0.5, -1] R3=[3.5, 0] R4=[7.5, 2.3] X=[R2 ,R1 ,R2 ,R4 ,R3 ,R1 ,R2 ,R3 ,R4 ,R1] Y=[[2,1] ,[1,1] ,[3,2] ,[2,2] ,[2,2] ,[1,2] ,[4,3] ,[3,3] ,[2,3] ,[1,3]] # Restaurantes a ordenar y sus nombres (test) RN1=[7.4, 6] RN2=[4.5, 0.5] RN3=[0.9, -2.5] RN4=[2.6, 2.9] RN5=[6.0, 4.6] Nombres=['RN1','RN2','RN3','RN4','RN5'] # Partiendo del ejemplo de los restuarantes (Bloque A) se quieren ordenar cinco #nuevos restaurantes (RN*) de los que no hay críticas. # Detallar el proceso e imprimir el nombre los restaurantes nuevos de mejor a peor #junto con su valoración del ranking # SOLUCIÓN: # Crear un modelo de ranking con los datos del bloque A from Rank import linearRank Ranker=linearRank() Ranker.fit(X,Y) # Crear el conjunto de test y evaluarlo con el modelo anterior XTe=[RN1,RN2,RN3,RN4,RN5] P=Ranker.predict(XTe) # Ordenar de mayor puntuación a menor e imprimir la valoración del ranking import numpy as np orden=np.argsort(-P) # Como artgsort ordena de menos a más, se cambia el signo de P para que ordene P de más a menos for i in orden: print('{} valor ranking:{:+6.4f}'.format(Nombres[i],P[i])) #%% Medida del error # Un grupo de críticos ha valorado algunos de los nuevos restaurantes. #Calcular una medida de calidad para la predicción anterior (P) tomando como # correcto(Y) lo valorado por los criticos: # Valoraciónes de los críticos # Cada fila es un crítico y las 5 columnas son los 5 restaurantes. #Cada crítico solo valoró (cuanto más mejor) alguno de los restaurantes, # si no hay valoración se indica con None Valoraciones=[ #RN1 ,RN2 ,RN3 ,RN4 ,RN5 <- Restaurante (Objeto) [3 ,None,None,4 ,2], # Crítico 1 [2 ,4 ,None,None,8], # Crítico 2 [None,27 ,53 ,45 ,27]] # Crítico 3 # SOLUCIÓN: # Por cada Crítico se crea un lote con los restaurantes que ha valorado. # Se añaden a YTe el par [valoración,lote] y en PTe P[restaurante] YTe=[] # Valor y lote en cada ejemplo de test PTe=[] # Predicción del modelo en cada ejemplo de test Res=[] # (el restaurante no es necesario para la solución, se muestra para mejora académica) for ilote in range(len(Valoraciones)): # Por cada lote lote=Valoraciones[ilote] for irest in range(len(lote)): # Por cada restaurante (objeto) valor=lote[irest] if valor!=None: YTe.append([valor,ilote]) PTe.append(P[irest]) Res.append(irest) # Imprimir YTe, P y el restaurante (el restaurante no es necesario para la solución, se muestra para mejora académica) print('\nYTe | PTe | Nombre restaurante (Objeto)') for i in range(len(YTe)): print('[{:2},{}] | {:+6.4f} | {}'.format(YTe[i][0],YTe[i][1],PTe[i],Nombres[Res[i]])) # Como es multi-evaluado se utilizará CIndex y como hay lotes se utilizará: from Rank import multiBatchCIndex ResCI=multiBatchCIndex(YTe,PTe) print('\nCIndex de las valoraciones del modelo sobre los nuevos restaurantes={:6.4f}' .format(ResCI)) #%% Ejercicio 1 # El restaurante NR6 gusta más que el NR7. Entrena un modelo con los datos #de los restaurantes del bloque A (X,Y) y los nuevos (XTe,YTe), evalúa NR6 y NR7 e # imprime los valores de ranking que ha predicho el modelo. #Comprueba si este modelo es coherente con NR6 >~ NR7 NR6=[3.5, 0.5] NR7=[6.1, 4.7] #<TODO BEGIN Ejercicio 1> # En el ejemplo anterior se había creado la YTe, esto es, para cada valoración de un experto #se indica el par, [valoración,lote], donde el lote coincide con el experto, ahora hay que hacer #lo mismo pero el lote no ha de coincidir con ninguno de los Y, por lo tanto simplemente se repite #el proceso anterior pero se suma (maxLotePrev+1) a iterador del blucle. Donde maxLotePrev es #el valor máximo de todos los lotes de Y. # Falta indicar los atributos (X) del restaurante. Se concatenan los atributos de los ejemplos que se #evalúan. Estos atributos están en XTe XTeObjLote=[] # Atributos del ejemplo de test YTeObjLote=[] # [Valor,Lote] del ejemplo de test maxLotePrev=np.array(Y)[:,1].max() # Obtener el valor máximo de id de lote de los ejemplos anteriores for ilote in range(len(Valoraciones)): # Por cada lote lote=Valoraciones[ilote] for irest in range(len(lote)): # Por cada restaurante (objeto) valor=lote[irest] if valor!=None: XTeObjLote.append(XTe[irest]) # Concata los atributos del restaurante YTeObjLote.append([valor,ilote+(maxLotePrev+1)]) # Los lotes serán valores consecutivos a partir del máximo del idLote # Crear un nuevo conjunto de datos concatenando los 2 anteriores XTodoTr=X+XTeObjLote YTodoTr=Y+YTeObjLote # Entrenar el modelo Ranker=linearRank() Ranker.fit(XTodoTr,YTodoTr) # Crear el conjunto de test y evaluarlo XTodoTe=[NR6,NR7] PTodoTe=Ranker.predict(XTodoTe) print('Valor de ranking para NR6:{:+6.4f}'.format(PTodoTe[0])) print('Valor de ranking para NR7:{:+6.4f}'.format(PTodoTe[1])) if PTodoTe[0] > PTodoTe[1]: print('El modelo SÍ es coherente con RN6 >~ RN7 ya que Model(RN6)={:+6.4f} > Model(RN7)={:+6.4f}' .format(PTodoTe[0],PTodoTe[1])) else: print('El modelo NO es coherente con RN6 >~ RN7 ya que Model(RN6)={:+6.4f} < Model(RN7)={:+6.4f}' .format(PTodoTe[0],PTodoTe[1])) #<TODO END Ejercicio 1>

Apartado E

# -*- coding: utf-8 -*- """ Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 3 : Ranking Bloque E : Estimación de la medida de calidad con varios lotes """ #%% # Como se indicó en el bloque A, los conjuntos de ejemplos de ranking están agrupados #por lotes. Para estimar una medida de calidad se realizará una validación cruzada #pero agrupando por lote, no por ejemplo. #%% Ejemplo restaurantes # Datos del bloque A # Restaurantes R1=[9.4, 5.0] R2=[0.5, -1] R3=[3.5, 0] R4=[7.5, 2.3] X=[R2 ,R1 ,R2 ,R4 ,R3 ,R1 ,R2 ,R3 ,R4 ,R1] Y=[[2,1] ,[1,1] ,[3,2] ,[2,2] ,[2,2] ,[1,2] ,[4,3] ,[3,3] ,[2,3] ,[1,3]] #%% Estimación del error con lotes from Rank import linearRank from Rank import multiBatchCIndex from sklearn.model_selection import cross_validate from sklearn.metrics import make_scorer from sklearn.model_selection import GroupKFold ranker=linearRank() # Los grupos son los lotes groups=[] for [value,idLote] in Y: groups.append(idLote) # Se ha de utilizar una validación cruzada donde se indica en groups los lotes #y se utiliza como cv un objeto de la clase GroupKFold CVscores=cross_validate(ranker,X,Y,scoring=make_scorer(multiBatchCIndex), groups=groups,cv=GroupKFold(n_splits=3)) # No puede haber más folds que lotes print('CIndex (proporción de pares correctamente ordenados en cada lote): {:6.4f}' .format(CVscores['test_score'].mean())) #%% Ejercicio 1 # Haz de crítico y añade unas nuevas preferencias sobre restaurantes. # Escribe las preferencias como R1 >~ R2, o R2 <~ R4 # Codifica estas preferencias y añádelas a X e Y # Estima el error con el máximo número de folds #<TODO BEGIN Ejercicio 1> # Preferencias como crítico # R2 <~ R4 # R3 >~ R4 >~ R1 # Codificación de las preferencias en los lotes 4 y 5 XN=[ R2 , R4 , R3 ,R4 , R1] YN=[[2,4],[3,4],[3,5],[2,5],[1,5]] # Se empieza en el lote 4, que el último fue el 3 # Se concatenan los datos XAll=X+XN YAll=Y+YN # Los grupos son los lotes groups=[] for [value,idLote] in YAll: groups.append(idLote) # Estimar la medida de calidad mediante cross validation CVscores=cross_validate(ranker,XAll,YAll,scoring=make_scorer(multiBatchCIndex), groups=groups,cv=GroupKFold(n_splits=5))# Hay 5 grupos, así que max de folds = 5 # Imprimir print('Datos nuevos: CIndex (proporción de pares correctamente ordenados en cada lote): {:6.4f}' .format(CVscores['test_score'].mean())) #<TODO END Ejercicio 1>

Actividad 1

# -*- coding: utf-8 -*- """ Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 3 : Ranking Actividad 1 """ #%% Actividad Presencial 1 def getObjeto(row): idEje=int(row[0]) XEje=[] for i in range(2,len(row)): if i==4: # Minor grouop, hay 12 diferentes del 0 al 11 (ver README-en.txt) v=int(row[i]) for iv in range(12): if iv==v: XEje.append(1) else: XEje.append(0) XEje.append(float(row[i])) return [idEje,XEje] def getLote(Objetos,row,idLote): LoteX=[] LoteY=[] for i in range(len(row)): # Por cada sushi v=int(row[i]) if v>=0: LoteX.append(Objetos[i]) LoteY.append([v,idLote]) return [LoteX,LoteY] #%% Leer los datos y generar los lotes # https://preference-learning.org/index.html#Datasets # https://www.kamishima.net/sushi/ import csv # Leer las descripciones de los objetos (descripciones de sushi) Objetos={} # Diccionario de key:idSushi, value:atributos de sushi with open('datasets/sushi/sushi3-2016/sushi3.idata', newline='') as icsv: csvreader = csv.reader(icsv, delimiter='\t') for row in csvreader: [idEje,XEje]=getObjeto(row) print(row) print(XEje) Objetos[idEje]=XEje print('Leídas {} descripciones de sushi'.format(len(Objetos))) #%% Leer las puntuaciones y crear el conjunto de datos de ranking Xsushi=[] Ysushi=[] with open('datasets/sushi/sushi3-2016/sushi3b.5000.10.score', newline='') as icsv: csvreader = csv.reader(icsv, delimiter=' ') idLote=0 for row in csvreader: [LoteX,LoteY]=getLote(Objetos,row,idLote) Xsushi=Xsushi+LoteX Ysushi=Ysushi+LoteY idLote=idLote+1 # if idLote>=1000: # break print('Creados {} ejemplos valorados a partir de {} lotes'. format(len(Ysushi),idLote)) #%% Actividad presencial 1: Estimar la calidad # Estima el CIndex del conjunto de datos (Xsushi,Ysushi) utilizando como ranker #linearRank con valores por defecto. # Imprime el resultado. #<TODO BEGIN Actividad 1> from Rank import linearRank,multiBatchCIndex from sklearn.model_selection import cross_validate from sklearn.metrics import make_scorer from sklearn.model_selection import GroupKFold # Los grupos son los lotes groups=[] for [value,idLote] in Ysushi: groups.append(idLote) ranker=linearRank() CVscores=cross_validate(ranker,Xsushi,Ysushi,scoring=make_scorer(multiBatchCIndex), groups=groups,cv=GroupKFold()) print('CIndex (proporción de pares correctamente ordenados en cada lote): {:6.4f}' .format(CVscores['test_score'].mean())) #<TODO END Actividad 1> #%% Actividad presencial 2: compara dos sushis # Utiliza el modelo del que se ha estimado el CIndex para evaluar estos 2 sushis: # Objetos según se leen del CSV s1Ori=['7','tamago','1','1','9','2.36807095343681','1.86622320768662','1.03246753246753','0.84'] s2Ori=['8','toro','1','0','1','0.551854655563967','2.05753217259652','4.48545454545455','0.8'] # Objetos con valores numéricos [ids1,s1]=getObjeto(s1Ori) [ids2,s2]=getObjeto(s2Ori) # 2.1 : Crea el modelo # 2.2 : Evalua ambos sushis, imprime sus evaluaciones # 2.3 : Implementa el código que indique cual es el mejor #<TODO BEGIN Actividad 2> # Paso a paso # 2.1 : Crea el modelo ranker.fit(Xsushi,Ysushi) # 2.2 : Evalua ambos sushis, imprime sus evaluaciones ev1=ranker.predict([s1])[0] ev2=ranker.predict([s2])[0] print('Sushi {} evaluado con {:+6.4f}'.format(s1Ori[0],ev1)) print('Sushi {} evaluado con {:+6.4f}'.format(s2Ori[0],ev2)) # 2.3 : Implementa el código que indique cual es el mejor if ev1>ev2: mejor=s1Ori[0] peor= s2Ori[0] else: mejor=s2Ori[0] peor= s1Ori[0] print('Sushi {} mejor que sushi {}'.format(mejor,peor)) #<TODO END Actividad 2>

Actividad 1 XGBRanker

# -*- coding: utf-8 -*- """ Tema 1 : Problemas Complejos de Aprendizaje Supervisado Sesión 3 : Ranking Actividad 1 """ #%% Actividad Alumno 1 def getObjeto(row): idEje=int(row[0]) XEje=[] for i in range(2,len(row)): if i==4: # Minor grouop, hay 12 diferentes del 0 al 11 (ver README-en.txt) v=int(row[i]) for iv in range(12): if iv==v: XEje.append(1) else: XEje.append(0) XEje.append(float(row[i])) return [idEje,XEje] def getLote(Objetos,row,idLote): LoteX=[] LoteY=[] for i in range(len(row)): # Por cada sushi v=int(row[i]) if v>=0: LoteX.append(Objetos[i]) LoteY.append([v,idLote]) return [LoteX,LoteY] #%% Leer los datos y generar los lotes # https://preference-learning.org/index.html#Datasets # https://www.kamishima.net/sushi/ import csv # Leer las descripciones de los objetos (descripciones de sushi) Objetos={} # Diccionario de key:idSushi, value:atributos de sushi with open('datasets/sushi/sushi3-2016/sushi3.idata', newline='') as icsv: csvreader = csv.reader(icsv, delimiter='\t') for row in csvreader: [idEje,XEje]=getObjeto(row) print(row) print(XEje) Objetos[idEje]=XEje print('Leídas {} descripciones de sushi'.format(len(Objetos))) #%% Leer las puntuaciones y crear el conjunto de datos de ranking Xsushi=[] Ysushi=[] with open('datasets/sushi/sushi3-2016/sushi3b.5000.10.score', newline='') as icsv: csvreader = csv.reader(icsv, delimiter=' ') idLote=0 for row in csvreader: [LoteX,LoteY]=getLote(Objetos,row,idLote) Xsushi=Xsushi+LoteX Ysushi=Ysushi+LoteY idLote=idLote+1 # if idLote>=1000: # break print('Creados {} ejemplos valorados a partir de {} lotes'. format(len(Ysushi),idLote)) #%% Actividad presencial 1: Estimar la calidad # Estima el CIndex del conjunto de datos (Xsushi,Ysushi) utilizando como ranker #linearRank con valores por defecto. # Imprime el resultado. #<TODO BEGIN Actividad 1> # # Estimación por validación cruzada (3 folds) del CIndex # cv = cross_validate(ranker, Xsushi, Ysushi, # scoring=make_scorer(CIndex), # cv=3) # print('CIndex (proporción de pares correctamente ordenados en cada lote): {:6.4f}' # .format(cv['test_score'].mean())) #<TODO END Actividad 1> #%% Actividad presencial 2: compara dos sushis # Utiliza el modelo del que se ha estimado el CIndex para evaluar estos 2 sushis: # Objetos según se leen del CSV s1Ori=['7','tamago','1','1','9','2.36807095343681','1.86622320768662','1.03246753246753','0.84'] s2Ori=['8','toro','1','0','1','0.551854655563967','2.05753217259652','4.48545454545455','0.8'] # Objetos con valores numéricos [ids1,s1]=getObjeto(s1Ori) [ids2,s2]=getObjeto(s2Ori) # 2.1 : Crea el modelo # 2.2 : Evalua ambos sushis, imprime sus evaluaciones # 2.3 : Implementa el código que indique cual es el mejor #<TODO BEGIN Actividad 2> # Paso a paso # 2.1 : Crea el modelo import numpy as np from xgboost import XGBRanker # === 1. Convertir Xsushi y Ysushi a arrays === X = np.array(Xsushi, dtype=np.float32) y = np.array([v for (v, lote) in Ysushi], dtype=np.float32) qids = np.array([lote for (v, lote) in Ysushi], dtype=np.int32) # === 2. Ordenar por ID de lote (requerido por XGBoost) === order = np.argsort(qids, kind="stable") X = X[order] y = y[order] qids = qids[order] # === 3. Obtener tamaños de grupo === _, counts = np.unique(qids, return_counts=True) group_sizes = counts.tolist() # === 4. Crear modelo con valores por defecto === model = XGBRanker( objective="rank:ndcg", # valor por defecto para ranking eval_metric="ndcg", # métrica estándar de ranking ) # === 5. Entrenar el modelo === model.fit(X, y, group=group_sizes) print("Modelo XGBRanker entrenado correctamente.") # 2.2 : Evalua ambos sushis, imprime sus evaluaciones p=model.predict([s1,s2]) # 2.3 : Implementa el código que indique cual es el mejor if p[0]>p[1]: mejor=s1Ori[1] peor= s2Ori[1] else: mejor=s2Ori[1] peor= s1Ori[1] print('Sushi {} mejor que sushi {}'.format(mejor,peor)) #<TODO END Actividad 2>

Tema 2 Sesion 1

Apartado A

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 2 : Cambios en la distribución Sesión 1 : Cuantificación Bloque A : Problemas de cuantificación """ from genToy import genToy from quantificationlib.baselines.cc import CC from quantificationlib.baselines.ac import AC,PAC from quantificationlib.multiclass.df import DFX import numpy as np import random from sklearn.svm import SVC import matplotlib.pyplot as plt # Generar conjuntos con diferente prevalencia en entrenamiento que en test preTr=0.5 # Prevalencia de entrenamiento preTe=0.05 # Prevalencia de test print('Prevalencia de generación: entrenamiento:{:4} test : {}'.format(preTr,preTe)) RG=random.Random() RG.seed(1) [XTr,YTr]=genToy(RG,100,prevalencia=preTr) # Mirar genToy.py [XTe,YTe]=genToy(RG,100,prevalencia=preTe) #%% Representación gráfica def pintaXY(X,Y,ax,tit,color0,color1): iPos=np.nonzero(Y)[0] # índices positivos iNeg=np.nonzero(Y-1)[0] # índices negativos ax.set_title(tit) ax.set_xlim([-4,+4]) ax.set_ylim([-4,+4]) ax.set_xlabel('Atributo 0') ax.set_ylabel('Atributo 1') ax.plot(X[iPos,0],X[iPos,1],'o',color=color1,label='Pos') ax.plot(X[iNeg,0],X[iNeg,1],'o',color=color0,label='Neg') if color0!=color1: ax.legend() fig,axs=plt.subplots(1,2,figsize=[6,3],layout='tight') pintaXY(XTr,YTr,axs[0],'Entrenamiento\nPrevalencia={}'.format(preTr),color0='blue',color1='green') pintaXY(XTe,YTe,axs[1],'Test (Sin categoría)\nPrevalencia=¿?',color0='grey',color1='grey') plt.savefig('CuantiEntrenamiento.pdf') fig=plt.figure(figsize=[3,3],layout='tight') pintaXY(XTe,YTe,plt.axes(),'Test\nPrevalencia={}'.format(preTe),color0='blue',color1='green') plt.savefig('CuantiTest.pdf') #%% Proceso de cuantificación # Clasificador Class=SVC(kernel='linear',C=1,probability=True) Class.fit(XTr,YTr) # Modelo # Clasificación del test ClaTe=Class.predict(XTe) # Estimación de probabilidad del entrenamiento y del test ProTr=Class.predict_proba(XTr) ProTe=Class.predict_proba(XTe) Nombres=['CC','AC','PAC','HFX'] PE=[None]*4 # Prevalencia estimada de cada algoritmo # Estimar la prevalencia con los diferentes algoritmos de cuantificación #%% CC Q=CC(estimator_test=Class) Q.fit(XTr,YTr) pres=Q.predict(XTe) pre=pres[np.argwhere(Q.classes_==1)[0][0]] PE[0]=pre #%% AC Q=AC(estimator_train=Class, estimator_test=Class) Q.fit(XTr,YTr) pres=Q.predict(XTe) pre=pres[np.argwhere(Q.classes_==1)[0][0]] PE[1]=pre #%% PAC Q=PAC(estimator_train=Class, estimator_test=Class) Q.fit(XTr,YTr) pres=Q.predict(XTe) pre=pres[np.argwhere(Q.classes_==1)[0][0]] PE[2]=pre #%% HDX Q=DFX() Q.fit(XTr,YTr) pres=Q.predict(XTe) pre=pres[np.argwhere(Q.classes_==1)[0][0]] PE[3]=pre #%% Calculo del valor de pérdida # Cálculo de P. Te. (Prevalencia del test) PTe=len(np.nonzero(YTe)[0])/len(YTe) print('Prevalencia obtenida del test : {:6.4f}'.format(PTe)) # Imprimir la PE y el valor de pérdida para algoritmo de cuantificación # l1 : distancia lineal, norma 1 (diferencia en valor absoluto) # l2 : distancia cuadrática, norma 2 (diferencia al cuadrado) for iac in range(len(PE)): pre=PE[iac] print('Prevalencia del test estimada con {:3}: {:6.4f} l1={:6.4f} l2={:6.4f}' .format(Nombres[iac],pre,abs(pre-PTe),(pre-PTe)**2)) #%% Ejercicio 1 # Para el experimento anterior variar la prevalencia del conjunto de test de #0,05 a 0,95 con paso 0,05. # Calcular la pérdida l1 y l2 para los 4 sistemas de cuantificación e imprimirla # Optativo: # Almacenar los valores l1 y hacer una gráfica # SALIDA: """ Prevalencia obtenida del test : 0.0500 Prevalencia del test estimada con CC : 0.1600 l1=0.1100 l2=0.0121 Prevalencia del test estimada con AC : 0.0476 l1=0.0024 l2=0.0000 Prevalencia del test estimada con PAC: 0.0557 l1=0.0057 l2=0.0000 Prevalencia del test estimada con HDy: 0.0911 l1=0.0411 l2=0.0017 Prevalencia obtenida del test : 0.1000 Prevalencia del test estimada con CC : 0.1400 l1=0.0400 l2=0.0016 Prevalencia del test estimada con AC : 0.0238 l1=0.0762 l2=0.0058 Prevalencia del test estimada con PAC: 0.0689 l1=0.0311 l2=0.0010 Prevalencia del test estimada con HDy: 0.1059 l1=0.0059 l2=0.0000 Prevalencia obtenida del test : 0.1500 Prevalencia del test estimada con CC : 0.2500 l1=0.1000 l2=0.0100 Prevalencia del test estimada con AC : 0.1548 l1=0.0048 l2=0.0000 Prevalencia del test estimada con PAC: 0.1610 l1=0.0110 l2=0.0001 Prevalencia del test estimada con HDy: 0.1705 l1=0.0205 l2=0.0004 Prevalencia obtenida del test : 0.2000 Prevalencia del test estimada con CC : 0.2800 l1=0.0800 l2=0.0064 Prevalencia del test estimada con AC : 0.1905 l1=0.0095 l2=0.0001 Prevalencia del test estimada con PAC: 0.1997 l1=0.0003 l2=0.0000 Prevalencia del test estimada con HDy: 0.1892 l1=0.0108 l2=0.0001 Prevalencia obtenida del test : 0.2500 Prevalencia del test estimada con CC : 0.3400 l1=0.0900 l2=0.0081 Prevalencia del test estimada con AC : 0.2619 l1=0.0119 l2=0.0001 Prevalencia del test estimada con PAC: 0.2755 l1=0.0255 l2=0.0006 Prevalencia del test estimada con HDy: 0.3138 l1=0.0638 l2=0.0041 Prevalencia obtenida del test : 0.3000 Prevalencia del test estimada con CC : 0.3600 l1=0.0600 l2=0.0036 Prevalencia del test estimada con AC : 0.2857 l1=0.0143 l2=0.0002 Prevalencia del test estimada con PAC: 0.2995 l1=0.0005 l2=0.0000 Prevalencia del test estimada con HDy: 0.3360 l1=0.0360 l2=0.0013 Prevalencia obtenida del test : 0.3500 Prevalencia del test estimada con CC : 0.3800 l1=0.0300 l2=0.0009 Prevalencia del test estimada con AC : 0.3095 l1=0.0405 l2=0.0016 Prevalencia del test estimada con PAC: 0.3267 l1=0.0233 l2=0.0005 Prevalencia del test estimada con HDy: 0.3233 l1=0.0267 l2=0.0007 Prevalencia obtenida del test : 0.4000 Prevalencia del test estimada con CC : 0.4300 l1=0.0300 l2=0.0009 Prevalencia del test estimada con AC : 0.3690 l1=0.0310 l2=0.0010 Prevalencia del test estimada con PAC: 0.3893 l1=0.0107 l2=0.0001 Prevalencia del test estimada con HDy: 0.3701 l1=0.0299 l2=0.0009 Prevalencia obtenida del test : 0.4500 Prevalencia del test estimada con CC : 0.4900 l1=0.0400 l2=0.0016 Prevalencia del test estimada con AC : 0.4405 l1=0.0095 l2=0.0001 Prevalencia del test estimada con PAC: 0.4659 l1=0.0159 l2=0.0003 Prevalencia del test estimada con HDy: 0.4863 l1=0.0363 l2=0.0013 Prevalencia obtenida del test : 0.5000 Prevalencia del test estimada con CC : 0.5200 l1=0.0200 l2=0.0004 Prevalencia del test estimada con AC : 0.4762 l1=0.0238 l2=0.0006 Prevalencia del test estimada con PAC: 0.4926 l1=0.0074 l2=0.0001 Prevalencia del test estimada con HDy: 0.5060 l1=0.0060 l2=0.0000 Prevalencia obtenida del test : 0.5500 Prevalencia del test estimada con CC : 0.5600 l1=0.0100 l2=0.0001 Prevalencia del test estimada con AC : 0.5238 l1=0.0262 l2=0.0007 Prevalencia del test estimada con PAC: 0.5049 l1=0.0451 l2=0.0020 Prevalencia del test estimada con HDy: 0.5371 l1=0.0129 l2=0.0002 Prevalencia obtenida del test : 0.6000 Prevalencia del test estimada con CC : 0.6100 l1=0.0100 l2=0.0001 Prevalencia del test estimada con AC : 0.5833 l1=0.0167 l2=0.0003 Prevalencia del test estimada con PAC: 0.5858 l1=0.0142 l2=0.0002 Prevalencia del test estimada con HDy: 0.5723 l1=0.0277 l2=0.0008 Prevalencia obtenida del test : 0.6500 Prevalencia del test estimada con CC : 0.6300 l1=0.0200 l2=0.0004 Prevalencia del test estimada con AC : 0.6071 l1=0.0429 l2=0.0018 Prevalencia del test estimada con PAC: 0.5958 l1=0.0542 l2=0.0029 Prevalencia del test estimada con HDy: 0.6056 l1=0.0444 l2=0.0020 Prevalencia obtenida del test : 0.7000 Prevalencia del test estimada con CC : 0.6800 l1=0.0200 l2=0.0004 Prevalencia del test estimada con AC : 0.6667 l1=0.0333 l2=0.0011 Prevalencia del test estimada con PAC: 0.6736 l1=0.0264 l2=0.0007 Prevalencia del test estimada con HDy: 0.6793 l1=0.0207 l2=0.0004 Prevalencia obtenida del test : 0.7500 Prevalencia del test estimada con CC : 0.7500 l1=0.0000 l2=0.0000 Prevalencia del test estimada con AC : 0.7500 l1=0.0000 l2=0.0000 Prevalencia del test estimada con PAC: 0.7620 l1=0.0120 l2=0.0001 Prevalencia del test estimada con HDy: 0.7285 l1=0.0215 l2=0.0005 Prevalencia obtenida del test : 0.8000 Prevalencia del test estimada con CC : 0.8100 l1=0.0100 l2=0.0001 Prevalencia del test estimada con AC : 0.8214 l1=0.0214 l2=0.0005 Prevalencia del test estimada con PAC: 0.7959 l1=0.0041 l2=0.0000 Prevalencia del test estimada con HDy: 0.8141 l1=0.0141 l2=0.0002 Prevalencia obtenida del test : 0.8500 Prevalencia del test estimada con CC : 0.7900 l1=0.0600 l2=0.0036 Prevalencia del test estimada con AC : 0.7976 l1=0.0524 l2=0.0027 Prevalencia del test estimada con PAC: 0.7973 l1=0.0527 l2=0.0028 Prevalencia del test estimada con HDy: 0.8137 l1=0.0363 l2=0.0013 Prevalencia obtenida del test : 0.9000 Prevalencia del test estimada con CC : 0.8500 l1=0.0500 l2=0.0025 Prevalencia del test estimada con AC : 0.8690 l1=0.0310 l2=0.0010 Prevalencia del test estimada con PAC: 0.8860 l1=0.0140 l2=0.0002 Prevalencia del test estimada con HDy: 0.9082 l1=0.0082 l2=0.0001 Prevalencia obtenida del test : 0.9500 Prevalencia del test estimada con CC : 0.8600 l1=0.0900 l2=0.0081 Prevalencia del test estimada con AC : 0.8810 l1=0.0690 l2=0.0048 Prevalencia del test estimada con PAC: 0.8882 l1=0.0618 l2=0.0038 Prevalencia del test estimada con HDy: 0.8994 l1=0.0506 l2=0.0026 """ #<TODO BEGIN Ejercicio 1> from quantificationlib.baselines.cc import CC from quantificationlib.baselines.ac import AC,PAC from quantificationlib.multiclass.df import DFX l1s=[] # Almacena todas las pérdidas l1 PorPreTes=list(range(5,100,5)) for PorPreTe in PorPreTes: # Porcentaje de prevalencia de test preTe=PorPreTe/100 # Prevalencia en proporcion [XTe,YTe]=genToy(RG,100,prevalencia=preTe) # Estimación de clasificación del test ClaTe=Class.predict(XTe) # Genera las predicciones de clase del clasificador entrenado (Class) para el test. # Estimación de probabilidad del test ProTe=Class.predict_proba(XTe) # Genera las predicciones probabilísticas del clasificador (probabilidad de cada clase). # Estimar la prevalencia con los diferentes algoritmos de cuantificación # CC Q=CC(estimator_test=Class) #Crea un cuantificador CC usando el clasificador Class para estimar las clases del test. Q.fit(XTr,YTr) pres=Q.predict(XTe) #Obtiene el vector de prevalencias estimadas para cada clase. pre=pres[np.argwhere(Q.classes_==1)[0][0]] #Extrae la prevalencia estimada solo para la clase positiva (1). PE[0]=pre # AC Q=AC(estimator_train=Class, estimator_test=Class) #6.1 Crea cuantificador AC usando el clasificador para entrenamiento y test. Q.fit(XTr,YTr) pres=Q.predict(XTe) #Calcula las prevalencias ajustadas. pre=pres[np.argwhere(Q.classes_==1)[0][0]] #Extrae prevalencia estimada de la clase positiva. PE[1]=pre # PAC Q=PAC(estimator_train=Class, estimator_test=Class) # Inicializa el cuantificador PAC. Q.fit(XTr,YTr) pres=Q.predict(XTe,predictions_test=ProTe) #Predice la prevalencia usando las probabilidades estimadas del test. pre=pres[np.argwhere(Q.classes_==1)[0][0]] #Toma la prevalencia estimada para la clase positiva. PE[2]=pre # HDy Q=DFX() #Crea el cuantificador basado en distancia de Hellinger. Q.fit(XTr,YTr) pres=Q.predict(XTe) #Extrae la prevalencia de la clase positiva. pre=pres[np.argwhere(Q.classes_==1)[0][0]] PE[3]=pre # Cálculo de P. Te. (Prevalencia del test) PTe=len(np.nonzero(YTe)[0])/len(YTe) #Calcula la prevalencia real de la clase 1 en el test: #np.nonzero(YTe) obtiene índices donde YTe==1. #Divide entre el total de YTe. print('\nPrevalencia obtenida del test : {:6.4f}'.format(PTe)) # Imprimir la PE y el valor de pérdida para algoritmo de cuantificación # l1 : distancia lineal, norma 1 (diferencia en valor absoluto) # l2 : distancia cuadrática, norma 2 (diferencia al cuadrado) l1sc=[None]*4 # l1 para sistema de cuentificación for iac in range(len(PE)): pre=PE[iac] print('Prevalencia del test estimada con {:3}: {:6.4f} l1={:6.4f} l2={:6.4f}' .format(Nombres[iac],pre,abs(pre-PTe),(pre-PTe)**2)) l1sc[iac]=abs(pre-PTe) l1s.append(l1sc) # Almacenar las l1 de cada sistema # Gráfica l1s=np.array(l1s) # Lo convierto a numpy.ndarray para poder seleccionar columnas PreTes=list(map(lambda x:x/100,PorPreTes)) # Dividir entre 100 cada Porcentaje de Prevalencia plt.figure() for iac in range(len(PE)): plt.plot(PreTes,l1s[:,iac],label=Nombres[iac]) plt.legend() plt.xticks([0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]) plt.xlabel('Prevalencia') plt.ylabel('l1') plt.savefig('Prevalencia_l1_4Algoritmos.pdf') #<TODO END Ejercicio 1>

Apartado B

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 2 : Cambios en la distribución Sesión 1 : Cuantificación Bloque B : Estimar pérdida en cuantificación """ from genToy import genToy from quantificationlib.baselines.cc import CC from quantificationlib.baselines.ac import AC,PAC from quantificationlib.multiclass.df import DFX from quantificationlib.bag_generator import PriorShift_BagGenerator from QUtils import dataSetFromQBags # from cuanti.utils import create_bags_with_multiple_prevalence import numpy as np import random from sklearn.svm import SVC from sklearn.model_selection import train_test_split # La estimación de funcioners de calidad en preTr=0.5 # Prevalencia de entrenamiento print('Prevalencia de generación: entrenamiento:{:4}'.format(preTr)) RG=random.Random() RG.seed(1) # Generar un conjunto de datos [X,Y]=genToy(RG,1000,prevalencia=preTr) # Dividirlo en entrenamiento y test [XTr,XTe,YTr,YTe]=train_test_split(X,Y,test_size=1/3,random_state=1,stratify=Y) # Crear el modelo de entrenamiento # Clasificador Class=SVC(kernel='linear',C=1,probability=True) # AC Q=AC(estimator_train=Class, estimator_test=Class) Q.fit(XTr,YTr) l1s=[] # Crear diferentes conjuntos de test con distinta prevalencia n_bags=100 BG=PriorShift_BagGenerator(n_bags=n_bags,random_state=1) bags=BG.generate_bags(XTe,YTe) for i in range(n_bags): [Xb,Yb]=dataSetFromQBags(XTe,YTe,bags,i) p=np.mean(Yb) pres=Q.predict(Xb) pe=pres[np.argwhere(Q.classes_==1)[0][0]] # Predicted prevalence l1=abs(pe-p) print('Prevalencia test:{:6.4f} AC:{:6.4f} l1={:6.4f}'.format(p,pe,l1)) l1s.append(l1) print('AC , l1 medio:{:6.4f}\n'.format(np.mean(l1s))) #%% Ejericio 1 # Para el sistema DFX para cada uno de los valores de bins [4,8,12] estimar l1 y l2 # SALIDA: """ DFX n_bins: 4 , l1 medio=0.019924 l2 medio=0.000614 DFX n_bins: 8 , l1 medio=0.021082 l2 medio=0.000673 DFX n_bins:12 , l1 medio=0.023663 l2 medio=0.000822 """ # #<TODO BEGIN Ejercicio 1> from genToy import genToy from quantificationlib.baselines.cc import CC from quantificationlib.baselines.ac import AC,PAC from quantificationlib.multiclass.df import DFX from quantificationlib.bag_generator import PriorShift_BagGenerator from QUtils import dataSetFromQBags bins=[4,8,12] l1bins=[] l2bins=[] for n_bins in bins: Q=DFX(n_bins=n_bins) #Crea un cuantificador DFX con el número de bins actual. Q.fit(XTr,YTr) l1s=[] l2s=[] # Crear diferentes conjuntos de test con distinta prevalencia n_bags=100 BG=PriorShift_BagGenerator(n_bags=n_bags,random_state=1) #Crea el generador de bolsas: bags=BG.generate_bags(XTe,YTe) #Genera n_bags bolsas a partir del dataset de test original XTe,YTe. for i in range(n_bags): [Xb,Yb]=dataSetFromQBags(XTe,YTe,bags,i) #Construye el dataset correspondiente a la bolsa i: p=np.mean(Yb) #Calcula la prevalencia real de la bolsa como la media de Yb (0/1). pres=Q.predict(Xb) #Obtiene las prevalencias estimadas por DFX para cada clase. pe=pres[np.argwhere(Q.classes_==1)[0][0]] # Predicted prevalence l1=abs(pe-p) #Extrae la prevalencia estimada de la clase positiva (1). l2=l1**2 # print('Prevalencia test:{:6.4f} PAC:{:6.4f} l1={:6.4f} l2={:6.4f}'.format(prev,pp,l1,l2)) l1s.append(l1) l2s.append(l2) l1bin=np.mean(l1s) l2bin=np.mean(l2s) l1bins.append(l1bin) l2bins.append(l2bin) print('DFX n_bins:{:2} , l1 medio={:8.6f} l2 medio={:8.6f}'. format(n_bins,l1bin,l2bin)) # #<TODO END Ejercicio 1>

Prepresencial

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ author: quevedo@uniovi.es """ from genToy import genToy import numpy as np import random from sklearn.svm import SVC import matplotlib.pyplot as plt # Generar conjuntos con diferente prevalencia en entrenamiento que en test nEjemplos=100 preTrDe=0.5 # Prevalencia de entrenamiento deseada RG=random.Random() RG.seed(1) [XTr,YTr]=genToy(RG,nEjemplos,prevalencia=preTrDe) # Mirar genToy.py pTr=np.mean(YTr) print('Prevalencia generada: entrenamiento :{:4.2f}'.format(pTr)) # Entrenar el clasificador Class=SVC(kernel='linear',C=1,probability=True) Class.fit(XTr,YTr) # Test [XTe,YTe]=genToy(RG,nEjemplos,prevalencia=0.95) # Generar ejemplo de test pTe=np.mean(YTe) print('Prevalencia generada: test :{:4.2f}'.format(pTe)) P=Class.predict(XTe) # Evaluar pCC=np.mean(P) # Prevalencia de la evaluación (Classify and Count) print('Prevalencia Clasificar y Contar (CC):{:4.2f}'.format(pCC)) PTes=[] PCCs=[] pTeDes=[por/100 for por in range(0,100,5)] for pTeDe in pTeDes: [XTe,YTe]=genToy(RG,nEjemplos,prevalencia=pTeDe) # Generar ejemplo de test pTe=np.mean(YTe) # Calcular prevalencia del test P=Class.predict(XTe) # Evaluar pCC=np.mean(P) # Prevalencia de la evaluación (Classify and Count) # Guardar los valores PTes.append(pTe) PCCs.append(pCC) # Gráfica plt.figure() plt.plot(PTes,PCCs,label='Prevalencia CC') plt.plot(PTes,PTes,label='Prevalencia Test') plt.plot([pTr],[pTr],label='Prevalencia entrenamiento',marker='+',markersize=20) plt.xlabel('Prevalencia de test') plt.ylabel('Prevalencia Clasificar y Contar') plt.xticks(pTeDes,rotation=90) plt.legend() plt.grid() plt.savefig('PreSesion.pdf',bbox_inches='tight')

QUtils

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ @author: quevedo@uniovi.es """ import numpy as np def dataSetFromQBags(X,Y,bags,n): """ Creates the dataset of the bag n from the dataset (X|Y) Params: X,Y : Data Set Attributess/Category bags : Bags returned by BagGenerator.generate_bags n : index of the bag in [0, n_bag] , where n_bag is the parameter of BagGenerator Returns [Xb,Yb: Xb|Yb : bag dataset """ # p=bags[0][0][n] inds=bags[1][:,n] Xb=[] Yb=[] for i in inds: Xb.append(X[i]) Yb.append(Y[i]) return [np.array(Xb),np.array(Yb)]

Tema 2 Sesion 2

Apartado A

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 2 : Cambios en la distribución Sesión 2 : Importancia Bloque A : Algoritmos de Estimación de la Importancia """ from IEM.IEM import CI,PIE,DIE,KLIEP import random import matplotlib.pyplot as plt import numpy as np from gen1DimNormal import gen1DimNormal #%% Ejercicio 1 # Modifica la generación del entrenamiento para que tenga una desviación típica de 10 # Ejecuta el bloque A y obtén las gráficas. # El test está distribuído en una zona más pequeña que el entrenamiento. # Las importancias para KLIEP y KDE se ajustan a esa zona, pero para PE no. # El problam para PE es que usa como clasficador probabilístico LogisticRegression #que es lineal. Prueba con otro clasificador probabilístico no lineal y comprueba #que se ajusta. # NOTA: Este código es una copia del bloque A, modificar lo que sea necesario # PISTA: SVC puede ser usado como clasificador probabilístico. from sklearn.svm import SVC #%% Creación de conjuntos con diferente distribución en X # Se crean dos conjuntos de ejemplos sin categoría (solo X) con un solo atributo. # XTrain tiene valores siguiendo una distribución normal(media=-1,sd=1) # XTest tiene valores siguiendo una distribución normal(media=+1,sd=1) RG=random.Random() RG.seed(1) nEje=100 dt=1 XTrain=gen1DimNormal(RG,nEje,-1,dt) XTest=gen1DimNormal(RG,nEje,+1,dt) #%% Dibujar la distribución del entrenamiento y test bins=10 fig=plt.figure() plt.title('Distribución de entrenamiento y test') plt.hist(XTrain[:,0],bins=bins,color='blue',label='XTrain',histtype='step') # fig=plt.figure() plt.hist(XTest[:,0],bins=bins,color='green',label='XTest',histtype='step') plt.legend() plt.xlabel('X') plt.ylabel('Número de ejemplos en cada bin') # plt.savefig('DistriEntre10Test1.pdf') #%% Cálculo de la importancia utilizando estimadores de importancia SVCProb=SVC(kernel='rbf',C=1,probability=True) IEs=[CI(),PIE(ProbClass=SVCProb),DIE(),KLIEP()] Importancias=[None]*4 # Importancias de cada estimador for iie in range(len(IEs)): IE=IEs[iie] # Obtener el Estimador de Importancia IE.fit(XTrain) # Utilizar el train (si fuera necesario) imp=IE.importance(XTest) # Calcular la importancia Importancias[iie]=imp # Almacenar la importancia del estimador #%% Mostrar en una gráfica las importancias calculadas fig,[[ax1,ax2],[ax3,ax4]]=plt.subplots(2,2,figsize=[8,5],layout='tight') axes=[ax1,ax2,ax3,ax4] for iie in range(len(IEs)): # Realizar la gráfica axe=axes[iie] # Obtener el eje donde pintar X=XTrain[:,0] # Tomar el primer atributo (solo hay uno) axe.plot(X,Importancias[iie],'x',color='blue') # Pintar la gráfica axe.set_title(IEs[iie].getName()) # Nombre del Estimador de importancia axe.set_xlabel('X') axe.set_ylabel('Importancia') # plt.savefig('ImportanciasLREntre10Test1.pdf') # plt.savefig('ImportanciasSVCProbaEntre10Test1.pdf') #<TODO END Ejercicio 1>

Apartado B

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 2 : Cambios en la distribución Sesión 2 : Importancia Bloque B : Estimación del error con Importancia """ from IEM.IEM import CI,PIE,DIE,KLIEP import random import matplotlib.pyplot as plt import numpy as np from sklearn.model_selection import cross_val_predict from sklearn.model_selection import train_test_split from QUtils import dataSetFromQBags from quantificationlib.bag_generator import PriorShift_BagGenerator from sklearn.svm import SVC from sklearn.metrics import zero_one_loss from gen1DimNormal import gen1DimNormal def genNormalMasMenos1(RG,nMas,nMenos): """ Se crea un conjunto de ejemplos con un atributo donde los de clase +1 tienen una distribución normal(+1,+1) y los de clase negativa normal(-1,+1) Params: RG : random.Random() nMas : Nº de ejemplos positivos nMenos : Nº de ejemplos negativos """ X=[] Y=[] for i in range(nMas): x=RG.normalvariate(+1,2) X.append([x]) Y.append(+1) for i in range(nMenos): x=RG.normalvariate(-1,2) X.append([x]) Y.append(-1) return [X,Y] #%% Información Inicial # Creación de conjuntos con diferente distribución en X # Se crea un conjunto de ejemplos con un atributo donde los de clase +1 tienen # una distribución normal(+1,+1) y los de clase negativa normal(-1,+1) RG=random.Random() RG.seed(1) [XTr,YTr]=genNormalMasMenos1(RG,nMas=20,nMenos= 5) [XTe,YTe]=genNormalMasMenos1(RG,nMas= 5,nMenos=20) # Fíjate en la diferencia con el Train (cambian los Mas por los Menos) # Crear un clasifiador Class=SVC(kernel='linear',C=1) # Generadores de importancia con los que estimar el error IEs=[CI(),PIE(),DIE()] #%% Aplicar la importancia para estimar el error del test XTe,YTe # Errores en entrenamiento CVPreds=cross_val_predict(Class,XTr,YTr,cv=3) # Fíjate que es con todo el conjunto de entrenamiento (y no con una parte Tr2) Errors=[zero_one_loss([YTr[i]],[CVPreds[i]]) for i in range(len(YTr))] print('Estimación del error para el test(Se conoce solo X) usando diferentes importancias') # Para cada Importancia ZOLImp=[] # Los Zero One Loss estimado según cada Importancia for iIE in range(len(IEs)): IE=IEs[iIE] IE.fit(XTr) imp=IE.importance(XTe) # Generar la importancia para el test # Estimar el error según esta importancia ErrsImp=[None]*len(imp) for j in range(len(imp)): ErrsImp[j]=Errors[j]*imp[j] # Se multiplica cada error del CV por esta importancia ErrImp=np.mean(ErrsImp) # La media será la importancia estimada por esta importancia print(' Importancia {:3} zero_one_loss={:6.4f}'.format(IEs[iIE].getName(),np.mean(ErrImp))) ZOLImp.append(ErrImp) #Ejercicio 1 """ Se obtiene la siguiente salida del código anterior: Estimación del error para el test(Se conoce solo X) usando diferentes importancias Importancia CI zero_one_loss=0.1200 Importancia PIE zero_one_loss=0.1470 Importancia DIE zero_one_loss=0.1459 Pregunta 1: ¿Cuál es la mejor importancia? Respuesta : No se puede saber por esta experimentación, habría que conocer el valor de zero_one_loss sobre el test y ver cuál se aproxima más. """ #Ejercicio 2 """ Obtén el error en test. Calcula la l1 de cada estimación de Importancia. """ # Valor verdadero de error en test print() print('Utilizando el test entero(Atributos y Categoría):') Class.fit(XTr,YTr) P=Class.predict(XTe) E=zero_one_loss(YTe,P) print('Error Verdadero en Test : {:6.4f}'.format(E)) l1s=[] for iIE in range(len(IEs)): l1=abs(E-ZOLImp[iIE]) print(' Importancia {:3} l1={:6.4f}'.format(IEs[iIE].getName(),l1)) l1s.append(l1) # Mejor Importancia posMejor=np.argmin(l1s) print('Mejor Importancia: {}'.format(IEs[posMejor].getName()))

Apartado C

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 2 : Cambios en la distribución Sesión 2 : Importancia Bloque C : Estimación de la calidad de la Importancia """ from IEM.IEM import CI,PIE,DIE,KLIEP import random import matplotlib.pyplot as plt import numpy as np from sklearn.model_selection import cross_val_predict from sklearn.model_selection import train_test_split from QUtils import dataSetFromQBags from quantificationlib.bag_generator import PriorShift_BagGenerator from sklearn.svm import SVC from sklearn.metrics import zero_one_loss from gen1DimNormal import gen1DimNormal def genNormalMasMenos1(RG,nMas,nMenos): """ Se crea un conjunto de ejemplos con un atributo donde los de clase +1 tienen una distribución normal(+1,+1) y los de clase negativa normal(-1,+1) Params: RG : random.Random() nMas : Nº de ejemplos positivos nMenos : Nº de ejemplos negativos """ X=[] Y=[] for i in range(nMas): x=RG.normalvariate(+1,2) X.append([x]) Y.append(+1) for i in range(nMenos): x=RG.normalvariate(-1,2) X.append([x]) Y.append(-1) return [X,Y] #%% Información Inicial # Creación de conjuntos con diferente distribución en X # Se crea un conjunto de ejemplos con un atributo donde los de clase +1 tienen # una distribución normal(+1,+1) y los de clase negativa normal(-1,+1) RG=random.Random() RG.seed(1) [XTr,YTr]=genNormalMasMenos1(RG,nMas=20,nMenos= 5) # Crear un clasifiador Class=SVC(kernel='linear',C=1) # Generadores de importancia a evaluar IEs=[CI(),PIE(),DIE()] #%% Estimación de la calidad de la importancia # Hay varias importancias, pero no hay ningún test. Se pretende estimar qué importancia # es la mejor # No se hará validación cruzada, en su lugar se realizará una partición train/test. # Para el test se generarán varios bags con varias distribuciones y se medirá # la calidad del acierto del error # Dividir el entrenamiento en entrenamiento2(Tr2) y test2(Te2) [XTr2,XTe2,YTr2,YTe2]=train_test_split(XTr,YTr,test_size=1/3,random_state=1,stratify=YTr) # Calcular las predicciones y los errores de Tr2 en CV CVPreds=cross_val_predict(Class,XTr2,YTr2,cv=3) Errors=[zero_one_loss([YTr2[i]],[CVPreds[i]]) for i in range(len(YTr2))] # Crear el modelo de clasificación para Tr2 Class.fit(XTr2,YTr2) # Entrenar cada Importancia a evaluar con Tr2 for i in range(len(IEs)): IEs[i].fit(XTr2) # Crear bags a partir del Test 2 n_bags=100 BG=PriorShift_BagGenerator(n_bags=n_bags,random_state=1) bags=BG.generate_bags(XTe2,YTe2) # L1: distancia entre el error estimado por cada importancia y el verdadero de test l1s=[[] for k in range(len(IEs))] for i in range(n_bags): # Crear la bag [Xb,Yb]=dataSetFromQBags(XTe2,YTe2,bags,i) # El error de esta bag Pb=Class.predict(Xb) Eb=zero_one_loss(Yb,Pb) # Error estimado según cada Importancia for iIE in range(len(IEs)): IE=IEs[iIE] imp=IE.importance(Xb) # Generar la importancia para este test # Estimar el error según esta importancia # Será la media del producto del error de cada ejemplo por su importancia ErrImp=np.mean([Errors[j]*imp[j] for j in range(len(imp))]) # Se calcula l1 como la distancia entre el error del modelo y el estimado # por esta importancia l1=abs(Eb-ErrImp) l1s[iIE].append(l1) # Se almacenan los l1 para cada importancia print('Calidad de la estimación del error usando solo el entrenamiento:') for iIE in range(len(IEs)): print(' Estimación calidad usando {:3} l1={:6.4f}'.format(IEs[iIE].getName(),np.mean(l1s[iIE]))) #%% Ejercicio 1 """ Se obtiene la siguiente salida del código anterior: Calidad de la estimación del error usando solo el entrenamiento: Importancia CI l1=0.3076 Importancia PIE l1=0.2226 Importancia DIE l1=0.2564 Pregunta 1: Utilizando solo el entrenamiento, ¿Cuál es la mejor Importancia? Respuesta: La mejor es PIE que tiene el menor l1 """

Apartado D

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 2 : Cambios en la distribución Sesión 2 : Importancia Bloque D : Mejora del aprendizaje con importancia """ from IEM.IEM import CI,PIE,DIE,KLIEP import random import matplotlib.pyplot as plt import numpy as np from sklearn.model_selection import cross_val_predict from sklearn.svm import SVC from sklearn.metrics import zero_one_loss from gen1DimNormal import gen1DimNormal #%% Creación de conjuntos con diferente distribución en X # Se crean dos conjuntos de ejemplos sin categoría (solo X) con un solo atributo. # XTrain tiene valores siguiendo una distribución normal(media=-1,sd=1) # XTest1 tiene valores siguiendo una distribución normal(media=-1,sd=1) # XTest2 tiene valores siguiendo una distribución normal(media=+1,sd=1) # NOTA: El test 1 tiene la misma distribución que el entrenamiento, mientras que # que el test2 la tiene diferente RG=random.Random() RG.seed(1) nEje=100 dt=1 XTrain=gen1DimNormal(RG,nEje,-1,dt) XTest1=gen1DimNormal(RG,nEje,-1,dt) XTest2=gen1DimNormal(RG,nEje,+1,dt) # La categoría será el signo de la X YTrain=list(map(lambda x:np.sign(x[0]),XTrain)) YTest1=list(map(lambda x:np.sign(x[0]),XTest1)) YTest2=list(map(lambda x:np.sign(x[0]),XTest2)) #%% Error en test sin importancia Class=SVC(kernel='linear',C=0.01) Class.fit(XTrain,YTrain) # El modelo es el mismo y se aplica a los 2 test # Test 1 Preds1=Class.predict(XTest1) print('Error sin importancia en test1: {:6.4f}'.format(zero_one_loss(YTest1,Preds1))) # Test 2 Preds2=Class.predict(XTest2) print('Error sin importancia en test2: {:6.4f}'.format(zero_one_loss(YTest2,Preds2))) #%% Utilizar importancia para mejorar el aprendizaje # En el proceso de aprendizaje ponderar cada ejemplo por la importancia permite #adecuar el modelo a la distribución del test. # Tiene como desventaja que hay que hacer un entrenamiento(fit) por cada evaluación #de test con una distribución diferente. # En SVC el método fit tiene el parámetro sample_weight que permite dar un peso #a cada ejemplo. Asignado a ese parámetro la importancia se permite ajustar el #modelo según la importancia # Estimador y cálculo de importancias para XTrain con respecto XTest1 y XTest2 IE=PIE() IE.fit(XTrain) imp1PIE=IE.importance(XTest1) imp2PIE=IE.importance(XTest2) # Test 1 Class.fit(XTrain,YTrain,sample_weight=imp1PIE) # El modelo es particular para este test Preds1=Class.predict(XTest1) print('Error con importancia en test1: {:6.4f}'.format(zero_one_loss(YTest1,Preds1))) # Test 2 Class.fit(XTrain,YTrain,sample_weight=imp2PIE) # El modelo es particular para este test Preds2=Class.predict(XTest2) print('Error con importancia en test2: {:6.4f}'.format(zero_one_loss(YTest2,Preds2))) #%% Ejercicio 1 # Variar la media del test desde -3 hasta +3 de uno en uno. # Calcular e imprimir el error en test sin y con importancia PIE # Opcional hacer una gráfica #SALIDA: # Ejercicio 1 # Entrenamiento media:-1 # Test media:-3. Error: sin importancia=0.0100 con importancia=0.0100 # Test media:-2. Error: sin importancia=0.0400 con importancia=0.0400 # Test media:-1. Error: sin importancia=0.1500 con importancia=0.1500 # Test media:+0. Error: sin importancia=0.4300 con importancia=0.0600 # Test media:+1. Error: sin importancia=0.8600 con importancia=0.1400 # Test media:+2. Error: sin importancia=0.9300 con importancia=0.0700 # Test media:+3. Error: sin importancia=1.0000 con importancia=0.0000 from IEM.IEM import CI,PIE,DIE,KLIEP import random import matplotlib.pyplot as plt import numpy as np from sklearn.model_selection import cross_val_predict from sklearn.svm import SVC from sklearn.metrics import zero_one_loss from gen1DimNormal import gen1DimNormal print('\nEjercicio 1') ErroresSin=[] # Almacenar errores y m para gráfica ErroresCon=[] ms=[] print('Entrenamiento media:-1') for m in range(-3,+3+1): ms.append(m) # Almaceno las m print('Test media:{:+d}. Error: '.format(m),end='') XTest=gen1DimNormal(RG,nEje,m,dt) # Generar el test YTest=list(map(lambda x:np.sign(x[0]),XTest)) # Sin importancia #<TODO BEGIN Ejercicio 1.1> Class.fit(XTrain,YTrain) #Entrena el clasificador base (Class) normalmente, sin pesos. PredsSin=Class.predict(XTest) # Evaluación del modelo ErrorSin=zero_one_loss(YTest,PredsSin) print('sin importancia={:6.4f} '.format(ErrorSin),end='') ErroresSin.append(ErrorSin) # Almaceno los errores sin importancia #<TODO END Ejercicio 1.1> # Con importancia #<TODO BEGIN Ejercicio 1.2> impPIE=IE.importance(XTest) #Calcula los pesos de importancia (importance weights) para cada ejemplo del test, usando el método de Importance Estimation (IE): # El peso mide cuánto cambia la distribución del test respecto al training. Class.fit(XTrain,YTrain,sample_weight=impPIE) #Entrena el clasificador, pero ahora cada ejemplo del training se pondera según los pesos de importancia. Esto ajusta el modelo a la distribución del test. PredsCon=Class.predict(XTest) # Evaluación del modelo ErrorCon=zero_one_loss(YTest,PredsCon) print('con importancia={:6.4f}'.format(ErrorCon)) ErroresCon.append(ErrorCon) # Almaceno los errores con importancia #<TODO END Ejercicio 1.2> # Gráfica plt.figure(figsize=[5,3],layout='tight') plt.title('Media de X en entrenamiento:-1. Y=sign(X)') plt.plot(ms,ErroresSin,label='Sin importancia') plt.plot(ms,ErroresCon,label='Con importancia') plt.xlabel('Media de X en test') plt.ylabel('Error en test') plt.legend() plt.savefig('ErrorTestSinConImportanciaVariandoDistTest.pdf') #<TODO END Ejercicio 1>

PreNopresencial

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 2 : Cambios en la distribución Sesión 2 : Importancia Bloque A : Algoritmos de Estimación de la Importancia """ import random import matplotlib.pyplot as plt import numpy as np from sklearn.model_selection import cross_val_predict from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier def genEjemplosNegPos(RG,nEje,nEjeNeg): X=[] Y=[] for n in range(nEje): x=[RG.random() for i in range(dim)] # Valor en uniforme(0,1) en dim dimensiones y=1 if sum(x)>dim/2 else -1 # Categoría if n<nEjeNeg and y==1 or n>=nEjeNeg and y==-1: # Hay que hacer un cambio x=[1-n for n in x] y=-y X.append(x) Y.append(y) X=np.array(X) Y=np.array(Y) return [X,Y] #%% Creación de conjuntos con diferente distribución en X # Se crean dos conjuntos de ejemplos sin categoría (solo X) con un solo atributo. # Tanto X # XTrain tiene valores siguiendo una distribución normal(media=-1,sd=1) # XTest1 tiene valores siguiendo una distribución normal(media=+1,sd=1) RG=random.Random() RG.seed(1) dim=2 # Entrenamiento nEje=100 nEjeNeg=90 # Test1 nEjeTest1=100 nEjeNegTest1=10 # Test2 nEjeTest2=100 nEjeNegTest2=90 # Crear entrenamiento y tests [X,Y] =genEjemplosNegPos(RG,nEje,nEjeNeg) [XTe1,YTe1]=genEjemplosNegPos(RG,nEjeTest1,nEjeNegTest1) [XTe2,YTe2]=genEjemplosNegPos(RG,nEjeTest1,nEjeNegTest2) # Entrenamiento Class=SVC(kernel='linear',C=1) # Class=SVC(kernel='rbf',C=1) # Class=RandomForestClassifier() Class.fit(X,Y) # Cross Validation PCV=cross_val_predict(Class,X,Y) FCV=np.where(PCV-Y)[0] # FCVallos # Test1 P1=Class.predict(XTe1) F1=np.where(P1-YTe1)[0] # FCVallos # Test2 P2=Class.predict(XTe2) F2=np.where(P2-YTe2)[0] # FCVallos # Suma de los valores X S=np.array([sum(x) for x in X]) # Pintar entrenamiento fig=plt.figure() plt.plot(S,Y,marker='x',linestyle='none',label='Entrenamiento',color='blue') plt.xlabel('Suma de x') plt.ylabel('Signo de la categoria real') plt.title('Entrenamiento') plt.savefig('T2_S2_Pre_Entrenamiento.pdf') # Pintar CV y Tests fig=plt.figure() # CV plt.plot(S,Y,marker='o',linestyle='none',label='Entre. CV Aciertos',fillstyle='none',color='orange') plt.plot(S[FCV],Y[FCV],marker='o',linestyle='none',label='Entre. CV Fallos',fillstyle='none',color='red') # Test1 STe1=np.array([sum(x) for x in XTe1]) plt.plot(STe1,YTe1*0.5,marker='+',linestyle='none',label='Test1 Aciertos',fillstyle='none',color='green') plt.plot(STe1[F1],YTe1[F1]*0.5,marker='+',linestyle='none',label='Test1 Fallos',fillstyle='none',color='red') # Test2 STe2=np.array([sum(x) for x in XTe2]) plt.plot(STe2,YTe2*0.25,marker='x',linestyle='none',label='Test2 Aciertos',fillstyle='none',color='green') plt.plot(STe2[F2],YTe2[F2]*0.25,marker='x',linestyle='none',label='Test2 Fallos',fillstyle='none',color='red') plt.ylim(-1.5,+1.5) plt.title('Dimensiones={}\n{}'.format(dim,Class)) plt.xlabel('Suma de x') plt.ylabel('Signo de la categoria real') plt.legend() plt.savefig('T2_S2_Pre_CV_Tests.pdf') # plt.savefig('T2_S2_Pre_CV_Test.pdf') # plt.savefig('T2_S2_Pre_CV.pdf') print('Error en CV : {:4.2f}'.format(len(FCV)/len(PCV))) print('Error en test1: {:4.2f}'.format(len(F1)/len(P1))) print('Error en test2: {:4.2f}'.format(len(F2)/len(P2))) # Error y multiplicarlo ErrCV=abs(PCV-Y) ErrCV=[0 if e==0 else 1 for e in ErrCV] # Pintar Error CV fig=plt.figure() plt.title('Error de la CV. Media={}'.format(np.mean(ErrCV))) plt.xlabel('Suma de x') plt.plot(S,ErrCV,marker='|',linestyle='none',label='Error CV',fillstyle='none',color='orange') plt.savefig('T2_S2_Pre_ErrorCV.pdf') # Calcular la importancia # Importancia sin normalizar de cada ejemplo def importanciaNN(x): return x**2 def importancia(X): iNN=np.array([importanciaNN(x) for x in X]) # Cálculo de la importanciaNN de cada ejemplos Media=np.mean(iNN) # Se obtiene la media impor=iNN/Media # Se divide entre la media pra obtener la importancia return impor imporX=importancia(S) # Pintar La importancia fig=plt.figure() plt.title('Importancia. Media={:6.4f}'.format(np.mean(imporX))) plt.xlabel('Suma de x') plt.plot(S,imporX,marker='_',linestyle='none',label='Error CV',fillstyle='none',color='blue') plt.savefig('T2_S2_Pre_Importance.pdf') # Error * importancia ErrCVImp=imporX*ErrCV # Pintar La importancia * error fig=plt.figure() plt.title('Error*Importancia. Media={:6.4f}'.format(np.mean(ErrCVImp))) plt.xlabel('Suma de x') plt.plot(S,ErrCVImp,marker='+',linestyle='none',label='Error CV',fillstyle='none',color='black') plt.savefig('T2_S2_Pre_ErrorCVxImportance.pdf') print('Error*Importancia: {:6.4f}'.format(np.mean(ErrCVImp)))

Actividad 1

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 2 : Cambios en la distribución Sesión 2 : Importancia Actividad 1 """ #%% Actividad 1 # DATOS: # Los datos de origen son tipos de hormigón: # https://archive.ics.uci.edu/ml/datasets/Concrete+Compressive+Strength # Se trata de prededir la fuerza del hormigon en función de varias características #del mismo. # Es un problema de REGRESIÓN # Todo lo visto de la importancia se puede aplicar igual regresión que a clasificación # Los datos se cargan y se dividen en entrenamiento y test: [XTr,YTr,XTe,YTe] # Se proporciona la media del entrenamiento y del test (es un dato equivalente #a la prevalencia) # ENUNCIADO # Se proporcionan dos regresores Reg1 y Reg2 # Se proporciona un estimador de Importancia IE # A Se quiere estimar cual es el mejor según MAE y utilizando IE si fuera conveniente, # en las siguientes SITUACIONES: # A.1 : No se tiene el test, solo se utiliza el entrenamiento (XTr,YTr) # A.2 : Además del entrenamiento se tienen los atributos del test, pero no su cagegoría # B ¿Cuál es el mejor estimador A.1 o A.2? ¿Cómo lo puedes saber? # C. Trata de mejor la predicción del mejor regresor según IE usando la propia IE import csv import numpy as np import random from sklearn.svm import SVR,SVC from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import cross_validate,cross_val_predict from sklearn.metrics import make_scorer,mean_absolute_error from IEM.IEM import PIE,DIE,KLIEP def concreteReader(): def _CategoryGaussNoisyOrder(RG,X,Y): orderVals=[] for v in Y: nv=RG.normalvariate(v,1) orderVals.append(nv) order=np.argsort(orderVals) return [np.array(X)[order],np.array(Y)[order]] X=[] Y=[] FName='imporDataset/Concrete_Data.csv' with open(FName) as Fcsv: csvreader = csv.reader(Fcsv, delimiter=',') header=True for row in csvreader: if header: header=False else: rowNum=list(map(float,row)) X.append(rowNum[:(len(row)-1)]) Y.append(rowNum[len(row)-1]) nEje=len(X) print('Leídos {} ejemplos de cemento media(Y)={:6.4f}'.format(nEje,np.mean(Y))) RG=random.Random() RG.seed(1) [X,Y]=_CategoryGaussNoisyOrder(RG,X,Y) nTr=int(nEje*(9/10)) nTe=nEje-nTr XTr=X[:nTr] YTr=Y[:nTr] XTe=X[nTr:] YTe=Y[nTr:] print(' Entrenamiento: ejemplos:{} media(Y)={:6.4f}'.format(nTr,np.mean(YTr))) print(' Test : ejemplos:{} media(Y)={:6.4f}'.format(nTe,np.mean(YTe))) return [XTr,YTr,XTe,YTe] # Obtener conjunto de datos [XTr,YTr,XTe,YTe]=concreteReader() # ¿Qué regresor es mejor? Reg1=SVR(kernel='linear',C=1) Reg2=RandomForestRegressor() # Estimador de Importancia a utilizar from sklearn.linear_model import LogisticRegression # IE=PIE(LogisticRegression(C=0.01,random_state=1,max_iter=10000)) IE=PIE(SVC(C=100,random_state=1,probability=True,max_iter=10000)) # Para C print('Reg1:',Reg1) print('Reg2:',Reg2) #%% Estimación del MAE sin tener en cuenta el TEST print('\nEstimando mediante CV (Sin utilizar el test)') # BEGIN A.1 CV1=cross_validate(Reg1,XTr,YTr,scoring={'MAE':make_scorer(mean_absolute_error)},cv=3) MAE1_CV=CV1['test_MAE'].mean() CV2=cross_validate(Reg2,XTr,YTr,scoring={'MAE':make_scorer(mean_absolute_error)},cv=3) MAE2_CV=CV2['test_MAE'].mean() # END A.1 print(' REG1 CV MAE={:6.4f}'.format(MAE1_CV)) print(' REG2 CV MAE={:6.4f}'.format(MAE2_CV)) print(' Mejor: ',end='') if MAE1_CV<MAE2_CV: print('Reg1') else: print('Reg2') #%% Estimación del MAE teniendo en cuenta los atributos del test (NO la categoría) # Se usará la importancia para estimar print('\nEstimando mediante CV con atributos de test junto con importancia PIE') # BEGIN A.2 # Errores en CV de cada ejemplo para cada regresor CVPreds1=cross_val_predict(Reg1,XTr,YTr,cv=3) CVErrors1=[mean_absolute_error([YTr[i]],[CVPreds1[i]]) for i in range(len(YTr))] CVPreds2=cross_val_predict(Reg2,XTr,YTr,cv=3) CVErrors2=[mean_absolute_error([YTr[i]],[CVPreds2[i]]) for i in range(len(YTr))] # Importancia PIE IE.fit(XTr) impPIE=IE.importance(XTe) MAE1_PIE=np.mean(np.array(CVErrors1)*np.array(impPIE)) MAE2_PIE=np.mean(np.array(CVErrors2)*np.array(impPIE)) # END A.2 print(' REG1 MAE PIE={:6.4f}'.format(MAE1_PIE)) print(' REG2 MAE PIE={:6.4f}'.format(MAE2_PIE)) print(' Mejor ',end='') if MAE1_PIE<MAE2_PIE: print('Reg1') else: print('Reg2') #%% Aprendizaje, evaluación y medida de error (MAE) del test (Valor verdadero) print('\nCalculando el error en test:') # BEGIN B # Regresor 1 Reg1.fit(XTr,YTr) pred=Reg1.predict(XTe) MAE1_Test=mean_absolute_error(YTe,pred) # Regresor 2 Reg2.fit(XTr,YTr) pred=Reg2.predict(XTe) MAE2_Test=mean_absolute_error(YTe,pred) print(' Reg1: MAE en test={:7.4f}'.format(MAE1_Test)) print(' Reg2: MAE en test={:7.4f}'.format(MAE2_Test)) print(' Mejor ',end='') if MAE1_Test<MAE2_Test: print('Reg1') else: print('Reg2') # END B # BEGIN C #%% Mejora del aprendizaje con importancia (Situación 4) print('\nAprendizaje mejorado con pesos de importancia (sample_weight):') # 1. Calculamos la importancia del entrenamiento respecto al test IE.fit(XTr) imp_train = IE.importance(XTe) # Pesos para cada ejemplo de XTr basados en su relevancia para XTe # 2. Reentrenamos los modelos usando sample_weight # Nota: Reg1 (SVR) y Reg2 (RandomForest) soportan sample_weight en sklearn Reg1.fit(XTr, YTr, sample_weight=imp_train) Reg2.fit(XTr, YTr, sample_weight=imp_train) # 3. Predecimos de nuevo sobre el test real preds1_imp = Reg1.predict(XTe) preds2_imp = Reg2.predict(XTe) # 4. Calculamos el nuevo MAE real MAE1_Test_Imp = mean_absolute_error(YTe, preds1_imp) MAE2_Test_Imp = mean_absolute_error(YTe, preds2_imp) print(' Reg1 con importancia: MAE en test={:7.4f}'.format(MAE1_Test_Imp)) print(' Reg2 con importancia: MAE en test={:7.4f}'.format(MAE2_Test_Imp)) # END C

IEM

import numpy as np import warnings import random from sklearn.linear_model import LogisticRegression from sklearn.neighbors import KernelDensity from IEM.implementations.DRE import DensityRatioEstimator import pdb class ImportanceEstimator: """ Base class for all Importance Estimator Methods Children classes must implement: _fit(self,XTrain) : previous calculous that involve only train _importance(self,XTrain,XTest): train’s importance estimation for this test """ def __init__(self,name=None): """ Params: - name : string , name of the importance estimator """ self.name=name self.XTrain=None def getName(self): return self.name def fit(self,XTrain): self.XTrain=XTrain return self._fit(XTrain) def _fit(self,XTrain): pass def importance(self,XTest): ie=self._importance(self.XTrain,XTest) # Check if min(ie)<0: raise Exception('ImportanceEstimator: {}._imporatance(...) outputs negative importances'.format(self.__class__.__name__)) if len(ie)!=len(self.XTrain): raise Exception('ImportanceEstimator: {}._imporatance(...) outputs {} values and the train dataset len is {}'. format(self.__class__.__name__,len(ie),len(self.XTrain))) # Adjust for mean(ie)=1 meanIE=sum(ie)/len(ie) if meanIE==0: # All train examples are equally important return [1]*len(ie) ie=list(map(lambda x:x/meanIE,ie)) return ie def _importance(self,XTrain,XTest): pass class CI(ImportanceEstimator): """ Constant Importance, method that allways returns constant importance for all train examples (returns 1 for all values) """ def __init__(self): super().__init__('CI') self.Ones=[] def _fit(self,XTrain): self.Ones=[1]*len(XTrain) return None def _importance(self,XTrain,XTest): return self.Ones class PIE(ImportanceEstimator): """ Probabilistic Importance Estimator. Calculates the importance as P_test(Train)/P_train(Train) """ def __init__(self,ProbClass=None): """ Params: - ProbClass : Classfier that outputs probabilistic predictions Must have methods: fit , predict_proba If None: linear_model.LogisticRegression(random_state=1) """ super().__init__('PIE') if ProbClass==None: self.ProbClass=LogisticRegression(random_state=1) else: self.ProbClass=ProbClass def _fit(self,XTrain): return None def _importance(self,XTrain,XTest): X = np.concatenate((XTrain, XTest)) Y = np.zeros(len(X)) Y[:len(XTrain)] = 1 self.ProbClass.fit(X, Y) probs=self.ProbClass.predict_proba(XTrain) pTrBeTrain=probs[:,1] pTrBeTest =probs[:,0] importance = pTrBeTest / pTrBeTrain return importance class DIE(ImportanceEstimator): """ Density Importance Estimator. Calculates the importance using the density D of train and test. """ def __init__(self,de=None): """ Params: - de : Density Estimator. Must have methods: fit, score_samples If None: sklearn.neighbors.KernelDensity(bandwidth=1, kernel='gaussian') """ super().__init__('DIE') if de==None: self.de=KernelDensity(bandwidth=1, kernel='gaussian') else: self.de=de self.DF_trainV=None def _fit(self,XTrain): self.de.fit(XTrain) self.DF_trainV = self.de.score_samples(XTrain) return self def _importance(self,XTrain,XTest): self.de.fit(XTest) DF_testV = self.de.score_samples(self.XTrain) importance = np.zeros(len(self.XTrain)) for i in range(len(self.XTrain)): importance[i] =np.exp(DF_testV[i]-self.DF_trainV[i]) return importance class KLIEP (ImportanceEstimator): def __init__(self): super().__init__('KLIEP') def _fit(self,XTrain): # Do nothing for fitting return None def _importance(self,XTrain,XTest): kliep = DensityRatioEstimator() XTrain=np.array(XTrain) XTest=np.array(XTest) with warnings.catch_warnings(): warnings.simplefilter("ignore") kliep.fit(XTrain, XTest) importance = kliep.predict(XTrain) return importance

gen1dimNormal

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ """ import numpy as np def gen1DimNormal(RG,nEje,m,dt): """ Crea un conjunto de ejenplos de una dimension con una distribución normal Parámetros: - RG : objeto random.Random() - nEje : número de ejemplos - m : media - dt : desviación típica Retorna: numpy.ndarray nEje x 1 (Matriz con una columna, no lista lineal) donde los valores siguen una distribución normal(m,dt) """ X=[] for c in range(nEje): x=RG.normalvariate(m,dt) X.append([x]) return np.array(X)

Quitls

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ @author: quevedo@uniovi.es """ import numpy as np def dataSetFromQBags(X,Y,bags,n): """ Creates the dataset of the bag n from the dataset (X|Y) Params: X,Y : Data Set Attributess/Category bags : Bags returned by BagGenerator.generate_bags n : index of the bag in [0, n_bag] , where n_bag is the parameter of BagGenerator Returns [Xb,Yb: Xb|Yb : bag dataset """ # p=bags[0][0][n] inds=bags[1][:,n] Xb=[] Yb=[] for i in inds: Xb.append(X[i]) Yb.append(Y[i]) return [np.array(Xb),np.array(Yb)]

Tema 3 Sesion 1

Apartado A

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 3 : Aprendizaje SemiSupervisado (ASS) Sesión 1 : Definición del problema y algoritmos de ASS Bloque A : Problemas semi-supervisados """ # En los conjuntos de datos que tienen una gran cantidad de ejemplos con categoría #desconocida se puede aprovechar ese conjunto de datos sin categoría para mejorar #el aprendizaje. Esto sería Aprendizaje Semisupervisado # En este tema solo se tratarán problemas de clasificación y se marcará con -1 #la categoría de los ejemplos de los que se desconoce el valor de la misma # Utilizaremos el conjuntos de datos letter-recognition: # https://archive.ics.uci.edu/ml/datasets/Letter+Recognition # La categoría es una letra y los atributos información sobre características #gráficas de esa letra manuscrita # Se tratará de distinguir dos letras con cierto parecido: M y N from SemiSuperDatasets.leeSemiSuperLetter import leeSemiSuperLetter from sklearn.metrics import accuracy_score from sklearn.semi_supervised import LabelPropagation,LabelSpreading import matplotlib.pyplot as plt import numpy as np import warnings # Atributos usados en la representación (Cambiar al gusto. Valores en [0;15]) ix=6 iy=12 # Letras usadas como categoría (Cambiar al gusto. Valores letras mayúsculas en inglés) L1='M' L2='N' # Se lee el dataset, dividido en entrenamiento y test # El entranamiento se divide en supervisado y no supervisado [XTrSuper,YTrSuper,XTrNoSuper,YTrNoSuper,XTe,YTe]=leeSemiSuperLetter(letras=[L1,L2],semilla=1,propTest=1/3.0,propEti=1/100.0) # Convertir letras en números de categorías n1=ord(L1)-ord('A') n2=ord(L2)-ord('A') plt.figure() plt.title('Entrenamiento: Letter M - N') plt.xlabel('Atributo {}'.format(ix)) plt.ylabel('Atributo {}'.format(iy)) plt.plot(np.array(XTrNoSuper)[:,ix],np.array(XTrNoSuper)[:,iy],'x',label='NS',markersize=12,color='tab:gray') plt.plot(np.array(XTrSuper)[np.array(YTrSuper)==n1,ix],np.array(XTrSuper)[np.array(YTrSuper)==n1,iy],marker='${}$'.format(L1),markersize=12,linestyle='None',color='tab:orange',label='M') plt.plot(np.array(XTrSuper)[np.array(YTrSuper)==n2,ix],np.array(XTrSuper)[np.array(YTrSuper)==n2,iy],marker='${}$'.format(L2),markersize=12,linestyle='None',color='tab:blue',label='N') plt.xticks([0,2,4,6,8,10,12,14]) plt.yticks([0,2,4,6,8,10,12,14,16]) # plt.legend() plt.savefig('EntreMNX.pdf') plt.figure() plt.title('Test: Letter M - N') plt.xlabel('Atributo {}'.format(ix)) plt.xticks([2,4,6,8,10,12,14]) plt.ylabel('Atributo {}'.format(iy)) plt.plot(np.array(XTe)[np.array(YTe)==n1,ix],np.array(XTe)[np.array(YTe)==n1,iy],marker='$|^{}|$'.format(L1),markersize=12,linestyle='None',color='tab:orange',label='M') plt.plot(np.array(XTe)[np.array(YTe)==n2,ix],np.array(XTe)[np.array(YTe)==n2,iy],marker='$|_{}|$'.format(L2),markersize=12,linestyle='None',color='tab:blue',label='N') plt.xticks([0,2,4,6,8,10,12,14]) plt.yticks([0,2,4,6,8,10,12,14,16]) # plt.legend() plt.savefig('TestMN.pdf') #%% Variando NS # Aprenderemos con diferentes proporciones de no etiquetado en el conjunto de #entrenamiento para estudiar como afecta al error en test # Evaluar el aprendizaje según aumenta el número de ejemplos no etiquetados #usando accuracy_score ntrSuper =len(XTrSuper) # Nº de ejemplos etiquetados ntrNoSuper=len(XTrNoSuper) # Nº de ejemplos no etiquetados # Algoritmos de aprendizaje semisupervisado LP=LabelPropagation() LS=LabelSpreading() # Proporciones de ejemplos no etiquetados PENS=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1] # Almacenes de aciertos para cada sistema no supervisado LPAcs =[] LSAcs =[] nNoSupers=[] # Almacén de Nº de ejemplos no etiquetados en cada iteración # NOTA: Los sistemas LabelPropagation y LabelSpreading dan algunos warnings # que con las siguientes instrucciones evitan que se muestren with warnings.catch_warnings(): warnings.simplefilter("ignore") for PNS in PENS: # El aprendizaje semi supervisado utiliza los ejemplos con y sin categoría # Crear el dataset con la proporción apropiada de no etiquetados nNoSuper=int(ntrNoSuper*PNS) # Nº de ejemplos no etiquetados nNoSupers.append(nNoSuper) # Almacenamos el Nº de no etiquetados XtrSuNoSu=XTrSuper+XTrNoSuper[:nNoSuper] # Entrenamiento con etiquetados y los primeros nNoSuper no etiquetados YtrSuNoSu=YTrSuper+YTrNoSuper[:nNoSuper] # Test con etiquetados y los primeros nNoSuper no etiquetados # LabelPropagation LP.fit(XtrSuNoSu,YtrSuNoSu) P=LP.predict(XTe) LPAc=accuracy_score(YTe,P) LPAcs.append(LPAc) # LabelSpreading LS.fit(XtrSuNoSu,YtrSuNoSu) P=LS.predict(XTe) LSAc=accuracy_score(YTe,P) LSAcs.append(LSAc) print('Ejemplos etiquetados:{:3}, no etiquetados:{:5}.'.format(ntrSuper,nNoSuper),end=' ') print(' Acierto: LP={:6.4f} LS={:6.4f}'.format(LPAc,LSAc)) #%% Gráfica de acierto - Ejemplos no etiquetado plt.figure() plt.title('Ejemplos etiquetados:{}'.format(ntrSuper)) plt.xlabel('Ejemplos no etiquetados') plt.ylabel('Acierto') plt.plot(nNoSupers,LPAcs,label='LabelPropagation') plt.plot(nNoSupers,LSAcs,label='LabelSpreading') plt.legend() plt.grid(axis='y') plt.savefig('LP_LS_Letter_MN.pdf') #%% Ejercicio 1 """ Se quiere mejorar la clasificación entre M y N añadiendo ejemplos no etiquetados de letras que se parezcan. En este caso se utilizarán las letras W y Z que rotándolas tienen similitudes con M y N. Se proporciona: Entrenamiento: Ejemplos etiquetados de M y N : XTrSuperWZ,YTrSuperWZ Ejemplos no etiquetados de M y N : XTrMNNoSuper,YTrMNNoSuper Ejemplos no etiquetados de W y Z : XTrNoSuperWZ,YTrNoSuperWZ Test: Ejemplos etiquetados de M y N : XTeMN,YTeMN Calcular la accuracy para LabelSpreading (LS) en las siguientes situaciones: A) Solo se utilizan ejemplos etiquetados de M y N Esto sería aprendizaje sueprvisado clásico. B) Se utilizan ejemplos etiquetados y no etiquetados de M y N Aprendizaje no supervisado clásico. C) Se utilizan ejemplos etiquetados de M y N junto con los no etiquetados de W y Z No tenemos ejemplos no etiquetados de M y N, ¿Podría mejorar con otros no etiquetados? D) Se utilizan ejemplos etiquetados y no etiquetados de M y N y no etiquetados de W y Z Utilizamos todos los ejemplos disponibles D) ¿Como se calcula la accuracy? E) ¿Cuál es la mejor opción? SALIDA: A) Accuracy LS=0.5905 B) Accuracy LS=0.7638 C) Accuracy LS=0.6248 D) Accuracy LS=0.7657 """ # Datos # Ejemplos de las letras N y M [XTrMNSuper,YTrMNSuper,XTrMNNoSuper,YTrMNNoSuper,XTeMN,YTeMN]=leeSemiSuperLetter(letras=['M','N'],semilla=1,propTest=1/3.0,propEti=1/100.0) # Ejemplos de las letras W y Z [XTrWZSuper,YTrWZSuper,XTrWZNoSuper,YTrWZNoSuper,XTeWZ,YTeWZ]=leeSemiSuperLetter(letras=['W','Z'],semilla=1,propTest=0,propEti=0) # NOTA: Los datos son listas python : type(XTrMNSuper) --> list # Para concatenar listas utilizar el operador '+' # Ejemplo: A=[[1,2],[3,4]] B=[[5,6],[7,8],[9,10]] AB=A+B print('A:',A) print('B:',B) print('A+B:',AB) # NOTA: implementar la solución dentro de este bloque para evitar mostrar warnings with warnings.catch_warnings(): warnings.simplefilter('ignore') #TODO BEGIN Ejercicio 1 # A) Solo se utilizan ejemplos etiquetados de M y N XTr=XTrMNSuper YTr=YTrMNSuper # LabelSpreading LS.fit(XTr,YTr) P=LS.predict(XTe) LSAc=accuracy_score(YTe,P) print('A) Accuracy LS={:6.4f}'.format(LSAc)) # B) Se utilizan ejemplos etiquetados y no etiquetados de M y N XTr=XTrMNSuper+XTrMNNoSuper YTr=YTrMNSuper+YTrMNNoSuper # LabelSpreading LS.fit(XTr,YTr) P=LS.predict(XTe) LSAc=accuracy_score(YTe,P) print('B) Accuracy LS={:6.4f}'.format(LSAc)) # C) Se utilizan ejemplos etiquetados de M y N junto con los no etiquetados de W y Z XTr=XTrMNSuper+XTrWZNoSuper YTr=YTrMNSuper+YTrWZNoSuper # LabelSpreading LS.fit(XTr,YTr) P=LS.predict(XTe) LSAc=accuracy_score(YTe,P) print('C) Accuracy LS={:6.4f}'.format(LSAc)) # D) Se utilizan ejemplos etiquetados de M y N junto con los no etiquetados de W y Z XTr=XTrMNSuper+XTrMNNoSuper+XTrWZNoSuper YTr=YTrMNSuper+YTrMNNoSuper+YTrWZNoSuper # LabelSpreading LS.fit(XTr,YTr) P=LS.predict(XTe) LSAc=accuracy_score(YTe,P) print('D) Accuracy LS={:6.4f}'.format(LSAc)) #END Ejercicio 1

Apartado B

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 3 : Aprendizaje SemiSupervisado (ASS) Sesión 1 : Parámetros y su optimización Blqoue B : Parámetros """ from SemiSuperDatasets.leeSemiSuperLetter import leeSemiSuperLetter from sklearn.metrics import accuracy_score from sklearn.semi_supervised import LabelPropagation,LabelSpreading import matplotlib.pyplot as plt import numpy as np import warnings # Los sistemas de aprendizaje semisupervisado LabelPropagation (LP) y #LabelSpreading (LS) tienen varios parámetros: # https://scikit-learn.org/stable/modules/generated/sklearn.semi_supervised.LabelPropagation.html # https://scikit-learn.org/stable/modules/generated/sklearn.semi_supervised.LabelSpreading.html # Los que vamos a manejar en esta práctica son (mirar descripción en la web): # - kernel : {‘knn’, ‘rbf’} # - gamma : float (para el kernel rbf) # - n_neighbors : int (para el kernel rbf) # Para LS también hay el parámetro: # - alpha : float en [0,1] # Partiendo del código de la sesión 1, modificarlo para que implemente estas variantes: # LP1 rbf gamma=1 # LP2 knn n_neighbors=3 # LS1 rbf gamma=1 # LS2 knn n_neighbors=3 alpha=0.1 # Solución: # Atributos usados en la representación (Cambiar al gusto. Valores en [0;15]) ix=6 iy=12 # Letras usadas como categoría (Cambiar al gusto. Valores letras mayúsculas en inglés) L1='M' L2='N' # Se lee el dataset, dividido en entrenamiento y test # El entranamiento se divide en supervisado y no supervisado [XTrSuper,YTrSuper,XTrNoSuper,YTrNoSuper,XTe,YTe]=leeSemiSuperLetter(letras=[L1,L2],semilla=1,propTest=1/3.0,propEti=1/100.0) #%% Variando NS # Aprenderemos con diferentes proporciones de no etiquetado en el conjunto de #entrenamiento para estudiar como afecta al error en test # Evaluar el aprendizaje según aumenta el número de ejemplos no etiquetados #usando accuracy_score ntrSuper =len(XTrSuper) # Nº de ejemplos etiquetados ntrNoSuper=len(XTrNoSuper) # Nº de ejemplos no etiquetados # Algoritmos de aprendizaje semisupervisado LP1=LabelPropagation(kernel='rbf',gamma=1,max_iter=1000) LP2=LabelPropagation(kernel='knn',n_neighbors=3,max_iter=1000) LS1=LabelSpreading(kernel='rbf',gamma=1,alpha=0.8,max_iter=1000) LS2=LabelSpreading(kernel='knn',n_neighbors=3,alpha=0.1,max_iter=1000) # Proporciones de ejemplos no etiquetados PENS=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1] # Almacenes de aciertos para cada sistema LP1Acs =[] LS1Acs =[] LP2Acs =[] LS2Acs =[] nNoSupers=[] # Almacén de Nº de ejemplos no etiquetados en cada iteración # NOTA: Los sistemas LabelPropagation y LabelSpreading dan algunos warnings # que con las siguientes instrucciones evitan que se muestren with warnings.catch_warnings(): warnings.simplefilter("ignore") for PNS in PENS: # El aprendizaje semi supervisado utiliza los ejemplos con y sin categoría # Crear el dataset con la proporción apropiada de no etiquetados nNoSuper=int(ntrNoSuper*PNS) # Nº de ejemplos no etiquetados nNoSupers.append(nNoSuper) # Almacenamos el Nº de no etiquetados XTrSuNoSu=XTrSuper+XTrNoSuper[:nNoSuper] # Entrenamiento con etiquetados y los primeros nNoSuper no etiquetados YTrSuNoSu=YTrSuper+YTrNoSuper[:nNoSuper] # Test con etiquetados y los primeros nNoSuper no etiquetados # LabelPropagation 1 LP1.fit(XTrSuNoSu,YTrSuNoSu) P=LP1.predict(XTe) LP1Ac=accuracy_score(YTe,P) LP1Acs.append(LP1Ac) # LabelSpreading 1 LS1.fit(XTrSuNoSu,YTrSuNoSu) P=LS1.predict(XTe) LS1Ac=accuracy_score(YTe,P) LS1Acs.append(LS1Ac) # LabelPropagation 2 LP2.fit(XTrSuNoSu,YTrSuNoSu) P=LP2.predict(XTe) LP2Ac=accuracy_score(YTe,P) LP2Acs.append(LP2Ac) # LabelSpreading 2 LS2.fit(XTrSuNoSu,YTrSuNoSu) P=LS2.predict(XTe) LS2Ac=accuracy_score(YTe,P) LS2Acs.append(LS2Ac) print('Ejemplos etiquetados:{:3}, no etiquetados:{:5}.'.format(ntrSuper,nNoSuper),end=' ') print(' Acierto: LP1={:6.4f} LP2={:6.4f} LS1={:6.4f} LS2={:6.4f}'. format(LP1Ac,LP2Ac,LS1Ac,LS2Ac)) #%% Gráfica de acierto - Ejemplos no etiquetado plt.figure() plt.title('Ejemplos etiquetados:{}'.format(ntrSuper)) plt.xlabel('Ejemplos no etiquetados') plt.ylabel('Acierto') plt.plot(nNoSupers,LP1Acs,label='LP 1') plt.plot(nNoSupers,LS1Acs,label='LS 1') plt.plot(nNoSupers,LP2Acs,label='LP 2') plt.plot(nNoSupers,LS2Acs,label='LS 2') plt.legend() plt.grid(axis='y') plt.savefig('LP_LS_Letter_MN.pdf') #%% Ejercicio 1 """ Para el total de ejemplos no supervisados y con el algoritmo LS con kernel='knn' alpha=0.1 varía el número de vecinos desde 1 hasta el doble del número de atributos. Calcula e imprime el acierto en cada iteración SALIDA: knn= 1 acierto: 0.4971 knn= 2 acierto: 0.4990 knn= 3 acierto: 0.5371 knn= 4 acierto: 0.5486 knn= 5 acierto: 0.5905 knn= 6 acierto: 0.6286 knn= 7 acierto: 0.6286 knn= 8 acierto: 0.6514 knn= 9 acierto: 0.6552 knn=10 acierto: 0.6610 knn=11 acierto: 0.6781 knn=12 acierto: 0.6914 knn=13 acierto: 0.7010 knn=14 acierto: 0.7162 knn=15 acierto: 0.7181 knn=16 acierto: 0.7124 knn=17 acierto: 0.7295 knn=18 acierto: 0.7143 knn=19 acierto: 0.7257 knn=20 acierto: 0.7295 knn=21 acierto: 0.7295 knn=22 acierto: 0.7295 knn=23 acierto: 0.7257 knn=24 acierto: 0.7219 knn=25 acierto: 0.7238 knn=26 acierto: 0.7219 knn=27 acierto: 0.7829 knn=28 acierto: 0.7943 knn=29 acierto: 0.8038 knn=30 acierto: 0.8057 knn=31 acierto: 0.8019 knn=32 acierto: 0.7905 """ vecinos=list(range(1,len(XTe[0])*2+1)) # Vecinos sobre los que iterar LSAcs=[] # Si se guardan aquí los aciertos, se genera una gráfica con los mismos #<TODO BEGIN Ejercicio 1> # Creamos conjunto de entrenamiento XTrSuNoSu=XTrSuper+XTrNoSuper YTrSuNoSu=YTrSuper+YTrNoSuper with warnings.catch_warnings(): warnings.simplefilter("ignore") for nn in vecinos: # Se crea el objeto de aprendizaje semisupervisado LS=LabelSpreading(kernel='knn',n_neighbors=nn,alpha=0.1,max_iter=1000) # Proceso de entrenamiento, test y cálculo de la accuracy LS.fit(XTrSuNoSu,YTrSuNoSu) P=LS.predict(XTe) LSAc=accuracy_score(YTe,P) # Guardar e imprimir la accuracy LSAcs.append(LSAc) print('knn={:2} acierto: {:6.4f}'.format(nn,LSAc)) #<TODO END Ejercicio 1> #%% Gráfica de acierto - Ejemplos no etiquetado plt.figure() plt.title('Variando vecinos'.format(ntrSuper)) plt.xlabel('Número de vecinos (nn)') plt.ylabel('Acierto') plt.plot(vecinos,LSAcs,label='LS(knn)') plt.legend() plt.grid(axis='y') plt.savefig('LS_knn_varia_nn.pdf')

NoPresencial

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 3 : Aprendizaje SemiSupervisado (ASS) Sesión 1 : Definición del problema y algoritmos de ASS Actividad del Campus Virtual """ import matplotlib.pyplot as plt import numpy as np from sklearn.semi_supervised import LabelPropagation,LabelSpreading from sklearn.metrics import accuracy_score import random def genTest(puntosLado=25): X=[] Y=[] def i2v(pl,i): mpl=pl/2 return (i-mpl)/mpl for f in range(puntosLado): y=i2v(puntosLado,f) for c in range(puntosLado): x=i2v(puntosLado,c) mod=(y**2+x**2)**0.5 if mod<0.5: X.append([x,y]) Y.append(0) elif mod>0.75: X.append([x,y]) Y.append(1) return [X,Y] def pinta(X,Y,titulo,fileName=None): X=np.array(X) Y=np.array(Y) plt.figure() plt.ylim([-1.1,1.75]) plt.xlim([-1.1,1.75]) plt.title(titulo) colors=['grey' ,'red' ,'blue' ] labels=['No etiquetado','Dentro','Fuera'] for cate in [-1,0,1]: inds=np.where(Y==cate)[0] X0=X[inds,0] X1=X[inds,1] plt.plot(X0,X1,color=colors[cate+1],linestyle='None',markersize=8,marker='o', label=labels[cate+1]) plt.legend(loc='upper left') if fileName!=None: plt.savefig(fileName) #%% EJERCICIO 1 """ Se tienen que clasificar los puntos en una zona donde hay un FOSO con el sistema LabelSpreading El foso está centrado en la posición (0,0) y empieza a una distancia 0.5 del centro y termina a una distancia 0.75. Solo se saben dos puntos: el punto (0,0) es de clase 0 el punto (1,1) es de clase 1. 1: Comprobar qué accuracy se obtiene sin ejemplos no supervisados 2: Añadir los ejemplos no supervisados 3: Comprobar qué accuracy se obtiene con ejemplos no supervisados 4: Modificar los hyper-parámetros (manualmente) de LabelSpreading para mejor esta última accuracy. Se Proporciona un conjunto de test: XTe , YTe Hay que crear el conjunto de entrenamiento y evaluarlo NOTA: en cda paso hay una llamada a la función pinta que genera un .pdf observa los .pdf como ayuda """ # Test [XTe,YTe]=genTest() pinta(XTe,YTe,'FOSO: Test','FOSO_Test.pdf') # Ejemplos supervisados de entrenamiento #TODO BEGIN 1.1 XTr=[[0,0],[1,1]] YTr=[ 0 , 1 ] #END 1.1 pinta(XTr,YTr,'FOSO: Entrenamiento solo etiquetados','FOSO_EntreSoloEti.pdf') # Sistema de aprendizaje no supervisado LabelSpreading max_iter=100000 LS=LabelSpreading(max_iter=max_iter) # Cambia manualmente los hiperparámetros para conseguir mejor accuracy #TODO BEGIN 1.2 LS=LabelSpreading(kernel='rbf',gamma=100,alpha=0.9999,max_iter=max_iter) #END 1.2 # Realiza un entrenamiento / test y guarda la accuracy en Acc #TODO 1.3 LS.fit(XTr,YTr) P=LS.predict(XTe) Acc=accuracy_score(YTe,P) #END 1.3 print('Accuracy sin ejemplos no supervisados: {:6.4f}'.format(Acc)) pinta(XTe,P,'FOSO: Predicción del test con:\nEntrenamiento solo etiquetados','FOSO_PredcSoloEti.pdf') # Añadir al entrenamiento (XTr,YTr) ejemplos no etiquetados RG=random.Random() RG.seed(1) for r in range(1000): # Punto en (x in [-1,+1],y in [-1,+1]) con distribución uniforme x1=RG.random()*2-1 x2=RG.random()*2-1 dis=(x1**2+x2**2)**0.5 # Distancia al centro (al (0,0)) # Insertar en XTr,YTr el punto (x1,x2) como no supervisado si fuera el caso #TODO BEGIN 1.4: if dis<0.5 or dis>0.75: XTr.append([x1,x2]) YTr.append(-1) #END 1.4 pinta(XTr,YTr,'FOSO: Entrenamiento etiquetados y no etiquetados','FOSO_EntreEtiNoEti.pdf') # Realiza un entrenamiento / test con los ejemplos supervisados y no supervisados # Guarda la accuracy en Acc #TODO 1.5: LS.fit(XTr,YTr) P=LS.predict(XTe) Acc=accuracy_score(YTe,P) # END TODO print('Accuracy con ejemplos no supervisados: {:6.4f}'.format(Acc)) pinta(XTe,P,'FOSO: Predicción del test con:\nEntrenamiento etiquetados y no etiquetados','FOSO_PredcEtiNoEti.pdf')

Actividad Presencial

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 3 : Aprendizaje SemiSupervisado (ASS) Sesión 1 : Definición del problema y algoritmos de ASS Actividad 1 """ import random import warnings from sklearn.svm import SVC from sklearn.metrics import accuracy_score from sklearn.model_selection import GridSearchCV from sklearn.metrics import make_scorer from sklearn.preprocessing import OneHotEncoder from sklearn.semi_supervised import LabelPropagation,LabelSpreading import matplotlib.pyplot as plt import numpy as np from SemiSuperDatasets.leeIris import divideTrainTest def dibujaIris(XTr0,XTr1,XTr2,titulo,etiquetados=None): nombresEachCat=['Setosa(0)','Virginica(1)','Versicolor(2)'] coloresEachCat=['tab:orange','g','b'] if etiquetados==None: nombresCat=nombresEachCat coloresCat=coloresEachCat else: nombresCat=[None,None,None] coloresCat=['tab:gray','tab:gray','tab:gray'] marca='o' attX=2 attY=3 attXNombre='Longitud del pétalo' attYNombre='Anchura del pétalo' X=[None]*3 X[0]=np.array(XTr0)[:,attX] X[1]=np.array(XTr1)[:,attX] X[2]=np.array(XTr2)[:,attX] Y=[None]*3 Y[0]=np.array(XTr0)[:,attY] Y[1]=np.array(XTr1)[:,attY] Y[2]=np.array(XTr2)[:,attY] plt.figure() plt.title(titulo) plt.xlabel(attXNombre) plt.ylabel(attYNombre) for p in range(len(X)): plt.plot(X[p],Y[p],color=coloresCat[p],marker=marca,linestyle='None',label=nombresCat[p]) if etiquetados!=None: e0=etiquetados[0] plt.plot(X[0][e0],Y[0][e0],color=coloresEachCat[0],marker=marca,linestyle='None',label=nombresEachCat[0]) e1=etiquetados[1] plt.plot(X[1][e1],Y[1][e1],color=coloresEachCat[1],marker=marca,linestyle='None',label=nombresEachCat[1]) e2=etiquetados[2] plt.plot(X[2][e2],Y[2][e2],color=coloresEachCat[2],marker=marca,linestyle='None',label=nombresEachCat[2]) plt.legend() plt.legend() plt.savefig('{}.pdf'.format(titulo)) def unEtiquetadoPorCategoria(XTr0,XTr1,XTr2,semilla): """ Crea unas categorías donde solo hay un ejemplo etiquetado por cada una de las tres categorías. Parámetros: - semilla : semilla del proceso aleatorio - nCate0|1|2 : número de ejemplos por cada categoría Retorna: [XTr0NoEti,XTr0Eti,XTr1NoEti,XTr1Eti,XTr2NoEti,XTr2Eti,e0,e1,e2]: De la categoría 0 XTr0NoEti: Conjunto de ejemplos no etiquetados (Todos menos 1) XTr0Eti : Conjunto de ejemplos etiquetados (Solo 1) (Análogo para el resto de categorías) e0,e1,e2 : índice (posición) del ejemplo etiquetado de cada categoría """ RG=random.Random() RG.seed(semilla) # Ejemplo etiquetado por cada categoría e0=RG.randrange(len(XTr0)) e1=RG.randrange(len(XTr1)) e2=RG.randrange(len(XTr2)) # Dividir en conjuntos etiquetados y no etiquetados XTr0NoEti=XTr0[:e0]+XTr0[(e0+1):] XTr0Eti=[XTr0[e0]] XTr1NoEti=XTr1[:e1]+XTr1[(e1+1):] XTr1Eti=[XTr1[e1]] XTr2NoEti=XTr2[:e2]+XTr2[(e2+1):] XTr2Eti=[XTr2[e2]] return [XTr0NoEti,XTr0Eti,XTr1NoEti,XTr1Eti,XTr2NoEti,XTr2Eti,e0,e1,e2] #%% EJERCICIO 1 """ Utilizaremos el conjuntos de datos iris: https://archive.ics.uci.edu/ml/machine-learning-databases/iris/ La categoría es un dígito que corresponde: 0 -> setosa 1 -> virginica 2 -> versicolor Se da la función divideTrainTest que divide el conjunto en train y test, dividiendo el train, a su vez, en tres conjuntos, uno de cada categoría. El objetivo es comprobar si al usar solo un ejemplo de cada categoría el resto de ejemplos usados como no etiquetados mejoran el aprendizaje. Se pide repetir 10 veces variando la semilla del generador de números aleatorios: - Seleccionar aleatoriamente 1 ejemplo de cada categoría, será el train supervisado. - El resto de ejemplos serán serán el entrenamiento no supervisado. Realizar 2 conjuntos de ejemplos: A) Solamente usar ejemplos etiquetados (3, 1 por cada categoría) B) Usar los ejemplos etiquetados y los no etiquetados Realizar un proceso de aprendizaje/evaluación y calcular el acierto para los sistemas: LabelPropagation(LP), y LabelSpreading(LS) tanto para el conjuto A) como el B) Calcular la mejora por utilizar ejemplos no etiquetados para LP y para LS Almacenar los aciertos de LP y LS Imprimir para cada sistema el acierto en A), en B) y la mejora Al final de las 10 repeticiones imprimir la media de las mejoras de LP y LS NOTA: Parte del código viene hecho. Rellenar en los bloques <TODO> </TODO> NOTA: Mirar creaDataset.pdf SALIDA: (Observar los .pdf) Iteración 0 Etiquetados: Se:24 Vi:26 Ve: 2 Acierto y mejora: - LP A)=0.8600 B)=0.9000 Mejora=0.0400 - LS A)=0.8600 B)=0.9200 Mejora=0.0600 Iteración 1 Etiquetados: Se: 8 Vi: 4 Ve:16 Acierto y mejora: - LP A)=0.8400 B)=0.9200 Mejora=0.0800 - LS A)=0.8400 B)=0.8800 Mejora=0.0400 Iteración 2 Etiquetados: Se: 3 Vi: 5 Ve: 5 Acierto y mejora: - LP A)=0.9200 B)=0.8800 Mejora=-0.0400 - LS A)=0.9200 B)=0.9000 Mejora=-0.0200 Iteración 3 Etiquetados: Se:15 Vi: 8 Ve:23 Acierto y mejora: - LP A)=0.8800 B)=0.8800 Mejora=0.0000 - LS A)=0.8800 B)=0.9000 Mejora=0.0200 Iteración 4 Etiquetados: Se:15 Vi:19 Ve: 6 Acierto y mejora: - LP A)=0.8000 B)=0.6600 Mejora=-0.1400 - LS A)=0.8000 B)=0.7800 Mejora=-0.0200 Iteración 5 Etiquetados: Se:16 Vi:22 Ve:33 Acierto y mejora: - LP A)=0.9000 B)=0.9200 Mejora=0.0200 - LS A)=0.9000 B)=0.9200 Mejora=0.0200 Iteración 6 Etiquetados: Se: 5 Vi:31 Ve:16 Acierto y mejora: - LP A)=0.8600 B)=0.9200 Mejora=0.0600 - LS A)=0.8600 B)=0.8600 Mejora=0.0000 Iteración 7 Etiquetados: Se:20 Vi: 9 Ve:25 Acierto y mejora: - LP A)=0.9200 B)=0.8800 Mejora=-0.0400 - LS A)=0.9200 B)=0.9200 Mejora=0.0000 Iteración 8 Etiquetados: Se:14 Vi:23 Ve:24 Acierto y mejora: - LP A)=0.8000 B)=0.7000 Mejora=-0.1000 - LS A)=0.8000 B)=0.8800 Mejora=0.0800 Iteración 9 Etiquetados: Se:29 Vi:23 Ve:17 Acierto y mejora: - LP A)=0.8800 B)=0.7000 Mejora=-0.1800 - LS A)=0.8800 B)=0.9600 Mejora=0.0800 Mejora media LP=-0.0300 LS=0.0260 """ # Lectura de datos iris # Ejemplo de llamada a divideTrainTest [XTr0,XTr1,XTr2,XTe,YTe]=divideTrainTest(semilla=1) # Dibuja este entrenamiento dibujaIris(XTr0,XTr1,XTr2,'Entrenamiento iris') #%% Solución # Algoritmos de aprendizaje semisupervisado #TODO 1.1 # Crear los objetos LP y LS de las clases LabelPropagation y LabelSpreading respectivamente LP=LabelPropagation() LS=LabelSpreading() #END 1.1 # Para almacenar las mejoras de LP y LS mejorasLP=[] mejorasLS=[] warnings.simplefilter("ignore") for rep in range(10): # Para 10 repeticiones # Se obtiene un ejemplo etiquetado aleatorio de cada categoria: # XTr0Eti, XTr1Eti, XTr2NoEti # Y los no etiquetados # XTr0NoEti, XTr1NoEti, XTr2NoEti [XTr0NoEti,XTr0Eti,XTr1NoEti,XTr1Eti,XTr2NoEti,XTr2Eti,e0,e1,e2]=unEtiquetadoPorCategoria(XTr0,XTr1,XTr2,semilla=rep) dibujaIris(XTr0,XTr1,XTr2,'Entrenamiento iris Iteración {}'.format(rep),etiquetados=[e0,e1,e2]) # Caso A) solo ejemplos etiquetados #TODO 1.2 # Crear el conjunto de ejemplos [XTr,YTr] con solo los ejemplos etiquetados. XTr=XTr0Eti+XTr1Eti+XTr2Eti YTr=[0,1,2] #END 1.2 # LabelPropagation #TODO 1.3 # Realiza un proceso de aprendizaje evaluación para LP # Calcula la accuracy con entrenamiento (XTr,YTr) y test (XTe,YTe) # Almacénala en la variable LPAc_A LP.fit(XTr,YTr) P=LP.predict(XTe) LPAc_A=accuracy_score(YTe,P) #END 1.3 # LabelSpreading #TODO 1.4 # Realiza un proceso de aprendizaje evaluación para LS # Calcula la accuracy con entrenamiento (XTr,YTr) y test (XTe,YTe) # Almacénala en la variable LSAc_A LS.fit(XTr,YTr) P=LS.predict(XTe) LSAc_A=accuracy_score(YTe,P) #END 1.4 # Caso B) ejemplos etiquetados y no etiquetados #TODO 1.5 # Crear el conjunto de ejemplos [XTr,YTr] con los ejemplos etiquetados y los no etiquetados XTrNoEti=XTr0NoEti+XTr1NoEti+XTr2NoEti XTr=XTr+XTrNoEti YTr=YTr+[-1]*len(XTrNoEti) #END 1.5 # LabelPropagation #TODO 1.6 # Realiza un proceso de aprendizaje evaluación para LP # Calcula la accuracy con entrenamiento (XTr,YTr) y test (XTe,YTe) # Almacénala en la variable LPAc_B LP.fit(XTr,YTr) P=LP.predict(XTe) LPAc_B=accuracy_score(YTe,P) #END 1.6 # LabelSpreading #TODO 1.7 # Realiza un proceso de aprendizaje evaluación para LS # Calcula la accuracy con entrenamiento (XTr,YTr) y test (XTe,YTe) # Almacénala en la variable LSAc_-b LS.fit(XTr,YTr) P=LS.predict(XTe) LSAc_B=accuracy_score(YTe,P) #END 1.7 #TODO 1.8 # Calcular las mejoras de LP y LS mejoraLP=LPAc_B-LPAc_A mejoraLS=LSAc_B-LSAc_A #END 1.8 # Almacenar las mejoras mejorasLP.append(mejoraLP) mejorasLS.append(mejoraLS) # Imprimir el índice de los 3 ejemplos etiquetados # Imprimir par LP y LS el acierto en la opción A), en B) y la mejora print('Iteración {} Etiquetados: Se:{:2} Vi:{:2} Ve:{:2} Acierto y mejora:'.format(rep,e0,e1,e2)) print(' - LP A)={:6.4f} B)={:6.4f} Mejora={:6.4f}'.format(LPAc_A,LPAc_B,mejoraLP)) print(' - LS A)={:6.4f} B)={:6.4f} Mejora={:6.4f}'.format(LSAc_A,LSAc_B,mejoraLS)) print('Mejora media LP={:6.4f} LS={:6.4f}'.format(np.mean(mejorasLP),np.mean(mejorasLS)))

Pre

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 3 : Aprendizaje SemiSupervisado (ASS) Sesión 1 : Definición del problema y algoritmos de ASS Bloque Pre : Problemas semi-supervisados """ from SemiSuperDatasets.leeSemiSuperLetter import leeSemiSuperLetter from sklearn.metrics import accuracy_score from sklearn.semi_supervised import LabelPropagation,LabelSpreading import matplotlib.pyplot as plt import numpy as np import warnings def getArribaAbajo(soloEtiquetaVertices=False): X=[] Y=[] nPuntos=20 for ix1 in range(nPuntos): x1=ix1/nPuntos for ix2 in range(nPuntos): x2=ix2/nPuntos if x2>0.4 and x2<0.6: continue exa=[x1,x2] if soloEtiquetaVertices: cate=-1 else: cate=1 if x2>0.5 else 0 X.append(exa) Y.append(cate) if soloEtiquetaVertices: Y[0] =0 Y[len(Y)-1]=+1 return [np.array(X),np.array(Y)] [XTr,YTr]=getArribaAbajo(soloEtiquetaVertices=True) [XTe,YTe]=getArribaAbajo() def pinta(X,Y,titulo,fichero=None): plt.figure() plt.title(titulo) for iExa in range(len(X)): colors=['tab:gray','tab:red','tab:blue'] exa=XTr[iExa] color=colors[Y[iExa]+1] plt.plot([exa[0]],[exa[1]],color=color,linestyle='None',markersize=12,marker='o') if(fichero!=None): plt.savefig(fichero) pinta(XTr,YTr,'Arriba/Abajo Entrenamiento','AA_Train.pdf') pinta(XTe,YTe,'Arriba/Abajo Test','AA_Test.pdf') XTrEti=[XTr[0,:],XTr[len(XTr)-1,:]] YTrEti=[YTr[0],YTr[len(YTr)-1]] LP=LabelPropagation() LP.fit(XTrEti,YTrEti) Pse=LP.predict(XTe) pinta(XTe,Pse,'Arriba/Abajo Predicción con solo etiquetados','AA_PredOnlyLabeled.pdf') LP.fit(XTr,YTr) P=LP.predict(XTe) pinta(XTe,P,'Arriba/Abajo Predicción con etiquetados y NO etiquetados','AA_PredLabeledAndUnlabeled.pdf')

ConcanateNE

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ @author: quevedo """ from sklearn.semi_supervised import LabelPropagation,LabelSpreading import numpy as np class concatenaNE_LP(LabelPropagation): """ Crea una versión de LabelPropagation que al aprender (fit) concatena un conjunto fijo de ejemplos no etiquetados. Funciona como LabelPropagation pero antes de aprender (fit) hay que utilizar setNE para indicar el conjunto de ejemplos no etiquetados """ def __init__(self,XNe=None,kernel='rbf', *, gamma=20, n_neighbors=7, max_iter=1000, tol=0.001, n_jobs=None): """ Params: XNe : Cadena que representa el conjunto de ejemplos no etiquetados. Tiene que ser de tal manera que mediante eval(XNe) se obtenga el conjunto de ejemplos original Ejemplo: X = [[1,2,3],[4,5,6]] Xstr=X.__str__() Conjunto de ejemplos no etiquetados. Se incorporarán con categoría -1 Si XNe==None no se concatenan ejemplos Para el resto ver el resto de parámetros ver: LabelPropagation """ super().__init__(kernel, gamma=gamma, n_neighbors=n_neighbors, max_iter=max_iter, tol=tol, n_jobs=n_jobs) self.XNe=XNe def fit(self,X,Y): if self.XNe==None: return self.fit(X,Y) X=np.array(X) XNe=eval(self.XNe) XA=np.concatenate([X,XNe]) Y=np.array(Y) YNe=[-1]*len(XNe) YA=np.concatenate([Y,YNe]) return LabelPropagation.fit(self,XA,YA) class concatenaNE_LS(LabelSpreading): """ Crea una versión de LabelPropagation que al aprender (fit) concatena un conjunto fijo de ejemplos no etiquetados. Funciona como LabelPropagation pero antes de aprender (fit) hay que utilizar setNE para indicar el conjunto de ejemplos no etiquetados """ def __init__(self,XNe=None,kernel='rbf', *, gamma=20, n_neighbors=7, alpha=0.2, max_iter=30, tol=0.001, n_jobs=None): """ Params: XNe : Cadena que representa el conjunto de ejemplos no etiquetados. Tiene que ser de tal manera que mediante eval(XNe) se obtenga el conjunto de ejemplos original Ejemplo: X = [[1,2,3],[4,5,6]] Xstr=X.__str__() Conjunto de ejemplos no etiquetados. Se incorporarán con categoría -1 Si XNe==None no se concatenan ejemplos Para el resto ver el resto de parámetros ver: LabelPropagation """ super().__init__(kernel, gamma=gamma, n_neighbors=n_neighbors, alpha=alpha, max_iter=max_iter, tol=tol, n_jobs=n_jobs) self.XNe=XNe def fit(self,X,Y): if self.XNe==None: return self.fit(X,Y) X=np.array(X) XNe=eval(self.XNe) XA=np.concatenate([X,XNe]) Y=np.array(Y) YNe=[-1]*len(XNe) YA=np.concatenate([Y,YNe]) return LabelSpreading.fit(self,XA,YA)

ssAccuracy

""" @author: quevedo """ from sklearn.metrics import accuracy_score def ssAccuracy(Y,P): """ Calcula accuracy_score sobre los ejemplos cuya Y no vale -1 """ Yf=[] Pf=[] for r in range(len(Y)): if Y[r]!=-1: Yf.append(Y[r]) Pf.append(P[r]) return accuracy_score(Yf,Pf)

Tema 3 Sesion 2

Apartado A

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 3 : Aprendizaje SemiSupervisado (ASS) Sesión 2 : Parámetros y su optimización Blqoue A : Estimación de error (CV) """ # En este bloque se mostará cómo estimar el error usando validación cruzada #en problemas semisupervisados import numpy as np import csv import random import warnings from SemiSuperDatasets.leeSemiSuperLetter import leeSemiSuperLetter from sklearn.metrics import accuracy_score from sklearn.model_selection import cross_val_score from sklearn.metrics import make_scorer from sklearn.semi_supervised import SelfTrainingClassifier,LabelPropagation,LabelSpreading from semisuperAA2.ssAccuracy import ssAccuracy from semisuperAA2.concatenaNE import concatenaNE_LP,concatenaNE_LS # Atributos usados en la representación (Cambiar al gusto. Valores en [0;15]) ix=6 iy=12 # Letras usadas como categoría (Cambiar al gusto. Valores letras mayúsculas en inglés) L1='O' L2='D' # Se lee el dataset, dividido en entrenamiento y test # El entranamiento se divide en supervisado y no supervisado # en este caso se toman 3/100 de ejemplos de entrenamiento para que haya algunos #más y así tener más ejemplos para los entrenamientos/test de la validación cruazada #del GridSerch [XTrSuper,YTrSuper,XTrNoSuper,YTrNoSuper,XTe,YTe]=leeSemiSuperLetter(letras=[L1,L2],semilla=1,propTest=1/3.0,propEti=3/100.0) warnings.simplefilter("ignore") #%% A) Estimar el error repartiendo los no etiquetados en los folds: print('\n** LabelPropagation:') # A.1 Se crea el conjunto de entrenamiento con los ejemplos etiquetados y no etiquetados X=XTrSuper+XTrNoSuper Y=YTrSuper+YTrNoSuper # A.2 Se utiliza un algoritmo semisupervisado original LP=LabelPropagation() # A.3 Se utiliza una validación cruzada con una medida de calidad que ignore # los ejemplos no etiquetados, en este caso ssAccuracy # Ver semisuperAA2/ssAccuracy.py PCVA=cross_val_score(LP,X,Y,scoring=make_scorer(ssAccuracy),cv=3) print(' Estimar el acierto repartiendo no etiquetados entre los folds:') print(' - Accuracy: {:6.4f}'.format(np.mean(PCVA))) #%% B) Estimar el error usando siempre todos los no etiquetados # B.1 El conjunto de entrenamiento son solo los ejemplos etiquetados X=XTrSuper Y=YTrSuper # B.2 Se utiliza un algoritmo semisupervisado que permite concatenar un conjunto # de ejemplos no etiquetados al hacer el entrenamiento. ConLP=concatenaNE_LP(XTrNoSuper) # B.3 Se utiliza una validación cruzada con una medida de calidad clásica PCVB=cross_val_score(ConLP,X,Y,scoring=make_scorer(accuracy_score),cv=3) print(' Estimar el acierto usando siempre el mismo conjunto de no etiquetados') print(' - Accuracy: {:6.4f}'.format(np.mean(PCVB))) #%% Ejercicio 1 """ Repetir las estimaciones anteriores de las 2 maneras para LabelSpreading SALIDA: ** LabelSpreading: Estimar el acierto repartiendo no etiquetados entre los folds: - Accuracy: 0.9061 Estimar el acierto usando siempre el mismo conjunto de no etiquetados - Accuracy: 0.9697 """ #TODO Ejercicio 1 # A) Estimar el error repartiendo los no etiquetados en los folds: print('\n** LabelSpreading:') # A.1 Se crea el conjunto de entrenamiento con los ejemplos etiquetados y no etiquetados X=XTrSuper+XTrNoSuper Y=YTrSuper+YTrNoSuper # A.2 Se utiliza un algoritmo semisupervisado original LS=LabelSpreading() # A.3 Se utiliza una validación cruzada con una medida de calidad que ignore # los ejemplos no etiquetados, en este caso ssAccuracy # Ver semisuperAA2/ssAccuracy.py PCVA=cross_val_score(LS,X,Y,scoring=make_scorer(ssAccuracy),cv=3) print(' Estimar el acierto repartiendo no etiquetados entre los folds:') print(' - Accuracy: {:6.4f}'.format(np.mean(PCVA))) # B) Estimar el error usando siempre todos los no etiquetados # B.1 El conjunto de entrenamiento son solo los ejemplos etiquetados X=XTrSuper Y=YTrSuper # B.2 Se utiliza un algoritmo semisupervisado que permite concatenar un conjunto # de ejemplos no etiquetados. ConLS=concatenaNE_LS(XTrNoSuper) # B.3 Se utiliza una validación cruzada con una medida de calidad clásica PCVB=cross_val_score(ConLS,X,Y,scoring=make_scorer(accuracy_score),cv=3) print(' Estimar el acierto usando siempre el mismo conjunto de no etiquetados') print(' - Accuracy: {:6.4f}'.format(np.mean(PCVB))) #END Ejercicio 1 #%% Ejercicio 2 """ Para LabelSpreading, haz un código que imprima cuál de las dos opciones de estimar el error es mejor """ #TODO Ejercicio 2 # Se utilizan todos los ejemplos etiquetados o no XTr=XTrSuper+XTrNoSuper YTr=YTrSuper+YTrNoSuper LS.fit(XTr,YTr) P=LS.predict(XTe) AccTest=accuracy_score(YTe,P) print('Accuracy en test: {:6.4f}'.format(AccTest)) AccA=np.mean(PCVA) AccB=np.mean(PCVB) DisA=abs(AccTest-AccA) DisB=abs(AccTest-AccB) if DisA<DisB: print('Mejor modo A) repartiendo no etiquetados entre los folds') else: print('Mejor modo B) usando siempre el mismo conjunto de no etiquetados') #END Ejercicio 2

Apartado B

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 3 : Aprendizaje SemiSupervisado (ASS) Sesión 2 : Parámetros y su optimización Blqoue B : Optimización de parámetros """ # Como se ha visto en el bloque anterior, los parámetros tienen una gran influencia #en la calidad de los sistemas. # Una manera adecuada para estimar los parámetros es utilizar GridSearchCV # Partiendo del código del Bloque A, añadir un sistema para LP y otro para LS #que optimice: # - gamma en [2**-2,2**-1,2**0,2**1,2**2] # - n_neighbors en [3,5,7,9,11] # Problema: # Los ejemplos que hay en el conjunto de datos son supervisados y no supervisados #y estos últimos también serán tratados por el CV del Grid Search, lo que #provocará que aparezcan en el los folds y por tanto en los tests. # Cuando se vaya a calcular la medida para un par Predicción(P) Valor en test(Y) #ocurrirá que habrá valores en Y que serán -1, esto es, no supervisados, y éstos #no tendrán que participar en el cálculo de la medida. # Solución: # Se crea una función de pérdida que solo tiene en cuenta los valores de la Y #que no son -1. Función ssAccuracy, línea 63. import csv import random import warnings from SemiSuperDatasets.leeSemiSuperLetter import leeSemiSuperLetter from sklearn.svm import SVC from sklearn.metrics import accuracy_score from sklearn.model_selection import GridSearchCV,train_test_split,StratifiedKFold from sklearn.metrics import make_scorer from semisuperAA2.ssAccuracy import ssAccuracy from semisuperAA2.concatenaNE import concatenaNE_LS from sklearn.preprocessing import OneHotEncoder from sklearn.semi_supervised import SelfTrainingClassifier,LabelPropagation,LabelSpreading import matplotlib.pyplot as plt # Atributos usados en la representación (Cambiar al gusto. Valores en [0;15]) ix=6 iy=12 # Letras usadas como categoría (Cambiar al gusto. Valores letras mayúsculas en inglés) L1='M' L2='N' # Se lee el dataset, dividido en entrenamiento y test # El entranamiento se divide en supervisado y no supervisado # en este caso se toman 3/100 de ejemplos de entrenamiento para que haya algunos #más y así tener más ejemplos para los entrenamientos/test de la validación cruazada #del GridSerch [XTrSuper,YTrSuper,XTrNoSuper,YTrNoSuper,XTe,YTe]=leeSemiSuperLetter(letras=[L1,L2],semilla=1,propTest=1/3.0,propEti=3/100.0) #%% Descomposición del entrenamiento en validación cruzada # Vamos a simular una descomposición entrenamiento/test de una validación cruzada #donde el conjunto de entrenamiento esté compuesto por los ejemplos etiquetados #y los no etiquetados. # Para ello usaremos train_test_split: # https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html # Concatenamos los ejemplos etiquetados y no etiquetados para obtener el conjunto #de entrenamiento completo X=XTrSuper+XTrNoSuper Y=YTrSuper+YTrNoSuper # [XFoldTr,XFoldTe,YFoldTr,YFoldTe]=train_test_split(X,Y,test_size=1.0/3,random_state=1) import numpy as np def dibujaSS(X,Y,titulo,Atx=6,Aty=12): colors=['tab:gray','tab:orange','tab:blue'] markers=['x','s','s'] markerssize=[12,8,8] npY=np.array(Y) npX=np.array(X) tit=titulo plt.figure(figsize=[6,6]) plt.axis([0,14,0,16]) cates=np.unique(Y) for icate in range(len(cates)): cate=cates[icate] indexes=np.where(npY==cate)[0] xp=npX[indexes,Atx] yp=npX[indexes,Aty] plt.plot(xp,yp,color=colors[icate],linestyle='',marker=markers[icate], markersize=markerssize[icate],label='Clase:{}. Ejemplos:{}'.format(cate,len(indexes))) plt.title(titulo) plt.legend(loc='upper right') plt.savefig('Letter_{}.pdf'.format(titulo)) SplitsFolds=StratifiedKFold(n_splits=3,shuffle=True, random_state=1) folds=SplitsFolds.split(X,Y) X=np.array(X) Y=np.array(Y) dibujaSS(X,Y,'Entrenamiento') for i, (train_index, test_index) in enumerate(folds): fX=X[test_index,:] fY=Y[test_index] dibujaSS(fX,fY,'Fold_{}'.format(i)) #%% Variando NS # Aprenderemos con diferentes proporciones de no etiquetado en el conjunto de #entrenamiento para estudiar como afecta al error en test ntrSuper =len(XTrSuper) # Nº de ejemplos etiquetador ntrNoSuper=len(XTrNoSuper) # Nº de ejemplos no etiquetados # Algoritmos de aprendizaje semisupervisado LP=LabelPropagation(kernel='knn',n_neighbors=7,max_iter=1000) LPGS=GridSearchCV(LP,{'n_neighbors':[8,16,32]}, scoring=make_scorer(ssAccuracy,greater_is_better=True),cv=3) LS=LabelSpreading(kernel='knn',n_neighbors=7,max_iter=1000) LSGS=GridSearchCV(LS,{'n_neighbors':[8,16,32]}, scoring=make_scorer(ssAccuracy,greater_is_better=True),cv=3) # Proporciones de ejemplos no etiquetados PENS=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1] # Almacenes de aciertos para cada sistema LPAcs =[] LSAcs =[] LPGSAcs =[] LSGSAcs =[] LPMejoraGS=[] LSMejoraGS=[] nNoSupers=[] # Nº de ejemplos no etiquetados en cada iteración warnings.simplefilter("ignore") for PNS in PENS: # Crear el dataset con la proporción apropiada de no supervisados nNoSuper=int(ntrNoSuper*PNS) nNoSupers.append(nNoSuper) XTrSuNoSu=XTrSuper+XTrNoSuper[:nNoSuper] YTrSuNoSu=YTrSuper+YTrNoSuper[:nNoSuper] print('-LabelPropagation') LP.fit(XTrSuNoSu,YTrSuNoSu) P=LP.predict(XTe) LPAc=accuracy_score(YTe,P) LPAcs.append(LPAc) LPGS.fit(XTrSuNoSu,YTrSuNoSu) P=LPGS.predict(XTe) LPGSAc=accuracy_score(YTe,P) LPGSAcs.append(LPGSAc) LPMejoraGS.append(LPGSAc-LPAc) print('LabelSpreading') LS.fit(XTrSuNoSu,YTrSuNoSu) P=LS.predict(XTe) LSAc=accuracy_score(YTe,P) LSAcs.append(LSAc) print('len(LSAcs)={}'.format(len(LSAcs))) LSGS.fit(XTrSuNoSu,YTrSuNoSu) P=LSGS.predict(XTe) LSGSAc=accuracy_score(YTe,P) LSGSAcs.append(LSGSAc) LSMejoraGS.append(LSGSAc-LSAc) print('Ejemplos etiquetados:{:5}, no etiquetados:{:5}.' .format(ntrSuper,nNoSuper)) print(' Acierto: LP={:6.4f} LPGS={:6.4f} LS={:6.4f} LSGS={:6.4f} '. format(LPAc,LPGSAc,LSAc,LSGSAc)) #%% Gráfica de acierto - Ejemplos no etiquetados plt.figure() plt.title('Ejemplos etiquetados:{}'.format(ntrSuper)) plt.xlabel('Ejemplos no etiquetados') plt.ylabel('Acierto') plt.plot(nNoSupers,LPAcs,label='LP') plt.plot(nNoSupers,LPGSAcs,label='LP GS') plt.plot(nNoSupers,LSAcs,label='LS') plt.plot(nNoSupers,LSGSAcs,label='LS GS') plt.legend() plt.savefig('Letter_Acierto_ConSin_GS.pdf') #%% Gráfica de mejora del Grid Search - Ejemplos no etiquetados plt.figure() plt.tight_layout(pad=1.5) plt.title('Ejemplos etiquetados:{}'.format(ntrSuper)) plt.xlabel('Ejemplos no etiquetados') plt.ylabel('Mejora en acierto del GS') plt.plot(nNoSupers,LPMejoraGS,label='LP Mejora GS') plt.plot(nNoSupers,LSMejoraGS,label='LS Mejora GS') plt.grid(axis='y') plt.legend() plt.savefig('Letter_Mejora_GS.pdf') #%% Ejercicio 1 """ Con el algoritmo LS con kernel='knn' calcular cuanto mejora al utilizar Grid Search donde se busca en n_neighbors entre los valores 8, 16 y 32. Pero en este caso en cada entrenamiento de LS (incluído en el GridSearch) se han de utilizar TODOS los ejemplos no supervisados Repite la llamanda a leeSemiSuperLetter variando la semilla 20 veces (de 1 a 20) Imprimir la mejora media y el porcentaje de veces que gana utilizar Grid Search Salida: Semilla= 1 Acierto LS=0.6476 LS con GS=0.8648 mejora=+0.2171 Semilla= 2 Acierto LS=0.6952 LS con GS=0.8533 mejora=+0.1581 Semilla= 3 Acierto LS=0.7105 LS con GS=0.8629 mejora=+0.1524 Semilla= 4 Acierto LS=0.6705 LS con GS=0.8648 mejora=+0.1943 Semilla= 5 Acierto LS=0.6438 LS con GS=0.8571 mejora=+0.2133 Semilla= 6 Acierto LS=0.6667 LS con GS=0.8667 mejora=+0.2000 Semilla= 7 Acierto LS=0.6857 LS con GS=0.8552 mejora=+0.1695 Semilla= 8 Acierto LS=0.7010 LS con GS=0.8667 mejora=+0.1657 Semilla= 9 Acierto LS=0.7048 LS con GS=0.8800 mejora=+0.1752 Semilla=10 Acierto LS=0.6800 LS con GS=0.8571 mejora=+0.1771 Semilla=11 Acierto LS=0.7200 LS con GS=0.8838 mejora=+0.1638 Semilla=12 Acierto LS=0.7029 LS con GS=0.8610 mejora=+0.1581 Semilla=13 Acierto LS=0.6533 LS con GS=0.8514 mejora=+0.1981 Semilla=14 Acierto LS=0.6400 LS con GS=0.8838 mejora=+0.2438 Semilla=15 Acierto LS=0.6876 LS con GS=0.8610 mejora=+0.1733 Semilla=16 Acierto LS=0.6610 LS con GS=0.8514 mejora=+0.1905 Semilla=17 Acierto LS=0.6952 LS con GS=0.8610 mejora=+0.1657 Semilla=18 Acierto LS=0.6724 LS con GS=0.8667 mejora=+0.1943 Semilla=19 Acierto LS=0.7105 LS con GS=0.8724 mejora=+0.1619 Semilla=20 Acierto LS=0.6514 LS con GS=0.8495 mejora=+0.1981 Mejora media=0.1835 Hay mejora en el 100.0% de los experimentos """ semillas=list(range(1,20+1)) LSMejoraGS=[] VecesMejoraGS=0 for semilla in semillas: [XTrSuper,YTrSuper,XTrNoSuper,YTrNoSuper,XTe,YTe]=leeSemiSuperLetter(letras=[L1,L2],semilla=semilla,propTest=1/3.0,propEti=3/100.0) # Ejemplos etiquetados y no etiquetados XTrSuNoSu=XTrSuper+XTrNoSuper YTrSuNoSu=YTrSuper+YTrNoSuper #TODO 1.1 GSLS=GridSearchCV(LS,{'n_neighbors':[8,16,32]}, scoring=make_scorer(accuracy_score,greater_is_better=True),cv=3) #END 1.1 with warnings.catch_warnings(): warnings.simplefilter("ignore") # Sin GridSearch #TODO 1.2 LS.fit(XTrSuNoSu,YTrSuNoSu) P=LS.predict(XTe) LSAc=accuracy_score(YTe,P) LSAcs.append(LSAc) #END 1.2 # Con Grid Search #TODO 1.3 LSGS.fit(XTrSuNoSu,YTrSuNoSu) P=LSGS.predict(XTe) LSGSAc=accuracy_score(YTe,P) LSGSAcs.append(LSGSAc) #END 1.3 #TODO 1.4 MejoraGS=LSGSAc-LSAc # Cáclulo de la mejora #END 1.4 LSMejoraGS.append(MejoraGS) # Almacenar la mejora if MejoraGS>0: VecesMejoraGS=VecesMejoraGS+1 # Contar cuando el GS mejora a no GS print('Semilla={:2} Acierto LS={:6.4f} LS con GS={:6.4f} mejora={:+6.4f}'. format(semilla,LSAc,LSGSAc,LSGSAc-LSAc)) print('Mejora media={:6.4f}'.format(sum(LSMejoraGS)/len(semillas))) print('Hay mejora en el {:3.1f}% de los experimentos'.format(100*VecesMejoraGS/len(semillas)))

Pre Semi

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 3 : Aprendizaje SemiSupervisado (ASS) Sesión 2 : Parámetros y su optimización Blqoue B : Optimización de parámetros """ # Como se ha visto en el bloque anterior, los parámetros tienen una gran influencia #en la calidad de los sistemas. # Una manera adecuada para estimar los parámetros es utilizar GridSearchCV # Partiendo del código del Bloque A, añadir un sistema para LP y otro para LS #que optimice: # - gamma en [2**-2,2**-1,2**0,2**1,2**2] # - n_neighbors en [3,5,7,9,11] # Problema: # Los ejemplos que hay en el conjunto de datos son supervisados y no supervisados #y estos últimos también serán tratados por el CV del Grid Search, lo que #provocará que aparezcan en el los folds y por tanto en los tests. # Cuando se vaya a calcular la medida para un par Predicción(P) Valor en test(Y) #ocurrirá que habrá valores en Y que serán -1, esto es, no supervisados, y éstos #no tendrán que participar en el cálculo de la medida. # Solución: # Se crea una función de pérdida que solo tiene en cuenta los valores de la Y #que no son -1. Función ssAccuracy, línea 63. import csv import random import warnings from SemiSuperDatasets.leeSemiSuperLetter import leeSemiSuperLetter from sklearn.svm import SVC from sklearn.metrics import accuracy_score from sklearn.model_selection import GridSearchCV,train_test_split,StratifiedKFold from sklearn.metrics import make_scorer from semisuperAA2.ssAccuracy import ssAccuracy from sklearn.preprocessing import OneHotEncoder from sklearn.semi_supervised import SelfTrainingClassifier,LabelPropagation,LabelSpreading import matplotlib.pyplot as plt # Atributos usados en la representación (Cambiar al gusto. Valores en [0;15]) ix=6 iy=12 # Letras usadas como categoría (Cambiar al gusto. Valores letras mayúsculas en inglés) L1='M' L2='N' # Se lee el dataset, dividido en entrenamiento y test # El entranamiento se divide en supervisado y no supervisado # en este caso se toman 3/100 de ejemplos de entrenamiento para que haya algunos #más y así tener más ejemplos para los entrenamientos/test de la validación cruazada #del GridSerch [XTrSuper,YTrSuper,XTrNoSuper,YTrNoSuper,XTe,YTe]=leeSemiSuperLetter(letras=[L1,L2],semilla=1,propTest=1/3.0,propEti=3/100.0) #%% Descomposición del entrenamiento en validación cruzada # Vamos a simular una descomposición entrenamiento/test de una validación cruzada #donde el conjunto de entrenamiento esté compuesto por los ejemplos etiquetados #y los no etiquetados. # Para ello usaremos train_test_split: # https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html # Concatenamos los ejemplos etiquetados y no etiquetados para obtener el conjunto #de entrenamiento completo X=XTrSuper+XTrNoSuper Y=YTrSuper+YTrNoSuper # [XFoldTr,XFoldTe,YFoldTr,YFoldTe]=train_test_split(X,Y,test_size=1.0/3,random_state=1) import numpy as np def dibujaSS(X,Y,titulo,Atx=6,Aty=12): colors=['tab:gray','tab:orange','tab:blue'] markers=['x','s','s'] markerssize=[12,8,8] npY=np.array(Y) npX=np.array(X) tit=titulo plt.figure(figsize=[6,6]) plt.axis([0,14,0,16]) cates=np.unique(Y).tolist() if -1 not in cates: cates=[-1]+cates for icate in range(len(cates)): cate=cates[icate] indexes=np.where(npY==cate)[0] if len(indexes)>0: xp=npX[indexes,Atx] yp=npX[indexes,Aty] plt.plot(xp,yp,color=colors[icate],linestyle='',marker=markers[icate], markersize=markerssize[icate],label='Clase:{}. Ejemplos:{}'.format(cate,len(indexes))) plt.title(titulo) plt.legend(loc='upper right') plt.savefig('Letter_{}.pdf'.format(titulo)) X=np.array(X) Y=np.array(Y) dibujaSS(X,Y,'Entrenamiento') dibujaSS(XTrSuper,YTrSuper,'Entrenamiento etiquetado') dibujaSS(XTrNoSuper,YTrNoSuper,'Entrenamiento NO etiquetado') # Los no etiquetados se distribuyen por los folds SplitsFolds=StratifiedKFold(n_splits=3,shuffle=True, random_state=1) folds=SplitsFolds.split(X,Y) for i, (train_index, test_index) in enumerate(folds): fX=X[test_index,:] fY=Y[test_index] dibujaSS(fX,fY,'Fold_{}'.format(i)) # Solo los ejemplos etiquetados se distribuyen por los folds SplitsFolds=StratifiedKFold(n_splits=3,shuffle=True, random_state=1) folds=SplitsFolds.split(XTrSuper,YTrSuper) for i, (train_index, test_index) in enumerate(folds): fX=X[test_index,:] fY=Y[test_index] dibujaSS(fX,fY,'Fold_{}'.format(i))

Actividad 1

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 3 : Aprendizaje SemiSupervisado (ASS) Sesión 2 : Parámetros y su optimización Actividad 1 """ from sklearn.semi_supervised import LabelSpreading from sklearn.metrics.pairwise import rbf_kernel,sigmoid_kernel,chi2_kernel,laplacian_kernel from SemiSuperDatasets.leeSemiSuperLetter import leeSemiSuperLetter from sklearn.model_selection import GridSearchCV from sklearn.metrics import accuracy_score,make_scorer import warnings import math import numpy as np # Letras usadas como categoría (Cambiar al gusto. Valores letras mayúsculas en inglés) L1='M' L2='N' [XTrSuper,YTrSuper,XTrNoSuper,YTrNoSuper,XTe,YTe]=leeSemiSuperLetter(letras=[L1,L2],semilla=1,propTest=1/3.0,propEti=3/100.0) XTr=XTrSuper+XTrNoSuper YTr=YTrSuper+YTrNoSuper #%% Ejericicio 0 """ Partiendo del problema de la sesión 2: Se quiere probar con varios kernels. A continuación se muestra un uso de entrenamiento/test con 4 opciones: A) predefinido (constante cadena) B) pairwise kernel (con valores por defecto) C) función que llama a pairwise kernel y que fija parámetros D) objeto que implementa el método __call__ y que se da valor a gamma en el constructor (__init__) En este ejercicio no hay que programar, solo entender lo hecho """ # A) Kernel 'rbf' # Se pasa como constante cadena. Gamma=20 LSrbf=LabelSpreading(kernel='rbf') LSrbf.fit(XTr,YTr) Prbf=LSrbf.predict(XTe) # B) Kernel rbf pairwise: # https://scikit-learn.org/stable/modules/metrics.html#metrics # gamma= 1 / atributos LSKrbf=LabelSpreading(kernel=rbf_kernel) LSKrbf.fit(XTr,YTr) PKrbf=LSKrbf.predict(XTe) # C) Kernel rbf donde se especifica el valor de gamma # Es necesario crear una función nueva, ya que el parámetro gamma no se puede #pasar explícitamente en la llamada al kernel # En este caso gamma=1 def miKernelRBFGammaFijo(X1,X2): return rbf_kernel(X1,X2,gamma=1) LSMKrbfGF=LabelSpreading(kernel=miKernelRBFGammaFijo) LSMKrbfGF.fit(XTr,YTr) PMKrbfGF=LSMKrbfGF.predict(XTe) # D) Kernel como llamada al método __call__ de un objeto donde el valor gamma #se para como parámetro al constructor. De esta manera se puede indicar el valor #de gamma sin que sea fijo como en el caso C) class MiKernelRBFGammaVariable: def __init__(self,gamma): self.gamma=gamma def __call__(self,X1,X2): return rbf_kernel(X1,X2,self.gamma) def __str__(self): return 'MiKernelRBFGammaVariable(gamma={})'.format(self.gamma) miKrbfGV=MiKernelRBFGammaVariable(gamma=2) LSMKrbfGV=LabelSpreading(kernel=miKrbfGV) LSMKrbfGV.fit(XTr,YTr) PMKrbfGV=LSMKrbfGV.predict(XTe) print('LS(rbf) : accuracy_score={:6.4f}'.format(accuracy_score(YTe,Prbf))) print('LS(Krbf) : accuracy_score={:6.4f}'.format(accuracy_score(YTe,PKrbf))) print('LS(MKrbfGF): accuracy_score={:6.4f}'.format(accuracy_score(YTe,PMKrbfGF))) print('LS(MKrbfGV): accuracy_score={:6.4f}'.format(accuracy_score(YTe,PMKrbfGV))) #%% Ejercicio 1 """ Repite los pasos B), C) y D) con el kernel Laplacian : laplacian_kernel Puedes utilizar las siglas: lpc NOTA: puedes copiar y pegar todo el código anterior y luego 1 seleccionas el texto pegado 2 reemplazar (Ctrl+r) "rbf" por "lpc" solo en la selección 3 cambiar rbf_kernel (ahora será lpc_kernel) por laplacian_kernel SALIDA: LS(Klpc) : accuracy_score=0.8762 LS(MKlpcGF): accuracy_score=0.9067 LS(MKlpcGV): accuracy_score=0.9048 """ #TODO 1 # B) Kernel lpc pairwise: # https://scikit-learn.org/stable/modules/metrics.html#metrics # gamma= 1 / atributos LSKlpc=LabelSpreading(kernel=laplacian_kernel) LSKlpc.fit(XTr,YTr) PKlpc=LSKlpc.predict(XTe) # C) Kernel lpc donde se especifica el valor de gamma # Es necesario crear una función nueva, ya que el parámetro gamma no se puede #pasar explícitamente en la llamada al kernel # En este caso gamma=1 def miKernellpcGammaFijo(X1,X2): return laplacian_kernel(X1,X2,gamma=1) LSMKlpcGF=LabelSpreading(kernel=miKernellpcGammaFijo) LSMKlpcGF.fit(XTr,YTr) PMKlpcGF=LSMKlpcGF.predict(XTe) # D) Kernel como llamada al método __call__ de un objeto donde el valor gamma #se para como parámetro al constructor. De esta manera se puede indicar el valor #de gamma sin que sea fijo como en el caso C) class MiKernelLPCGammaVariable: def __init__(self,gamma): self.gamma=gamma def __call__(self,X1,X2): return laplacian_kernel(X1,X2,self.gamma) def __str__(self): return 'MiKernellpcGammaVariable(gamma={})'.format(self.gamma) miKlpcGV=MiKernelLPCGammaVariable(gamma=2) LSMKlpcGV=LabelSpreading(kernel=miKlpcGV) LSMKlpcGV.fit(XTr,YTr) PMKlpcGV=LSMKlpcGV.predict(XTe) print('LS(Klpc) : accuracy_score={:6.4f}'.format(accuracy_score(YTe,PKlpc))) print('LS(MKlpcGF): accuracy_score={:6.4f}'.format(accuracy_score(YTe,PMKlpcGF))) print('LS(MKlpcGV): accuracy_score={:6.4f}'.format(accuracy_score(YTe,PMKlpcGV))) #END 1 #%% Ejercicio 2 """ Se quiere buscar el mejor conjunto de hiperparámetros para LS entre los kernels: rfb con gamma [0.1,1,10] lpc con gamma [0.1,1,10] Crear un modelo con ese mejor kernel y aplicarlo al test PISTA: Se puede utilizar un grid search sobre LS para determinar el kernel, pero no se puede utilizar para buscar el hiperparámetro gamma de lpc porque no está como parámetro del objeto LS. La solución que se propone es crear 3 kernels rfb y 3 kernels lpc mediante objetos kernel (opción D) y utilizarlos en un grid search donde solo varíe el parámetro kernel. PISTA: utiliza la función ssAccuracy (los test pueden tener ejemplos no etiquetados) """ def ssAccuracy(Y,P): """ Calcula accuracy_score sobre los ejemplos cuya Y no vale -1 """ Yf=[] Pf=[] for r in range(len(Y)): if Y[r]!=-1: Yf.append(Y[r]) Pf.append(P[r]) return accuracy_score(Yf,Pf) #TODO 2 KernelsGS=[MiKernelRBFGammaVariable(gamma=0.1), MiKernelRBFGammaVariable(gamma=1), MiKernelRBFGammaVariable(gamma=10), MiKernelLPCGammaVariable(gamma=0.1), MiKernelLPCGammaVariable(gamma=1), MiKernelLPCGammaVariable(gamma=10)] LS=LabelSpreading(max_iter=1000) LSGS=GridSearchCV(LS,{'kernel':KernelsGS}, scoring=make_scorer(ssAccuracy,greater_is_better=True),cv=3) #END 2 LSGS.fit(XTr,YTr) P=LSGS.predict(XTe) print('GridSearch(LS) : best kernel={}'.format(LSGS.best_estimator_.kernel)) print('GridSearch(LS): accuracy_score={:6.4f}'.format(accuracy_score(YTe,P)))

NoPresencial

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 3 : Aprendizaje SemiSupervisado (ASS) Sesión 2 : Definición del problema y algoritmos de ASS Actividad del Campus Virtual """ import warnings import matplotlib.pyplot as plt import numpy as np from sklearn.semi_supervised import LabelPropagation,LabelSpreading from sklearn.metrics import accuracy_score import random def genTest(puntosLado=25): X=[] Y=[] def i2v(pl,i): mpl=pl/2 return (i-mpl)/mpl for f in range(puntosLado): y=i2v(puntosLado,f) for c in range(puntosLado): x=i2v(puntosLado,c) mod=(y**2+x**2)**0.5 if mod<0.5: X.append([x,y]) Y.append(0) elif mod>0.75: X.append([x,y]) Y.append(1) return [X,Y] def pinta(X,titulo): X=np.array(X) plt.figure() plt.title(titulo) X0=X[:,0] X1=X[:,1] plt.plot(X0,X1,color='grey',linestyle='None',markersize=12,marker='o') #%% Ejercicio 1 """ Se tienen que clasificar los puntos en una zona donde hay un FOSO. El foso está centrado en la posición (0,0) y empieza a una distancia 0.5 del centro y termina a una distancia 0.75. Solo se saben dos puntos: el punto (0,0) es de clase 0 y el punto (1,1) es de clase 1. Pero sí se conocen los ejemplos no supervisados: XNs Crear un sistema de aprendizaje no supervisasdo untilizando LabelSpreading de manera que ajuste los hyperparámetros gamma y alpha (Se indican valores) y que al ajustarlos tenga en cuenta TODOS los no supervisados en cada aprendizaje que haga Realizar un entrenamiento / test , calcular la accuracy e imprimirla Se piden 3 situaciones: 1) No se utilizan no supervisados en ningún caso 2) Se utilizan PARTE de los no supervisados en el GridSearchCV y TODOS al entrenar el modelo final 3) Se utilizan TODOS los no supervisados, tanto en el GridSearch como en el modelo final NOTA: Hiperparámetro recomendado a usar en LabelSpreading max_iter=100000 Ejemplo de salida: 1) Accuracy SIN ejemplos no etiquetados: 0.2559 Hyperparámetros elegidos:{'alpha': 0.9, 'gamma': 1} 2) Accuracy CON PARTE de ejemplos no etiquetados en en cada fit del GS y CON TODOS los ejemplos no etiquetados en train: 0.2559 Hyperparámetros elegidos:{'alpha': 0.9, 'gamma': 1} 3) Accuracy CON TODOS los ejemplos no etiquetados en cada fit: 1.0000 Hyperparámetros elegidos:{'alpha': 0.9, 'gamma': 100} """ # Test [XTe,YTe]=genTest() pinta(XTe,'FOSO') # Ejemplos con categoría XTr=[[0,0],[1,1],[0.1,0],[-0.92,1],[0,0.1],[1,-0.89],[-0.11,-0.1],[-0.91,-0.9]] YTr=[ 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 ] # No etiquetados XNs=XTe # Valores para ajustar valoresGamma=[10**+i for i in range(0,+3+1)] valoresAlpha=[1-(10**-i) for i in range(1,5)] # Sistema de aprendizaje no supervisado from sklearn.metrics import accuracy_score from semisuperAA2.ssAccuracy import ssAccuracy from sklearn.metrics import make_scorer from sklearn.semi_supervised import LabelSpreading from sklearn.model_selection import GridSearchCV from sklearn.metrics import make_scorer # NOTA: Hiperparámetro recomendado a usar en LabelSpreading max_iter=100000 with warnings.catch_warnings(): warnings.simplefilter("ignore") #%% SIN NO etiquetados #TODO 1.1 LS=LabelSpreading(max_iter=max_iter) LSGS=GridSearchCV(LS,{'gamma':valoresGamma,'alpha':valoresAlpha}, scoring=make_scorer(accuracy_score,greater_is_better=True),cv=2) #END 1.1 # Train Test #TODO 1.2 LSGS.fit(XTr,YTr) P=LSGS.predict(XTe) Acc=accuracy_score(YTe,P) #END 1.2 print('1) Accuracy SIN ejemplos no etiquetados: {:6.4f}'.format(Acc)) print(' Hyperparámetros elegidos:{}\n'.format(LSGS.best_params_)) #%% CON PARTE de ejemplos no etiquetados en en cada fit del GridSearch y CON TODOS los ejemplos no etiquetados en train #TODO 1.3 LS=LabelSpreading(max_iter=max_iter) LSGS=GridSearchCV(LS,{'gamma':valoresGamma,'alpha':valoresAlpha}, scoring=make_scorer(ssAccuracy,greater_is_better=True),cv=2) #END 1.3 # Train Test #TODO 1.4 XTrNS=XTr+XNs YTrNS=YTr+[-1]*len(XNs) LSGS.fit(XTrNS,YTrNS) P=LSGS.predict(XTe) Acc=accuracy_score(YTe,P) #END 1.4 print('2) Accuracy CON PARTE de ejemplos no etiquetados en en cada fit del GS\n y CON TODOS los ejemplos no etiquetados en train: {:6.4f}'.format(Acc)) print(' Hyperparámetros elegidos:{}\n'.format(LSGS.best_params_)) #%% CON TODOS los NO etiquetados tanto es la estimación de los hyperparámetros como en train #TODO 1.5 from semisuperAA2.concatenaNE import concatenaNE_LS LS=concatenaNE_LS(XNs,max_iter=max_iter) LSGS=GridSearchCV(LS,{'gamma':valoresGamma,'alpha':valoresAlpha}, scoring=make_scorer(accuracy_score,greater_is_better=True),cv=2) #END 1.5 # Train Test #TODO 1.6 LSGS.fit(XTr,YTr) P=LSGS.predict(XTe) Acc=accuracy_score(YTe,P) #END 1.6 print('3) Accuracy CON TODOS los ejemplos no etiquetados en cada fit: {:6.4f}'.format(Acc)) print(' Hyperparámetros elegidos:{}\n'.format(LSGS.best_params_))

Tema 4 Sesion 1

Apartado A

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 4 : Aprendizaje No Supervisado (ANS) Sesión 1 : Definición del problema y algoritmos de ANS Bloque A : Sistemas de Clustering transductivos """ # Para conjuntos sin categoría puede ser útil hacer grupos (clusters) # Utilizaremos los algoritmos de clústering de sklearn # https://scikit-learn.org/stable/modules/clustering.html # Los sistemas de clustering transductivos solo asignan clusters a los ejemplos #de entrenamiento. # Desde el punto de vista de la implementación no tienen método predict, si no, #fit_predict, que realiza una aprendizaje y predicción del cluster de los ejemplos #de entrenamiento # En este bloque se muestra los clusters creados por el algoritmo #AgglomerativeClustering from simpleGen import simpleGen,pintaSimpleClusters from sklearn.cluster import AgglomerativeClustering,DBSCAN import matplotlib.pyplot as plt import numpy as np import random nejemplos=50 # Número de ejemplos no etiqeutados por cada distrubución RG=random.Random() # Generador de números aleatorios RG.seed(1) # Semilla del generador de números aleatorios for sd in [0.1, 0.5, 1]: # Para diferentes valores de desviación típica (sd) simple=simpleGen(sd=sd) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetados CSAC=AgglomerativeClustering(n_clusters=2) # Crear el objeto de Clustering clusters = CSAC.fit_predict(X) pintaSimpleClusters(clusters,X,'sd={} AgglomerativeClustering'.format(sd),'AgglomerativeClustering_sd_{}'.format(sd)) #%% Ejercicio 1 """ Para cada conjunto de datos simple con sd en [0.1; 0.5; 1.0] Crea 2 clústers con AgglomerativeClustering Imprime para cada clúster cuántos ejemplos tiene. NOTAS: El número de clusters viene en el campo n_clusters del objeto (CSAC). Estos se numeran de 0 a (n_clusters-1) El objeto retornado por AgglomerativeClustering.fit_predict (clusters) es una lista con el identificador del cluster que el algoritmo asigna a cada ejemplo El código: indices=np.where(clusters==label)[0] retorna los índices que están asignados al clúster label. PISTA: Utiliza el código del bucle anterior y cambia 'pintaClusters' por un código que imprima el número de ejemplos de cada clúster SALIDA simple sd=0.1 Clúster 0 Ejemplos:50 Clúster 1 Ejemplos:50 simple sd=0.5 Clúster 0 Ejemplos:49 Clúster 1 Ejemplos:51 simple sd=1 Clúster 0 Ejemplos:59 Clúster 1 Ejemplos:41 """ for sd in [0.1, 0.5, 1]: # Para diferentes valores de desviación típica (sd) simple=simpleGen(sd=sd) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetados #TODO Ejercicio 1 CSAC=AgglomerativeClustering(n_clusters=2) clusters = CSAC.fit_predict(X) print('simple sd={}'.format(sd)) for label in range(CSAC.n_clusters): indices=np.where(clusters==label)[0] print(' Clúster {} Ejemplos:{}'.format(label,len(indices))) #END Ejercicio 1 #%% Ejercicio 2 """ Basado en el ejercicio 1 realizar otro que utilice DBSCAN https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html Este algoritmo no tiene como hiperparámetro el número de clústers (n_clusters) sino eps, que es la distancia máxima para indicar vecindad. En vez de iterar por el valor de sd para simple, fijar sd=1 e iterar por eps en [0.1,0.5, 1] NOTA: Este algoritmo descarta algunos ejemplos de agregarlos a clústers, los etiqueta con valor -1 PISTA: Este algoritmo no tiene el campo n_clusters. En su lugar se puede utilizar el siguiente bucle para iterar por las etiquetas: for label in np.unique(clusters): SALIDA: ver figuras: DBSCAN_eps=*.pdf DBSCAN(eps=0.5) Clúster -1 Ejemplos:30 Clúster 0 Ejemplos:6 Clúster 1 Ejemplos:5 Clúster 2 Ejemplos:12 Clúster 3 Ejemplos:11 Clúster 4 Ejemplos:20 Clúster 5 Ejemplos:6 Clúster 6 Ejemplos:6 Clúster 7 Ejemplos:4 DBSCAN(eps=0.75) Clúster -1 Ejemplos:7 Clúster 0 Ejemplos:84 Clúster 1 Ejemplos:9 DBSCAN(eps=1) Clúster -1 Ejemplos:2 Clúster 0 Ejemplos:98 """ simple=simpleGen(sd=1) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetados for eps in [0.5, 0.75, 1]: # Para diferentes valores de desviación típica (sd) #TODO Ejercicio 2 CSDBS=DBSCAN(eps=eps) clusters = CSDBS.fit_predict(X) print('DBSCAN(eps={})'.format(eps)) for label in np.unique(clusters): indices=np.where(clusters==label)[0] # Índices del clúster label print(' Clúster {} Ejemplos:{}'.format(label,len(indices))) #END Ejercicio 2 pintaSimpleClusters(clusters,X,'DBSCAN(eps={})'.format(eps),'DBSCAN_eps={}'.format(eps))

Apartado B

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 5 : Aprendizaje No Supervisado (ANS) Sesión 1 : Definición del problema y algoritmos de ANS Bloque B : Sistemas de Clustering inductivos """ # Los Sistemas de ANS inductivos permiten asignar clusters a ejemplos que #no son de entrenamiento. # Desde el punto de vista de la implementación tienen los métodos fit y predict. # En este ejemplo se utilizará el algoritmo KMeans # https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html # Una vez entrenado, el objeto KMeans tiene el campo # cluster_centers_ : lista con el centroide de cada cluster from simpleGen import simpleGen,pintaSimpleClusters from sklearn.cluster import KMeans,MeanShift import numpy as np import random nejemplos=50 # Número de ejemplos no etiqeutados por cada distrubución RG=random.Random() # Generador de números aleatorios RG.seed(1) # Semilla del generador de números aleatorios for sd in [0.1, 0.5, 1]: # Para diferentes valores de desviación típica (sd) simple=simpleGen(sd=sd) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetados CSKMeans=KMeans(n_clusters=2,random_state=1) # Crear el objeto de Clustering CSKMeans.fit(X) clusters=CSKMeans.predict(X) pintaSimpleClusters(clusters,X,'KMeans(n_clusters={}) sd={}'.format(CSKMeans.n_clusters,sd),'KMeans_sd_{}_'.format(sd),CSKMeans.cluster_centers_) #%% Ejercicio 1 """ Para cada conjunto de datos simple con sd en [0.1; 0.5; 1.0] Crea 2 clústers con KMeans Imprime para cada clúster cuántos ejemplos tiene. NOTAS: CSKMeans.cluster_centers_ almacena los centroides de los clústers creados. El número de centroides es el número de clusters clusters es una lista con el identificador del cluster que el algoritmo asigna a cada ejemplo El código: indices=np.where(clusters==label)[0] retorna los índices que están asignados al clúster label. SALIDA simple sd=0.1 Clúster 0 Ejemplos:50 Clúster 1 Ejemplos:50 simple sd=0.5 Clúster 0 Ejemplos:49 Clúster 1 Ejemplos:51 simple sd=1 Clúster 0 Ejemplos:55 Clúster 1 Ejemplos:45 """ #<TODO BEGIN Ejercicio 1> for sd in [0.1, 0.5, 1]: simple=simpleGen(sd=sd) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetados #TODO 1 CSKMeans=KMeans(n_clusters=2,random_state=1) #Crea un modelo de K-Means configurado para: CSKMeans.fit(X) #Entrena el modelo K-Means sobre los datos generados X. clusters=CSKMeans.predict(X) #Clasifica cada punto en uno de los 2 clústeres según los centros aprendidos. print('simple sd={}'.format(sd)) for label in range(len(CSKMeans.cluster_centers_)): #Itera sobre los índices de los clústeres. Como n_clusters=2, esto equivale a: for label in [0,1]: indices=np.where(clusters==label)[0] #Obtiene los índices de los ejemplos asignados a ese clúster. print(' Clúster {} Ejemplos:{}'.format(label,len(indices))) #END 1 #%% Ejercicio 2 """ Basado en el ejercicio 1 realizar otro que utilice MeanShift https://scikit-learn.org/stable/modules/generated/sklearn.cluster.MeanShift.html Este algoritmo no tiene como hiperparámetro el número de clústers (n_clusters) sino el ancho de banda (bandwidth). El número de clusters se calcula automáticamente para los datos dados y el bandwidth En vez de iterar por el valor de sd para simple, fijar sd=1 e iterar bandwidth en [1,1.25,1.5,1.75,2,None] (Cuando se utiliza None se calcula automáticament un valor) SALIDA: Ficheros: simple_MeanShift_bandwidth=*.pdf MeanShift bandwidth=1 Clúster 0 Ejemplos:22 Clúster 1 Ejemplos:15 Clúster 2 Ejemplos:16 Clúster 3 Ejemplos:11 Clúster 4 Ejemplos:8 Clúster 5 Ejemplos:10 Clúster 6 Ejemplos:9 Clúster 7 Ejemplos:7 Clúster 8 Ejemplos:1 Clúster 9 Ejemplos:1 MeanShift bandwidth=1.25 Clúster 0 Ejemplos:54 Clúster 1 Ejemplos:20 Clúster 2 Ejemplos:26 MeanShift bandwidth=1.5 Clúster 0 Ejemplos:56 Clúster 1 Ejemplos:44 MeanShift bandwidth=1.75 Clúster 0 Ejemplos:53 Clúster 1 Ejemplos:47 MeanShift bandwidth=2 Clúster 0 Ejemplos:100 """ simple=simpleGen(sd=1) Xs=simple(RG,nejemplos) # Generar los ejemplos no etiquetados for bandwidth in [1,1.25,1.5,1.75,2,None]: # Para diferentes valores de bandwidth #TODO Ejercicio 2 CSMeanShift=MeanShift(bandwidth=bandwidth) #Crea un objeto del algoritmo de clustering MeanShift usando el bandwidth actual. CSMeanShift.fit(Xs) #Entrena el modelo MeanShift sobre los datos X. clusters=CSMeanShift.predict(X) #Asigna cada punto a uno de los clústeres obtenidos durante el entrenamiento. print('MeanShift bandwidth={}'.format(bandwidth)) for label in range(len(CSMeanShift.cluster_centers_)): #Recorre cada clúster encontrado por MeanShift. Su longitud indica cuántos clústeres hay. indices=np.where(clusters==label)[0] print(' Clúster {} Ejemplos:{}'.format(label,len(indices))) #END Ejercicio 2 pintaSimpleClusters(clusters,X,'MeanShift(bandwidth={})'.format(bandwidth),'MeanShift_bandwidth={}'.format(bandwidth),CSMeanShift.cluster_centers_)

Apartado C

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 4 : Aprendizaje No Supervisado (ANS) Sesión 1 : Definición del problema y algoritmos de ANS Bloque C : Definir distancia """ # Un parámetro crítico para realizar clústers es la distancia, entendida como #función que dados 2 ejemplos retorna un valor numérico que pueda ser entendida #como distancia # En este ejemplo se utilizará el algoritmo AgglomerativeClustering # https://scikit-learn.org/stable/modules/generated/sklearn.cluster.AgglomerativeClustering.html # Tiene el parámetro metric que permite definir la distancia from simpleGen import concentricoGen,pintaSimpleClusters from sklearn.cluster import AgglomerativeClustering import numpy as np import random # Crear conjunto concéntrico nejemplos=200 # Número de ejemplos no etiquetados por cada distrubución RG=random.Random() # Generador de números aleatorios RG.seed(1) conGen=concentricoGen() X=conGen(RG,nejemplos,nejemplos) pintaSimpleClusters(None,X,'datos concéntricos','datosConcen.pdf') # Clústers con distancia euclídea cluGen=AgglomerativeClustering(n_clusters=2,linkage='average',metric='euclidean') C=cluGen.fit_predict(X) pintaSimpleClusters(C,X,'datos concéntricos. AgglomerativeClustering(euclidean) ','datosConcenAgloEucli.pdf') # Clústers con distancia determinada solo por el radio class distancia: """ Clase padre de distancias. Calcula la matriz de distancias (simétrica con diagonal 0). Clase abstracta. Las clases hijas necesitan definir _distanciaPar(self,E1,E2) Que dados dos ejemplos retorna su distancia """ def __call__(self,X): """ Retorna la matriz de distancias de la lista de ejemplos Parámetros: -X : lista de ejemplos (solo atributos, sin categoría) """ M=np.zeros([len(X),len(X)]) for i in range(len(X)-1): for j in range(i+1,len(X)): M[i,j]=self._distanciaPar(X[i],X[j]) M[j,i]=M[i,j] return M def _distanciaPar(self,E1,E2): """ Método a ser redefinido en la clase hija. Dados dos ejemplos retorna su distancia. """ pass class distanciaRadio(distancia): """ Clase que define la distancia radio. """ def _distanciaPar(self,E1,E2): """ Distancia Radio entre dos ejemplos. Se calcula la distancia del punto 0 a E1 y a E2, serán los radios r1 y r2 La distancia entre los radios será la distancia entre los ejemplos. """ r1=0 r2=0 for i in range(len(E1)): r1=r1+E1[i]**2 r2=r2+E2[i]**2 r1=r1**0.5 r2=r2**0.5 return abs(r1-r2) cluGen=AgglomerativeClustering(n_clusters=2,linkage='average',metric=distanciaRadio()) C=cluGen.fit_predict(X) pintaSimpleClusters(C,X,'datos concéntricos. AgglomerativeClustering(disRadio) ','datosConcenAglodisRadio.pdf') #%% Ejercicio 1 """ Crea una distancia entre lo parecidos que son los valores de los ejemplos. Paso 1: Piensa una medida de similitud (MS) entre los valores(atributos) de un ejemplo. Si un ejemplo tiene todos los valores iguales valdrá 0, si no, aumentará. Paso 2: La distancia entre dos ejemplos será la distancia entre sus MS. Esa distancia puede ser en valor absoluto, cuadrática, ... NOTA: Se puede calcular la igualdad de un ejemplo E como la desviación típica de los valores del ejemplo: np.std(E) SALIDA: ver plots/datosConcenAglodistanciaIgualdad.pdf """ class distanciaIgualdad(distancia): def _distanciaPar(self,E1,E2): #TODO 1.1 # Igualdad de cada uno de los ejemplos I1=np.std(E1) # Calculamos la igualdad del ejemplo 1 I2=np.std(E2) # Calculamos la igualdad del ejemplo 2 #END 1.1 #TODO 1.2 # Retornar la distancia entre esas igualdades return abs(I1-I2) # La distancia entre las igualdades nos da la # distancia de este par de ejemplos #END 1.2 cluGen=AgglomerativeClustering(n_clusters=2,linkage='average',metric=distanciaIgualdad()) C=cluGen.fit_predict(X) pintaSimpleClusters(C,X,'datos concéntricos. AgglomerativeClustering(distanciaIgualdad) ','datosConcenAglodistanciaIgualdad.pdf')

Pre No supervisado

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 4 : Aprendizaje No Supervisado (ANS) Sesión 1 : Definición del problema y algoritmos de ANS Bloque Pre : Problemas no supervisados """ # Hay conjuntos de datos que no tienen una categoría, solo atributos y sus valores. # En este bloque se muestra un conjunto de ejemplos llamado 'simple' que tiene #dos atributos y ejemplos que siguen dos distribuciones normales en media: # (+1,+1) y (-1,-1). # Se gereran para desviaciones dípicas (sd) 0.1, 0.5 y 1 from simpleGen import simpleGen import matplotlib.pyplot as plt import numpy as np import random from sklearn.metrics.pairwise import euclidean_distances def cluAleaSimple(RG,X): CluTra=[] for x in X: # Para cada ejemplo # Calcular un ejemplo de la distribución negativa y otro de la positiva x1NegAlea=RG.normalvariate(-1,1) x2NegAlea=RG.normalvariate(-1,1) x1PosAlea=RG.normalvariate(+1,1) x2PosAlea=RG.normalvariate(+1,1) # Secalculan las distancias a cada ejemplo generado dNeg=euclidean_distances([x,[x1NegAlea,x2NegAlea]])[0][1] dPos=euclidean_distances([x,[x1PosAlea,x2PosAlea]])[0][1] # El cluster lo determinará el más cercano CluTra.append(-1 if dNeg<dPos else +1) return np.array(CluTra) nejemplos=50 # Número de ejemplos no etiqeutados por cada distrubución RG=random.Random() # Generador de números aleatorios for sd in [0.1, 0.5, 1]: # Para diferentes valores de desviación típica (sd) simple=simpleGen(sd=sd) # Generador de ejemplos no etiquetados RG.seed(1) # Semilla del generador de números aleatorios X=simple(RG,nejemplos) # Generar los ejemplos no etiquetados # Pintar los ejemplos plt.figure() plt.xlim([-3,+3]) plt.ylim([-3,+3]) plt.plot(X[:,0],X[:,1],linestyle='None',marker='o',color='tab:gray') plt.xlabel('Atributo 0') plt.ylabel('Atributo 1') plt.title('simple {0}+{0} ejemplos. sd={1}'.format(nejemplos,simple.sd)) plt.savefig('plots/simple_sd_{}.pdf'.format(simple.sd)) # Hay dos tipos de clústers: # Transductivo: define una partición del conjunto de ejemplos, # no se puede aplicar a ejemplos no vistos # Inductivo : existe un modelo que permite crear una partición sobre el conjunto # de entrenamiento y sobre ejempos no vistos # Usando el ejemplo de SD=1 simple=simpleGen(sd=1) RG.seed(1) # Semilla del generador de números aleatorios X=simple(RG,nejemplos) # Se crea un Transductivo aleatorio, utilizando las mismas distribuciones con #que fueron creados los ejemplos CluTra=cluAleaSimple(RG,X) # Pintar el cluster plt.figure() plt.xlim([-3,+3]) plt.ylim([-3,+3]) indNeg=np.where(CluTra==-1) plt.plot(X[indNeg,0],X[indNeg,1],linestyle='None',marker='o',color='red') indPos=np.where(CluTra==+1) plt.plot(X[indPos,0],X[indPos,1],linestyle='None',marker='o',color='blue') plt.xlabel('Atributo 0') plt.ylabel('Atributo 1') plt.title('Cluster Transductivo aleatorio'.format(nejemplos,simple.sd)) plt.savefig('plots/ClusTrans.pdf'.format(simple.sd)) # Se crea un cluster inductivo con el modelo atributo0>atributo1 CluInd=np.array([+1 if x[0]>x[1] else -1 for x in X]) # Pintar el cluster plt.figure() plt.xlim([-3,+3]) plt.ylim([-3,+3]) indNeg=np.where(CluInd==-1) plt.plot(X[indNeg,0],X[indNeg,1],linestyle='None',marker='o',color='red') indPos=np.where(CluInd==+1) plt.plot(X[indPos,0],X[indPos,1],linestyle='None',marker='o',color='blue') plt.xlabel('Atributo 0') plt.ylabel('Atributo 1') plt.title('Cluster Inductivo atr0>atr1'.format(nejemplos,simple.sd)) plt.savefig('plots/ClusInduc.pdf'.format(simple.sd))

Actividad Presencial

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 4 : Aprendizaje No Supervisado (ANS) Sesión 1 : Definición del problema y algoritmos de ANS Actividad 1 """ from simpleGen import pintaSimpleClusters from NoSuperDatasets.leeIris import leeIris import numpy as np import random def grid(xmin=1,xmax=7,ymin=0,ymax=3,step=0.1): """ Crea un conjunto de datos sin etiquetar de dos atributos. Los valores están en los intervalos [xmin,xmax] para el primer atributo e [ymin,ymax] para el segundo. Los valores se obtienen consecutivamente cada step (paso) """ # Valores verticales Y=[] y=ymin while y<=ymax: Y.append(y) y=y+step # Valores horizontales X=[] x=xmin while x<=xmax: X.append(x) x=x+step M=[] for y in Y: for x in X: M.append([x,y]) return np.array(M) XIris=leeIris() XGrid=grid(xmin=1,xmax=7,ymin=0,ymax=3,step=0.1) #%% Ejercicio 1 """ DATOS: XIris es un conjunto no etiquetado del dataset iris donde solo hay 2 atributos (los dos más relevantes) XGrid es un conjunto no etiquetado en el mismo dominio que XIris pero con ejemplos secuenciales cada 'step' que en este caso es 0.1 (una rejilla de ejemplos) ENUNCIADO: Se quieren hacer tres clusters sobre XIris y luego evaluar con esos clusters los ejemplos de XGrid. ¿Cuántos ejemplos de cada clase hay en XIris? ¿Y en XGrid? PISTA: Fíjate en el enunciado para elegir el sistema de cluster adecuado SALIDA: ver figuras iris_KMeans.pdf y iris_KMeans_Grid.pdf Iris: Clúster 0 ejemplos:50 Clúster 1 ejemplos:48 Clúster 2 ejemplos:52 XGrid: Clúster 0 ejemplos:497 Clúster 1 ejemplos:597 Clúster 2 ejemplos:736 """ print('\nEjercicio 1') #TODO 1.1 # Elegir el sistema de clustering : CS # Se elige KMeans porque se puede indicar el número de clústers y es inductivo #(se puede aplicar el modelo a otros ejemplos) from sklearn.cluster import KMeans CS=KMeans(n_clusters=3,random_state=1) #END 1 # Obtener clústers con XIris y aplicarlos tanbién a XGrid #TODO 1.2 CS.fit(XIris) # Creo el modelo de clúster con el Iris clustersIris=CS.predict(XIris)# Clústers de XIris clustersGrid=CS.predict(XGrid)# Clústers de XGrid #END 1.2 # Contar ejemplos en cada clúster print('Iris:') #TODO 1.3 for label in range(CS.n_clusters): indices=np.where(clustersIris==label)[0] print(' Clúster {} ejemplos:{}'.format(label,len(indices))) #END 1.3 print('XGrid:') #TODO 1.4 for label in range(CS.n_clusters): indices=np.where(clustersGrid==label)[0] print(' Clúster {} ejemplos:{}'.format(label,len(indices))) #END 1.4 # Pinta clústers pintaSimpleClusters(clustersIris,XIris,'XIris (n_clusters={})'.format(CS.n_clusters),'XIris',CS.cluster_centers_,xlim=[1,7],ylim=[0,3]) pintaSimpleClusters(clustersGrid,XGrid,'XGrid (n_clusters={})'.format(CS.n_clusters),'XGrid',CS.cluster_centers_,xlim=[1,7],ylim=[0,3]) #%% Ejercicio 2 """ Se quieren agrupar los lirios por normales y especiales. Los normales son los que están cerca del punto medio. Los especiales son los que están alejados del punto medio Utiliza un sistema de clustering que genere dos clústeres: normales y especiales Para ello crea la distanciaAlMedio NOTAS: El punto medio de los lirios se puede conseguir como IrisMean=np.mean(XIris,0) Utiliza el constructor (__init__) para pasar el punto medio de iris a la distancia Luego utiliza ese punto medio en el método _distanciaPar PISTA: Utiliza una distancia que mida la diferencia entre las distancias al punto medio SALIDA: ver Iris_Aglomerative_DisMean.pdf """ IrisMean=np.mean(XIris,0) from sklearn.cluster import AgglomerativeClustering class distancia: """ Clase padre de distancias. Calcula la matriz de distancias (simétrica con diagonal 0). Clase abstracta. Las clases hijas necsitan definir _distanciaPar(self,E1,E2) Que dados dos ejemplos retorna su distancia """ def __call__(self,X): """ Retorna la matriz de distancias de la lista de ejemplos Parámetros: -X : lista de ejemplos (solo atributos, sin categoría) """ M=np.zeros([len(X),len(X)]) for i in range(len(X)-1): for j in range(i+1,len(X)): M[i,j]=self._distanciaPar(X[i],X[j]) M[j,i]=M[i,j] return M def _distanciaPar(self,E1,E2): """ Método a ser redefinido en la clase hija. Dados dos ejemplos retorna su distancia. """ pass class distanciaAlMedio(distancia): # Crea un constructor que almacene el Punto Medio (IrisMean) #TODO 2.1 def __init__(self,IrisMean): self.IrisMean=IrisMean #END 2.1 def _distanciaPar(self,E1,E2): # PISTA: Utilizar un código similar al de distanciaRadio pero que la # Distancia en vez de cada ejemplo al (0,0) sea al IrisMean #TODO 2.2 r1=0 r2=0 for i in range(len(E1)): r1=r1+(E1[i]-self.IrisMean[i])**2 r2=r2+(E2[i]-self.IrisMean[i])**2 r1=r1**0.5 r2=r2**0.5 return abs(r1-r2) #END 2.2 cluGen=AgglomerativeClustering(n_clusters=2,linkage='average', # Asigna a metric un objeto distanciaAlMedio que # tenga el punto medio de XIris #TODO 2.3 metric=distanciaAlMedio(IrisMean) #END 2.3 ) C=cluGen.fit_predict(XIris) pintaSimpleClusters(C,XIris,'Iris AgglomerativeClustering(disMedio) ','Iris_Aglomerative_DisMean.pdf',xlim=[1,7],ylim=[0,3])

SimpleGen

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ """ import matplotlib.pyplot as plt import numpy as np import random import math class simpleGen: """ Crea un conjunto no etiquetado donde los ejemplos se obtienen de una distribución normal centrada en (-1,-1) y (+1,+1). """ def __init__(self,sd=0.1): self.sd=sd # Desviación estándar de la distribución normal def __call__(self,RG,nejemplos): """ Parámetros: - RG : random.Random(). - nejemplos : entero, número de ejemplos generados para cada una de las distribuciones (-1,-1) y (+1,+1) Retorna X : matriz de tipo numpy.ndarray con 2 atributos y (nejemplos+nejemplos) ejemplos """ X=[] for e in range(nejemplos): X.append(self._genExample(RG,-1,-1)) X.append(self._genExample(RG,+1,+1)) return np.array(X) def _genExample(self,RG,mu1,mu2): return [RG.normalvariate(mu1,self.sd),RG.normalvariate(mu2,self.sd)] class concentricoGen: """ Crea un conjunto no etiquetado donde los ejemplos se obtienen de una distribución uniforme sobre un círculo de radio r1 y un anillo de radios r21 y r22 """ def __init__(self,r1=0.5,r21=1.5,r22=2): self.r1=r1 self.r21=r21 self.r22=r22 def __call__(self,RG,eje1=100,eje2=100): X=[] # Circunferencia interior for i in range(eje1): radio =RG.random()*self.r1 angulo=RG.random()*math.pi*2 x=math.cos(angulo)*radio y=math.sin(angulo)*radio X.append([x,y]) # Anillo exterior for i in range(eje2): radio =RG.random()*(self.r22-self.r21)+self.r21 angulo=RG.random()*math.pi*2 x=math.cos(angulo)*radio y=math.sin(angulo)*radio X.append([x,y]) return X def pintaSimpleClusters(clusters,X,titulo,fileName,centroides=[],xlim=[-3,+3],ylim=[-3,+3]): """ Función que pinta clusters hechos sobre conjuntos de datos 'simple' Pinta sobre los 2 primeros atributos en el intervalo [-3,+3] Parámetros: - clusters : lista con el número de cluster de cada ejemplo (-1 no pertenece a ningún clúster) Si None todos los valores serán -1 - X : Valores de los ejemplos (generados por simpleGen) - titulo : String. Título de la figura - fileName : String. nombre del fichero sin extensión (la extensión será .pdf) Si vale None no se guarad en fichero Se guardará en la carpeta plots/ - centroides: Lista de centroides. Si es vacía no se pinta nada. """ colores=['tab:orange','tab:blue'] centroCols=['tab:green','tab:red'] plt.figure() if type(clusters)==type(None): clusters=[-1]*len(X) labels=np.unique(clusters) RG=None X=np.array(X) for ilabel in range(len(labels)): label=labels[ilabel] if label==-1: color='tab:gray' # No asignados a ningún cluster ccolor=color elif ilabel<len(colores): color=colores[ilabel] ccolor=centroCols[ilabel] else: if RG==None: RG=random.Random() RG.seed(1) color=(RG.random(),RG.random(),RG.random()) ccolor=color indices=np.where(clusters==label)[0] plt.xlim(xlim) plt.ylim(ylim) plt.plot(X[indices,0],X[indices,1],linestyle='None',marker='o',color=color,label='Ejemplos {}'.format(label)) if len(centroides)>0: centroide=centroides[ilabel] plt.plot([centroide[0]],[centroide[1]],linestyle='None',marker='x',markersize=18,color=ccolor,label='Centroide {}'.format(label)) plt.title(titulo) plt.xlabel('Atributo 0') plt.ylabel('Atributo 1') plt.legend() if fileName!=None: plt.savefig('plots/{}.pdf'.format(fileName))

Tema 4 Sesion 2

Apartado A

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 4 : Aprendizaje No Supervisado (ANS) Sesión 2 : Calidad Bloque A : Medidas de calidad """ # Aunque no se tenga categoría se pueden calcular medidas de calida de partición #en clústers. En esta práctica se utilizarán las de sklearn: # https://scikit-learn.org/stable/modules/model_evaluation.html # Algunas de estas medidas necesitan saber el valor real (ground truth) como: # rand_score # adjusted_mutual_info_score # homogeneity_score # completeness_score # v_measure_score # fowlkes_mallows_score # Otras no necesitan conocer el valor real de la partición # silhouette_score (better as higher) # calinski_harabasz_score (better as higher) # davies_bouldin_score (better as lower) # En esta práctica utilizaremos estas últimas from simpleGen import simpleGen,pintaSimpleClusters from sklearn.cluster import MeanShift from sklearn.metrics import silhouette_score ,calinski_harabasz_score,davies_bouldin_score import numpy as np import random import matplotlib.pyplot as plt # Crear el conjunto de ejemplos nejemplos=50 # Número de ejemplos no etiqeutados por cada distrubución RG=random.Random() # Generador de números aleatorios RG.seed(1) # Semilla del generador de números aleatorios simple=simpleGen(sd=1) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetadossd=1 # bandwidth de 1 a 2 con paso 0.1 bandwidths=[bd/10 for bd in range(10,20+1)] # Almacenar los valores de calidad para cada métrica si=[] # silhouette_score ca=[] # calinski_harabasz_score da=[] # davies_bouldin_score for bandwidth in bandwidths: # Para diferentes valores de bandwidth # Proceso de aprendizaje no supervisado CSMeanShift=MeanShift(bandwidth=bandwidth) # Crear el objeto de Clustering CSMeanShift.fit(X) clusters = CSMeanShift.predict(X) # Cálculo de valores para las funciones de pédida n_clusters=len(np.unique(clusters)) if n_clusters>1: si.append(silhouette_score(X,clusters)) ca.append(calinski_harabasz_score(X,clusters)) da.append(davies_bouldin_score(X,clusters)) else: # si solo hay un clúster no se aplican si.append(None) ca.append(None) da.append(None) metricValues=[si,ca,da] metricNames=['silhouette','calinski_harabasz','davies_bouldin'] for iMetric in range(len(metricValues)): plt.figure() plt.title('MeanShift') plt.plot(bandwidths,metricValues[iMetric],marker='x') plt.ylabel(metricNames[iMetric]) plt.xlabel('bandwidth') plt.savefig('plots/A_MeanShift_{}'.format(metricNames[iMetric])) #%% Ejercicio 1 """ DATOS: Las listas si, ca y da tienen los valores de las métricas: silhouette_score, calinski_harabasz_score y davies_bouldin_score respectivamente La lista bandwidths tiene los valores de bandwidth ENUNCIADO: Haz un código que calcule el mejor valor de bandwidth según cada métrica Imprimir el valor para cada métrica NOTA: Usa np.argmax o np.argmin para obtener el índice del mayor o menor valor en un array SALIDA: silhouette mejor bandwidth=1.7 calinski_harabasz mejor bandwidth=1.7 davies_bouldin mejor bandwidth=1.6 """ # Calcula los índices del mejor valor de bandwith para cada medida #TODO 1 ibest_si=np.argmax(si) # silhouette (si) ibest_ca=np.argmax(ca) # calinski_harabasz (ca) ibest_da=np.argmin(da) # davies_bouldin (da) #END 1 print('silhouette mejor bandwidth={}'.format(bandwidths[ibest_si])) print('calinski_harabasz mejor bandwidth={}'.format(bandwidths[ibest_ca])) print('davies_bouldin mejor bandwidth={}'.format(bandwidths[ibest_da]))

Apartado B

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 4 : Aprendizaje No Supervisado (ANS) Sesión 2 : Calidad Bloque B : Influencia de atributos """ # En general, los algoritmos de ANS son muy sensibles al número de atributos. # Pero no es lo mismo si son atributos relevantes o irrelevantes. # En este bloque se estudia el caso en que se fija el número de clústers y se #varían tanto los atributos relevantes como irrelevantes. from simpleGen import simpleGen,pintaSimpleClusters from sklearn.cluster import KMeans,AgglomerativeClustering from sklearn.metrics import silhouette_score ,calinski_harabasz_score,davies_bouldin_score import numpy as np import random import matplotlib.pyplot as plt #%% Ejercicio 1 """ Añade el código necesario para en cada iteración calcular silhouette_score tanto del algoritmo KMeans como del AgglomerativeClustering SALIDA: atr rel= 2 no rel= 0 silhouette_score KMeans=0.4792 AgglomerativeClustering=0.4524 atr rel= 50 no rel= 0 silhouette_score KMeans=0.4297 AgglomerativeClustering=0.4297 atr rel=100 no rel= 0 silhouette_score KMeans=0.4190 AgglomerativeClustering=0.4190 atr rel= 2 no rel= 50 silhouette_score KMeans=0.0307 AgglomerativeClustering=0.0262 atr rel= 2 no rel=100 silhouette_score KMeans=0.0124 AgglomerativeClustering=0.0144 """ # Parámetros del conjunto de ejemplos nejemplos=50 # Número de ejemplos no etiquetados por cada distrubución RG=random.Random() # Generador de números aleatorios RG.seed(1) # Semilla del generador de números aleatorios sd=1 # Sistemas ANS CSKMeans=KMeans(n_clusters=2,random_state=1) CSAggclu =AgglomerativeClustering(n_clusters=2) # Variando el número de atributos relevantes for atrRel in [2,50,100]: # Crear el conjunto de ejemplos simple=simpleGen(sd=sd,atrRel=atrRel,atrNoRel=0) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetados sd=1 # Proceso de aprendizaje con KMeans CSKMeans.fit(X) clustersKM=CSKMeans.predict(X) pintaSimpleClusters(clustersKM,X,'simple(atrRel={}) KMeans'.format(atrRel),'B_KMeans_Rel={}'.format(atrRel)) # Proceso de aprendizaje con AgglomerativeClustering clustersAC=CSAggclu.fit_predict(X) pintaSimpleClusters(clustersAC,X,'simple(atrRel={}) AgglomerativeClustering'.format(atrRel),'B_AggClu_Rel={}'.format(atrRel)) #TODO 1.1 siKM=silhouette_score(X,clustersKM) # silhouette para los clusters de KMeans siAC=silhouette_score(X,clustersAC) # silhouette para los clusters de AgglomerativeClustering #END 1.1 print('atr rel={:3} no rel= 0 silhouette_score KMeans={:6.4f} AgglomerativeClustering={:6.4f}'.format(atrRel,siKM,siAC)) # Variando el número de atributos NO relevantes for atrNoRel in [50,100]: # Crear el conjunto de ejemplos simple=simpleGen(sd=1,atrRel=2,atrNoRel=atrNoRel) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetadossd=1 # Proceso de aprendizaje con KMeans CSKMeans.fit(X) clustersKM=CSKMeans.predict(X) pintaSimpleClusters(clustersKM,X,'simple(atrNoRel={}) KMeans'.format(atrNoRel),'B_KMeans_noRel={}'.format(atrNoRel)) # Proceso de aprendizaje con AgglomerativeClustering clustersAC=CSAggclu.fit_predict(X) pintaSimpleClusters(clustersAC,X,'simple(atrNoRel={}) AgglomerativeClustering'.format(atrNoRel),'B_AggClu_noRel={}'.format(atrNoRel)) #TODO 1.2 siKM=silhouette_score(X,clustersKM) # silhouette para los clusters de KMeans siAC=silhouette_score(X,clustersAC) # silhouette para los clusters de AgglomerativeClustering #END 1.2 print('atr rel= 2 no rel={:3} silhouette_score KMeans={:6.4f} AgglomerativeClustering={:6.4f}'.format(atrNoRel,siKM,siAC))

Apartado C

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 4 : Aprendizaje No Supervisado (ANS) Sesión 2 : Calidad Bloque C : Influencia de atributos 2 (Outliers) """ # Los sistemas que no tienen un parámetro con el número de clústers requieren #ser ajustados según el número de atributos. # Observa el ejemplo de MeanShift variando el parámetro bandwidth para un #conjunto tipo simple con 50 atributos relevantes. from simpleGen import simpleGen,pintaSimpleClusters from sklearn.cluster import MeanShift, DBSCAN from sklearn.metrics import silhouette_score, calinski_harabasz_score, davies_bouldin_score from sklearn.metrics import silhouette_score import numpy as np import random import matplotlib.pyplot as plt # Parámetros del conjunto de ejemplos nejemplos=50 # Número de ejemplos no etiquetados por cada distrubución RG=random.Random() # Generador de números aleatorios sd=1 # Desviación típica atrRel=50 # Atributos relevantes # Crear el conjunto de ejemplos RG.seed(1) # Semilla del generador de números aleatorios simple=simpleGen(sd=sd,atrRel=atrRel) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetadossd=1 # Variando bandwidth print('simple(attRel={}) MeanShift:'.format(atrRel)) for bandwidth in [1,2,4,6,8,10,12,14]: # Sistemas ANS CSMeanSh=MeanShift(bandwidth=bandwidth) # Proceso de aprendizaje con MeanShift CSMeanSh.fit(X) clustersMS=CSMeanSh.predict(X) # Dibujar los clusters pintaSimpleClusters(clustersMS,X,'simple(atrRel={}) MeanShift(bandwidth={})' .format(atrRel,bandwidth),'C_MeanShift(bandwidth={})'.format(bandwidth)) # Imprimir información y cálculo de calinski_harabasz_score n_clusters=len(np.unique(clustersMS)) if n_clusters>1 and n_clusters<len(X): ca=calinski_harabasz_score(X,clustersMS) else: ca='None' print(' bandwidith={:2} clusters={:3} calinski_harabasz={}' .format(bandwidth,n_clusters,ca)) # Cuando hay ejemplos que no están asignados a ningún clúster (outliers) no hay #que tenerlos en cuenta a la hora de calcular la medida. # La función clusterMetric(X,clusters,metric) realiza este proceso def clusterMetric(X,clusters,metric,worstValue=-np.inf): """ Calcula la métrica metric tomando como clústers de un solo ejemplo los ejemplos que no estén en ningún clúster Parámetros: - X : conjunto de datos - clusters : lista con el número de clúster de cada ejemplo (puede ser -1) - metric : métrica de clústers que no necesita el valor verdadero - worstValue: valor que retorna si solo hay un cluster o hay un cluster por cada ejemplo Retorna: [metric_value,n_clusters,n_samples] - metric_value : valor de la métrica o None si el número de clústers es 1 o el número de ejemplos - n_clusters : número de clusters (sin contar el -1) - n_samples : número de ejemplos que están en algún clúster (sin contar el -1) """ clusterSet=np.unique(clusters) # Si solo hay un clúster o hay tantos como ejemplos if len(clusterSet)==1 or len(clusterSet)==len(X): value=worstValue # Se retorna el peor valor elif min(clusterSet)>=0: # No hay -1 value= metric(X,clusters) # Lo que retorne la métrica else: # Cambiar todos los -1 por un clúster nuevo cluNuevo=max(clusterSet)+1 clustersNuevo=[] for c in clusters: if c==-1: clustersNuevo.append(cluNuevo) cluNuevo=cluNuevo+1 else: clustersNuevo.append(c) value=metric(X,clustersNuevo) # Cálculo del Nº de clústers sin -1 n_clusters=len(clusterSet) if min(clusterSet)==-1: n_clusters=n_clusters-1 # Cálculo del nº de ejemplos que están en algún clúster indNoNeg=np.where(np.array(clusters)>=0)[0] n_samples=len(indNoNeg) return [value,n_clusters,n_samples] # Ejercicio 1 # Para el conjunto de ejemplos de este bloque realizar clusters con el algoritmo #DBSCAN variando eps en [2,4,6,8,10,12,14] # Imprimir el número de clústers y el valor de la métrica calinski_harabasz para #los ejemplos que están en algún clúster. # Opcional: realiza el gráfico de los clústers generados # NOTA: Utiliza clusterMetric # SALIDA: ver figuras C_DBSCAN(eps=*).pdf # simple(attRel=50) DBSCAN: # eps= 2 clusters= 0 calinski_harabasz=None # eps= 4 clusters= 0 calinski_harabasz=None # eps= 6 clusters= 0 calinski_harabasz=None # eps= 8 clusters= 2 calinski_harabasz=43.172984366909176 # eps=10 clusters= 2 calinski_harabasz=104.39818911983511 # eps=12 clusters= 2 calinski_harabasz=104.39818911983511 # eps=14 clusters= 1 calinski_harabasz=None #<TODO BEGIN Ejercicio 1> # Variando eps print('simple(attRel={}) DBSCAN:'.format(atrRel)) for eps in [2,4,6,8,10,12,14]: # Sistemas ANS CSDBSCAN=DBSCAN(eps=eps) # Proceso de clustering clustersDS=CSDBSCAN.fit_predict(X) # Calcular calinski_harabasz_score cuando hay clústers que pueden valer -1 [ca,n_clusters,n_samples]=clusterMetric(X,clustersDS,calinski_harabasz_score) # Imprimir información y cálculo de calinski_harabasz_score print(' eps={:2} en {} clusters hay {} ejemplos, calinski_harabasz={}' .format(eps,n_clusters,n_samples,ca)) # Opcional: Dibujar los clusters pintaSimpleClusters(clustersDS,X,'simple(atrRel={}) DBSCAN(eps={})' .format(atrRel,eps),'C_DBSCAN(eps={})'.format(eps)) #<TODO END Ejercicio 1>

Ac no presencial

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 4 : Aprendizaje No Supervisado (ANS) Sesión 2 : Calidad Actividad del Campus Virtual """ import matplotlib.pyplot as plt import numpy as np from simpleGen import simpleGen,pintaSimpleClusters from sklearn.metrics import silhouette_score, calinski_harabasz_score, davies_bouldin_score from cluster_distance import cluster_distance # intra_cluster_distance,inter_cluster_distance from sklearn.cluster import MeanShift, DBSCAN, KMeans, AgglomerativeClustering import random def getRandomCluster(RG,nExa,nClus): """ Genera un cluster aleatorio para nExa ejemplos utilizando nClus cluster Parametros: RG : objeto random.Random() nExa : entero, número de ejemplos nClus: entero, número de clusters """ clus=[0]*nExa # Al menos, un ejemplo de cada clúster for i in range(nClus): clus[i]=i # El resto aleatorio con distribución uniforme for i in range(nClus,nExa): clus[i]=RG.randrange(nClus) # Ahora se reordena al aleatoriamente RG.shuffle(clus) return clus #%% Generar n puntos en 2D en cada una de las 4 zonas # Cada zona está determianda por su punto medio : [-1,-2],[-1,+2],[+1,-2],[+1,+2] n=5 CentroZonas=[[-1,-2],[-1,+2],[+1,-2],[+1,+2]] sd=0.25 RG=random.Random() RG.seed(1) X=[] # Puntos for iCZ in range(len(CentroZonas)): centro=CentroZonas[iCZ] centrox=centro[0] centroy=centro[1] for i in range(n): x=RG.normalvariate(0,sd)+centrox y=RG.normalvariate(0,sd)+centroy X.append([x,y]) X=np.array(X) pintaSimpleClusters([-1]*len(X),X,'Ejemplos sin agrupar') #%% Crear nParticiones al azar de nClus cada una # Cada partición es una asignación a clústers de los ejemplos X RG=random.Random() seed=1 RG.seed(seed) nParticiones=10000 nClus=4 nExa=len(X) particiones=[None]*nParticiones for p in range(nParticiones): particiones[p]=getRandomCluster(RG,nExa,nClus) # Pinta, a modo de ejemplo, una partición pintaSimpleClusters(particiones[0],X,'Partición 0') #%% Multi objetivo lineal def multiObtetivoLinear(paresMedidasCalidadPesos,clusters,X): """ Crea una función lineal usando una lista de pares: medidas de calidad de clústers pesos Evalúa los clústers en X usando esta función lineal Params: paresMedidasCalidadPesos : lista [medida de calidad de clústers, peso] clusters : lista con los índices de los clústers para cada ejemplo X : ejemplos no etiquetados (atributos) Returns: la suma del producto de cada valoración de la medida por su peso """ return sum([medida(X,clusters)*peso for [medida,peso] in paresMedidasCalidadPesos]) #Ejemplo de uso # Se quiere evaluar la partición 0 usando una medida de calidad que sea: # calinski_harabasz_score*2+silhouette_score*1 paresMedidasCalidadPesos=[[calinski_harabasz_score,2],[silhouette_score,1]] calidadMOLin=multiObtetivoLinear(paresMedidasCalidadPesos,particiones[0],X) print('Partición 0: medida de calidad multiobjetivo lineal: {:6.4f}'.format(calidadMOLin)) #%% Ejercicio 1 """ DATOS: X : Ejemplos no etiquetados (Atributos) particiones: Lista con todas las particiones (cada partición es una división en clústers). ENUNCIADO: Crea unos pares calidad pesos que utilicen - silhouette_score - calinski_harabasz_score - davies_bouldin_score - intra_cluster_distance - inter_cluster_distance Y que de un valor más grande cuanto mejor Obtén el índice de la partición de particiones que tiene el mejor valor de esta función multi objetivo """ CD=cluster_distance() intra_cluster_distance=CD.intra_cluster_distance inter_cluster_distance=CD.inter_cluster_distance bestP =None # Guarda el índice de la mejor particion bestScore=None # Guarda el mejor valor #TODO 1.1 # El signo determina si es mejor cuando más grande (+1) o más pequeño(-1) paresMedidasCalidadPesos=[[calinski_harabasz_score,+1], [silhouette_score ,+1], [davies_bouldin_score ,-1], [intra_cluster_distance ,-1], [inter_cluster_distance ,+1]] #END 1.1 for p in range(nParticiones): #TODO 1.2 MOScore=multiObtetivoLinear(paresMedidasCalidadPesos,particiones[p],X) # Score de la función multi objetivo lineal #END 1.2 #TODO 1.3 if bestScore==None or bestScore<MOScore: # Si el nuevo es mejor que el mejor actual #END 1.3 # Se almacena el nuevo como el mejor actual bestScore=MOScore bestP =p print('Mejor partición {} MOScore={:6.4f}'.format(bestP,bestScore)) pintaSimpleClusters(particiones[bestP],X,'Partición {} MOScore={:6.4f}'.format(bestP,bestScore))

Actividad Presencial

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 4 : Aprendizaje No Supervisado (ANS) Sesión 2 : Calidad Actividad 1 """ from simpleGen import simpleGen,pintaSimpleClusters from sklearn.metrics import silhouette_score, calinski_harabasz_score from sklearn.cluster import MeanShift, DBSCAN, KMeans, AgglomerativeClustering import numpy as np import random from sklearn.decomposition import PCA,TruncatedSVD import matplotlib.pyplot as plt # Cuando hay attributos no relvantes se pueden utilizar estrategias de reducción #de atributos no supervisadas, por ejmeplo Principal component analysis (PCA): # https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html # Estos sistemas suelen tener un parámetro que determina cuantos atributos generan #(el número de componentes). # En esta práctica se observa como varía una medida de calidad cuando se hacen #clústers sobre una reducción de atributos variando el número de componentes # Parámetros del conjunto de ejemplos nejemplos=50 # Número de ejemplos no etiquetados por cada distrubución RG=random.Random() # Generador de números aleatorios sd=1 atrNoRel=100 # Crear el conjunto de ejemplos RG.seed(1) # Semilla del generador de números aleatorios simple=simpleGen(sd=sd,atrNoRel=atrNoRel) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetados # Sistemas ANS CSKMeans=KMeans(n_clusters=2)#(n_clusters=2,random_state=1) # Proceso de aprendizaje con KMeans clustersKM=CSKMeans.fit_predict(X) # Calcular la medida de calidad v =silhouette_score(X,clustersKM) # Variando el número de atributos NO relevantes vs=[] # Valores de la medida sin reducción vReds=[] # Valores de la medida con reducción ncs=list(range(1,min([len(X),len(X[0])]))) # número de componentes desde 1 a atributos-1 for n_components in ncs: # Sistema reductor de atributos Red=PCA() Red.n_components=n_components XRed=Red.fit_transform(X) # Proceso de aprendizaje con KMeans sobre el conjunto reducido clustersKMRed=CSKMeans.fit_predict(XRed) # Calcular la medida de calidad con reducción vRed=silhouette_score(X,clustersKMRed) # Almacenar las medidas de calidad vs.append(v) # Almacena siempre el mismo valor vReds.append(vRed) # Imprimir las medidas print('atr no rel={:3} silhouette_score KMeans={:6.4f} KMeans(Red(n_components={:2})={:6.4f}'. format(atrNoRel,v,n_components,vRed)) plt.figure() plt.plot(ncs,vs,label='Sin reducción') plt.plot(ncs,vReds,label='Reducción PCA') plt.ylabel('silhouette_score') plt.xlabel('n_components') plt.legend() plt.title('KMeans(n_clusters=2)') plt.savefig('plots/Presencial_PCA_KMeans.pdf') #%% ENUNCIADO actividad 1 # Variando el número de atributos no relevantes (atrNoRel) de 10 a 100 de 10 en 10, #se crea un conjunto de ejemplos 'simple' (código propuesto) # Calcular la medida silhouette_score para # 1- el sistema de clustering SClus # 2- el sistema que reduce atributos y luego aplica SClus # La función redCluster eligen el mejor número de componentes según una medida # Mirar el código, leer los comentarios y completar el código marcado como: # BEGIN 1.<x> # END 1.<x> # para x en {a,b,c,d,e,f} # SALIDA: plots/RedYClus_AgglomerativeClustering.pdf # Atr no rel= 10 silhouette_score cluster=0.0712 red+cluster=0.0781 # Atr no rel= 20 silhouette_score cluster=0.0498 red+cluster=0.0325 # Atr no rel= 30 silhouette_score cluster=0.0511 red+cluster=0.0316 # Atr no rel= 40 silhouette_score cluster=0.0274 red+cluster=0.0157 # Atr no rel= 50 silhouette_score cluster=0.0231 red+cluster=0.0201 # Atr no rel= 60 silhouette_score cluster=0.0215 red+cluster=0.0170 # Atr no rel= 70 silhouette_score cluster=0.0160 red+cluster=0.0130 # Atr no rel= 80 silhouette_score cluster=0.0142 red+cluster=0.0092 # Atr no rel= 90 silhouette_score cluster=0.0155 red+cluster=0.0089 # Atr no rel=100 silhouette_score cluster=0.0126 red+cluster=0.0079 def redCluster(SRed,SClus,X,metrica,best=+1): """ Función que hace un proceso de reducción y luego otro de clustering Para elegir el número de componentes itera desde 1 al número de atributos y Toma el mejor según la métrica. Parámetros: SRed : Sistema de reducción de parámetros. Tiene que tener: Hyperparámetro: n_components Método : fit_transform Por ejemplo PCA() SClus : Sistema de clustering. Tiene que tener: Método : fit_predict X : Matriz. Conjunto de datos sin categoría metrica : Métrica de clustering. best : Si +1 la métrica es mejor cuanto mayor Si -1 la métrica es mejor cuanto menor Por defecto: +1 """ bestMetrica=None bestCluster=None ncs=list(range(1,min([len(X),len(X[0])]))) # número de componentes desde 1 a atributos-1 for n_components in ncs: # Sistema reductor de atributos: utilizar n_components y luego fit_transform # BEGIN 1.a SRed.n_components=n_components XRed=SRed.fit_transform(X) # END 1.a # Proceso de clustering sobre el conjunto reducido # BEGIN 1.b clustersRed=SClus.fit_predict(XRed) # END 1.b # Calcular la medida de calidad # BEGIN 1.c vRed=metrica(X,clustersRed) # IMPORTANTE utilizar X, no XRed # END 1.c # Quedarse con la mejor medida y clúster hasta el momento if bestMetrica==None or vRed!=None and bestMetrica*best<vRed*best: bestMetrica=vRed bestCluster=clustersRed # Retornar el cluster de la mejor metrica return bestCluster # BEGIN ACTIVIDAD 1 SRed=PCA() SClus=AgglomerativeClustering(n_clusters=2) # Experimentar para diferentes números de atributos no relevantes vs=[] vReds=[] nejemplos=50 # Número de ejemplos no etiquetados por cada distrubución RG=random.Random() # Generador de números aleatorios sd=2 anr=list(range(10,100+1,10)) # Atributos no relevantes for atrNoRel in anr: # Crear el conjunto de ejemplos RG.seed(1) # Semilla del generador de números aleatorios simple=simpleGen(sd=sd,atrNoRel=atrNoRel) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetados # Proceso de clustering co el conjunto original # BEGIN 1.d clusters=SClus.fit_predict(X) # END 1.d # Cáculo de la métrica silhouette_score # BEGIN 1.e v=silhouette_score(X,clusters) # END 1.e vs.append(v) # Proceso de reducción + clustering clustersRed=redCluster(SRed,SClus,X,silhouette_score) # Cáculo de la métrica silhouette_score # BEGIN 1.f vRed=silhouette_score(X,clustersRed) # END 1.f vReds.append(vRed) print('Atr no rel={:3} silhouette_score cluster={:6.4f} red+cluster={:6.4f}' .format(atrNoRel,v,vRed)) plt.figure() plt.plot(anr,vs,label='Clúster') plt.plot(anr,vReds,label='Reducción+clúster') plt.ylabel('silhouette_score') plt.xlabel('Atributos no relevantes') plt.legend() plt.title('AgglomerativeClustering(n_clusters=2)') plt.savefig('plots/RedYClus_AgglomerativeClustering.pdf') # END ACTIVIDAD 1 #%% ENUNCIADO actividad 2 # Repite el ejercicio anterior para el sistema DBSCAN(eps=4) # PISTA: DBSCAN puede generar predicciones como outliers. Hay que tratarlas # adecuamete # PISTA: redCluster toma como tercer parámetro una función métrica, esto es una # función de la forma f(X,clusters) -> valor # PISTA: de clusterMetric solo nos es útil para este ejercicio el primer elemento # que retorna (metric_value) # SALIDA: plots/RedYClus_DBSCAN.pdf # Atr no rel= 10 silhouette_score cluster=None red+cluster=0.1956345243580752 # Atr no rel= 20 silhouette_score cluster=None red+cluster=0.06628188881909468 # Atr no rel= 30 silhouette_score cluster=None red+cluster=0.04110672152494071 # Atr no rel= 40 silhouette_score cluster=None red+cluster=0.002860862358982693 # Atr no rel= 50 silhouette_score cluster=None red+cluster=0.03241486726938161 # Atr no rel= 60 silhouette_score cluster=None red+cluster=0.023773086495309844 # Atr no rel= 70 silhouette_score cluster=None red+cluster=0.033602048790723614 # Atr no rel= 80 silhouette_score cluster=None red+cluster=0.022763502354880352 # Atr no rel= 90 silhouette_score cluster=None red+cluster=0.026082035594245 # Atr no rel=100 silhouette_score cluster=None red+cluster=0.013064686052516329 SRed=PCA() SClus=DBSCAN(eps=5) # BEGIN ACTIVIDAD 2 def clusterMetric(X,clusters,metric,worstValue=-np.inf): """ Calcula la métrica metric tomando como clústers de un solo ejemplo los ejemplos que no estén en ningún clúster Parámetros: - X : conjunto de datos - clusters : lista con el número de clúster de cada ejemplo (puede ser -1) - metric : métrica de clústers que no necesita el valor verdadero - worstValue: valor que retorna si solo hay un cluster o hay un cluster por cada ejemplo Retorna: [metric_value,n_clusters,n_samples] - metric_value : valor de la métrica o None si el número de clústers es 1 o el número de ejemplos - n_clusters : número de clusters (sin contar el -1) - n_samples : número de ejemplos que están en algún clúster (sin contar el -1) """ clusterSet=np.unique(clusters) # Si solo hay un clúster o hay tantos como ejemplos if len(clusterSet)==1 or len(clusterSet)==len(X): value=worstValue # Se retorna el peor valor elif min(clusterSet)>=0: # No hay -1 value= metric(X,clusters) # Lo que retorne la métrica else: # Cambiar todos los -1 por un clúster nuevo cluNuevo=max(clusterSet)+1 clustersNuevo=[] for c in clusters: if c==-1: clustersNuevo.append(cluNuevo) cluNuevo=cluNuevo+1 else: clustersNuevo.append(c) value=metric(X,clustersNuevo) # Cálculo del Nº de clústers sin -1 n_clusters=len(clusterSet) if min(clusterSet)==-1: n_clusters=n_clusters-1 # Cálculo del nº de ejemplos que están en algún clúster indNoNeg=np.where(np.array(clusters)>=0)[0] n_samples=len(indNoNeg) return [value,n_clusters,n_samples] def clusterMetric_silhouette_score(X,clusters): return clusterMetric(X,clusters,silhouette_score)[0] # Experimentar para diferentes números de atributos no relevantes vs=[] vReds=[] nejemplos=50 # Número de ejemplos no etiquetados por cada distrubución RG=random.Random() # Generador de números aleatorios sd=2 anr=list(range(10,100+1,10)) # Atributos no relevantes for atrNoRel in anr: # Crear el conjunto de ejemplos RG.seed(1) # Semilla del generador de números aleatorios simple=simpleGen(sd=sd,atrNoRel=atrNoRel) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetados # Proceso de clustering clusters=SClus.fit_predict(X) v=clusterMetric(X,clusters,silhouette_score)[0] vs.append(v) # Proceso de reducción + clustering clustersRed=redCluster(SRed,SClus,X,clusterMetric_silhouette_score) vRed=clusterMetric(X,clustersRed,silhouette_score)[0] vReds.append(vRed) print('Atr no rel={:3} silhouette_score cluster={} red+cluster={}' .format(atrNoRel,v,vRed)) plt.figure() plt.plot(anr,vs,label='Clúster') plt.plot(anr,vReds,label='Reducción+clúster') plt.ylabel('silhouette_score') plt.xlabel('Atributos no relevantes') plt.legend() plt.title('DBSCAN(eps=4)') plt.savefig('plots/RedYClus_DBSCAN.pdf') # END ACTIVIDAD 2

Tema 5 Sesion 1

Apartado A

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 5 : Detección de anomalías Sesión 1 : Detección de anomalías Bloque A : Detección de outliers """ import numpy as np import random from sklearn.ensemble import IsolationForest from sklearn.neighbors import LocalOutlierFactor from sklearn.covariance import EllipticEnvelope import matplotlib.pyplot as plt from matplotlib.patches import Rectangle from sklearn.svm import SVC from sklearn.metrics import accuracy_score def plotOutliers(X,Y,titulo,fileName=None): plt.figure() ax=plt.axes() ax.add_patch(Rectangle([0,0],2,2,edgecolor='black' ,facecolor='None')) ax.add_patch(Rectangle([0,0],1,1,edgecolor='tab:blue' ,facecolor='None')) ax.add_patch(Rectangle([1,1],1,1,edgecolor='tab:orange',facecolor='None')) plt.title(titulo) plt.xlabel('x0') plt.ylabel('x1') plt.xlim([-1,3]) plt.ylim([-1,3]) colIO=['tab:grey','tab:red'] col01=['tab:blue','tab:orange'] classes=np.unique(Y) if min(classes)==-1: # Hay outliers col=colIO labels=['Outliers','Inliers'] else: col=col01 labels=['Clase {}'.format(cla) for cla in classes] cc=0 for cla in classes: indCla=np.where(Y==cla)[0] plt.plot(X[indCla,0],X[indCla,1],linestyle='None',marker='o',color=col[cc], label=labels[cc]) cc=cc+1 plt.legend() if type(fileName)!=type(None): plt.savefig('plots/{}.pdf'.format(fileName)) def genCuadros(RG,nIrre=0,nEjeClass=10): X=[] Y=[] for cla in [0,1]: for n in range(nEjeClass): x1=RG.random()+cla x2=RG.random()+cla row=[x1,x2] for i in range(nIrre): row.append(RG.random()) X.append(row) Y.append(cla) return [np.array(X),np.array(Y)] def generaOutFuera02(nOut,nIrre=0): X=[] Y=[] for i in range(nOut): cla=RG.randint(0,1) x0=RG.random()+RG.choice([-1,2]) x1=RG.random()+RG.choice([-1,2]) row=[x0,x1] for i in range(nIrre): row.append(RG.random()) X.append(row) Y.append(cla) return [np.array(X),np.array(Y)] def generaOutEn02(nOut,nIrre=0): X=[] Y=[] for i in range(nOut): cla=RG.randint(0,1) x0=RG.random() x1=RG.random() if RG.random()>0.5: x0=x0+1 else: x1=x1+1 row=[x0,x1] for i in range(nIrre): row.append(RG.random()) X.append(row) Y.append(cla) return [np.array(X),np.array(Y)] """ Ejercicio 1: Observa y cambia Esta actividad muestra como se eliminan outliers y el efecto que tiene en el aprendizaje. Ejecuta bloque a bloque este script. Fíjate en el código y en los dibujos que se muestran. Cambia el sistema de detección de outliers (hay varios comentados en la sección de parámetros) ¿Cuál es mejor? """ #%% Parámetros y datos: Cuadros: entrenamiento y test # Parámetros RG=random.Random() RG.seed(1) # Semilla nIrre=4 # Nº de atributos irrelevantes nEjeEntre= 10 # Ejemplos entrenamiento por cada clase nEjeTest =100 # Ejemplos test por cada clase nEjeOut = 10 # Nº de Outliers # Algoritmo de detección de outliers OutDet=IsolationForest(random_state=1) # OutDet=LocalOutlierFactor() # OutDet=EllipticEnvelope(random_state=1) # Clasificador Class=SVC(kernel='linear',C=1) [XTr,YTr]=genCuadros(RG,nIrre=nIrre,nEjeClass=nEjeEntre) # Entrenamiento [XTe,YTe]=genCuadros(RG,nIrre=nIrre,nEjeClass=nEjeTest ) # Test print('Cuadros Atributos:{} (2 relevantes). Ejemplos entrenamiento:{} test:{}' .format(len(XTr[0]),len(XTr),len(XTe))) plotOutliers(XTe,YTe,'Test: Cuadros','Cuadros_01_Test') plotOutliers(XTr,YTr,'Entrenamiento: Cuadros original','Cuadros_02_EntreOriginal') #%% Clasificar y evaluar sin outliers Class.fit(XTr,YTr) P=Class.predict(XTe) Acc=accuracy_score(YTe,P) print('Evaluación sin outliers: accuracy={:6.4f}'.format(Acc)) plotOutliers(XTe,P,'Evaluación SIN outliers: accuracy={:6.4f}'.format(Acc), 'Cuadros_03_EvalOriginal') #%% Inserción de outliers FUERA del rango de los atributos print('Outliers FUERA del rango de atributos:') [XOut,YOut]=generaOutFuera02(nEjeOut,nIrre=nIrre) XTrOut=np.concatenate([XTr,XOut]) YTrOut=np.concatenate([YTr,YOut]) plotOutliers(XTrOut,YTrOut,'Entrenamiento con {} outliers fuera de [0;2]'.format(nEjeOut), 'Cuadros_04_ConOutliersFuera02') Class.fit(XTrOut,YTrOut) P=Class.predict(XTe) Acc=accuracy_score(YTe,P) print(' Evaluación CON outliers: accuracy={:6.4f}'.format(Acc)) plotOutliers(XTe,P,'Evaluación CON outliers: accuracy={:6.4f}'.format(Acc), 'Cuadros_05_EvaluacionConOutliersFuera02') #%% Calcular outliers outValueTr=OutDet.fit_predict(XTrOut) indOut=np.where(outValueTr==-1)[0] indIn =np.where(outValueTr==+1)[0] print(' Entrenamiento Inliers={:4} Outliers={:3}'.format(len(indIn),len(indOut))) plotOutliers(XTrOut,outValueTr,'Outliers detectados (clase -1)'.format(OutDet), 'Cuadros_06_OutliersFuera02Detectados') #%% Eliminar outliers, clasificar y evaluar XTrIn=XTrOut[indIn] YTrIn=YTrOut[indIn] plotOutliers(XTrIn,YTrIn,'Entranamiento CON inliers', 'Cuadros_07_QuitandoOutliersFuera02Detectados') Class.fit(XTrIn,YTrIn) P=Class.predict(XTe) Acc=accuracy_score(YTe,P) print(' Evaluación CON inliers: accuracy={:6.4f}'.format(Acc)) plotOutliers(XTe,P,'Evaluación CON inliers: accuracy={:6.4f}'.format(Acc), 'Cuadros_08_EvalQuitandoOutliersFuera02Detectados') #%% Inserción de outliers DENTRO del rango de los atributos print('Outliers DENTRO del rango de atributos:') [XOut,YOut]=generaOutEn02(nEjeOut,nIrre=nIrre) XTrOut=np.concatenate([XTr,XOut]) YTrOut=np.concatenate([YTr,YOut]) plotOutliers(XTrOut,YTrOut,'Entrenamiento con {} outliers DENTRO de [0;2]'.format(nEjeOut), 'Cuadros_09_ConOutliersDentro02') Class.fit(XTrOut,YTrOut) P=Class.predict(XTe) Acc=accuracy_score(YTe,P) print(' Evaluación CON outliers: accuracy={:6.4f}'.format(Acc)) plotOutliers(XTe,P,'Evaluación CON outliers: accuracy={:6.4f}'.format(Acc), 'Cuadros_10_EvaluacionConOutliersDentro02') #%% Calcular outliers outValueTr=OutDet.fit_predict(XTrOut) indOut=np.where(outValueTr==-1)[0] indIn =np.where(outValueTr==+1)[0] print(' Entrenamiento Inliers={:4} Outliers={:3}'.format(len(indIn),len(indOut))) plotOutliers(XTrOut,outValueTr,'Outliers detectados (clase -1)'.format(OutDet), 'Cuadros_11_OutliersDentro02Detectados') #%% Eliminar outliers, clasificar y evaluar XTrIn=XTrOut[indIn] YTrIn=YTrOut[indIn] plotOutliers(XTrIn,YTrIn,'Entranamiento CON inliers', 'Cuadros_12_QuitandoOutliersDentro02Detectados') Class.fit(XTrIn,YTrIn) P=Class.predict(XTe) Acc=accuracy_score(YTe,P) print(' Evaluación CON inliers: accuracy={:6.4f}'.format(Acc)) plotOutliers(XTe,P,'Evaluación CON inliers: accuracy={:6.4f}'.format(Acc), 'Cuadros_13_EvalQuitandoOutliersDentro02Detectados')

Apartado B

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 5 : Detección de anomalías Sesión 1 : Detección de anomalías Bloque A : Detección de outliers """ import numpy as np import random from sklearn.ensemble import IsolationForest from sklearn.neighbors import LocalOutlierFactor from sklearn.covariance import EllipticEnvelope import matplotlib.pyplot as plt from matplotlib.patches import Rectangle from sklearn.svm import SVC from sklearn.metrics import accuracy_score def plotOutliers(X,Y,titulo,fileName=None): plt.figure() ax=plt.axes() ax.add_patch(Rectangle([0,0],2,2,edgecolor='black' ,facecolor='None')) ax.add_patch(Rectangle([0,0],1,1,edgecolor='tab:blue' ,facecolor='None')) ax.add_patch(Rectangle([1,1],1,1,edgecolor='tab:orange',facecolor='None')) plt.title(titulo) plt.xlabel('x0') plt.ylabel('x1') plt.xlim([-1,3]) plt.ylim([-1,3]) colIO=['tab:grey','tab:red'] col01=['tab:blue','tab:orange'] classes=np.unique(Y) if min(classes)==-1: # Hay outliers col=colIO labels=['Outliers','Inliers'] else: col=col01 labels=['Clase {}'.format(cla) for cla in classes] cc=0 for cla in classes: indCla=np.where(Y==cla)[0] plt.plot(X[indCla,0],X[indCla,1],linestyle='None',marker='o',color=col[cc], label=labels[cc]) cc=cc+1 plt.legend() if type(fileName)!=type(None): plt.savefig('plots/{}.pdf'.format(fileName)) def genCuadros(RG,nIrre=0,nEjeClass=10): X=[] Y=[] for cla in [0,1]: for n in range(nEjeClass): x1=RG.random()+cla x2=RG.random()+cla row=[x1,x2] for i in range(nIrre): row.append(RG.random()) X.append(row) Y.append(cla) return [np.array(X),np.array(Y)] def generaOutEnClase(nOut,nIrre=0): X=[] Y=[] for i in range(nOut): cla=RG.randint(0,1) x0=RG.random() x1=RG.random() if RG.random()>0.5: cla=1 else: x0=x0+1 x1=x1+1 cla=0 row=[x0,x1] for i in range(nIrre): row.append(RG.random()) X.append(row) Y.append(cla) return [np.array(X),np.array(Y)] """ Ejercicio 1: Observa y cambia Esta actividad muestra como se eliminan outliers y el efecto que tiene en el aprendizaje. Ejecuta bloque a bloque este script. Fíjate en el código y en los dibujos que se muestran. Cambia el sistema de detección de outliers (hay varios comentados en la sección de parámetros) ¿Cuál es mejor? """ #%% Parámetros y datos: Cuadros: entrenamiento y test # Parámetros RG=random.Random() RG.seed(1) # Semilla nIrre=4 # Nº de atributos irrelevantes nEjeEntre= 10 # Ejemplos entrenamiento por cada clase nEjeTest =100 # Ejemplos test por cada clase nEjeOut = 10 # Nº de Outliers # Algoritmo de detección de outliers OutDet=IsolationForest(random_state=1) # OutDet=LocalOutlierFactor() # OutDet=EllipticEnvelope(random_state=1) # Clasificador Class=SVC(kernel='linear',C=1) [XTr,YTr]=genCuadros(RG,nIrre=nIrre,nEjeClass=nEjeEntre) # Entrenamiento [XTe,YTe]=genCuadros(RG,nIrre=nIrre,nEjeClass=nEjeTest ) # Test print('Cuadros Atributos:{} (2 relevantes). Ejemplos entrenamiento:{} test:{}' .format(len(XTr[0]),len(XTr),len(XTe))) plotOutliers(XTe,YTe,'Test: Cuadros','CuadrosB_01_Test') plotOutliers(XTr,YTr,'Entrenamiento: Cuadros original','CuadrosB_02_EntreOriginal') #%% Clasificar y evaluar sin outliers Class.fit(XTr,YTr) P=Class.predict(XTe) Acc=accuracy_score(YTe,P) print('Evaluación sin outliers: accuracy={:6.4f}'.format(Acc)) plotOutliers(XTe,P,'Evaluación SIN outliers: accuracy={:6.4f}'.format(Acc), 'CuadrosB_03_EvalOriginal') #%% Inserción de outliers dentro de los dominios de las clases print('Outliers en el dominio de las clases:') [XOut,YOut]=generaOutEnClase(nEjeOut,nIrre=nIrre) XTrOut=np.concatenate([XTr,XOut]) YTrOut=np.concatenate([YTr,YOut]) plotOutliers(XTrOut,YTrOut,'Entrenamiento con {} outliers en las clases'.format(nEjeOut), 'CuadrosB_04_ConOutliersDentroClases') Class.fit(XTrOut,YTrOut) P=Class.predict(XTe) Acc=accuracy_score(YTe,P) print(' Evaluación CON outliers: accuracy={:6.4f}'.format(Acc)) plotOutliers(XTe,P,'Evaluación CON outliers: accuracy={:6.4f}'.format(Acc), 'CuadrosB_05_EvaluacionConOutliersDentro') #%% Calcular outliers outValueTr=OutDet.fit_predict(XTrOut) indOut=np.where(outValueTr==-1)[0] indIn =np.where(outValueTr==+1)[0] print(' Entrenamiento Inliers={:4} Outliers={:3}'.format(len(indIn),len(indOut))) plotOutliers(XTrOut,outValueTr,'Outliers detectados (clase -1)'.format(OutDet), 'CuadrosB_06_OutliersDentroClasesDetectados') #%% Eliminar outliers, clasificar y evaluar XTrIn=XTrOut[indIn] YTrIn=YTrOut[indIn] plotOutliers(XTrIn,YTrIn,'Entranamiento CON inliers', 'CuadrosB_07_QuitandoOutliersDentroClasesDetectados') Class.fit(XTrIn,YTrIn) P=Class.predict(XTe) Acc=accuracy_score(YTe,P) print(' Evaluación CON inliers: accuracy={:6.4f}'.format(Acc)) plotOutliers(XTe,P,'Evaluación CON inliers: accuracy={:6.4f}'.format(Acc), 'CuadrosB_08_EvalQuitandoOutliersDentroClasesDetectados') #%% Quedarse con inliers clase a clase XTrClaIn=[] # Ejemplos inliers detectados clase a clase YTrClaIn=[] # La categoría es redundante, pero por simplificar el código (opción docente) classes=np.unique(YTrOut) for cla in classes: indCla=np.where(YTrOut==cla)[0] XCla=XTrOut[indCla] # Ejemplos de la clase cla YCla=YTrOut[indCla] # Es algo redundante outValueTr=OutDet.fit_predict(XCla) indIn =np.where(outValueTr==+1)[0] XClaIn=XCla[indIn] YClaIn=YCla[indIn] XTrClaIn.append(XClaIn) YTrClaIn.append(YClaIn) print(' Inliers en clase {}:{:2} de un total de {:2}'.format(cla,len(XClaIn),len(XCla))) plotOutliers(XCla,outValueTr,'Outliers detectados (clase -1) de la clase {}'.format(cla), 'CuadrosB_09_OutliersDentroClase_{}_Detectados'.format(cla)) XTrClaIn=np.concatenate(XTrClaIn) YTrClaIn=np.concatenate(YTrClaIn) plotOutliers(XTrClaIn,YTrClaIn,'Entranamiento CON inliers clase a clase', 'CuadrosB_10_OutliersClaseAClase') #%% Clasificar y evaluar Class.fit(XTrClaIn,YTrClaIn) P=Class.predict(XTe) Acc=accuracy_score(YTe,P) print(' Evaluación CON inliers clase a clase: accuracy={:6.4f}'.format(Acc)) plotOutliers(XTe,P,'Evaluación CON inliers clase a clase: accuracy={:6.4f}'.format(Acc), 'CuadrosB_11_EvalQuitandoOutliersClaseAClaseDetectados')

Apartado C

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 5 : Detección de anomalías Sesión 1 : Detección de anomalías Bloque C : Detección de ejemplos novedosos (novelty) """ import numpy as np import random import matplotlib.pyplot as plt from sklearn.svm import OneClassSVM from sklearn.ensemble import IsolationForest def genNovelty(RG,nNormales,nNovedosos): X=[] sd=0.25 mediaX1=0 mediaX2=0 # Ejemplos normales for i in range(nNormales): x1=RG.normalvariate(mediaX1,sd) x2=RG.normalvariate(mediaX2,sd) X.append([x1,x2]) # Ejemplos cada vez más novedosos for i in range(nNovedosos): mediaX1=1#mediaX1+0.1 mediaX2=1#mediaX2+0.1 x1=RG.normalvariate(mediaX1,sd) x2=RG.normalvariate(mediaX2,sd) X.append([x1,x2]) return np.array(X) def plotOneData(X,label,marker,color): plt.plot(X[:,0],X[:,1],label=label,linestyle='None',marker=marker,color=color) def plot2D(XTr,XTe,XTrNo,XTeNo,title,filename): plt.figure() plt.title(title) plt.xlabel('X0') plt.ylabel('X1') plotOneData(XTr,'Entrenamiento','o','blue') plotOneData(XTe,'Test','o','green') plotOneData(XTrNo,'Novedad en Entre.','x','magenta') plotOneData(XTeNo,'Novedad en Test','x','orange') plt.legend() plt.savefig(filename) #%% Generación de datos normales y novedosos RG=random.Random() RG.seed(1) XTr=genNovelty(RG,nNormales=25,nNovedosos= 0) # Entrenamiento todos normales XTe=genNovelty(RG,nNormales=25,nNovedosos=25) # Test 15 normalesy 15 novedosos X=np.concatenate([XTr,XTe]) # Todos #%% Aplicar sistema de detección de anomalías: OneClassSVM nu=0.1 AD=OneClassSVM(nu=nu) AD.fit(XTr) # En test PTe=AD.predict(XTe) ind=np.where(PTe==-1)[0] # Índices a ejemplos considerados novedad XTeNo=XTe[ind,:] # Ejemplos novedosos # En entrenamiento PTr=AD.predict(XTr) ind=np.where(PTr==-1)[0] # Índices a ejemplos consideredos novedad XTrNo=XTr[ind,:] # Ejemplos novedosos plot2D(XTr,XTe,XTrNo,XTeNo,'OneClassSVM(nu={})'.format(nu),'plots/OneClassSVM_CorteOriginal.pdf') print('OneClassSVM(nu={})'.format(nu)) print(' Ejemplos de entrenamiento:{} novedad:{:2}'.format(len(XTr),len(XTrNo))) print(' Ejemplos de Test :{} novedad:{:2}'.format(len(XTe),len(XTeNo))) #%% No todas las novedades lo son con la misma 'intensidad'. # Obtenemos la función de decisión. # El signo es la predicción, pero cuanto más negativa más novedad. DFTe=AD.decision_function(XTe) plt.figure() plt.title('OneClassSVM(nu={})'.format(nu)) plt.xlabel('X0') plt.ylabel('Función de decisión') plt.plot(XTe[:,0],DFTe,linestyle='None',marker='.',color='navy',label='Función de decisión') plt.plot(XTe[:,0],[0] *len(XTe),linestyle='solid',marker=None,color='black',label='Punto de corte original(0)') plt.plot(XTe[:,0],[-0.3]*len(XTe),linestyle='solid',marker=None,color='red',label='Punto de corte=-0.3') plt.legend() plt.savefig('plots/OneClassSVM_DF.pdf') #%% Actividad 1 # Vista la gráfica anterior nos parece mejor que la separación entre novedosas # y no novedosas esté en -0.3 en vez de 0 # Modifica PTe de mamera que tenga el valor del signo de la función de decisión (DF) # a la que se le resta el valor de separacion, en este caso -0.3 # Imprime el número de ejemplos novedosos en este caso # NOTA: puedes usar la función np.sign que retorna el signo de un numero #TODO Actividad 1 # Modificar la predicción en test PTe=np.sign(DFTe-(-0.3)) #justa las predicciones de test (PTe) usando un nuevo umbral.DFTe contiene los valores de la función de decisión (la distancia al hiperplano o frontera) para el conjunto de test.Al restar -0.3 (que equivale a hacer DFTe + 0.3), estamos desplazando la frontera de decisión.np.sign() calcula el signo del resultado: si el valor es positivo devuelve +1 (normal) y si es negativo devuelve -1 (novedad). # Calcular la DF de train DFTr=AD.decision_function(XTr) #Obtiene las puntuaciones de la función de decisión para los datos de entrenamiento (XTr) usando el modelo entrenado (AD). Valores más altos significan datos más "normales" o internos, y valores más bajos o negativos indican datos más lejanos o anómalos. # Modificar la predicción en train PTr=np.sign(DFTr-(-0.3)) # Aplica exactamente la misma lógica del punto anterior pero sobre los datos de entrenamiento. Reasigna las etiquetas en PTr (+1 o -1) basándose en el nuevo punto de corte de -0.3. #Calcular cuantos ejemplos novedosos hay ahora en train y test ind=np.where(PTe==-1)[0] # Busca y almacena en la variable ind las posiciones (índices) de todos los elementos del conjunto de test que fueron clasificados como novedad (-1). XTeNo=XTe[ind,:] # : Filtra la matriz XTe para quedarse únicamente con las filas (características) de los ejemplos que han sido identificados como novedades en test. ind=np.where(PTr==-1)[0] #Reutiliza la variable ind para buscar ahora los índices de los elementos del conjunto de entrenamiento que fueron clasificados como novedad (-1). XTrNo=XTr[ind,:] # Ejemplos novedosos print('OneClassSVM(nu={}) Punto de corte=-0.3'.format(nu)) print(' Ejemplos de entrenamiento:{} novedad:{:2}'.format(len(XTr),len(XTrNo))) print(' Ejemplos de Test :{} novedad:{:2}'.format(len(XTe),len(XTeNo))) #END TODO Actividad 1 plot2D(XTr,XTe,XTrNo,XTeNo,'OneClassSVM(nu={}) Punto de corte=-0.3'.format(nu),'plots/OneClassSVM_CorteCambiado.pdf')

Apartado D

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 5 : Detección de anomalías Sesión 1 : Detección de anomalías Bloque D : Detección de ejemplos novedosos (novelty) con autoencoders """ """ NOTA: Instalar Torch: conda install pytorch cpu-only -c pytorch """ from AutoencoderNovelty import AutoencoderNovelty import numpy as np import random import matplotlib.pyplot as plt def genNovelty(RG,nNormales,nNovedosos): X=[] sd=0.2 mediaX1=0 mediaX2=0 # Ejemplos normales for i in range(nNormales): x1=RG.normalvariate(mediaX1,sd) x2=RG.normalvariate(mediaX2,sd) X.append([x1,x2]) # Ejemplos cada vez más novedosos for i in range(nNovedosos): mediaX1=1 mediaX2=1 x1=RG.normalvariate(mediaX1,sd) x2=RG.normalvariate(mediaX2,sd) X.append([x1,x2]) return np.array(X) def plotOneData(X,label,marker,color): plt.plot(X[:,0],X[:,1],label=label,linestyle='None',marker=marker,color=color) def plot2D(XTr,XTe,XTrNo,XTeNo,title,filename): plt.figure() plt.title(title) plt.xlabel('X0') plt.ylabel('X1') plotOneData(XTr,'Entrenamiento','o','blue') plotOneData(XTe,'Test','o','green') plotOneData(XTrNo,'Novedad en Entre.','x','magenta') plotOneData(XTeNo,'Novedad en Test','x','orange') plt.legend() plt.savefig(filename) #%% Generación de datos normales y novedosos RG=random.Random() RG.seed(2) XTr=genNovelty(RG,nNormales=25,nNovedosos= 0) # Entrenamiento todos normales XTe=genNovelty(RG,nNormales=175,nNovedosos=25) # Test 15 normalesy 15 novedosos X=np.concatenate([XTr,XTe]) # Todos #%% Aplicar sistema de detección de anomalías: AutoencoderNovelty AD=AutoencoderNovelty() AD.fit(XTr) # En test PTe=AD.predict(XTe) ind=np.where(PTe==-1)[0] # Índices a ejemplos considerados novedad XTeNo=XTe[ind,:] # Ejemplos novedosos # En entrenamiento PTr=AD.predict(XTr) ind=np.where(PTr==-1)[0] # Índices a ejemplos consideredos novedad XTrNo=XTr[ind,:] # Ejemplos novedosos plot2D(XTr,XTe,XTrNo,XTeNo,'AutoencoderNovelty','plots/Autoencoder.pdf') print('AutoencoderNovelty') print(' Ejemplos de entrenamiento:{} novedad:{:2}'.format(len(XTr),len(XTrNo))) print(' Ejemplos de Test :{} novedad:{:2}'.format(len(XTe),len(XTeNo))) #%% Ejercicio 1 """ Observa la gráfica AutoencoderNovelty. No hay ningún ejemplo de entrenamiento marcado como novedad. ¿Porqué es así? Se quiere que solo los ejemplos de test que están en la parte superior derecha se traten como novedad. ¿Qué se podría cambiar en el AutoencoderNovelty? Modifica la versión 2 (v2) para lograrlo. (Está copiada a continuación) PISTA: Mira los parámetros del constructor """ #%% Aplicar sistema de detección de anomalías: AutoencoderNovelty v2 # Solución # Ningún ejemplo de entrenamiento está tratado como novedad porque el valor tope # de novedad es el máximo del error de reconstrucción en entrenamiento y por tanto # ningún ejemplo de entrenamiento supera ese límite # Para conseguir que haya menos novedad se puede subir el valor tope de novedad # Se usará el parámetro calculoTh que calcula el valor tope de novedad # Propuesta: sumar al máximo la desviación típica de los errores de reconstrucción # Versión con creación de función def miCalculoTh(ers): return max(ers)+np.std(ers) AD=AutoencoderNovelty(calculoTh=miCalculoTh) # Versión con programación funcional # AD=AutoencoderNovelty(calculoTh=lambda ers : max(ers)+np.std(ers)) AD.fit(XTr) # En test PTe=AD.predict(XTe) ind=np.where(PTe==-1)[0] # Índices a ejemplos considerados novedad XTeNo=XTe[ind,:] # Ejemplos novedosos # En entrenamiento PTr=AD.predict(XTr) ind=np.where(PTr==-1)[0] # Índices a ejemplos consideredos novedad XTrNo=XTr[ind,:] # Ejemplos novedosos plot2D(XTr,XTe,XTrNo,XTeNo,'AutoencoderNovelty v2','plots/Autoencoder_v2.pdf') print('AutoencoderNovelty v2') print(' Ejemplos de entrenamiento:{} novedad:{:2}'.format(len(XTr),len(XTrNo))) print(' Ejemplos de Test :{} novedad:{:2}'.format(len(XTe),len(XTeNo)))

Prepresencial

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 5 : Detección de anomalías Sesión 1 : Detección de anomalías Bloque Pre : Detección de anomalías """ import numpy as np import random from sklearn.svm import SVC import matplotlib.pyplot as plt def genPosNeg(RG,nExa=10): X=[] Y=[] for cate in [-1,+1]: for n in range(nExa): x=RG.random()*cate X.append([x]) Y.append(cate) return [X,Y] def dibuja(X,Y,titulo,filename): Y=np.array(Y) X=np.array(X) plt.figure(figsize=[6,2]) plt.title(titulo) plt.xlabel('X') plt.ylabel('Categoría') plt.ylim([-1.15,+1.15]) for cate in [-1,+1]: ind=np.where(Y==cate) XPos=X[ind,:].flatten() plt.plot(XPos,[cate]*len(XPos),linestyle='None',marker='o') plt.savefig(filename) #%% Programa principal Cla=SVC(kernel='linear',gamma=1,C=1) # Con un outlier RG=random.Random() RG.seed(1) [XTr,YTr]=genPosNeg(RG) [XTe,YTe]=genPosNeg(RG) # Se añade un outlier XTr.append([-10]) YTr.append(+1) dibuja(XTr,YTr,'Entrenamiento con outlier','plots/preTrainWithOutlier.pdf') Cla.fit(XTr,YTr) P=Cla.predict(XTe) dibuja(XTe,P,'Predicción de test','plots/preEvalTestModelWithOutlier.pdf') # Quitamos el outlier XTr=XTr[:(len(XTr)-1)] YTr=YTr[:(len(YTr)-1)] dibuja(XTr,YTr,'Entrenamiento sin outlier','plots/preTrainNoOutlier.pdf') Cla.fit(XTr,YTr) P=Cla.predict(XTe) dibuja(XTe,P,'Predicción de test','plots/preEvalTestModelNoOutlier.pdf')

Actividad 1 presencial

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 5 : Detección de anomalías Sesión 1 : Detección de anomalías Actividad 1 """ from datasets.leeIris import leeIris import matplotlib.pyplot as plt from sklearn.ensemble import IsolationForest from sklearn.neighbors import LocalOutlierFactor from sklearn.covariance import EllipticEnvelope import numpy as np from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score import random def pintaClassOutliers(outValue,X,Y,titulo,fileName,xlim=None,ylim=None): """ Función que pinta clusters hechos sobre conjuntos de datos 'simple' Pinta sobre los 2 primeros atributos en el intervalo [-3,+3] Parámetros: - outValue : lista donde -1 indica outlier y -1 inlier - [X,Y] : Valores de los ejemplos - titulo : String. Título de la figura - fileName : String. nombre del fichero sin extensión (la extensión será .pdf) Si vale None no se guarad en fichero Se guardará en la carpeta plots/ """ colores=['tab:orange','tab:blue','tab:red'] YOut=list(map(lambda o,y:y if o==+1 else -1,outValue,Y)) plt.figure() labels=np.unique(YOut) RG=None for ilabel in range(len(labels)): label=labels[ilabel] if label==-1: color='tab:gray' # No asignados a ninguna clase elif label<len(colores): color=colores[label] else: if RG==None: RG=random.Random() RG.seed(1) color=(RG.random(),RG.random(),RG.random()) ccolor=color indices=np.where(YOut==label)[0] if xlim!=None: plt.xlim(xlim) if ylim!=None: plt.ylim(ylim) plt.plot(X[indices,0],X[indices,1],linestyle='None',marker='o',color=color,label='clase {}'.format(label) if label>=0 else 'outliers') plt.title(titulo) plt.xlabel('Atributo 0') plt.ylabel('Atributo 1') plt.legend(loc='upper left') if fileName!=None: plt.savefig('plots/{}.pdf'.format(fileName)) def randomMove(RG,YTr,CatSource,CatTarget,proportion): indSou=np.where(YTr==CatSource)[0] nMove=int(len(indSou)*proportion) RG.shuffle(indSou) for i in indSou[:nMove]: YTr[i]=CatTarget # ACTIVIDAD 1 # Se lee el conjunto iris con los 2 atributos relevantes. # Se divide en entrenamien to y test # En el entrenamietno se intercambian algunos valores de la categoría (Y). # La gráfica plots/IrisSwapped.pdf muestra como queda. # Se realiza un aprendizaje/evaluación con Random Forest. # Se lee el conjunto de ejemplos iris (solo 2 atributos) [X,Y]=leeIris() [XTr,XTe,YTr,YTe]=train_test_split(X,Y,test_size=1/3, stratify=Y,random_state=5) xlim=[0,7] ylim=[0,3] # Se intercambian al azar algunas categorías RG=random.Random() RG.seed(1) randomMove(RG,YTr,CatSource=1,CatTarget=2,proportion=0.25) randomMove(RG,YTr,CatSource=0,CatTarget=1,proportion=0.25) outValue=[1]*len(YTr) pintaClassOutliers(outValue,XTr,YTr,'iris swapped','IrisSwapped',xlim=xlim,ylim=ylim) Class=RandomForestClassifier(random_state=1) # Aprender con todos los ejemplos Class.fit(XTr,YTr) P=Class.predict(XTe) Acc=accuracy_score(P,YTe) print('Accuracy con todos({}) los ejemplos : {:6.4f}'.format(len(XTr),Acc)) # ENUNCIADO ACTIVIDAD 1 """ Utilizar dos estrategias de eliminación de outliers: todos los ejemplos y clase a clase Realizar con los inliers otro aprendizaje/evaluación y calcular la accuracy ¿Se ha conseguido mejorar con alguna estrategia? """ #TODO ACTIVIDAD 1 # sobre todo el conjunto: Calcular outliers y eliminarlos OutDet=IsolationForest(random_state=1) #Instancia el detector de outliers. En este caso utiliza Isolation Forest, un algoritmo basado en árboles de decisión que aisla las anomalías de forma # eficiente. El random_state=1 asegura que el resultado sea siempre el mismo si vuelves a ejecutar el código. # ALTERNATIVAS A USAR EL IsolationForest # OutDet=LocalOutlierFactor(novelty=True) # OutDet=EllipticEnvelope(random_state=1) outValueTr=OutDet.fit_predict(XTr) # Entrena el detector con los datos de entrenamiento (XTr) y predice si cada dato es normal o un outlier. Guarda el resultado en outValueTr. pintaClassOutliers(outValueTr,XTr,YTr,'iris swapped(junto)','IrisSwapped_junto',xlim=xlim,ylim=ylim) indexInlayer=np.where(outValueTr==+1)[0] # Busca las posiciones (índices) de todos los elementos cuyo valor es +1 (los datos normales o inliers). print('Entrenamiento Inliers (Junto): {} ejemplos'.format(len(indexInlayer))) XTrIn=XTr[indexInlayer] YTrIn=YTr[indexInlayer] #Crea un nuevo conjunto de entrenamiento filtrado (XTrIn e YTrIn) que contiene únicamente los datos que pasaron el filtro de inliers. # Apreder sin los outlayers Class.fit(XTrIn,YTrIn) P=Class.predict(XTe) Acc=accuracy_score(P,YTe) print('Accuracy con inlayers (junto) : {:6.4f}'.format(Acc)) # Clase a clase: Calcular outliers y eliminarlos XTrClaIn=[] # Ejemplos inliers detectados clase a clase YTrClaIn=[] # La categoría es redundante, pero por simplificar el código (opción docente) classes=np.unique(YTr) #Extrae las clases o categorías únicas que existen en las etiquetas (por ejemplo: [0, 1, 2]). for cla in classes: indCla=np.where(YTr==cla)[0] #: Encuentra los índices o posiciones de los datos que pertenecen únicamente a la clase actual XCla=XTr[indCla] # Ejemplos de la clase cla YCla=YTr[indCla] # Es algo redundante outValueTr=OutDet.fit_predict(XCla) #Ajusta el detector y predice los outliers únicamente con los datos de esta clase. Esto permite identificar qué puntos son "raros" respecto a sus compañeros de clase. indIn =np.where(outValueTr==+1)[0] #Encuentra los índices locales de los datos clasificados como normales (+1) dentro de esta clase. XClaIn=XCla[indIn] YClaIn=YCla[indIn] XTrClaIn.append(XClaIn) #Como las listas contenían bloques separados por clase, np.concatenate une todos los fragmentos en una sola matriz de datos continua (un solo bloque para X y otro para Y). YTrClaIn.append(YClaIn) print(' Inliers en clase {}:{:2} de un total de {:2}'.format(cla,len(XClaIn),len(XCla))) XTrClaIn=np.concatenate(XTrClaIn) YTrClaIn=np.concatenate(YTrClaIn) print('Entrenamiento total Inliers={:4} Outliers={:4}' .format(len(XTrClaIn),len(XTr)-len(XTrClaIn))) # Apreder sin los outlayers Class.fit(XTrClaIn,YTrClaIn) P=Class.predict(XTe) Acc=accuracy_score(P,YTe) print('Accuracy con inlayers (Clase a Clase): {:6.4f}'.format(Acc)) # END ACTIVIDAD 1 #%% ENUNCIADO ACTIVIDAD 2 """ Se quieren combinar varios sistemas de detección de outliers de manera que solo se tome como outlier un ejemplo si para todos sistemas se indica que es outlier. Utilizar la clase outlierCombina Aplicarlo al caso de detección de outliers por clase """ class outlierCombina: """ Combina detectores de outliers indicando como outliers los ejemplos que todos los detectores indican que son outliers """ def __init__(self,ODList): """ Parámetros: - ODList : lista de detectores de outliers """ self.ODList=ODList def fit_predict(self,X): Preds=[] # Todas las predicciones for OD in self.ODList: POD=OD.fit_predict(X) Preds.append(POD) # Preds tiene tanatas filas como detectores de outliers hay en self.ODList # Cada columna son las predicciones que se han hecho para un ejemplo # Se queire que la predicción P sea oulier solamente si todas las predicciones # para cada ejemplo indican que es outliar # TODO 2.1 P=np.max(Preds,axis=0) # Si hay un +1 para algún OD (Detector de Outliers), # ese ejemplo ya es no outlier # END return np.array(P) # Calcular outliers y eliminarlos clase a clase print('\nCombinando dos sistemas de detección de outliers') XTrIn=[] YTrIn=[] OutDet1=IsolationForest(random_state=1) OutDet2=LocalOutlierFactor() OutDet3=EllipticEnvelope(random_state=1) #TODO 2.2 Crea una lista con varios OD (Detector de Outliers) ODList=[OutDet1,OutDet2] #END #TODO 2.3 Crea objeto outlierCombina que utiliza lista anterior OutDetCom=outlierCombina(ODList) #END for c in np.unique(YTr): indexc=np.where(YTr==c)[0] XTrc=XTr[indexc,:] YTrc=YTr[indexc] #TODO 2.4 Utiliza el detector de outliers combinado outValueTr=OutDetCom.fit_predict(XTrc) #END print('Entrenamiento clase {} Inliers={:4} Outliers={:4}'.format(c,len(np.where(outValueTr==+1)[0]),len(np.where(outValueTr==-1)[0]))) pintaClassOutliers(outValueTr,XTrc,YTrc,'iris swapped','IrisSwapped_class_{}'.format(c),xlim=xlim,ylim=ylim) # Insertar los inliers en el conjunto [XTrIn,YTrIn] indexInlayer=np.where(outValueTr==+1)[0] XTrIn=XTrIn+XTrc[indexInlayer,:].tolist() YTrIn=YTrIn+YTrc[indexInlayer].tolist() print('Entrenamiento total Inliers={:4} Outliers={:4}' .format(len(XTrIn),len(XTr)-len(XTrIn))) # Apreder sin los outlayers Class.fit(XTrIn,YTrIn) P=Class.predict(XTe) Acc=accuracy_score(P,YTe) print('Accuracy con inlayers (por clases): {:6.4f}'.format(Acc)) #%% ENUNCIADO ACTIVIDAD 3

Actividad2 presencial

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 5 : Detección de anomalías Sesión 1 : Detección de anomalías Actividad 2 """ from datasets.leeIris import leeIris import matplotlib.pyplot as plt import numpy as np from sklearn.ensemble import RandomForestClassifier from random import random from sklearn.model_selection import train_test_split def pintaClass(X,Y,titulo,fileName=None,xlim=None,ylim=None): """ Función que pinta datsets de clasificación Parámetros: - [X,Y] : Valores de los ejemplos - titulo : String. Título de la figura - fileName : String. nombre del fichero sin extensión (la extensión será .pdf) Si vale None no se guarad en fichero Se guardará en la carpeta plots/ """ if type(Y)==type(None): Y=np.array([-1]*len(X)) colores=['tab:orange','tab:blue','tab:red'] plt.figure() labels=np.unique(Y) RG=None for ilabel in range(len(labels)): label=int(labels[ilabel]) if label==-1: color='tab:gray' # No asignados a ninguna clase elif label<len(colores): color=colores[label] else: if RG==None: RG=random.Random() RG.seed(1) color=(RG.random(),RG.random(),RG.random()) ccolor=color indices=np.where(Y==label)[0] if xlim!=None: plt.xlim(xlim) if ylim!=None: plt.ylim(ylim) plt.plot(X[indices,0],X[indices,1],linestyle='None',marker='o',color=color,label='clase {}'.format(label)) plt.title(titulo) plt.xlabel('Atributo 0') plt.ylabel('Atributo 1') plt.legend(loc='upper left') if fileName!=None: plt.savefig('plots/{}.pdf'.format(fileName)) def leeIris12(seed=1): [X,Y]=leeIris() # Iris with categories 1 or 2 indIris01=np.where(Y>=1)[0] X12=X[indIris01,:] Y12=Y[indIris01] # Iris with categories 2 indIris0=np.where(Y==0)[0] X0=X[indIris0,:] Y0=Y[indIris0] # Train test over Iris 01 [XTr,XTe,YTr,YTe]=train_test_split(X12,Y12,test_size=1/3, stratify=Y12,random_state=seed) # Iris 2 is added to test XTe=np.concatenate([XTe,X0]) YTe=np.concatenate([YTe,Y0]) return [XTr,YTr,XTe,YTe] # ENUNCIADO ACTIVIDAD 1 """ Se han recogido varios lirios (iris) y se ha creado un conjunto etiquetado con algunos lirios de los tipos 1 y 2 Se ha realizado un proceso de aprendizaje que crea un modelo que diferencia entre los tipos 1 y 2 (Class) Se quiere evaluarlo sobre el resto de lirios que se tienen que no están etiquetados, y que no solo tienen que ser de tipo 1 o 2. Ha de predecirse 1 o 2 para los lirios que se cree que son de clase 1 o 2 y si no se cree que es de esa clase se ha de predecir -1 """ # Se lee el conjunto de ejemplos iris (solo 2 atributos) [XTr,YTr,XTe,_]=leeIris12() xlim=[0,7] ylim=[0,3] outValue=[] pintaClass(XTr,YTr ,'iris 12 : train',xlim=xlim,ylim=ylim) pintaClass(XTe,None,'iris 12 : test' ,xlim=xlim,ylim=ylim) Class=RandomForestClassifier(random_state=1) Class.fit(XTr,YTr) # SOLUCIÓN # TODO 1.1 # 1 Se realiza una predicción P=Class.predict(XTe) #END # 2 Se detecta la novedad en el test # TODO 1.2 from AutoencoderNovelty import AutoencoderNovelty AD=AutoencoderNovelty(calculoTh=lambda ers:max(ers)+np.std(ers)) # El umbral se calcula sumando el error de reconstrucción máximo (max(ers)) más la desviación estándar de los errores (np.std(ers)). Cualquier dato de test con un error de reconstrucción mayor a este umbral será considerado una "novedad". AD.fit(XTr) # En test PNovelty=AD.predict(XTe) #END # 3 Se combina como indica el enunciado: si hay novedad -> novedad, si no la predicción de Class # Guarda la predicción en P (Para luego pintarla) # TODO 1.3 for i in range(len(XTe)): if PNovelty[i]==-1: P[i]=-1 # END pintaClass(XTe,P,'iris 12 : predicción' ,xlim=xlim,ylim=ylim)

Tema 6 Sesion 1

MDPU

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 6 : Procesos de decisión de Markov Sesión 1 : Procesos de decisión de Markov Bloque A : Expresión del problema en función de P (Probabilidades de transición) y R (Reconpensas) Optimización de la Política usando un MDPSolver """ #https://pymdptoolbox.readthedocs.io/en/latest/api/mdp.html#mdptoolbox.mdp.MDP # Se quiere representar según un Proceso de Decisión de Markov (DPM) la siguiente situación: # Se tiene una nave que puede estar a la (I)zquierda o a la (D)erecha. #Se puede controlar este elemento móvil mediante las acciones (I)zquierda y #(D)erecha. # Hay un ET que puede estar en las dos posiciones de la nave. #Este elemento no se puede controlar. # La nave puede disparar. # El objetivo es que la nave dispare cuando esté en la misma posición que el ET. # Cuando se mueve la nave, el extraterrestre (ET) puede ir a I o D con igual probabilidad. # Cuando dispara la nave y no está en la misma posición que el ET #no ocurre nada. En este caso la recompensa es de -1 # Cuando dispara la nave y está en la misma posición que el ET, el #ET cambia de posición con probabilidad 0.75 y se queda con #probabilidad 0.25. En este caso la recompensa es de +1 # Solución: Definición de estados y acciones # Hay 4 estados correspondientes a las 4 combinaciones de la nave y el ET. # <Posición de la nave>: I,D (Izquierda o derecha) # <Posición del ET> : I,D (Izquierda o derecha) # Estados <Posición de la nave><Posición del ET> # - II # - ID # - DI # - DD # Hay 3 acciones, # - I: mover a la izquierda # - D: mover a la derecha # - S: disparar # Solución: Uso de mdptoolbox import numpy as np import mdptoolbox # El estado XY indica que la nave está en X y el ET en Y # Los nombres solo son útiles para imprimir la política y el valor de una manera #humanamente inteligible # Estados: II(0), ID(1), DI(2), DD(3) SNombres=['II','ID','DI','DD'] # Acciones: I(0) ,D(1) ,S(2) ANombres=['I','D','S'] #%% Probabilidades de cambio de estado según la acción # Se crea una matriz de probabilidad por cada acción # Estas matrices son cuadradas: NºEstados x NºEstados # El valor de la fila f y la columna c es la probabilidad de que estando en el #estado f y ejecutando la acción asociada a la matriz (hay una por cada acción) #se pase al estado c # P de la acción I(zquierda) # Estado destino: II ID DI DD PI=[ [0.5,0.5,0 ,0], # Estado origen II [0.5,0.5,0 ,0], # Estado origen ID [0.5,0.5,0 ,0], # Estado origen DI [0.5,0.5,0 ,0]] # Estado origen DD # Explicación de un caso: # Si se está en el estado DI (nave a la Derecha y ET a la Izquierda) #y se ejecuta I (Mover a la Izquierda) las probabilidades de II son 0.5, las de #ID son 0.5 y el resto 0. Esto significa que la nave irá a la izquierda pero # el extaterrestre se moverá a la derecha o quedará a la izquierda con igual # probabilidad. Que es lo indicado en el enunciado. # P de la acción D(erecha) # Estado destino: II ID DI DD PD=[ [0 ,0 ,0.5,0.5], # Estado origen II [0 ,0 ,0.5,0.5], # Estado origen ID [0 ,0 ,0.5,0.5], # Estado origen DI [0 ,0 ,0.5,0.5]] # Estado origen DD # P de la acción disparo (S)hoot # Estado destino: II ID DI DD PS= [[0.25,0.75,0 ,0 ], # Estado origen II [0 ,1 ,0 ,0 ], # Estado origen ID [0 ,0 ,1 ,0 ], # Estado origen DI [0 ,0 ,0.75,0.25]] # Estado origen DD # Explicación: # Para el orígenes ID solo puede ir ID, lo mismo para DI. Esto implementa la #parte del enunciado en la que indica que si se dispara y no está el ET en el #mismo sitio no pasa nada. # Para los orígenes donde coinciden, se queda en ese estado con probabilidad 0.25 #y cambia el ET con probabilidad 0.75 # mdptoolbox.mdp no acepta que P y R sean de tipo list # Admite que P y R sean numpy.Array P=np.array([PI,PD,PS]) #%% Reconpensas # El orden de las acciones de R (reconpensas) ha de ser el mismo que el de P # Por cada acción se crea una matriz de recompensas cuadradas: NºEstados x NºEstados # El valor de la fila f y la columna c es la reconpensa por cambiar del estado #f al estado c al aplicar la acción de la matriz correspondiente. # Los valores de P que sean 0 definen situaciones imposibles. # Aunque no es obligatorio se recomienda marcar esas posiciones al definir R #para evitar posibles confusiones. El valor que se ponga no tendrá efecto. # En este caso se define la variable i que será la que se use para marcar las #situaciones imposibles en las recompensas. El valor que se de a i no tiene efecto i=0 # R de la acción I(zquierda) # Estado destino: II ID DI DD RI= [[ 0, 0, i, i], # Estado origen II [ 0, 0, i, i], # Estado origen ID [ 0, 0, i, i], # Estado origen DI [ 0, 0, i, i]] # Estado origen DD # R de la acción D(erecha) # Estado destino: II ID DI DD RD= [[ i, i, 0, 0], # Estado origen II [ i, i, 0, 0], # Estado origen ID [ i, i, 0, 0], # Estado origen DI [ i, i, 0, 0]] # Estado origen DD # R de la acción disparo S(hot) # Estado destino: II ID DI DD RS= [[+1,+1, i, i], # Estado origen II [ i,-1, i, i], # Estado origen ID [ i, i,-1, i], # Estado origen DI [ i, i,+1,+1]] # Estado origen DD R=np.array([RI,RD,RS]) MDPSolver = mdptoolbox.mdp.PolicyIteration(P, R, discount=0.9) MDPSolver.run() print('mdptoolbox.mdp.PolicyIteration') print('Política de acciones:') for s in range(len(MDPSolver.policy)): print(' Si estás en el estado {} haz {}'.format(SNombres[s],ANombres[MDPSolver.policy[s]])) print('\nValor esperado según empieces en el estado:') for s in range(len(MDPSolver.V)): print(' {} valor esperado: {:6.4f}'.format(SNombres[s],MDPSolver.V[s])) print('Valor esperado medio: {:6.4f}'.format(np.mean(MDPSolver.V))) #%%Ejercicio 1 """ Resuelve el proceso anterior usando mdptoolbox.mdp.QLearning Salida mdptoolbox.mdp.QLearning Política de acciones: Si estás en el estado II haz S Si estás en el estado ID haz I Si estás en el estado DI haz I Si estás en el estado DD haz I Valor esperado según empieces en el estado: II valor esperado : 4.3428 ID valor esperado : 3.4548 DI valor esperado : 3.5670 DD valor esperado : 3.5427 Valor esperado medio: 3.7268 """ #TODO Ejerccio 1 MDPSolver = mdptoolbox.mdp.QLearning(P, R, discount=0.9) MDPSolver.run() print('\n\nmdptoolbox.mdp.QLearning') print('Política de acciones:') for s in range(len(MDPSolver.policy)): print(' Si estás en el estado {} haz {}'.format(SNombres[s],ANombres[MDPSolver.policy[s]])) print('\nValor esperado según empieces en el estado:') for s in range(len(MDPSolver.V)): print(' {} valor esperado : {:6.4f}'.format(SNombres[s],MDPSolver.V[s])) print('Valor esperado medio: {:6.4f}'.format(np.mean(MDPSolver.V))) #<TODO END Ejerccio 1> #%%Ejercicio 2 """ Se quiere que haya un coste de 1 (recompensa de -1) cada vez que haya un movimiento Se considera un movimiento cuando: a) se ejecuta la acción izquierda y se pasa de la derecha a la izquierda b) se ejecuta la acción derecha y se pasa de la izquierda a la derecha Modifica solo los elementos necesarios del MDP (usa PolicyIteration) Repite el proceso anterior con esta representación P1 ¿Cambia la política? ¿Qué significa? P2 ¿Cambian los valores? ¿Porqué? SALIDA Hay coste (recompensa negativa) al moverse Política de acciones: Si estás en el estado II haz S Si estás en el estado ID haz I Si estás en el estado DI haz D Si estás en el estado DD haz S Valor esperado según empieces en el estado: II valor esperado : 4.4898 ID valor esperado : 3.6735 DI valor esperado : 3.6735 DD valor esperado : 4.4898 Valor esperado medio: 4.0816 """ #TODO Ejercicio 2 # R de la acción I(zquierda) # Estado destino: II ID DI DD RI= [[ 0, 0, i, i], # Estado origen II [ 0, 0, i, i], # Estado origen ID [-1,-1, i, i], # Estado origen DI [-1,-1, i, i]] # Estado origen DD # R de la acción D(erecha) # Estado destino: II ID DI DD RD= [[ i, i,-1,-1], # Estado origen II [ i, i,-1,-1], # Estado origen ID [ i, i, 0, 0], # Estado origen DI [ i, i, 0, 0]] # Estado origen DD # RI= [[ 0, 0, i, i], # Estado origen II # [ 0, 0, i, i], # Estado origen ID # [ 0, 0, i, i], # Estado origen DI # [ 0, 0, i, i]] # Estado origen DD # # R de la acción D(erecha) # # Estado destino: II ID DI DD # RD= [[ i, i, 0, 0], # Estado origen II # [ i, i, 0, 0], # Estado origen ID # [ i, i, 0, 0], # Estado origen DI # [ i, i, 0, 0]] # Estado origen DD R=np.array([RI,RD,RS]) MDPSolver = mdptoolbox.mdp.PolicyIteration(P, R, discount=0.9) # MDPSolver = mdptoolbox.mdp.QLearning(P, R, discount=0.9) MDPSolver.run() print('\n\nHay coste (recompensa negativa) al moverse') print('Política de acciones:') for s in range(len(MDPSolver.policy)): print(' Si estás en el estado {} haz {}'.format(SNombres[s],ANombres[MDPSolver.policy[s]])) print('\nValor esperado según empieces en el estado:') for s in range(len(MDPSolver.V)): print(' {} valor esperado : {:6.4f}'.format(SNombres[s],MDPSolver.V[s])) print('Valor esperado medio: {:6.4f}'.format(np.mean(MDPSolver.V))) # P1 ¿Cambia la política? ¿Qué significa? # Sí, cambia. Sin coste de moMDPSolvermiento en el estado DI se mueve a la izquierda # (cambia a estados II o ID). Con coste de moMDPSolvermiento si está en DI propone # la acción D (se queda a la derecha) # P2 ¿Cambian los valores? ¿Porqué? # Los valores no cambian ya que cuando hay un coste este nunca se aplica ya que #no se ejecuta ningún moMDPSolvermiento (si está a la izqueirda queda a la izquierda y #si está a la derecha queda a la derecha) #END Ejerccio 2

Actividad

# -*- coding: utf-8 -*- """ Tema 6 : Procesos de decisión de Markov Sesión 1 : Procesos de decisión de Markov Actividad 1 """ #%% Ejercicio 1 """ En una competición de puntería hay 2 objetivos uno grande y otro pequeño. En cada instante hay solo un objetivo disponible. La aparición de uno u otro en cada instante es equiprobable. Se puede disparar o esperar. Si se espera hay una penalización de un punto. Si se dispara se puede acertar o fallar. Si está el objetivo grande, la probabilidad de acertar es de 0.75 y la de fallar de 0.25. Si se acierta se tiene una recompensa de 5 y si se falla una penalización de 10. Si está el objetivo pequeño, la probabilidad de acertar es de 0.25 y la de fallar de 0.75. Si se acierta se tiene una recompensa de 10 y si se falla una penalización de 5. Tras fallar o acertar, independientemente de la acción realizada, se haría disponible un objetivo (vuelve al inicio). Plantear este problema como un proceso de decisión de Markov y calcular una política utilizando el resolvedor PolicyIteration con un descuento de 0,99. Calcular el valor esperado para cada estado y el valor medio. PISTA: Se puede realizar con 4 estados: G - Aparece un objetivo Grande P - Aparece un objetivo Pequeño F - Hay un Fallo A - Hay un Acierto """ #%% Solución import numpy as np import mdptoolbox #TODO Actividad 1 # Los objetivos pueden estar en dos estados: objetivo (G)rande, objetivo (P)equeño. #Pero hay que conocer si se ha acertado o no, así que necesitamos otros dos estados: # (A)cierto y (F)allo. # Acciones hay 2 (Di)sparar o (Es)perar. SNombres=['G','P','F','A'] ANombres= ['Es','Di'] i=0 # usado para marcar las probabilidades y reconpensas que no pueden realizarse # Después de un (A)cierto i (F)allo, independienbtemente de la acción, se pasa #al estado G o P con probabilidad 0.5 # Si se (Es)spera: se pasa al estado G o P con probabilidad 0.5 #Estado destino: G ,P F, A PEs= [[0.5,0.5, i, i ],# Origen G [0.5,0.5, i, i ],# Origen P [0.5,0.5, i, i ],# Origen F [0.5,0.5, i, i ]]# Origen A # Si se (Di)spara: #Estado destino: G ,P ,F ,A PDi= [[i ,i ,0.25,0.75],# Origen G [i ,i ,0.75,0.25],# Origen P [0.5,0.5,i ,i ],# Origen F [0.5,0.5,i ,i ]]# Origen A P=np.array([PEs,PDi]) #%% Recompensas # Desde los estados F o A nunca hay penalización ni reconpensa para ir al estado #G o P inicial # Si se (Es)spera tanto desde el estado G o P hay una penalización de 1 #Estado destino: G ,P , F, A REs= [[-1,-1, i, i ],# Origen G [-1,-1, i, i ],# Origen P [ 0, 0, i, i ],# Origen F [ 0, 0, i, i ]]# Origen A # Si se (Di)spara: #Estado destino: G ,P ,F ,A RDi= [[i ,i ,-10, +5],# Origen G [i ,i , -5,+10],# Origen P [0 ,0 ,i ,i ],# Origen F [0 ,0 ,i ,i ]]# Origen A R=np.array([REs,RDi]) #%% Resolver MDPSolver = mdptoolbox.mdp.PolicyIteration(P, R, discount=0.99) MDPSolver.run() print('Política de acciones:') for s in range(len(MDPSolver.policy)): print(' Si estás en el estado {} haz {}'.format(SNombres[s],ANombres[MDPSolver.policy[s]])) print('\nValor esperado según empieces en el estado:') for s in range(len(MDPSolver.V)): print(' {} valor esperado: {:6.4f}'.format(SNombres[s],MDPSolver.V[s])) print('Valor medio: {:6.4f}'.format(np.mean(MDPSolver.V))) #END Actividad 1

Actividad racha

# -*- coding: utf-8 -*- """ Tema 6 : Procesos de decisión de Markov Sesión 1 : Procesos de decisión de Markov Actividad 1.1 (Continuación de la 1) """ #%% Ejercicio 2: Racha """ En una competición de puntería hay 2 objetivos uno grande y otro pequeño. En cada instante hay solo un objetivo disponible. La aparición de uno u otro en cada instante es equiprobable. Se puede disparar o esperar. Si se espera hay una penalización de un punto. Si se dispara se puede acertar o fallar. Si está el objetivo grande, la probabilidad de acertar es de 0.75 y la de fallar de 0.25. Si se acierta se tiene una reconpensa de 5 y si se falla una penalización de 10. Si está el objetivo pequeño, la probabilidad de acertar es de 0.25 y la de fallar de 0.75. Si se acierta se tiene una reconpensa de 10 y si se falla una penalización de 5. Tras fallar se haría disponible un objetivo (vuelve al inicio). NUEVO: Tras acertar se está en RACHA lo que significa que si se acertó un objetivo grande vuelve a aparecer un objetivo grande y se acertó un objetivo pequeño vuelve a aparecer el objetivo pequeño. Plantear este problema como un proceso de decisión de Markov y calcular una política utilizando el resolvedor PolicyIteration con un descuento de 0,99. Calcular el valor esperado para cada estado y el valor medio. PISTA: Se puede realizar con 5 estados: G - Aparece un objetivo Grande P - Aparece un objetivo Pequeño F - Hay un Fallo AG- Hay un Acierto del objetivo Grande AP- Hay un Acierto del objetivo Pequeño """ #%% Solución import numpy as np import mdptoolbox SNombres=['G','P','F','AP','AG'] ANombres= ['Es','Di'] #TODO Actividad 1 #%% Estados # Los objetivos pueden estar en dos estados: objetivo (G)rande, objetivo (P)equeño. #Pero hay que conocer si se ha acertado o no, así que necesitamos otros dos estados: # (A)cierto y (F)allo. # Acciones hay 2 (Di)sparar o (Es)perar. i=0 # usado para marcar las probabilidades y reconpensas que no pueden realizarse # Después de un (A)cierto i (F)allo, independienbtemente de la acción, se pasa #al estado G o P con probabilidad 0.5 # Si se (Es)spera: se pasa al estado G o P con probabilidad 0.5 #Estado destino: G ,P F AP AG PEs= [[0.5,0.5, i, i, i],# Origen G [0.5,0.5, i, i, i ],# Origen P [0.5,0.5, i, i, i ],# Origen F [0.5,0.5, i, i, i ],# Origen AP [0.5,0.5, i, i, i ]]# Origen AG # Si se (Di)spara: #Estado destino: G ,P ,F ,AP AG PDi= [[i ,i ,0.25,i ,0.75],# Origen G [i ,i ,0.75,0.25,i ],# Origen P [0.5,0.5,i ,i ,i ],# Origen F [i ,1 ,i ,i ,i ],# Origen AP [1 ,i ,i ,i ,i ]]# Origen AG P=np.array([PEs,PDi]) #%% Reconpensas # Desde los estados F o A nunca hay penalización ni reconpensa para ir al estado #G o P inicial # Si se (Es)spera tanto desde el estado G o P hay una penalización de 1 #Estado destino: G ,P , F, AP AG REs= [[-1,-1, i, i, i ],# Origen G [-1,-1, i, i, i ],# Origen P [ 0, 0, i, i, i ],# Origen F [ 0, 0, i, i, i ],# Origen AP [ 0, 0, i, i, i ]]# Origen AG # Si se (Di)spara: #Estado destino: G ,P ,F ,AP AG RDi= [[i ,i ,-10,i , +5],# Origen G [i ,i , -5,+10,i ],# Origen P [0 ,0 ,i ,i ,i ],# Origen F [i ,0 ,i ,i ,i ],# Origen AP [0 ,i ,i ,i ,i ]]# Origen AG R=np.array([REs,RDi]) #%% Resolver MDPSolver = mdptoolbox.mdp.PolicyIteration(P, R, discount=0.99) MDPSolver.run() print('Política de acciones:') for s in range(len(MDPSolver.policy)): print(' Si estás en el estado {} haz {}'.format(SNombres[s],ANombres[MDPSolver.policy[s]])) print('\nValor esperado según empieces en el estado:') for s in range(len(MDPSolver.V)): print(' {} valor esperado: {:6.4f}'.format(SNombres[s],MDPSolver.V[s])) print('Valor medio: {:6.4f}'.format(np.mean(MDPSolver.V))) #END Actividad 1

Tema 7 Sesion 1

Clase EstadoVehiculo

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ @author: quevedo """ from RL_MDP.Estado import Estado class EstadoVehiculo(Estado): def __init__(self,nombre,cuartosGas,pinchado=True): # EjerTaller Estado.__init__(self,nombre) self.cuartosGas=cuartosGas self.pinchado=pinchado # EjerTaller def getCuartosGas(self): """ Retorna los cuartos de Gas que tiene un vehículo en este estado. """ return self.cuartosGas def getPinchado(self): # EjerTaller """ Retorna si el aceite está usado o no """ return self.pinchado

Ruta

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ @author: quevedo """ from RL_MDP.Accion import Accion class Ruta(Accion): """ Define la ruta (acción) que realiza un vehículo. Se ha de difinir los cuartos de Gas que consume esta ruta. Calcula la recompensa en función del estado del vehículo. Clase padre abstracta para crear hijas redefiniendo getRecompensa """ def __init__(self,nombre,cuartosGas,penaNoGas,probPinchar=0,esTaller=False): # EjerTaller """ Parámetros: - nombre : nombre de la ruta - cuartosGas : Entero en [0;4] 0 cadena que será una expresión a evaluar. La expresión puede utilizar RG objeto random.Random(); La expresión ha de retorna un entero en [0;4] Cuartos de Gas que se consumen en esta ruta - penaNoGas : Penalización (valor negativo) por intentar hacer esta ruta y no tener combustible suficiente - probPinchar: probabilida de pinchar. Un valor flotante en [0;1]. # EjerTaller - esTaller : Indica si esta ruta es un Taller. Si es un taller cambia # EjerTaller el estado de Pinchado a False y los cuartos a 0 """ Accion.__init__(self,nombre) self.cGas=cuartosGas self.penaNoGas=penaNoGas self.probPinchar=probPinchar # EjerTaller self.Taller=esTaller # EjerTaller def getCuartosGas(self,RG): cGas=self.cGas if type(cGas)==int: # Constant return self.cGas if type(cGas)==str: # Evaluation return eval(cGas) def esTaller(self): # EjerTaller return self.Taller def getEstadoNuevoRecompensa(self,estadoActual,listaEstados,RG): """ La acción cambia el estadoActual por el nuevoEstado Parámetros: - estadoActual : Estado actual. objeto hijo de Estado - listaEstados : Lista con todos los estados del entorno - RG : Generador de aleatoriedad. Objeto de clase random.Random() Retorna: [estadoNuevo,recompensa] - estadoNuevo : elemento de listaEstados - recompensa : valor numérico con la recompensa tras haber ejecutado la acción actual y pasar del estado estadoActual al estadoNuevo """ gasTiene =estadoActual.getCuartosGas() # Gas que tiene pinchado =estadoActual.getPinchado() # Si hay una rueda pinchada o no # EjerTaller gasNecesita =self.getCuartosGas(RG) # Gas que necesita para completar la ruta cuartosTrasRuta=min([4,gasTiene-gasNecesita]) # Cálculo de los cuartos de Gas que quedan tras la ruta esTaller =self.esTaller() # Si es una ruta a taller # EjerTaller # Se queda sin Gas if cuartosTrasRuta<0: # Retorna el estado correspondiente a 0 cuartos de Gas junto con la penalización por qeudarse sin Gas return [self._estadoCuartosPinchado(listaEstados,0,pinchado),self.penaNoGas] # entonces penalización # Si es un taller # EjerTaller if esTaller: estadoTrasAccion =self._estadoCuartosPinchado(listaEstados,0,False) else: # EjerTaller # Comprobar si pincha o no en esta ruta if self.probPinchar>=RG.random(): # Hay pinchazo pinchado=True estadoTrasAccion=self._estadoCuartosPinchado(listaEstados,cuartosTrasRuta,pinchado) # Calcula el estado tras la acción recompensa =self.getRecompensa(RG,estadoActual,estadoTrasAccion) # Calcula Recompensa de esta acción # Si se pincha se divide la recompensa entre 2 if pinchado: # EjerTaller recompensa=recompensa/2 # Retorna el estado correspondiente a cuartosTrasRuta cuartos de Gas(estadoTrasAcccion) #junto con la recompensa return [estadoTrasAccion,recompensa] def _estadoCuartosPinchado(self,listaEstados,cuartos,pinchado): # EjerTaller """ Retorna el estado de listaEstados que tiene los cuartos de Gas indicados en cuartos y el valor de esPinchado() indicado por Pinchado """ for e in listaEstados: if e.getCuartosGas()==cuartos and e.getPinchado()==pinchado: return e print('ERROR: No hay estados con "{}" cuartos de GAS y que pinchado sea {}'.formnat(cuartos,pinchado)) exit() def getRecompensa(self,RG,estadoActual,estadoTrasAcccion): pass class RutaUniforme(Ruta): """ Crea una ruta con una recompensa con distribución uniforme en el intervalo [a,b] Es independiente del estado (solo un estado) """ def __init__(self,nombre,cuartosGas,penaNoGas,probPinchar,a,b):# EjerTaller Ruta.__init__(self,nombre,cuartosGas,penaNoGas,probPinchar)# EjerTaller self.a=a self.b=b def getRecompensa(self,RG,estadoActual,estadoTrasAcccion): return RG.uniform(self.a,self.b) class RutaNormal(Ruta): """ Crea una ruta con una recompensa con distribución normal de media m y distribución típica d Es independiente del estado (solo un estado) """ def __init__(self,nombre,cuartosGas,penaNoGas,probPinchar,m,d):# EjerTaller Ruta.__init__(self,nombre,cuartosGas,penaNoGas,probPinchar)# EjerTaller self.m=m self.d=d def getRecompensa(self,RG,estadoActual,estadoTrasAcccion): return RG.normalvariate(self.m,self.d) class RutaGas(Ruta): """ Ruta a la Gasolimera """ def __init__(self,nombre): Ruta.__init__(self,nombre,cuartosGas=-4,penaNoGas=None,probPinchar=0)# EjerTaller def getRecompensa(self,RG,estadoActual,estadoTrasAcccion): return 0 class RutaTaller(Ruta): # EjerTaller """ Ruta al Taller """ def __init__(self,nombre): Ruta.__init__(self,nombre,cuartosGas=0,penaNoGas=None,probPinchar=0,esTaller=True)# EjerTaller def getRecompensa(self,RG,estadoActual,estadoTrasAcccion): return 0

RutasTraller

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tema 7 : Aprendizaje por refuerzo Sesión 1 : Definición y ejecución de un RL Bloque A : Definición y ejecución de un RL """ from Ruta import RutaUniforme,RutaNormal,RutaGas,RutaTaller # EjerTaller from EstadoVehiculo import EstadoVehiculo from RL_MDP.Entorno import Entorno from RL_MDP.Agente import Agente import matplotlib.pyplot as plt import numpy as np # Ejercicio 1 # Crear en un proyecto nuevo copia de este donde: # El estado del vehículo, además, de los cuartos de Gas que tiene indicará si ha pinchado (Sí o No) # Si hay pinchazo las recompensas por realizar rutas serán la mitad # Crear una nueva ruta Taller que repare el pinchazo (pase pinchado de True a False) y deje a vehículo sin Gas # Tendrá que haber un nuevo parámetro de Ruta que indique si es Taller o no # Las rutas tendrán una probabilidad de que haya un pinchazo #%% Crea una lista con 5 rutas más la (Gas)olinera y el taller # EjerTaller penaNoGas=-1 Ru1=RutaUniforme('U0_10',cuartosGas=1 ,penaNoGas=penaNoGas,probPinchar=0.0,a=0,b=10) Ru2=RutaUniforme('U5_9' ,cuartosGas='max([1,int(RG.normalvariate(1,1))])' ,penaNoGas=penaNoGas,probPinchar=0.1,a=5,b= 9) Ru3=RutaNormal ('N5_2' ,cuartosGas=1 ,penaNoGas=penaNoGas,probPinchar=0.0,m=5,d= 2) Ru4=RutaNormal ('N9_1' ,cuartosGas=2 ,penaNoGas=penaNoGas,probPinchar=0.2,m=9,d= 1) Ru5=RutaNormal ('N6_2' ,cuartosGas='0 if RG.random()<0.1 else 1' ,penaNoGas=penaNoGas,probPinchar=0.1,m=6,d= 2) RuG=RutaGas ('Gas') RuT=RutaTaller ('Taller') lRutas=[Ru1,Ru2,Ru3,Ru4,Ru5,RuG,RuT] # Crea una lista con los estados un vehículo # EjerTaller lEstadosVehiculo=[] for c in range(4+1): for p in [False,True]: ev=EstadoVehiculo('C{}P{}'.format(c,0 if p==False else 1),cuartosGas=c,pinchado=p) lEstadosVehiculo.append(ev) # Crea el entorno seedEntorno=1 Transporte=Entorno(listaAcciones=lRutas,listaEstados=lEstadosVehiculo,seed=seedEntorno) #%% Crea un agente seedAgente=1 Conductor=Agente(listaAcciones=Transporte.getListaAcciones(), listaEstados =Transporte.getListaEstados() , seed=seedAgente,eps=0.1,epsFactor=1) #%% Ejecuta el RL Rs=[] # Recompensas de cada iteración As=[] # Acciones de cada iteración Iters=50000 # Número de iteraciones s=Transporte.getEstadoInicial() for i in range(Iters): a=Conductor.decide(s) # Decide que acción hacer ante el estado s [s,r]=Transporte.make(s,a) # El entorno responde ante la acción a en el esatado s #y retorna el nuevo estado y la recompensa Conductor.setRecompensa(r,s) #indicando al agente la recompensa obtenida y el #estado al que llega(feedback) el agente se actualiza # Almacenar la acción y la recompensa en cada iteración As.append(a) Rs.append(r) # Prompt if i%1000==0: print('.',end='') print('Resultados del RL:') Conductor.printP() # Imprime cubo de probabilidades RMedia=np.mean(Rs) # Media de recompensas print('- Iteración {} recompensa media: {:6.4f}'.format(Iters,RMedia)) # Política obtenida print('- Política:') MDP=Conductor.getMDP() lAcciones=Transporte.getListaAcciones() # Lista de acciones (para poder nombrarlas) for s in range(len(MDP.policy)): print(' * Si estás en el estado {} haz {}'.format(lEstadosVehiculo[s].getNombre(),lAcciones[MDP.policy[s]].getNombre())) #%% Recompensa media en cada iteración RMediaItera=[] RSumaItera=0 for i in range(len(Rs)): RSumaItera=RSumaItera+Rs[i] RMediaItera.append(RSumaItera/(i+1)) Iter=list(range(len(Rs))) # Lista de iteraciones plt.figure() plt.plot(Iter,RMediaItera) # plt.ylim((0,9)) plt.grid() plt.title('RL_MDP') plt.xlabel('Iteración') plt.ylabel('Recompensa media') #%% Proporción de acciones ejecutadas en cada iteración Iter=list(range(len(Rs))) # Lista de iteraciones plt.figure() for a in range(Transporte.getNAcciones()): aSuma=0 aMediaItera=[] for i in range(len(As)): if a==As[i].getIndex(): aSuma=aSuma+1 aMediaItera.append(aSuma/(i+1)) plt.plot(Iter,aMediaItera,label=lAcciones[a].getNombre()) plt.legend() plt.grid() plt.title('RL_MDP') plt.xlabel('Iteración') plt.ylabel('Proporción de la acción en cada iteración') # Ejercicio 2 # Añade el cansancio a RL_MDP_RutaTaller # Cada vez que se realiza una ruta se incrementa el cansancio. # Cada Ruta permite definir cuanto aumenta el cansancio con un valor entero en [0,3] # El valor máximo es 3 # Hay una nueva Ruta Descanso que pone el cansancio a 0 # Al hacer una ruta (excepto Gasolinera, Taller y Descanso) la recompensa se # multiplica por 3/(3+cansancio)

EJER FINAL

Ejercici1

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Ejercicio 1 """ #%% Datos from simpleGen import simpleGen import random import warnings warnings.simplefilter("ignore") # Parámetros del conjunto de ejemplos nejemplos=50 # Número de ejemplos no etiquetados atrNoRel=2 # Nº de atributos no relevantes atrRel=2 # Nº de atributos relevantes nAtr=atrRel+atrNoRel # Nº de atributos total # Crear el conjunto de ejemplos RG=random.Random() # Generador de números aleatorios RG.seed(1) # Semilla del generador de números aleatorios sd=1 simple=simpleGen(sd=sd,atrRel=atrRel,atrNoRel=atrNoRel) X=simple(RG,nejemplos) # Generar los ejemplos no etiquetados #%% Enunciado """ Ejercicio 1 (Este ejercicio es algo más corto que uno típico de examen) Se quieren crear clústers del conjunto X, luego calcular el cluster para el ejemplo zero e imprimir el índice (número) del mismo Utilizar dos algoritmos diferentes e indicar cual es mejor. """ zero=[0,0,0,0] import numpy as np from sklearn.cluster import MeanShift, KMeans from sklearn.metrics import silhouette_score # ************ # Utilizo KMeans SC=KMeans() SC.fit(X) clusters=SC.predict(X) ic=SC.predict([zero]) print('KMeans: índice de zero',ic[0]) KMss=silhouette_score(X,clusters) # # ************ # # Utilizo MeanShift SC=MeanShift() SC.fit(X) clusters=SC.predict(X) ic=SC.predict([zero]) print('MeanShift: índice de zero',ic[0]) n_clusters=len(np.unique(clusters)) if n_clusters>1 and n_clusters<len(X): MSss=silhouette_score(X,clusters) else: MSss=-np.inf if KMss>MSss: print('Mejor KMeans') else: print('Mejor MeanShift')

Ejercicio2

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Ejercicio 2 """ #%% Datos from PaquetesInversion import PaqueteInversionPasado,PaquetesInversionFuturos [X,Y]=PaqueteInversionPasado() [X1,X2,X3,X4,X5]=PaquetesInversionFuturos() #%% Enunciado """ Ejercicio 2: inversión Se tiene información de un paquete de inversiones(X,Y) donde cada inversión se califica como buena(valor 1 en Y) o mala(valor 0 en Y). Tiene 4 atributos correspondientes a información financiera de las mismas: Nivel de riesgo Liquidez Valor liquidativo Volatilidad histórica Las inversiones buenas dan un beneficio de +5 y las malas de -3. See tienen 5 paquetes de inversión de futuro: [X1,X2,X3,X4,X5]. Se han de contratar los paquetes enteros, y el objetivo es elegir cual es el mejor paquete y cuánto beneficio se obtiene. Hay que comparar dos métodos de elegir el mejor paquete. El software elegirá el mejor Utilizando el mejor se decidirá cuál es el mejor paquete de inversión. Se imprimirá el nombre del mejor paquete (X1,...) y el beneficio estimado """ #%% EJER 2 import numpy as np from sklearn.svm import SVC from sklearn.model_selection import train_test_split from quantificationlib.baselines.cc import CC from quantificationlib.baselines.ac import AC from quantificationlib.bag_generator import PriorShift_BagGenerator from QUtils import dataSetFromQBags # Dividirlo en entrenamiento y test [XTr,XTe,YTr,YTe]=train_test_split(X,Y,test_size=1/3,random_state=1,stratify=Y) p=np.mean(YTr) #Qué hace: Calcula la media de las etiquetas de entrenamiento (YTr). Como las etiquetas son binarias ($0$ y $1$), la media representa exactamente la proporción de casos positivos (prevalencia) originales. Luego la imprime en pantalla print('Prevalencia entrenamiento: {:6.4f}'.format(p)) # Clasificador (Común para ámbos métodos) Class=SVC(kernel='linear',C=1,probability=True) # Instancia un clasificador SVM con kernel lineal. El parámetro probability=True es indispensable porque el método de cuantificación AC requerirá las probabilidades predichas de pertenencia a la clase, no solo la etiqueta final. # ******************* # Método AC Q=AC(estimator_train=Class, estimator_test=Class) Q.fit(XTr,YTr) l1s=[] # Crear diferentes conjuntos de test con distinta prevalencia n_bags=100 BG=PriorShift_BagGenerator(n_bags=n_bags,random_state=1) bags=BG.generate_bags(XTe,YTe) #Inicializa una lista vacía l1s para guardar los errores. Define que creará 100 muestras de prueba ficticias (n_bags) #generadas mediante Prior Shift (desplazamiento de la probabilidad a priori). Esto significa que el generador tomará los datos de test originales (XTe, YTe) y construirá 100 subconjuntos ("bolsas"), cada uno forzado a tener una mezcla/prevalencia de positivos radicalmente diferente (desde $0\%$ hasta $100\%$). for i in range(n_bags): [Xb,Yb]=dataSetFromQBags(XTe,YTe,bags,i) p=np.mean(Yb) pres=Q.predict(Xb) pe=pres[np.argwhere(Q.classes_==1)[0][0]] # Predicted prevalence l1=abs(pe-p) #print('Prevalencia test:{:6.4f} AC:{:6.4f} l1={:6.4f}'.format(p,pe,l1)) l1s.append(l1) ACl1=np.mean(l1s) ACQ=Q print('AC , l1 medio:{:6.4f}'.format(ACl1)) # ******************* # Método CC Q=CC( estimator_test=Class) Q.fit(XTr,YTr) l1s=[] # Crear diferentes conjuntos de test con distinta prevalencia n_bags=100 BG=PriorShift_BagGenerator(n_bags=n_bags,random_state=1) bags=BG.generate_bags(XTe,YTe) for i in range(n_bags): [Xb,Yb]=dataSetFromQBags(XTe,YTe,bags,i) p=np.mean(Yb) pres=Q.predict(Xb) pe=pres[np.argwhere(Q.classes_==1)[0][0]] # Predicted prevalence l1=abs(pe-p) #print('Prevalencia test:{:6.4f} AC:{:6.4f} l1={:6.4f}'.format(p,pe,l1)) l1s.append(l1) CCl1=np.mean(l1s) CCQ=Q print('CC , l1 medio:{:6.4f}'.format(CCl1)) # ******************* # Elegir el mejor Modelo if ACl1<CCl1: Q=ACQ print('Mejor modelo AC') else: Q=CCQ print('Mejor modelo CC') #Compara los errores medios de ambos métodos (ACl1 y CCl1). # Aquel método que tenga el error medio más bajo (más cercano a 0) es asignado a la variable genérica Q como el modelo definitivo de producción, e imprime cuál fue el ganador. # ******************* # El mejor paquete será el que tena más prevalencia tenga (más inversiones buenas) # Buscar en [X1,X2,X3,X4,X5] el que tenga más prevalencia mejorBene=-np.inf mejorIndex=None listX=[X1,X2,X3,X4,X5] #Prepara la optimización. Inicializa el mejor beneficio en menos infinito (-np.inf), el índice ganador en None, y agrupa en una lista listX los 5 lotes de datos sin etiquetar. for i in range(5): # Calcular la prevalencia de X_i XTe=listX[i] p=Q.predict(XTe) p1=p[np.argwhere(Q.classes_==1)[0][0]] #Toma el paquete actual listX[i], usa el cuantificador ganador Q para estimar la prevalencia en este lote desconocido y almacena la proporción estimada de inversiones buenas en la variable p1 # Calcular cuantos ejemplos son positivos y cuántos negativos nEje=len(XTe) nPos=nEje*p1 nNeg=nEje*(1-p1) # Calcular el beneficio bene=5*nPos-3*nNeg # Quedarse con el mejor if bene>mejorBene: mejorBene=bene mejorIndex=i # Imporimir el mejor print('Mejor paquete: X{}, beneficio={:6.2f}'.format(mejorIndex+1,mejorBene)) #END EJER 2

Ejercicio3

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ @author: quevedo@uniovi.es """ import numpy as np from RL_MDP.Accion import Accion class Ruta(Accion): """ Define la ruta (acción) que realiza un vehículo. Se ha de difinir los cuartos de Gas que consume esta ruta. Calcula la recompensa en función del estado del vehículo. Clase padre abstracta para crear hijas redefiniendo getRecompensa """ def __init__(self,nombre,cuartosGas,penaNoGas,probPinchar=0,esTaller=False,modificaAnimo=0): # EjerTaller """ Parámetros: - nombre : nombre de la ruta - cuartosGas : Entero en [0;4] 0 cadena que será una expresión a evaluar. La expresión puede utilizar RG objeto random.Random(); La expresión ha de retorna un entero en [0;4] Cuartos de Gas que se consumen en esta ruta - penaNoGas : Penalización (valor negativo) por intentar hacer esta ruta y no tener combustible suficiente - probPinchar: probabilida de pinchar. Un valor flotante en [0;1]. # EjerTaller - esTaller : Indica si esta ruta es un Taller. Si es un taller cambia # EjerTaller el estado de Pinchado a False y los cuartos a 0 - modificaAnimo : valor numérico, negativo(tiende a emperar el ánimo) o positivo (tiende a mejorar el ánimo) """ Accion.__init__(self,nombre) self.cGas=cuartosGas self.penaNoGas=penaNoGas self.probPinchar=probPinchar # EjerTaller self.Taller=esTaller # EjerTaller self.modificaAnimo=modificaAnimo def getCuartosGas(self,RG): cGas=self.cGas if type(cGas)==int: # Constant return self.cGas if type(cGas)==str: # Evaluation return eval(cGas) def esTaller(self): # EjerTaller return self.Taller def getEstadoNuevoRecompensa(self,estadoActual,listaEstados,RG): """ La acción cambia el estadoActual por el nuevoEstado Parámetros: - estadoActual : Estado actual. objeto hijo de Estado - listaEstados : Lista con todos los estados del entorno - RG : Generador de aleatoriedad. Objeto de clase random.Random() Retorna: [estadoNuevo,recompensa] - estadoNuevo : elemento de listaEstados - recompensa : valor numérico con la recompensa tras haber ejecutado la acción actual y pasar del estado estadoActual al estadoNuevo """ gasTiene =estadoActual.getCuartosGas() # Gas que tiene pinchado =estadoActual.getPinchado() # Si hay una rueda pinchada o no # EjerTaller gasNecesita =self.getCuartosGas(RG) # Gas que necesita para completar la ruta cuartosTrasRuta=min([4,gasTiene-gasNecesita]) # Cálculo de los cuartos de Gas que quedan tras la ruta esTaller =self.esTaller() # Si es una ruta a taller # EjerTaller animo =estadoActual.getAnimo() modificaAnimo =self.modificaAnimo animoTrasRuta =int(np.sign(animo+modificaAnimo)) # Se queda sin Gas if cuartosTrasRuta<0: # Retorna el estado correspondiente a 0 cuartos de Gas junto con la penalización por qeudarse sin Gas return [self._estadoCuartosPinchadoAnimo(listaEstados,0,pinchado,animoTrasRuta),self.penaNoGas] # entonces penalización # Si es un taller # EjerTaller if esTaller: estadoTrasAccion =self._estadoCuartosPinchadoAnimo(listaEstados,0,False,animoTrasRuta) else: # EjerTaller # Comprobar si pincha o no en esta ruta if self.probPinchar>=RG.random(): # Hay pinchazo pinchado=True estadoTrasAccion=self._estadoCuartosPinchadoAnimo(listaEstados,cuartosTrasRuta,pinchado,animoTrasRuta) # Calcula el estado tras la acción recompensa =self.getRecompensa(RG,estadoActual,estadoTrasAccion) # Calcula Recompensa de esta acción # Si se pincha se divide la recompensa entre 2 if pinchado: # EjerTaller recompensa=recompensa/2 if animoTrasRuta==-1: recompensa=recompensa/2 elif animoTrasRuta==+1: recompensa=recompensa*2 # Retorna el estado correspondiente a cuartosTrasRuta cuartos de Gas(estadoTrasAcccion) #junto con la recompensa return [estadoTrasAccion,recompensa] def _estadoCuartosPinchadoAnimo(self,listaEstados,cuartos,pinchado,animo): # EjerTaller """ Retorna el estado de listaEstados que tiene los cuartos de Gas indicados en cuartos y el valor de esPinchado() indicado por Pinchado """ for e in listaEstados: if e.getCuartosGas()==cuartos and e.getPinchado()==pinchado and e.getAnimo()==animo: return e print('ERROR: No hay estados con "{}" cuartos de GAS y que pinchado sea {}'.formnat(cuartos,pinchado)) exit() def getRecompensa(self,RG,estadoActual,estadoTrasAcccion): pass class RutaUniforme(Ruta): """ Crea una ruta con una recompensa con distribución uniforme en el intervalo [a,b] Es independiente del estado (solo un estado) """ def __init__(self,nombre,cuartosGas,penaNoGas,probPinchar,modificaAnimo,a,b):# EjerTaller Ruta.__init__(self,nombre,cuartosGas,penaNoGas,probPinchar,modificaAnimo=modificaAnimo)# EjerTaller self.a=a self.b=b def getRecompensa(self,RG,estadoActual,estadoTrasAcccion): return RG.uniform(self.a,self.b) class RutaNormal(Ruta): """ Crea una ruta con una recompensa con distribución normal de media m y distribución típica d Es independiente del estado (solo un estado) """ def __init__(self,nombre,cuartosGas,penaNoGas,probPinchar,modificaAnimo,m,d):# EjerTaller Ruta.__init__(self,nombre,cuartosGas,penaNoGas,probPinchar,modificaAnimo=modificaAnimo)# EjerTaller self.m=m self.d=d def getRecompensa(self,RG,estadoActual,estadoTrasAcccion): return RG.normalvariate(self.m,self.d) class RutaGas(Ruta): """ Ruta a la Gasolimera """ def __init__(self,nombre,modificaAnimo): Ruta.__init__(self,nombre,cuartosGas=-4,penaNoGas=None,probPinchar=0,modificaAnimo=modificaAnimo)# EjerTaller def getRecompensa(self,RG,estadoActual,estadoTrasAcccion): return 0 class RutaTaller(Ruta): # EjerTaller """ Ruta al Taller """ def __init__(self,nombre,modificaAnimo): Ruta.__init__(self,nombre,cuartosGas=0,penaNoGas=None,probPinchar=0,esTaller=True,modificaAnimo=modificaAnimo)# EjerTaller def getRecompensa(self,RG,estadoActual,estadoTrasAcccion): return 0