Sobre coelhos e lobos: um exemplo completo de agent-based model (ABM – Parte 2)

Segundo post da série. Veja os outros: Parte 1, Parte 3, Parte 4 e Parte 5.


Giant_20Rabbit_20or_20Small_20Wolf2_original.jpgNo ultimo post, mostrei como representar agentes de Agent-based Models no R utilizando Reference Classes, que permitem guardar “atributos” e “ações” num único objeto. Neste post, trarei um exemplo de implementação completa de um ABM — um modelo simples e bastante famoso chamado Predator & Prey. Com isso, teremos um overview de toda a estrutura de uma simulação.

Haverá dois tipos de agentes, coelhos e lobos. Coelhos têm a capacidade de se reproduzir e lobos têm a capacidade de caçar coelhos e, se estiverem alimentados, também podem se reproduzir. Se não se alimentarem, os lobos podem morrer. O objetivo da simulação é observar as dinâmicas demográficas desses dois grupos de animais (basicamente, o tamanho da população). A estrutura básica da simulação se dará conforme o pseudo-código abaixo:

Definimos parâmetros
  Número inicial de lobos a serem criados (num_lobos)
  Número inicial de coelhos a serem criados (num_coelhos)
  Taxa de fertilidade dos lobos (fertilidade_lobos)
  Taxa de fertilidade dos coelhos (fertilidade_coelhos)
  Probabilidade de um lobo morrer de fome (prob_morrer_de_fome)
  Numero de rounds (rounds)

Definimos as classes "Lobo" e "Coelho"

Criamos uma quantidade "num_lobos" de lobos
Criamos uma quantidade "num_coelhos" de coelhos

Inicio de um loop:
  Rodada dos coelhos
    Cada coelho se reproduz com probabilidade "fertilidade_coelhos"

  Rodada dos lobos
    Cada lobo caça coelhos e os encontra com uma probabilidade 
      proporcional ao tamanho da população de coelhos. Se for 
      bem sucedido na caça, se reproduz com probabilidade igual
      a "fertilidade_lobos". Caso contrário, morre com probabilidade
      "prob_morrer_de_fome".

  Se não houver mais lobos ou coelhos
    Termine o loop

  Se o número de repetições atingir "rounds"
    Termine o loop

 

Vejamos então como fazer isso no R. Primeiro criamos os parâmetros:

# Parametros

num_lobos = 100
prob_morrer_de_fome = .6
fertilidade_lobos = .4

num_coelhos = 1000
fertilidade_coelhos = .2

rounds = 50

Depois definimos as classes de agentes, usando as Reference Classes, explicadas no post anterior. Primeiramente os lobos:

Lobo = setRefClass("Lobo",
  methods = list(
    come_e_reproduz = function(){
      if( ((length(coelhos)/num_coelhos)^2) > runif(1) ){

        if(length(coelhos) > 0){
          coelhos = coelhos[-length(coelhos)]
          assign("coelhos", coelhos, envir = .GlobalEnv)
        }

        if (fertilidade_lobos > runif(1)){
          lobos[[length(lobos)+1]] = Lobo$new()
          assign("lobos", lobos, envir = .GlobalEnv)
        }

      }else if (prob_morrer_de_fome > runif(1)){
        lobos = lobos[-length(lobos)]
        assign("lobos", lobos, envir = .GlobalEnv)
      }
}))

Então os coelhos:

Coelho = setRefClass("Coelho",
  methods = list(
    reproduz = function(){
      if (fertilidade_coelhos > runif(1)){
        coelhos[[length(coelhos)+1]] = Coelho$new()
        assign("coelhos", coelhos, envir = .GlobalEnv)
      }
}))

Observem alguns pontos importantes:

  • Nenhum dos dois tipos de agentes possui atributos. Ambos possuem apenas “ações”. Lobos comem e se reproduzem; coelhos apenas se reproduzem. Deste modo, nenhuma informação foi passada para o argumento “fields”, que usualmente é exigido pelas Reference Classes.
  • Dentro da classe Lobo, a função “come_e_reproduz” faz referência a dois objetos que ainda não existem no ambiente do R, pois ainda não os criamos. Trata-se de um objeto chamado “lobos” (que será uma lista contendo todos os lobos criados) e de outro chamado “coelhos” (a lista dos coelhos criados). Ainda assim, já podemos fazer referência a eles.
  • Os dois objetos que ainda não existem serão criados no ambiente principal do R (.GlobalEnv). Para que possamos modificá-los a partir dessas funções que apenas existiram dentro das classes “Lobo” e “Coelho”, devemos especificar que estamos de fato acessando algo do ambiente principal e o sobrescrevendo. Para isso, utilizei o comando assign. Certamente há formas mais simples e “limpas” de fazer isso. Mas para os fins deste post, a estratégia empregada serve. Para saber mais sobre a estrutura de ambientes do R, veja isto.

Agora que as classes já existem, podemos “instanciá-las”. Primeiramente os  lobos :

lobos = list()
for(i in 1:num_lobos)
 lobos[[i]] = Lobo$new()

Agora os coelhos:

coelhos = list()
for(i in 1:num_coelhos)
 coelhos[[i]] = Coelho$new()

Como adiantado nos tópicos acima, os lobos e coelhos existentes são guardados dentro de listas. Agora já estamos prestes a fazer a simulação rodar. Mas antes, é bom criar dois objetos que guardarão as informações de nosso interesse: o número de lobos e coelhos existentes em cada round. Serão dois vetores que, de início, trazem as quantidades iniciais de cada tipo de agente.

num_lobos_no_tempo = num_lobos
num_coelhos_no_tempo = num_coelhos

Agora, pau na máquina:

for(t in 1:rounds){
  # Rodada dos coelhos
  for(coelho in coelhos)
    coelho$reproduz()

  # Rodada dos lobos
  for(lobo in lobos)
    lobo$come_e_reproduz()

  # Atualizando as quantidades de interesse
  num_lobos_no_tempo = c(num_lobos_no_tempo, length(lobos))
  num_coelhos_no_tempo =c(num_coelhos_no_tempo,length(coelhos))

  # Condições sob as quais o loop é interrompido
  if((length(coelhos)==0)|
     (length(lobos)==0)|
     ((length(coelhos)+length(lobos)) > 100000))
    break

  # Imprime na tela os resultados do round
  print(paste("round", t,
              "-- num coelhos =", length(coelhos),
              "-- num lobos =", length(lobos)))
}

E assim, a simulação segue:

pp

Agora podemos compilar e plotar os resultados:

library(ggplot2)

resultados = data.frame(num = c(num_lobos_no_tempo,
                                num_coelhos_no_tempo),
                        animal = rep(c("lobo","coelhos"),
                                       each = rounds + 1),
                        tempo = rep(0:rounds, 2))

ggplot(resultados, aes(x = tempo, y = num, group = animal)) +
   geom_line(aes(color=animal),lwd= 2)

Pronto:

result1

O mais interessante é observar a influência de mudanças nos parâmetros. Esse é um dos objetivos fundamentais de uma análise usando ABM. Criando condições e mecanismos artificiais, podemos alterar características essenciais da situação e obter contra-factuais — e, por consequência uma forma de efeitos causais. Vejam dois exemplos de resultados produzidos por parâmetros diferentes:

Internet a fora, é possível achar inúmeros outros exemplos.

É importante sublinhar que todos os eventos que acontecem nesse modelo simples de simulação são aleatórios. Coelhos se reproduzem, lobos caçam… etc… Tudo ocorre como se fosse um sorteio. Por isso, rodar a mesma simulação duas vezes pode não produzir os mesmos resultados. O que se costuma fazer é repetir diversas vezes todo o processo e plotar diversos gráficos de linha; cada um representando uma “linha do tempo alternativa”. Assim, podemos observar se há um padrão, apesar do caráter estocástico.

Foi isso, por exemplo, que fizeram Bernardo Furtado e  Isaque Eberhardt em um trabalho bem recente, em que procuraram simular o funcionamento básico de uma economia com ABM. Vejamos gráficos abaixo, reproduzidos desse artigo:

bernardo1bernardo2


Com isso dá pra ter uma ideia um pouco mais tangível sobre o que são ABMs e quais as suas utilidades. Quem de fato executar esses códigos aqui apresentados logo perceberá que a simulação se torna muito lenta nos rounds em que há grande quantidade de agentes. Às vezes, por qualquer razão, o número de lobos cai muito e há uma explosão na população de coelhos. Como estamos fazendo um loop que percorre cada agente um-a-um, rounds com, digamos, 30 mil coelhos acabam por durar particularmente muito… Diversas soluções poderiam ser implementadas: otimizar o código, computação paralela, compilar as funções utilizadas etc… Mas isso é coisa pra outra hora.

 

 

 

Anúncios

5 respostas em “Sobre coelhos e lobos: um exemplo completo de agent-based model (ABM – Parte 2)

  1. Pingback: Simulando modelos baseados em agentes no R | Análise Real

  2. Pingback: Do bar. Modelando a racionalidade limitada com ABM: o modelo El Farol (ABM – Parte 3) | SOCIAIS & MÉTODOS

  3. Pingback: Simulando a segregação racial: o modelo de Schelling (ABM – Parte 4) | SOCIAIS & MÉTODOS

  4. Pingback: Sociedade, caos e complexidade (ABM – Parte 5, final) | SOCIAIS & MÉTODOS

  5. Pingback: Simulando o trânsito e os limites de velocidade | SOCIAIS & MÉTODOS

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s