Saltar al contenido

# procesos-estocasticos-discretos-simulacion-estados-y-tiempos-de-absorcion-con-pydtmc

Procesos Estocásticos Discretos: Simulación, Estados y Tiempos de Absorción con PyDTMC

Volver a la portada del curso
Notebook

Cálculo Práctico de Tiempos de Absorción

Sección 4 · Tiempos de Absorción

Cálculo práctico de tiempos de absorción

En una cadena absorbente hay dos preguntas de negocio: ¿dónde termina el proceso? y ¿cuánto tarda en terminar? En un embudo de ventas eso es la tasa de conversión final y el ciclo de venta esperado. En este notebook respondes ambas con la matriz fundamental, las calculas con PyDTMC y las verificas con 10,000 simulaciones. Descarga el notebook adjunto y ejecútalo celda por celda.

La forma canónica

Si ordenas los estados con los transitorios primero y los absorbentes después, la matriz de transición toma la forma canónica:

$$P = \begin{pmatrix} Q & R \\ 0 & I \end{pmatrix}$$

$Q$ contiene las transiciones entre estados transitorios y $R$, las transiciones de transitorios a absorbentes. Las tres cantidades clave salen de ahí:

$$N = (I - Q)^{-1}, \qquad t = N\mathbf{1}, \qquad B = NR$$

$N_{ij}$ es el número esperado de visitas al estado transitorio $j$ partiendo de $i$, contando la visita inicial. La suma de cada fila, $t_i$, es el número esperado de pasos hasta la absorción. $B_{ik}$ es la probabilidad de terminar en el estado absorbente $k$ partiendo de $i$.

Paso 1: la cadena y la matriz fundamental

Usamos el embudo semanal de la primera lección: Lead y Prospecto son transitorios; Cliente y Perdido, absorbentes.

from pydtmc import MarkovChain

embudo = MarkovChain([[0.5, 0.3, 0.2, 0.0],
                      [0.2, 0.4, 0.2, 0.2],
                      [0.0, 0.0, 1.0, 0.0],
                      [0.0, 0.0, 0.0, 1.0]],
                     ["Lead", "Prospecto", "Cliente", "Perdido"])
print(embudo.is_absorbing, embudo.transient_states)
print(embudo.fundamental_matrix)        # [[2.5, 1.25], [0.833, 2.083]]
print(embudo.mean_absorption_times())   # [3.75, 2.917]
print(embudo.absorption_probabilities())

Un lead pasa en promedio 2.5 semanas como Lead y 1.25 como Prospecto, así que tarda $t = 3.75$ semanas en resolverse. Un prospecto tarda 2.92. absorption_probabilities() devuelve la matriz $[[0.75, 0.583], [0.25, 0.417]]$: el 75% de los leads termina comprando y el 58.3% de los prospectos también.

Paso 2: verificar con simulación

Las fórmulas son exactas, pero conviene comprobarlas. Simulas 10,000 leads hasta que cada uno llega a un estado absorbente:

import numpy as np

rng = np.random.default_rng(42)
P = embudo.p
pasos, finales = [], []
for _ in range(10_000):
    s, t = 0, 0                    # 0 = Lead
    while s < 2:                   # 2 y 3 son absorbentes
        s = rng.choice(4, p=P[s])
        t += 1
    pasos.append(t)
    finales.append(s)
print(np.mean(pasos), np.mean(np.array(finales) == 2))  # 3.732  0.754

La simulación da 3.73 semanas y 75.4% de conversión, a menos de 0.02 de los valores exactos. Además te da algo que la media no dice: la mediana es 3 semanas, pero el percentil 90 es 7. La varianza del tiempo de absorción se calcula como $(2N - I)t - t^2$ y vale 8.23 para un lead; el tiempo de cierre es muy disperso.

Paso 3: escenarios

El valor práctico de este modelo está en comparar intervenciones antes de ejecutarlas. El notebook evalúa dos:

  • Mejorar el cierre: un prospecto compra con 0.3 en lugar de 0.2 y se pierde con 0.1. La conversión de un lead sube de 0.75 a 0.875 sin cambiar el tiempo esperado.
  • Acelerar la calificación: un lead pasa a prospecto con 0.5 en lugar de 0.3 y permanece como lead con 0.3. El ciclo baja a 3.44 semanas, pero la conversión cae a 0.688, porque empujas más gente hacia el estado donde se pierden clientes.

El segundo resultado no es intuitivo, y por eso conviene calcularlo en lugar de suponerlo.

Trampas comunes

  • La orientación de absorption_probabilities(). PyDTMC devuelve filas = estados absorbentes y columnas = estados transitorios, es decir, $B^\top$. Si esperas la forma del libro, transpón.
  • mean_number_visits() no es $N$. Esa función no cuenta la visita inicial: en la diagonal da $N_{ii} - 1$ (1.5 en lugar de 2.5 para Lead) y reporta inf en los estados recurrentes.
  • Si la cadena no es absorbente (por ejemplo, tiene una clase cerrada que no es un solo estado), estos métodos devuelven None. Revisa is_absorbing primero.
  • Bucles sin tope en la simulación. Con una matriz mal construida el while no termina; en código de producción agrega un máximo de pasos.

Cierre

Para cualquier proceso con estados finales, calcula $t$ y $B$ con PyDTMC, verifícalos con una simulación y después usa la misma cadena para comparar escenarios. Es el flujo completo que vas a aplicar en el proyecto final.

Recursos