def busquedaLocal(data, k, MAX_EVALUACIONES=MAX_EVALUACIONES_GL, w_param=-1): """ @brief Función de busqueda local para hallar un vector de pesos. @param data Lista con el conjunto de datos. @param k Valor de vecinos que se quieren calcular en KNN. @param MAX_EVALUACIONES Número máximo de evaluaciones, por defecto es MAX_EVALUACIONES_GL=15000 @param w_param Vector de pesos del que se quiere arrancar la búsqueda local. Por defecto el valor es -1, con lo que se toma una solución inicial aleatoria. @return Devuelve un vector de pesos. """ #Obtengo las clases de las tuplas labels_np = np.array([d[-1] for d in data]) #Convierto todas las tuplas menos la clase a un numpy array data_np = np.array([d[:-1] for d in data]) #El máximo número de vecinos a explorar es 20 por la dimension MAX_VECINOS = 20 * (len(data[0]) - 1) vecinos = 0 evaluaciones = 0 #Inicializo la solución w = primerVector(len(data[0]) - 1) if w_param == -1 else w_param posicion_mutacion = 0 #Inicializo la valoración de la solución tc, tr = knn.Valoracion(data_np, data_np, k, np.array(w), labels_np, labels_np, True) valoracion_actual = tc + tr #Bucle principal while evaluaciones < MAX_EVALUACIONES and vecinos < MAX_VECINOS: evaluaciones += 1 vecinos += 1 #Tomo un vecino con el operador de mutación vecino, posicion_mutacion = auxiliar.mutacion(w, posicion_mutacion) #Calculo su valoración tc, tr = knn.Valoracion(data_np, data_np, k, np.array(vecino), labels_np, labels_np, True) valoracion_vecino = tc + tr #Si ha mejorado a la solución w entonces la reemplazamos if valoracion_vecino > valoracion_actual: vecinos = 0 w = vecino valoracion_actual = valoracion_vecino posicion_mutacion = 0 elif posicion_mutacion == len(w): posicion_mutacion = 0 #Devuelve la solución como un numpy array y el número de evaluaciones return np.array(w), evaluaciones
def GeneticoEstacionario(data, k, operador_cruce): ''' @brief Algoritmo genético estacionario. @param data Conjunto de datos. @param k Número de vecinos para el KNN. @param operador_cruce Operador de cruce usado. @return Devuelve el mejor individuo de la población final. ''' #Se fija el número de padres en función del operador num_padres = 0 if operador_cruce == cruceAritmetico: num_padres = 4 elif operador_cruce == cruceBLX: num_padres = 2 else: print("Has pasado un operador de cruce no válido.") return (-1) #Se toman las tuplas y sus clases data_np = np.array([d[:-1] for d in data]) labels_np = np.array([d[-1] for d in data]) #Se genera la población inicial de forma aleatoria con sus valoraciones poblacion = generaPoblacionInicial(len(data[0][:-1])) valoraciones = np.array([ knn.Valoracion(data_np, data_np, k, w, labels_np, labels_np, True) for w in poblacion ]) valoraciones = np.sum(valoraciones, axis=1) evaluaciones = TAM_POBLACION #Bucle principal while evaluaciones < MAX_EVALUACIONES: #Hijos con el operador aritmetico if num_padres == 4: padres = [torneoBinario(poblacion, valoraciones) for i in range(4)] hijo1 = operador_cruce(poblacion[padres[0]], poblacion[padres[1]]) hijo2 = operador_cruce(poblacion[padres[2]], poblacion[padres[3]]) #Hijos con el operador blx else: padres = [torneoBinario(poblacion, valoraciones) for i in range(2)] hijo1 = operador_cruce(poblacion[padres[0]], poblacion[padres[1]]) hijo2 = operador_cruce(poblacion[padres[0]], poblacion[padres[1]]) #Se hace la mutación en los dos hijos generados for i in range(len(hijo1)): if random.randint(1, 1000) <= PROB_MUTACION * 1000: hijo1, pos = auxiliar.mutacion(hijo1, i) for i in range(len(hijo2)): if random.randint(1, 1000) <= PROB_MUTACION * 1000: hijo2, pos = auxiliar.mutacion(hijo2, i) #Se añaden los dos hijos con sus valoraciones poblacion = np.append(poblacion, [hijo1], axis=0) tc, tr = knn.Valoracion(data_np, data_np, k, poblacion[-1], labels_np, labels_np, True) valoraciones = np.append(valoraciones, tc + tr) poblacion = np.append(poblacion, [hijo2], axis=0) tc, tr = knn.Valoracion(data_np, data_np, k, poblacion[-1], labels_np, labels_np, True) valoraciones = np.append(valoraciones, tc + tr) #Se toman los TAM_POBLACION mejores de la población después de añadir a los hijos indices_nueva_poblacion = np.argpartition(valoraciones, 2)[::-1][:TAM_POBLACION] poblacion = poblacion[indices_nueva_poblacion] valoraciones = valoraciones[indices_nueva_poblacion] evaluaciones += 2 #Se devuelve al mejor de la población valoraciones_final = np.array([ knn.Valoracion(data_np, data_np, k, w, labels_np, labels_np, True) for w in poblacion ]) valoraciones_final = np.sum(valoraciones_final, axis=1) return np.array(poblacion[np.argmax(valoraciones_final)])
def GeneticoGeneracional(data, k, operador_cruce): ''' @brief Algoritmo genético Generacional. @param data Conjunto de datos. @param k Número de vecinos en el KNN. @param operador_cruce Operador usado para cruzar individuos. ''' #Toma las tuplas y sus clases data_np = np.array([d[:-1] for d in data]) labels_np = np.array([d[-1] for d in data]) #Número de características ncar = len(data[0][:-1]) #Inicializa la población poblacion = generaPoblacionInicial(ncar) #Número de mutaciones prefijado mutaciones = int(PROB_MUTACION * TAM_POBLACION * ncar) #Número de parejas a tomar num_parejas = int(TAM_POBLACION * PROB_CRUCE_AGG) evaluaciones = TAM_POBLACION #Calcula las valoraciones y al mejor de la población valoraciones = np.array([ knn.Valoracion(data_np, data_np, k, w, labels_np, labels_np, True) for w in poblacion ]) valoraciones = np.sum(valoraciones, axis=1) mejor_solucion_ind = np.argmax(valoraciones) mejor_solucion_valor = valoraciones[mejor_solucion_ind] mejor_solucion = poblacion[mejor_solucion_ind] #Bucle principal while evaluaciones < MAX_EVALUACIONES: hijos = [] #Para cada pareja se hace el cruce for i in range(num_parejas): if operador_cruce == cruceAritmetico: padres = [ torneoBinario(poblacion, valoraciones) for i in range(4) ] hijos.append( operador_cruce(poblacion[padres[0]], poblacion[padres[1]])) hijos.append( operador_cruce(poblacion[padres[2]], poblacion[padres[3]])) hijos.append( operador_cruce(poblacion[padres[0]], poblacion[padres[2]])) hijos.append( operador_cruce(poblacion[padres[1]], poblacion[padres[2]])) else: padres = [ torneoBinario(poblacion, valoraciones) for i in range(2) ] hijos.append( operador_cruce(poblacion[padres[0]], poblacion[padres[1]])) hijos.append( operador_cruce(poblacion[padres[0]], poblacion[padres[1]])) #Se mutan los hijos for i in range(mutaciones): cr = random.randint(0, len(hijos) - 1) gen = random.randint(0, ncar - 1) hijos[cr], pos = auxiliar.mutacion(hijos[cr], gen) #Se rellena la población de hijos con un torneo binario for i in range(len(hijos), TAM_POBLACION): hijos.append(poblacion[torneoBinario(poblacion, valoraciones)]) poblacion = np.array(hijos) #Se recalculan las valoraciones valoraciones = np.array([ knn.Valoracion(data_np, data_np, k, w, labels_np, labels_np, True) for w in poblacion ]) valoraciones = np.sum(valoraciones, axis=1) evaluaciones += TAM_POBLACION #Se comprueba si la peor solución de esta población es mejor que el mejor de la anterior, si no es asi se reemplaza peor_solucion_ind = np.argmin(valoraciones) peor_solucion_valor = valoraciones[peor_solucion_ind] peor_solucion = poblacion[peor_solucion_ind] if peor_solucion_valor < mejor_solucion_valor: poblacion[peor_solucion_ind] = mejor_solucion mejor_solucion_ind = np.argmax(valoraciones) mejor_solucion_valor = valoraciones[mejor_solucion_ind] mejor_solucion = poblacion[mejor_solucion_ind] #Se devuelve al mejor de la población return np.array(mejor_solucion)
def EnfriamientoSimulado(data, k, MAX_EVALS=15000): ''' @brief Función que implementa el algoritmo de enfriamiento simulado @param data Conjunto de datos @param k Constante que se emplea en la valoración para el KNN @param MAX_EVALS Número máximo de evaluaciones, por defecto es 15000 @return Devuelve una solución de APC ''' #Se toman las tuplas y sus clases data_np = np.array([d[:-1] for d in data]) labels_np = np.array([d[-1] for d in data]) #Número de características ncar = len(data_np[0]) #Solución inicial sol = np.random.uniform(0, 1, ncar) mejor_sol = np.copy(sol) valoracion = knn.Valoracion(data_np, data_np, k, sol, labels_np, labels_np, True, True) valoracion_mejor_sol = valoracion #Temperatura inicial. Probablemente mal (reemplazar por 100-valoracion) T0 = (MU * (valoracion)) / (-np.log(PHI)) #Temperatura final #Si la temperatura inicial es menor que la inicial entonces bajamos la temperatura final TF = 1e-03 if 1e-03 > T0 else T0 - 1e-03 #Número de enfriamientos, máximos vecinos y máximos éxitos max_vecinos = 10.0 * ncar K = 1 M = MAX_EVALS / max_vecinos max_exitos = 0.1 * max_vecinos #Beta beta = (T0 - TF) / (M * T0 * TF) #Inicializa la temperatura y evaluaciones t = T0 evaluaciones = 1 #Bucle principal while t > TF and evaluaciones < MAX_EVALS: #Inicializo el número de vecinos considerados vecinos = 0 #Booleano que indica si el vecino ha sido aceptado como solución aceptados = 0 #Mientras que no se acepte la solución y no se halla considerado el máximo número de vecinos while aceptados < max_exitos and vecinos < max_vecinos: vecinos += 1 evaluaciones += 1 #Se obtiene el vecino y se ignora pos_nueva vecino, pos_nueva = auxiliar.mutacion( sol, np.random.randint(0, ncar - 1)) valoracion_vecino = knn.Valoracion(data_np, data_np, k, vecino, labels_np, labels_np, True, True) #Diferencia entre las valoraciones delta = valoracion - valoracion_vecino #Si la solución es mejor o un valor aleatorio cumple la condicion if delta < 0 or np.random.uniform(0, 1) < np.exp(-delta / (t * K)): #Aceptamos la solución sol = vecino valoracion = valoracion_vecino aceptados += 1 #Actualizamos la mejor solución si es necesario if valoracion_mejor_sol < valoracion: mejor_sol = np.copy(sol) valoracion_mejor_sol = valoracion #Disminuyo la temperatura t = enfriamiento(t, beta) K += 1 return np.array(sol)
def Memetico(data, k, operador_cruce, nGeneraciones, prob_bl, mejores=False): ''' @brief Algoritmo memético. @param data Conjunto de datos. @param k Número de vecinos para el KNN. @param operador_cruce Operador de cruce usado. @param nGeneraciones Número de generaciones en las que se ejecutará la búsqueda local. @param prob_bl Porcentaje de individuos a los que se aplica la búsqueda local. @param mejores Booleano que indica si aplicamos la búsqueda local sobre los mejores individuos de la población. @return Devuelve al mejor individuo de la población final. ''' #Toma las tuplas y sus clases data_np = np.array([d[:-1] for d in data]) labels_np = np.array([d[-1] for d in data]) ncar = len(data[0][:-1]) #Genera la población inicial poblacion = geneticos.generaPoblacionInicial(ncar, TAM_POBLACION) #Número de mutaciones prefijado mutaciones = int(PROB_MUTACION * TAM_POBLACION * ncar) #Número de parejas num_parejas = int(TAM_POBLACION * PROB_CRUCE_AGG) evaluaciones = TAM_POBLACION #Actualiza las valoraciones y la mejor solución valoraciones = np.array([ knn.Valoracion(data_np, data_np, k, w, labels_np, labels_np, True) for w in poblacion ]) valoraciones = np.sum(valoraciones, axis=1) mejor_solucion_ind = np.argmax(valoraciones) mejor_solucion_valor = valoraciones[mejor_solucion_ind] mejor_solucion = poblacion[mejor_solucion_ind] contador_generaciones = 1 #Bucle principal while evaluaciones < MAX_EVALUACIONES: #Cada nGeneraciones if contador_generaciones % nGeneraciones == 0: n_elem_bl = int(prob_bl * TAM_POBLACION) individuos = [] #Aplicamos BL a una muestra aleatoria de n_elem_bl elementos if not mejores: individuos = random.sample(range(TAM_POBLACION), n_elem_bl) #Le aplicamos la BL a los n_elem_bl mejores de la población else: individuos = valoraciones.argsort()[-n_elem_bl:][::-1] for ind in individuos: poblacion[ind], ev = busqueda_local.busquedaLocal( data, k, 2 * len(data_np[0])) evaluaciones += ev #Actualiza las valoraciones valoraciones = np.array([ knn.Valoracion(data_np, data_np, k, w, labels_np, labels_np, True) for w in poblacion ]) valoraciones = np.sum(valoraciones, axis=1) evaluaciones += TAM_POBLACION contador_generaciones += 1 hijos = [] #Genera los hijos for i in range(num_parejas): if operador_cruce == geneticos.cruceAritmetico: padres = [ geneticos.torneoBinario(poblacion, valoraciones, TAM_POBLACION) for i in range(4) ] hijos.append( operador_cruce(poblacion[padres[0]], poblacion[padres[1]])) hijos.append( operador_cruce(poblacion[padres[2]], poblacion[padres[3]])) hijos.append( operador_cruce(poblacion[padres[0]], poblacion[padres[2]])) hijos.append( operador_cruce(poblacion[padres[1]], poblacion[padres[2]])) else: padres = [ geneticos.torneoBinario(poblacion, valoraciones, TAM_POBLACION) for i in range(2) ] hijos.append( operador_cruce(poblacion[padres[0]], poblacion[padres[1]])) hijos.append( operador_cruce(poblacion[padres[0]], poblacion[padres[1]])) #Muta los hijos for i in range(mutaciones): cr = random.randint(0, len(hijos) - 1) gen = random.randint(0, ncar - 1) hijos[cr], pos = auxiliar.mutacion(hijos[cr], gen) #Rellena la población de hijos con un torneo binario for i in range(len(hijos), TAM_POBLACION): hijos.append(poblacion[geneticos.torneoBinario( poblacion, valoraciones, TAM_POBLACION)]) poblacion = np.array(hijos) #Actualiza las valoraciones y comprueba si la peor solución de esta población es peor que la mejor de la anterior valoraciones = np.array([ knn.Valoracion(data_np, data_np, k, w, labels_np, labels_np, True) for w in poblacion ]) valoraciones = np.sum(valoraciones, axis=1) evaluaciones += TAM_POBLACION peor_solucion_ind = np.argmin(valoraciones) peor_solucion_valor = valoraciones[peor_solucion_ind] peor_solucion = poblacion[peor_solucion_ind] if peor_solucion_valor < mejor_solucion_valor: poblacion[peor_solucion_ind] = mejor_solucion mejor_solucion_ind = np.argmax(valoraciones) mejor_solucion_valor = valoraciones[mejor_solucion_ind] mejor_solucion = poblacion[mejor_solucion_ind] #Devuelve la mejor solución return np.array(mejor_solucion)