Alura > Cursos de Data Science > Cursos de Data Science > Conteúdos de Data Science > Primeiras aulas do curso Otimização: aplicando a programação por restrições

Otimização: aplicando a programação por restrições

Problema da grade de propagandas em uma rede de televisão - Apresentação

Boas-vindas ao curso de Otimização: Programação por restrições! Me chamo João Miranda e serei o seu instrutor neste curso.

Audiodescrição: João é um homem branco com cabelo médio preso em um coque, com as laterais raspadas. Usa bigode e cavanhaque. Veste uma camiseta preta lisa. Ao fundo, uma parede branca com uma iluminação verde e azul.

O que vamos aprender?

Já se perguntou como são escolhidos os tipos de propagandas que passam durante os intervalos dos programas de TV? Neste curso, vamos desenvolver um projeto de programação por restrições para entender melhor como alocar propagandas nos horários disponíveis para publicidade em um canal de televisão.

Vamos considerar fatores como horário e público-alvo para garantir que as propagandas sejam direcionadas da melhor forma possível através de otimização. No curso, não vamos utilizar a biblioteca Pyomo; em vez disso, vamos nos concentrar no uso da ferramenta OR Tools do Google.

Pré-requisitos

Para acompanhar esse conteúdo, é necessário ter conhecimento em Python e também em programação linear.

Vamos começar?

Problema da grade de propagandas em uma rede de televisão - Fazendo a leitura dos dados

Pense em uma emissora de TV comum que tem vários anunciantes interessados em colocar seus comerciais nos intervalos comerciais.

Problema da grade de propagandas em uma rede de televisão

Com a popularidade das Smart TVs, agora podemos obter informações sobre o perfil de cada TV, incluindo quantas pessoas de cada segmento demográfico estão assistindo aos anúncios.

Se tivermos acesso a esses dados de visibilidade, como podemos garantir que as propagandas sejam colocados nos intervalos certos para alcançar o público-alvo e maximizar sua visibilidade?

Vamos usar Python e técnicas de otimização para alocar esses comerciais da melhor forma possível nos intervalos disponíveis. Para começar, vamos usar um conjunto de dados que inclui a visibilidade de cada anunciante nessa rede de TV.

Realizando o upload do arquivo

Para começar dentro do Google Colab, vamos fazer o upload do arquivo contendo esses dados de visibilidade. No menu lateral esquerdo, selecionamos o ícone de pasta que representa os arquivos e clicamos no primeiro ícone de fazer o upload do arquivo.Na nossa máquina, selecionamos o arquivo visibilidade.csv.

Esse arquivo estará disponível na atividade "Preparando Ambiente" antes desta aula. Antes de começar a assistir esse conteúdo, é importante que você faça o download desse arquivo para ser utilizado no projeto.

Vamos clicar duas vezes no arquivo visibilidade.csv e, a partir de agora, podemos copiar o caminho desse arquivo para fazer a leitura dessa base de dados. Para isso, clicamos nos três pontos ao lado do arquivo, selecionamos a opção "Copiar caminho" e, agora, podemos fechar o menu lateral esquerdo dos arquivos clicando no ícone de xis ("X").

Importando a biblioteca Pandas

Na primeira célula de código, importamos a biblioteca Pandas. Ela será fundamental para a leitura e manipulação dos dados. Portanto, na primeira célula, importamos o pandas as pd.

import pandas as pd

Executamos a célula pressionando "Ctrl + Enter".

Lendo a base de dados

Na próxima célula, faremos a leitura da base de dados. Para isso, digitamos dados = pd.read_csv() e inserimos o caminho do arquivo entre as aspas, utilizando "Ctrl + V" para colar o caminho.

dados = pd.read_csv('/content/visibilidade.csv')

Em seguida, na mesma célula, para visualizar os dados, digitamos dados e executamos com "Ctrl + Enter".

dados = pd.read_csv('/content/visibilidade.csv')
dados

Como retorno, obtemos:

#EsportivaMaxTechInovaEnergiaVivaSuperTechBebaBem
072655
141181
287917
357655
478336
..................
95108111
9695527
9774667
9892399
9986983

Temos um dataframe com 100 linhas e 5 colunas, representando 100 registros e os seguintes anunciantes da rede de televisão: Esportiva Max, TechInova, Energia Viva, SuperTech e BebaBem. Cada linha do dataframe corresponde a um slot de tempo onde as propagandas serão alocadas, com as colunas representando os diferentes anunciantes e as linhas representando os slots de tempo.

No índice 0, encontramos o primeiro período disponível; no índice 1, temos o segundo período, e assim por diante, totalizando 100 intervalos de tempo distintos. Quanto aos valores dentro do dataframe, representam a visibilidade do anunciante naquele intervalo de tempo específico.

Por exemplo, no primeiro intervalo de tempo (índice 0), o Esportiva Max possui uma visibilidade de 7, o TechInova de 2, o Energia Viva de 6, o SuperTech de 5 e o Beba Bem de 5. Estes números estão relacionados a dezenas de milhares de televisões. Esses valores indicam a intensidade e a quantidade de pessoas que poderão assistir e ser alcançadas pelo público-alvo durante aquele período.

A partir desses dados, vamos querer alocar o melhor anunciante para cada um dos slots de tempo para aumentar a visibilidade.Para fazer isso, vamos utilizar a otimização e vamos utilizar a biblioteca ORTools do Google.

Importando a biblioteca ORTools

Para utilizar a biblioteca ORTools, vamos ter que instalá-la no ambiente do Colab. Na próxima célula, escrevemos !pip install ortools.

!pip install ortools

Esse código será utilizado para instalar essa ferramenta OR Tools do Google. Vamos executar o código e ele vai começar a fazer a instalação dessa biblioteca.

Depois de fazer a instalação, vamos fazer uma transformação nesse DataFrame para ser mais fácil de utilizar com essa biblioteca. Vamos armazenar a informação dos slots de tempo em uma lista. Isto é, iremos colocar o valor do 0 até o 99 em uma lista.

Logo após, armazenamos todo o restante dos dados do DataFrame em um dicionário. Dessa maneira, vai ficar mais fácil utilizar nessa ferramenta do OR Tools.

Transformando os slots em lista

Na próxima célula, vamos transformar aquelas informações em uma lista e um dicionário. Primeiro, armazenamos os slots de tempo. Para isso, escrevemos slots_tempo_disponiveis = dados.index.tolist().

Dessa maneira, vamos pegar o índice do DataFrame e transformar para uma lista com a função tolist(). Na mesma célula, digitamos essa variável, slots_tempo_disponiveis, e vamos executar para verificar se foi construída a lista com sucesso.

slots_tempo_disponiveis = dados.index.tolist()
slots_tempo_disponiveis

Obtemos a seguinte lista de valores do 0 até 99:

A lista abaixo foi parcialmente transcrita:

[0,

1

2

3

4

5

6

7

99]

Com isso, temos todos os slots de tempo nessa variável.

Agora, vamos armazenar o restante dos dados em um dicionário. Para isso, utilizamos o método to_dict(): dados_visibilidade = dados.to_dict().

dados_visibilidade = dados.to_dict()

Assim, transformamos o nosso DataFrame em um dicionário. Cada uma das chaves do dicionário será um dos anunciantes e os valores serão os dados de visibilidade. Na mesma célula, vamos escrever dados_visibilidade e executar esse código para verificar se foi feita a transformação com sucesso.

dados_visibilidade = dados.to_dict()
dados_visibilidade

Obtemos um dicionário:

O dicionário abaixo foi parcialmente transcrito:

42: 1,

43: 4,

44: 8,

45: 2,

46: 3,

47: 1,

48: 1,

'SuperTech': {0: 5,

1: 8,

2: 1,

3: 5,

4: 3,

Se descemos, obtemos um dicionário contendo o nome do anunciante na chave do dicionário e o valor daquela chave será o dado de visibilidade daquele anunciante em cada um dos slots de tempo.

Conclusão e Próximos Passos

Agora que já temos os nossos dados e fizemos as transformações necessárias e também fizemos a instalação da Biblioteca ORTools, podemos começar a modelar o nosso problema de otimização utilizando essa ferramenta para obter a solução da melhor alocação dos anunciantes nos slots de tempo.

Mas vamos fazer isso no próximo vídeo!

Problema da grade de propagandas em uma rede de televisão - Modelo de programação inteira

Conseguimos realizar a leitura da base de dados, que contém os dados de visibilidade de cada anunciante que deseja colocar suas propagandas na rede de televisão. Mas, a partir desses dados, como vamos escolher os melhores anunciantes para cada um dos slots de tempo disponíveis para a publicidade?

Vamos utilizar a otimização para traduzir o nosso problema, que já conhecemos, para um problema de programação linear inteira. A partir desse problema, vamos conseguir encontrar uma solução dos melhores anunciantes para cada slot de tempo.

Modelo de programação linear inteira

Como faremos isso? Vamos criar variáveis de decisão nesse nosso modelo, e essa variável de decisão será justamente decidir se o anunciante será alocado ou não no slot de tempo.

Portanto, essa variável de decisão terá o valor de 0 ou 1. O valor 0 indicará que aquele anunciante não foi alocado naquele intervalo de tempo. E o valor 1 indicará que aquele anunciante foi alocado naquele intervalo de tempo.

Nosso problema tem o objetivo de atingir o maior número de pessoas com esses anúncios, e atingir também o público-alvo correto. Para fazer isso, no problema de programação linear inteira, vamos construir uma função objetivo que terá o objetivo de maximizar a visibilidade total dos anunciantes.

Vamos começar!

No Google Colab, vamos primeiro importar um solucionador desse tipo de problema de programação linear inteira, a partir da biblioteca ORTools. Então, na primeira linha, escrevemos from ortools.linear_solver import pywraplp.

from ortools.linear_solver import pywraplp

Na mesma célula, vamos inicializar o nosso modelo: modelo = pywraplp.Solver.CreateSolver('SCIP').

from ortools.linear_solver import pywraplp

modelo = pywraplp.Solver.CreateSolver('SCIP')

O tipo de solver que vamos escolher será justamente um que consegue resolver esse problema de programação linear inteira com restrições.

Variáveis de decisão

Na mesma célula, vamos primeiro criar as nossas variáveis de decisão. Será o valor 0, se não quisermos alocar o anunciante no intervalo de tempo, e o valor 1, se quisermos alocar o anunciante no intervalo de tempo.

Para isso, como teremos uma variável de decisão para cada anunciante e para cada intervalo de tempo, vamos fazer um for percorrendo cada um dos anunciantes e cada um dos intervalos de tempo. E vamos armazenar essas variáveis de decisão em um dicionário. Então, chamamos o dicionário de x.

Para tal, digitamos x = {}. E, a partir disso, começamos a alocar em cada chave desse dicionário as variáveis de decisão. Então, vamos percorrer primeiro os anunciantes: for anunciante in dados_visibilidade:. Esse dado de visibilidade é justamente aquele dicionário contendo a informação do nome do anunciante, o intervalo de tempo e a quantidade de visibilidade daquele anunciante.

Logo após, dentro desse for, percorremos os slots de tempo: for slot in slots_tempo_disponiveis:. Esses slots de tempo disponíveis é aquela lista de slots de tempo do 0 até o 99.

from ortools.linear_solver import pywraplp

modelo = pywraplp.Solver.CreateSolver('SCIP')

x = {}
for anunciante in dados_visibilidade:
    for slot in slots_tempo_disponiveis:

Agora que já percorremos os anunciantes dos slots de tempo, vamos criar a variável de decisão para esse anunciante e para aquele slot de tempo específico dentro do dicionário x. Para isso, escrevemos x[anunciante, slot] = modelo.BoolVar(f"x[{anunciante, slot}]").

O tipo será BoolVar() por ser valor 0 ou 1. Dentro dos parênteses, passamos o nome da variável de decisão. Portanto, informamos o nome do anunciante e o slot de tempo usando f string: f"x[{anunciante, slot}]").

from ortools.linear_solver import pywraplp

modelo = pywraplp.Solver.CreateSolver('SCIP')

x = {}
for anunciante in dados_visibilidade:
    for slot in slots_tempo_disponiveis:
            x[anunciante, slot] = modelo.BoolVar(f"x[{anunciante, slot}]")

Dessa maneira, conseguimos construir todas as variáveis de decisão do nosso modelo para cada anunciante e para cada slot de tempo.

Função objetivo

Maximizar a visibilidade total dos produtos

Agora, como o nosso objetivo é maximizar a visibilidade total dos anunciantes, vamos construir uma função objetivo maximize, que tem o objetivo de maximizar um valor.

Escrevemos: modelo.Maximize(sum(dados_visibilidade[anunciante][slot] * x[anunciante, slot] for anunciante in dados_visibilidade for slot in slots_tempo_disponiveis)).

Dentro do modelo.Maximize() passamos uma função objetivo para aumentar o valor da visibilidade. Portanto, usamos sum() para somar todos os valores de visibilidade dos anunciantes que foram selecionados.

Os anunciantes que foram selecionados possuem como variável de decisão (x) o valor igual a um. Portanto, multiplicamos o valor do dado de visibilidade do anunciante somente pelo valor um do anunciante selecionado.

Em sum(dados_visibilidade[anunciante][slot]) estamos acessando o anunciante e o slot no dicionário dados_visibilidade. Na sequência, multiplicamos pela variável de decisão do anunciante. Assim, somamos os dados de visibilidade somente dos anunciantes que estão selecionados. Isso porque o valor da variável de decisão será igual a um.

Logo após, percorremos os anunciantes e os slots. Para isso, usamos o for anunciante in dados_visibilidade for slot in slots_tempo_disponiveis dentro do sum().

from ortools.linear_solver import pywraplp

modelo = pywraplp.Solver.CreateSolver('SCIP')

x = {}
for anunciante in dados_visibilidade:
    for slot in slots_tempo_disponiveis:
            x[anunciante, slot] = modelo.BoolVar(f"x[{anunciante, slot}]")

modelo.Maximize(sum(dados_visibilidade[anunciante][slot] * x[anunciante, slot]  for anunciante in dados_visibilidade for slot in slots_tempo_disponiveis))

Agora que estabelecemos a função objetivo para o nosso modelo, podemos avançar para a definição das restrições do problema. Até este ponto, ainda não determinamos como será selecionado o valor dessa variável de decisão.

Restrições

Só podemos alocar um anunciante para cada slot de tempo, não podemos colocar mais de um anunciante em cada slot de tempo. Temos que fazer uma restrição para o modelo entender que é necessário fazer isso. Caso contrário, ele vai colocar o valor 1 para todos os valores de anunciante e slot de tempo, porque dessa maneira ele vai maximizar o valor da visibilidade.

Vamos criar nossa restrição, que também vai depender do slot de tempo. Iremos percorrer o slot de tempo escrevendo for slot in slots_tempo_disponiveis. Em seguida, adicionaremos uma restrição na ferramenta ORTools com a linha modelo.Add(sum(x[anunciante, slot] for anunciante in dados_visibilidade) == 1).

Dentro de Add() estamos passando uma expressão matemática, em cada slot de tempo somamos as variáveis de decisão. E o valor dessa soma deve ser igual a um, isso significa que somamos as variáveis de cada slot de tempo dos anunciantes e para que seja igual a um, indica que somente um dos anunciantes será alocado naquele intervalo de tempo. Portanto, terá o valor um e o restante o valor zero.

from ortools.linear_solver import pywraplp

modelo = pywraplp.Solver.CreateSolver('SCIP')

x = {}
for anunciante in dados_visibilidade:
    for slot in slots_tempo_disponiveis:
            x[anunciante, slot] = modelo.BoolVar(f"x[{anunciante, slot}]")

modelo.Maximize(sum(dados_visibilidade[anunciante][slot] * x[anunciante, slot]  for anunciante in dados_visibilidade for slot in slots_tempo_disponiveis))

for slot in slots_tempo_disponiveis:
    modelo.Add(sum(x[anunciante, slot] for anunciante in dados_visibilidade) == 1)

Com isso, adicionamos a restrição indicando que a soma das variáveis de decisão em cada slot de tempo deve ser igual a um.

Agora, podemos resolver o nosso modelo de programação em linha inteira. Para isso, escrevemos status = modelo.Solve().

from ortools.linear_solver import pywraplp

modelo = pywraplp.Solver.CreateSolver('SCIP')

x = {}
for anunciante in dados_visibilidade:
    for slot in slots_tempo_disponiveis:
            x[anunciante, slot] = modelo.BoolVar(f"x[{anunciante, slot}]")

modelo.Maximize(sum(dados_visibilidade[anunciante][slot] * x[anunciante, slot]  for anunciante in dados_visibilidade for slot in slots_tempo_disponiveis))

for slot in slots_tempo_disponiveis:
    modelo.Add(sum(x[anunciante, slot] for anunciante in dados_visibilidade) == 1)

status = modelo.Solve()

Assim, estamos armazenando qual o status dessa solução dentro da variável status().

Verificando o status

Agora, verificamos se o status indica que obtivemos uma solução ótima, ou seja, se encontramos a melhor solução possível. Para isso, vamos verificar if status == pywraplp.Solver.OPTIMAL:.

from ortools.linear_solver import pywraplp

modelo = pywraplp.Solver.CreateSolver('SCIP')

x = {}
for anunciante in dados_visibilidade:
    for slot in slots_tempo_disponiveis:
            x[anunciante, slot] = modelo.BoolVar(f"x[{anunciante, slot}]")

modelo.Maximize(sum(dados_visibilidade[anunciante][slot] * x[anunciante, slot]  for anunciante in dados_visibilidade for slot in slots_tempo_disponiveis))

for slot in slots_tempo_disponiveis:
    modelo.Add(sum(x[anunciante, slot] for anunciante in dados_visibilidade) == 1)

status = modelo.Solve()

if status == pywraplp.Solver.OPTIMAL:

Isso permite checar se o status da solução é o melhor resultado possível dentro de todas as possibilidades.

Inserindo os anunciantes para cada slot de tempo

Em seguida, vamos começar a inserir os anunciantes para cada slot de tempo, criando assim uma grade de anúncios. Dentro do bloco if, vamos iniciar grade = [].

from ortools.linear_solver import pywraplp

modelo = pywraplp.Solver.CreateSolver('SCIP')

x = {}
for anunciante in dados_visibilidade:
    for slot in slots_tempo_disponiveis:
            x[anunciante, slot] = modelo.BoolVar(f"x[{anunciante, slot}]")

modelo.Maximize(sum(dados_visibilidade[anunciante][slot] * x[anunciante, slot]  for anunciante in dados_visibilidade for slot in slots_tempo_disponiveis))

for slot in slots_tempo_disponiveis:
    modelo.Add(sum(x[anunciante, slot] for anunciante in dados_visibilidade) == 1)

status = modelo.Solve()

if status == pywraplp.Solver.OPTIMAL:
    grade = []

Com isso, criamos uma lista contendo todos os anunciantes que serão alocados.

Na sequência, imprimimos qual foi a visibilidade máxima da nossa solução. A partir da função objetivo, que é o modelo.Maximize(), conseguimos encontrar qual foi a visibilidade total dessa alocação. Escrevemos: print('Visibilidade total máxima:', modelo.Objective().Value()).

from ortools.linear_solver import pywraplp

modelo = pywraplp.Solver.CreateSolver('SCIP')

x = {}
for anunciante in dados_visibilidade:
    for slot in slots_tempo_disponiveis:
            x[anunciante, slot] = modelo.BoolVar(f"x[{anunciante, slot}]")

modelo.Maximize(sum(dados_visibilidade[anunciante][slot] * x[anunciante, slot]  for anunciante in dados_visibilidade for slot in slots_tempo_disponiveis))

for slot in slots_tempo_disponiveis:
    modelo.Add(sum(x[anunciante, slot] for anunciante in dados_visibilidade) == 1)

status = modelo.Solve()

if status == pywraplp.Solver.OPTIMAL:
    grade = []

Dessa forma, encontramos o valor da função objetivo encontrada no problema.

Logo após, imprimimos o resultado da grade, das alocações que foram feitas dos anunciantes. Então vamos escrever:

print('Alocações:')
for slot in slots_tempo_disponiveis:
        for anunciante in dados_visibilidade:
                if x[anunciante, slot].solution_value() == 1:
                        grade.append(anunciante)
                        print('Anunciante', anunciante, 'alocado para o slot de tempo', slot)

Em for slot in slots_tempo_disponiveis indicamos "para cada slot de tempo"; e em for anunciante in dados_visibilidade representamos "para cada anuciante". Usando o if x[anunciante, slot].solution_value() == 1:, checamos se a variável de decisão daquele anunciante e intervalo de tempo possui valor igual a um.

Se o valor for igual a um, imprimimos o resultado do anunciante na tela. Podemos usar o ==1 ou deixar somente .solution_value():. Isso porque se o valor for zero, não entra no if. Ao entrar no if, adicionamos o valor na lista que chamamos de grade usando grade.append(anunciante).

Na sequência, inserimos o print() com o anunciante alocado em cada slot de tempo. Assim, temos a informação de cada anunciante alocado em cada intervalo de tempo.

Por enquanto, temos:

from ortools.linear_solver import pywraplp

modelo = pywraplp.Solver.CreateSolver('SCIP')

x = {}
for anunciante in dados_visibilidade:
    for slot in slots_tempo_disponiveis:
        x[anunciante, slot] = modelo.BoolVar(f"x[{anunciante, slot}]")

modelo.Maximize(sum(dados_visibilidade[anunciante][slot] * x[anunciante, slot]  for anunciante in dados_visibilidade for slot in slots_tempo_disponiveis))

for slot in slots_tempo_disponiveis:
    modelo.Add(sum(x[anunciante, slot] for anunciante in dados_visibilidade) == 1)

status = modelo.Solve()

grade = []
if status == pywraplp.Solver.OPTIMAL:
    print('Visibilidade total máxima:', modelo.Objective().Value())
    print('Alocações:')
    for slot in slots_tempo_disponiveis:
        for anunciante in dados_visibilidade:
            if x[anunciante, slot].solution_value() == 1:
                grade.append(anunciante)
                print('Anunciante', anunciante, 'alocado para o slot de tempo', slot)

Após isso, verificamos também se o valor for igual a zero, o que significa que o anunciante não foi alocado no intervalo de tempo correspondente.

Depois de incluir essa informação para cada anunciante alocado em cada intervalo de tempo, adicionamos um bloco else após o if que verifica se a solução é ótima. Se a solução não for ótima, isso indica que o modelo não encontrou a melhor solução possível.

Então no final do nosso código, digitamos um else: e passamos um print('O problema não possui solução ótima.').

Logo após podemos imprimir justamente aquela grade, que é aquela lista contendo somente o nome dos anunciantes. Então colocamos dentro da lista o nome de cada anunciante, então no final podemos colocar grade e executar o nosso código para encontrar essa solução.

from ortools.linear_solver import pywraplp

modelo = pywraplp.Solver.CreateSolver('SCIP')

x = {}
for anunciante in dados_visibilidade:
    for slot in slots_tempo_disponiveis:
        x[anunciante, slot] = modelo.BoolVar(f"x[{anunciante, slot}]")

modelo.Maximize(sum(dados_visibilidade[anunciante][slot] * x[anunciante, slot]  for anunciante in dados_visibilidade for slot in slots_tempo_disponiveis))

for slot in slots_tempo_disponiveis:
    modelo.Add(sum(x[anunciante, slot] for anunciante in dados_visibilidade) == 1)

status = modelo.Solve()

grade = []
if status == pywraplp.Solver.OPTIMAL:
    print('Visibilidade total máxima:', modelo.Objective().Value())
    print('Alocações:')
    for slot in slots_tempo_disponiveis:
        for anunciante in dados_visibilidade:
            if x[anunciante, slot].solution_value() == 1:
                grade.append(anunciante)
                print('Anunciante', anunciante, 'alocado para o slot de tempo', slot)
else:
    print('O problema não possui solução ótima.')
        
grade

É possível que leve algum tempo, já que ele precisa fazer todos os cálculos para determinar as melhores variáveis de decisão. Ao executar com "Ctrl + Enter", notamos que ele concluiu rapidamente e nos mostrou a visibilidade máxima de 888, junto com as alocações.

O retorno abaixo foi parcialmente transcrito:

Visibilidade total máxima: 888.0

Alocações:

Anunciante EsportivaMax alocado para o slot de tempo 0

Anunciante SuperTech alocado para o slot de tempo 1

Anunciante EnergiaViva alocado para o slot de tempo 2

Anunciante TechInova alocado para o slot de tempo 3

Anunciante TechInova alocado para o slot de tempo 4

… Grade de propaganda:

['EsportivaMax',

'SuperTech',

'EnergiaViva',

'TechInova',

'TechInova',

'EsportivaMax',

… ]

No intervalo de tempo zero, o anunciante EsportivaMax foi alocado primeiro, seguido pelo Supertech e depois o Energia Viva, e assim por diante. Ao final do nosso output, teremos apenas a lista com os nomes dos anunciantes.

Conclusão e Próximos Passos

É interessante observar que conseguimos resolver o problema de alocação das propagandas utilizando a programação linear inteira. Se desejarmos adicionar restrições mais complexas, como a programação linear inteira lidaria com elas? Descobriremos no próximo vídeo!

Sobre o curso Otimização: aplicando a programação por restrições

O curso Otimização: aplicando a programação por restrições possui 157 minutos de vídeos, em um total de 50 atividades. Gostou? Conheça nossos outros cursos de Data Science em Data Science, ou leia nossos artigos de Data Science.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Data Science acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas