Optimización de la programación de programas de televisión utilizando algoritmos genéticos en Python

Optimización de programación TV con algoritmos genéticos en Python

Un tutorial práctico que explica cómo optimizar la programación de programas de televisión utilizando algoritmos genéticos en Python

Foto de Glenn Carstens-Peters en Unsplash

Hace mucho tiempo que no escribo una nueva publicación en VoAGI. Durante dos años, he estado investigando qué mejoras se pueden hacer en el sector de los medios de comunicación tradicionales a través del aprendizaje automático y el aprendizaje profundo. Una de estas áreas de investigación son las técnicas de optimización. Como en todas las industrias, la optimización es esencial en los medios de comunicación. Por lo tanto, en este artículo, quiero compartir la planificación de programas de televisión mediante la integración en un algoritmo evolutivo, un algoritmo genético. Recuerda, esto es solo una implementación sencilla. La vida real va mucho más allá de esta simplicidad.

¿QUÉ ES LA OPTIMIZACIÓN Y POR QUÉ LA NECESITAMOS?

¿Qué es la optimización? Quiero empezar con esta pregunta. La optimización consiste en buscar valores que minimicen o maximicen una función objetivo dada. ¿Y qué pasa con la función objetivo? La función objetivo es una representación matemática de la medida de rendimiento que estamos tratando de maximizar o minimizar. Si el problema es un problema de minimización, podemos llamarlo función de coste; si es un problema de maximización, podemos llamarlo función de aptitud.

Enriquezcamos esta explicación con un ejemplo. Detente un minuto e imagina que tienes un restaurante. Nuestro objetivo es maximizar sus beneficios modificando el menú (por menú me refiero a los platos del menú). El primer método que se nos ocurre es utilizar ingredientes más baratos. Se puede obtener más beneficio reduciendo la calidad de los ingredientes utilizados. Pero así no funcionan las cosas en la vida real. Cuando se reduce la calidad del producto, los clientes reducen su demanda de platos elaborados con ingredientes de menor calidad. Por lo tanto, no es posible alcanzar el objetivo deseado.

Como puedes imaginar, es un problema de optimización para el propietario del restaurante crear un menú para maximizar sus beneficios. Por ejemplo, el propietario del restaurante puede analizar qué platos se venden en qué momentos y trazar un plan. Las técnicas de optimización permitirán al propietario del restaurante tomar decisiones basadas en datos y obtener los mejores resultados posibles.

Ahora imagina que trabajas como planificador de programas para una estación de televisión. Recuerda que tus competidores son fuertes, pero aún tienes programas que pueden competir. El principal problema que hay que decidir es qué programa se debe emitir en qué momento. Parece fácil. Un bolígrafo y algo de papel son suficientes. ¿Es realmente así?

Aunque la planificación de programas de televisión parece sencilla, se vuelve muy compleja con la participación de diversos factores. Aquí tienes algunos de ellos:

Preferencias de los espectadores: ¿Qué géneros de contenido televisivo prefieren los espectadores?

Horarios: ¿Qué tipo de programas prefieren los espectadores en qué períodos?

Programas de antes y después: Algunos programas transfieren la audiencia que recogen durante el período de emisión al siguiente programa.

Preferencias de programas de los canales competidores: ¿Qué programa están emitiendo los canales competidores en qué momento?

Días festivos, ocasiones especiales y tendencias estacionales: ¿Cómo cambian las preferencias de los espectadores? ¿Existen tendencias actuales?

Contenido nuevo y antiguo: ¿Los programas emitidos son nuevos? ¿O son reposiciones?

Tramas y cliffhangers: ¿El programa tiene una trama? ¿O cliffhanger?

Estos son solo algunos factores. Puede que hayas notado que docenas de factores afectan a la planificación de programas de televisión. Por lo tanto, sería adecuado utilizar algoritmos de optimización para resolver este tipo de problemas.

¿QUÉ SON LAS EVALUACIONES Y LOS ALGORITMOS GENÉTICOS?

Voy a explicar brevemente las evaluaciones y los algoritmos genéticos en esta parte. Los algoritmos evolutivos (EA) son técnicas de optimización que pueden resolver muchos problemas de optimización desafiantes sin requerir conocimientos específicos sobre la estructura del problema; en otras palabras, son independientes del problema. Los algoritmos evolutivos (EA) pueden manejar funciones objetivo lineales y no lineales sin requerir información sobre la estructura del problema. Por otro lado, el algoritmo genético pertenece a la familia de los algoritmos de búsqueda y utiliza los principios de la evolución. Al implementar procesos de reproducción y selección natural, puede producir soluciones de alta calidad. El algoritmo genético es una técnica muy efectiva para resolver problemas de optimización.

A continuación puedes ver un diagrama de flujo simple para un algoritmo genético. Nuestro primer paso es crear una población inicial. La población inicial contiene cromosomas seleccionados al azar (más claramente, la población inicial es un conjunto de cromosomas). Después de crear la población, se calcula el valor de la función de aptitud para cada individuo. Los algoritmos genéticos utilizan un cromosoma para representar a cada individuo. El valor de aptitud de cada individuo es independiente de los demás. De esta manera, se pueden realizar múltiples cálculos al mismo tiempo. Después de calcular los valores de aptitud, entran en juego tres fases diferentes del algoritmo genético: selección, cruce y mutación. La fase de selección es responsable de seleccionar cromosomas de la población. El objetivo es crear mejores generaciones. El proceso de cruce se encarga de desarrollar nuevos descendientes a partir de los individuos seleccionados. Este proceso generalmente se realiza tomando dos individuos seleccionados a la vez e intercambiando partes de sus cromosomas para crear dos nuevos cromosomas que representen a los descendientes. Por último, el operador cambia uno o más genes en la fase de mutación. La probabilidad de este cambio es muy baja. La característica más importante de la fase de mutación es evitar que el sistema quede atrapado en un mínimo local.

Diagrama de flujo de algoritmos genéticos (Eser Saygın)

IMPLEMENTACIÓN

Acabo de dar información básica sobre el algoritmo genético. Ahora explicaré el algoritmo genético paso a paso utilizando Python. Nuestro problema, como se ve en el título, es qué programa se emitirá en qué momento. En primer lugar, hay un punto importante que debo enfatizar. El problema que implementaremos en un momento dado es un ejemplo simple. Como mencioné, muchos factores afectan la implementación del problema en la vida real. Por esta razón, la fase de identificación del problema es la parte que consume más tiempo.

PASOS

Primero, comenzamos definiendo nuestro conjunto de datos. Como mencioné anteriormente, el conjunto de datos a continuación es un ejemplo simple. El conjunto de datos muestra las calificaciones de varios programas a lo largo de 18 horas (06:00-24:00). En la vida real, es necesario emitir en cada intervalo de tiempo para medir la puntuación de calificación de un programa en diferentes intervalos de tiempo.

# Muestra de conjunto de datos de calificación de programas para cada intervalo de tiempo.
calificaciones = {'noticias': [0.1, 0.1, 0.4, 0.3, 0.5, 0.4, 0.3, 0.2, 0.1, 0.2, 0.3, 0.5, 0.5, 0.4, 0.3, 0.2, 0.1, 0.2],
                 'fútbol_en_vivo': [0.0, 0.0, 0.0, 0.2, 0.1, 0.3, 0.2, 0.1, 0.4, 0.3, 0.4, 0.5, 0.4, 0.6, 0.4, 0.3, 0.4, 0.3],
                 'película_a': [0.1, 0.1, 0.2, 0.4, 0.3, 0.2, 0.1, 0.2, 0.3, 0.4, 0.5, 0.4, 0.3, 0.4, 0.3, 0.5, 0.3, 0.4],
                 'película_b': [0.2, 0.1, 0.1, 0.3, 0.2, 0.1, 0.2, 0.3, 0.4, 0.5, 0.4, 0.3, 0.4, 0.5, 0.4, 0.3, 0.4, 0.5],
                 'reality_show': [0.3, 0.4, 0.3, 0.4, 0.4, 0.5, 0.3, 0.4, 0.5, 0.4, 0.3, 0.2, 0.1, 0.2, 0.3, 0.2, 0.2, 0.3],
                 'serie_de_tv_a': [0.2, 0.3, 0.2, 0.1, 0.1, 0.2, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.5, 0.6, 0.4, 0.5, 0.4, 0.3],
                 'serie_de_tv_b': [0.1, 0.2, 0.3, 0.3, 0.2, 0.3, 0.3, 0.1, 0.4, 0.3, 0.4, 0.3, 0.5, 0.3, 0.4, 0.6, 0.4, 0.3],
                 'programa_de_música': [0.3, 0.3, 0.3, 0.2, 0.2, 0.1, 0.2, 0.4, 0.3, 0.3, 0.3, 0.3, 0.2, 0.3, 0.2, 0.3, 0.5, 0.3],
                 'documental': [0.3, 0.3, 0.4, 0.3, 0.2, 0.2, 0.3, 0.4, 0.4, 0.3, 0.2, 0.2, 0.2, 0.1, 0.1, 0.3, 0.3, 0.2],
                 'Boxeo': [0.4, 0.3, 0.3, 0.2, 0.2, 0.1, 0.1, 0.1, 0.1, 0.3, 0.3, 0.3, 0.2, 0.3, 0.4, 0.3, 0.4, 0.6]}

A continuación, puedes ver las otras variables. Estas variables son hiperparámetros que se utilizarán en Algoritmos Genéticos. También he creado dos listas diferentes para usar más adelante.

GEN = 100POP = 50CO_R = 0.8MUT_R = 0.2EL_S = 2all_programs = list(ratings.keys()) # todos los programasall_time_slots = list(range(6, 24)) # franjas horarias

Como mencionamos en nuestro artículo, nuestro primer trabajo será inicializar la población. Puedes encontrar la función que he creado para este propósito a continuación. Como puedes ver, la función necesita dos listas de entrada: una lista de programas y una lista de franjas horarias. Ya hemos definido estas listas anteriormente. La función genera todos los horarios potenciales.

def initialize_pop(programs, time_slots):    if not programs:        return [[]]    all_schedules = []    for i in range(len(programs)):        for schedule in initialize_pop(programs[:i] + programs[i + 1:], time_slots):            all_schedules.append([programs[i]] + schedule)    return all_schedules

A continuación, definiremos nuestra función de aptitud. La función de aptitud es responsable de medir la calidad de cada horario. Toma el horario como entrada y devuelve la puntuación total de calificación. (La lista que llamamos horario es un horario de emisión que consta de programas de televisión.)

def fitness_function(schedule):    total_rating = 0    for time_slot, program in enumerate(schedule):        total_rating += ratings[program][time_slot]    return total_rating

Después de definir la función de aptitud, podemos pasar a la fase de selección. La fase de selección tiene como objetivo encontrar el horario más óptimo. Para esto, podemos usar la siguiente función que creamos. La función verifica el valor de aptitud de cada horario y elige aquel con el valor más alto.

def finding_best_schedule(all_schedules):    best_schedule = []    max_ratings = 0    for schedule in all_schedules:        total_ratings = fitness_function(schedule)        if total_ratings > max_ratings:            max_ratings = total_ratings            best_schedule = schedule    return best_schedule

La fase de selección es seguida por la fase de cruce. En la fase de cruce, las soluciones de dos padres se combinan con la ayuda de AG para formar una nueva descendencia. En el problema del horario de televisión, este proceso cambia los programas (genes) encontrados en dos soluciones. Este proceso crea diversas combinaciones de programas de televisión. Puedes ver la función de cruce a continuación.

def crossover(schedule1, schedule2):    crossover_point = random.randint(1, len(schedule1) - 2)    child1 = schedule1[:crossover_point] + schedule2[crossover_point:]    child2 = schedule2[:crossover_point] + schedule1[crossover_point:]    return child1, child2

La fase final es la fase de mutación. Como mencionamos antes, en la fase de mutación, se forman nuevas descendencias cambiando el material genético de los cromosomas. En el problema de optimización de programas de televisión, podemos pensar en esto como cambiar el programa al azar. Recuerda, la probabilidad de mutación es muy baja. Además, puedes asignar esta posibilidad como un hiperparámetro.

def mutate(schedule):    mutation_point = random.randint(0, len(schedule) - 1)    new_program = random.choice(all_programs)    schedule[mutation_point] = new_program    return schedule

Ahora que hemos definido todas nuestras funciones, podemos ejecutar la función de aptitud.

# llamando a la función de aptitud.def evaluate_fitness(schedule):    return fitness_function(schedule)

Los datos que necesitamos para nuestro algoritmo genético están listos. Ahora podemos definir el algoritmo. Este algoritmo utilizará el schedule_inicial, las generaciones, el tamaño_de_población, la tasa_de_cruce, la tasa_de_mutación y el tamaño_de_elitismo. Ya los hemos descrito antes. Dado que son hiperparámetros, podemos modificarlos pero no es necesario. La función comienza creando la población inicial con el schedule_inicial proporcionado y luego agregando horarios aleatorios. Después de eso, se ejecuta un bucle durante el número especificado de generaciones y se genera una nueva población para cada generación utilizando las operaciones de selección, cruce y mutación. El elitismo ayuda a preservar a los individuos más exitosos de la generación anterior basándose en sus puntuaciones de aptitud. Una vez que se ha actualizado la población, se convierte en la población actual para la próxima generación. Después de eso, la función devuelve el mejor horario de la generación anterior.

def genetic_algorithm(schedule_inicial, generaciones=GEN, tamaño_de_población=POP, tasa_de_cruce=CO_R, tasa_de_mutación=MUT_R, tamaño_de_elitismo=EL_S):        población = [schedule_inicial]    for _ in range(tamaño_de_población - 1):        horario_aleatorio = schedule_inicial.copy()        random.shuffle(horario_aleatorio)        población.append(horario_aleatorio)    for generación in range(generaciones):        nueva_población = []        # Elitismo        población.sort(key=lambda horario: fitness_function(horario), reverse=True)        nueva_población.extend(población[:tamaño_de_elitismo])        while len(nueva_población) < tamaño_de_población:            padre1, padre2 = random.choices(población, k=2)            if random.random() < tasa_de_cruce:                hijo1, hijo2 = crossover(padre1, padre2)            else:                hijo1, hijo2 = padre1.copy(), padre2.copy()            if random.random() < tasa_de_mutación:                hijo1 = mutate(hijo1)            if random.random() < tasa_de_mutación:                hijo2 = mutate(hijo2)            nueva_población.extend([hijo1, hijo2])        población = nueva_población    return población[0]

Ahora estamos listos para obtener los resultados.

initial_best_schedule = encontrar_mejor_horario(todas_las_posibles_programaciones)rem_t_slots = len(todos_los_intervalos_de_tiempo) - len(initial_best_schedule)genetic_schedule = algoritmo_genetico(initial_best_schedule, generaciones=GEN, tamaño_población=POP, tamaño_elitismo=EL_S)final_schedule = initial_best_schedule + genetic_schedule[:rem_t_slots]print("\nHorario Óptimo Final:")for intervalo_tiempo, programa in enumerate(final_schedule):    print(f"Intervalo de Tiempo {todos_los_intervalos_de_tiempo[intervalo_tiempo]:02d}:00 - Programa {programa}")print("Total de Calificaciones:", función_de_fitness(final_schedule))

Después de que se ha ejecutado el algoritmo genético, combinamos los horarios inicialmente mejores y genéticos para crear el horario óptimo final. Finalmente, imprimimos el horario óptimo con los programas asignados, mostrando el intervalo de tiempo, el programa correspondiente y las calificaciones totales obtenidas en el horario óptimo final.

CONCLUSIÓN

La planificación de programas es crucial para los canales de televisión en el sector de los medios de comunicación tradicionales, donde la competencia es alta. En este caso, hemos mostrado cómo mejorar la programación de televisión utilizando un algoritmo genético, una herramienta poderosa que puede ayudar a maximizar las calificaciones de los espectadores. Considera utilizar un algoritmo genético para optimizar un problema de programación, como la programación de programas de televisión. Con sus capacidades poderosas, puede ayudarte a crear un horario que maximice la participación y las calificaciones de los espectadores.

En mis próximos artículos, planeo explorar varios algoritmos genéticos como Competitive Co-Evolutionary (CCQGA) y Quantum (QGA). También puedo incluir contenido adicional en el medio.

Gracias por tomar el tiempo para leer este artículo. Si deseas conectarte conmigo, no dudes en agregarme en LinkedIn.

https://www.linkedin.com/in/esersaygin/

FUENTES

Hands-On Genetic Algorithms with Python: Applying genetic algorithms to solve real-world deep learning and artificial intelligence problems por Eyal Wirsansky (Autor)

Applied Evolutionary Algorithms for Engineers Using Python 1st Editionpor Leonardo Azevedo Scardua (Autor)

CÓDIGO COMPLETO

import random##################################### DEFINICIÓN DE PARÁMETROS Y CONJUNTO DE DATOS ################################################################# Conjunto de programas de calificación de muestra para cada intervalo de tiempo.ratings = {    'noticias': [0.1, 0.1, 0.4, 0.3, 0.5, 0.4, 0.3, 0.2, 0.1, 0.2, 0.3, 0.5, 0.5, 0.4, 0.3, 0.2, 0.1, 0.2],    'fútbol_en_vivo': [0.0, 0.0, 0.0, 0.2, 0.1, 0.3, 0.2, 0.1, 0.4, 0.3, 0.4, 0.5, 0.4, 0.6, 0.4, 0.3, 0.4, 0.3],    'película_a': [0.1, 0.1, 0.2, 0.4, 0.3, 0.2, 0.1, 0.2, 0.3, 0.4, 0.5, 0.4, 0.3, 0.4, 0.3, 0.5, 0.3, 0.4],    'película_b': [0.2, 0.1, 0.1, 0.3, 0.2, 0.1, 0.2, 0.3, 0.4, 0.5, 0.4, 0.3, 0.4, 0.5, 0.4, 0.3, 0.4, 0.5],    'reality_show': [0.3, 0.4, 0.3, 0.4, 0.4, 0.5, 0.3, 0.4, 0.5, 0.4, 0.3, 0.2, 0.1, 0.2, 0.3, 0.2, 0.2, 0.3],    'serie_de_tv_a': [0.2, 0.3, 0.2, 0.1, 0.1, 0.2, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.5, 0.6, 0.4, 0.5, 0.4, 0.3],    'serie_de_tv_b': [0.1, 0.2, 0.3, 0.3, 0.2, 0.3, 0.3, 0.1, 0.4, 0.3, 0.4, 0.3, 0.5, 0.3, 0.4, 0.6, 0.4, 0.3],    'programa_musical': [0.3, 0.3, 0.3, 0.2, 0.2, 0.1, 0.2, 0.4, 0.3, 0.3, 0.3, 0.3, 0.2, 0.3, 0.2, 0.3, 0.5, 0.3],    'documental': [0.3, 0.3, 0.4, 0.3, 0.2, 0.2, 0.3, 0.4, 0.4, 0.3, 0.2, 0.2, 0.2, 0.1, 0.1, 0.3, 0.3, 0.2],    'Boxeo': [0.4, 0.3, 0.3, 0.2, 0.2, 0.1, 0.1, 0.1, 0.1, 0.3, 0.3, 0.3, 0.2, 0.3, 0.4, 0.3, 0.4, 0.6]}GEN = 100POP = 50CO_R = 0.8MUT_R = 0.2EL_S =

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

El mercado negro de GitHub que ayuda a los programadores a hacer trampa en el concurso de popularidad

La popularidad en GitHub puede abrir puertas valiosas para programadores y startups. Las tiendas underground venden e...

Inteligencia Artificial

Riesgos de la IA y la Extinción El Futuro Precario de la Humanidad en Medio de una Revolución de la IA

Explora los alarmantes riesgos de AI que plantea la revolución de AI en curso. Los expertos advierten del peligro inm...

Inteligencia Artificial

La actualización de Super Resolución de Video NVIDIA RTX mejora la calidad del video, preserva los detalles y se expande a las GPU de la serie GeForce RTX 20'.

NVIDIA anunció hoy una actualización de RTX Video Super Resolution (VSR) que ofrece una mayor fidelidad gráfica gener...

Aprendizaje Automático

Acelerando el Acelerador Científico Acelera la Computación de Alto Rendimiento de CERN con GPUs y IA.

Nota del editor: Esto es parte de una serie que perfila a investigadores que avanzan en la ciencia con cómputo de alt...

Inteligencia Artificial

Inteligencia Artificial Explicativa (IAE)

Hola, tecnófilos y mentes curiosas. Bienvenidos al próximo capítulo del libro de Inteligencia Artificial. Adentrémono...