import numpy as np
# ---------------------------------------------------------
# 1) Definindo os estados e a matriz de transicao
# ---------------------------------------------------------
estados = ["Ensolarado", "Nublado", "Chuvoso"]
# Matriz de transicao P (linhas = estado atual, colunas = proximo estado)
# Ensolarado Nublado Chuvoso
# Ensolarado 0.70 0.20 0.10
# Nublado 0.30 0.40 0.30
# Chuvoso 0.20 0.30 0.50
matriz_transicao = np.array([
[0.70, 0.20, 0.10], # a partir de Ensolarado
[0.30, 0.40, 0.30], # a partir de Nublado
[0.20, 0.30, 0.50], # a partir de Chuvoso
])
assert np.allclose(matriz_transicao.sum(axis=1), 1.0), "As linhas da matriz devem somar 1!"
class CadeiaDeMarkovClima:
"""Modelo de previsao de clima usando Cadeia de Markov."""
def __init__(self, estados, matriz_transicao):
self.estados = estados
self.matriz_transicao = matriz_transicao
self.indice_estado = {nome: i for i, nome in enumerate(estados)}
def prever_distribuicao(self, estado_inicial, n_dias):
"""
Calcula a distribuicao de probabilidade sobre os estados
apos 'n_dias', multiplicando o vetor de estado inicial
pela matriz de transicao elevada a n_dias (P^n).
"""
vetor_estado = np.zeros(len(self.estados))
vetor_estado[self.indice_estado[estado_inicial]] = 1.0
matriz_n_dias = np.linalg.matrix_power(self.matriz_transicao, n_dias)
distribuicao_final = vetor_estado @ matriz_n_dias
return dict(zip(self.estados, distribuicao_final))
def simular_sequencia(self, estado_inicial, n_dias, semente=None):
"""
Simula uma sequencia de estados climaticos dia a dia,
sorteando o proximo estado com base nas probabilidades
da linha correspondente da matriz de transicao.
"""
rng = np.random.default_rng(semente)
sequencia = [estado_inicial]
estado_atual = estado_inicial
for _ in range(n_dias):
i = self.indice_estado[estado_atual]
probabilidades = self.matriz_transicao[i]
proximo_estado = rng.choice(self.estados, p=probabilidades)
sequencia.append(proximo_estado)
estado_atual = proximo_estado
return sequencia
def distribuicao_estacionaria(self):
"""
Calcula a distribuicao estacionaria (de equilibrio) da cadeia,
resolvendo pi * P = pi com soma(pi) = 1.
"""
n = len(self.estados)
A = np.vstack([self.matriz_transicao.T - np.eye(n), np.ones(n)])
b = np.zeros(n + 1)
b[-1] = 1.0
pi, *_ = np.linalg.lstsq(A, b, rcond=None)
return dict(zip(self.estados, pi))
# ---------------------------------------------------------
# 2) Testando o sistema
# ---------------------------------------------------------
if __name__ == "__main__":
modelo = CadeiaDeMarkovClima(estados, matriz_transicao)
print("=== Previsao: distribuicao apos 1 dia (hoje = Ensolarado) ===")
print(modelo.prever_distribuicao("Ensolarado", 1))
print("\n=== Previsao: distribuicao apos 3 dias (hoje = Ensolarado) ===")
print(modelo.prever_distribuicao("Ensolarado", 3))
print("\n=== Previsao: distribuicao apos 7 dias (hoje = Chuvoso) ===")
print(modelo.prever_distribuicao("Chuvoso", 7))
print("\n=== Simulacao de uma sequencia real de 10 dias (comecando Ensolarado) ===")
print(modelo.simular_sequencia("Ensolarado", 10, semente=42))
print("\n=== Distribuicao estacionaria (longo prazo) ===")
print(modelo.distribuicao_estacionaria())
Saída real ao executar
=== Previsao: distribuicao de probabilidade apos 1 dia (hoje = Ensolarado) ===
Ensolarado: 0.7000
Nublado: 0.2000
Chuvoso: 0.1000
=== Previsao: distribuicao de probabilidade apos 3 dias (hoje = Ensolarado) ===
Ensolarado: 0.5100
Nublado: 0.2680
Chuvoso: 0.2220
=== Previsao: distribuicao de probabilidade apos 7 dias (hoje = Chuvoso) ===
Ensolarado: 0.4535
Nublado: 0.2834
Chuvoso: 0.2631
=== Simulacao de uma sequencia real de 10 dias (comecando Ensolarado) ===
Ensolarado -> Nublado -> Nublado -> Chuvoso -> Chuvoso -> Ensolarado -> Chuvoso -> Chuvoso -> Chuvoso -> Ensolarado -> Ensolarado
=== Distribuicao estacionaria (longo prazo) ===
Ensolarado: 0.4565
Nublado: 0.2826
Chuvoso: 0.2609