Formación · Programación actuarial

Actuaría en R y Python: código abierto

Programar convierte una valuación en algo que se puede revisar, repetir y auditar. Aquí encontrarás un catálogo verificado de paquetes actuariales de código abierto en R, Python y Julia, cuatro recetas que ejecutamos para comprobar que corren, con sus resultados reales, y las prácticas que exigen los estándares sobre modelos.

20
paquetes verificados
4
recetas ejecutadas
52,135
IBNR del triángulo RAA
Por qué programarR, Python o JuliaCatálogoChain-ladderGLM PoissonAnualidadesVaR y TVaREntornoLibros y cursosBuenas prácticasPreguntasProfundizar
01

Por qué programar en actuaría

Una valuación actuarial es una cadena de decisiones: qué datos se depuran, qué supuestos se adoptan, qué método se aplica y cómo se presentan los resultados. En una hoja de cálculo esa cadena queda repartida en cientos de celdas y es difícil de revisar. En un script de R o Python cada paso queda escrito, en orden, con comentarios. Quien revisa puede leerlo de arriba abajo, ejecutarlo de nuevo y obtener el mismo número.

Eso es reproducibilidad: con los mismos datos, el mismo código y la misma semilla aleatoria, el resultado se repite. Es también la base de la auditoría. Un auditor o un supervisor que recibe el código y los datos puede verificar la reserva de siniestros ocurridos no reportados o el pasivo laboral sin depender de la memoria de quien lo calculó, y los cambios entre un cierre y otro quedan registrados en el historial de versiones.

Los estándares de práctica empujan en esa dirección. El ASOP No. 56 de la Actuarial Standards Board de Estados Unidos, sobre modelación, está vigente desde el 1 de octubre de 2020 y pide al actuario entender el modelo, probarlo, aplicar controles de gobierno para mitigar el riesgo de modelo y documentarlo con el detalle suficiente para que otro actuario calificado pueda evaluar el trabajo. La IAA tiene un estándar modelo dedicado al tema, el ISAP 1A sobre gobernanza de modelos (fechado el 1 de diciembre de 2018 en su catálogo), y el CONAC promueve estándares sustancialmente consistentes con los internacionales (ver estándares actuariales). Un modelo escrito como código, con pruebas y control de versiones, cumple esos principios casi por construcción.

Hay además una razón práctica: el ecosistema abierto ya resolvió buena parte del trabajo repetitivo. El triángulo de desarrollo, el chain-ladder de Mack, el GLM con offset de exposición o la tabla de mortalidad paramétrica están implementados, probados por miles de usuarios y documentados. El valor del actuario está en elegir bien, validar y explicar.

02

R, Python o Julia: cómo elegir

R

Estadística y reservas

Nació para el análisis estadístico y tiene los paquetes actuariales más antiguos y maduros: ChainLadder, actuar, lifecontingencies, StMoMo. Su fórmula y ~ x y la función glm() son el estándar en textos de modelos lineales. Ideal para reservas, estudios de experiencia y reportes con R Markdown o Quarto.

Python

Integración y automatización

Lenguaje general que domina en ingeniería de datos y aprendizaje automático. El CAS mantiene chainladder en Python; statsmodels y scikit-learn cubren GLM y modelos predictivos; lifelib ofrece modelos de vida completos. Conviene cuando el cálculo debe conectarse con bases de datos, APIs o procesos productivos.

Julia

Velocidad en modelos grandes

Compila a código nativo y alcanza velocidades cercanas a C sin perder legibilidad. La comunidad JuliaActuary publica paquetes para tablas de mortalidad, contingencias de vida, curvas de tasas y estudios de experiencia. Útil para proyecciones póliza por póliza y escenarios estocásticos masivos.

Regla práctica: elige el lenguaje que usa tu equipo y aprende a leer los otros dos. Las recetas de abajo muestran el mismo cálculo en R y en Python para que compares sintaxis con resultados idénticos.
04

Receta 1: chain-ladder sobre el triángulo RAA

El triángulo RAA contiene siniestros acumulados del negocio facultativo automático de responsabilidad civil general, años de origen 1981 a 1990, publicados por la Reinsurance Association of America en 1991. Es un ejemplo clásico de la literatura de reservas estocásticas, usado por Thomas Mack y por England y Verrall. Viene incluido tanto en ChainLadder de R como en chainladder de Python, así que sirve para comprobar que las dos implementaciones coinciden. El método se explica a detalle en reservas técnicas.

Python 3.13 · chainladder 0.10.1
import chainladder as cl

# Triángulo RAA incluido en el paquete (siniestros acumulados, años de origen 1981 a 1990)
raa = cl.load_sample("raa")
print(raa)

# Chain-ladder determinístico: factores de desarrollo ponderados por volumen
dev = cl.Development(average="volume").fit(raa)
print(dev.ldf_.round(4))

modelo = cl.Chainladder().fit(raa)
print(modelo.ultimate_.round(0))
print("IBNR total:", round(float(modelo.ibnr_.sum()), 0))

# Error estándar de Mack
mack = cl.MackChainladder().fit(raa)
print(mack.summary_.round(0))
print("Error estándar total:", round(float(mack.total_mack_std_err_.values.ravel()[0]), 0))
Salida obtenida al ejecutar
         12       24       36       48       60       72       84       96       108      120
1981  5012.0   8269.0  10907.0  11805.0  13539.0  16181.0  18009.0  18608.0  18662.0  18834.0
1982   106.0   4285.0   5396.0  10666.0  13782.0  15599.0  15496.0  16169.0  16704.0      NaN
1983  3410.0   8992.0  13873.0  16141.0  18735.0  22214.0  22863.0  23466.0      NaN      NaN
1984  5655.0  11555.0  15766.0  21266.0  23425.0  26083.0  27067.0      NaN      NaN      NaN
1985  1092.0   9565.0  15836.0  22169.0  25955.0  26180.0      NaN      NaN      NaN      NaN
1986  1513.0   6445.0  11702.0  12935.0  15852.0      NaN      NaN      NaN      NaN      NaN
1987   557.0   4020.0  10946.0  12314.0      NaN      NaN      NaN      NaN      NaN      NaN
1988  1351.0   6947.0  13112.0      NaN      NaN      NaN      NaN      NaN      NaN      NaN
1989  3133.0   5395.0      NaN      NaN      NaN      NaN      NaN      NaN      NaN      NaN
1990  2063.0      NaN      NaN      NaN      NaN      NaN      NaN      NaN      NaN      NaN
        12-24   24-36   36-48   48-60   60-72   72-84   84-96  96-108  108-120
(All)  2.9994  1.6235  1.2709  1.1717  1.1134  1.0419  1.0333  1.0169   1.0092
         2261
1981  18834.0
1982  16858.0
1983  24083.0
1984  28703.0
1985  28927.0
1986  19501.0
1987  17749.0
1988  24019.0
1989  16045.0
1990  18402.0
IBNR total: 52135.0
       Latest     IBNR  Ultimate  Mack Std Err
1981  18834.0      NaN   18834.0           NaN
1982  16704.0    154.0   16858.0         143.0
1983  23466.0    617.0   24083.0         592.0
1984  27067.0   1636.0   28703.0         713.0
1985  26180.0   2747.0   28927.0        1452.0
1986  15852.0   3649.0   19501.0        1995.0
1987  12314.0   5435.0   17749.0        2204.0
1988  13112.0  10907.0   24019.0        5354.0
1989   5395.0  10650.0   16045.0        6332.0
1990   2063.0  16339.0   18402.0       24566.0
Error estándar total: 26881.0
R 4.3.3 · ChainLadder 0.2.21
suppressPackageStartupMessages(library(ChainLadder))

# Triángulo RAA incluido en el paquete (Reinsurance Association of America, 1991)
data(RAA)
print(RAA)

# Factores de desarrollo ponderados por volumen
f <- sapply(1:9, function(k)
  sum(RAA[1:(10 - k), k + 1]) / sum(RAA[1:(10 - k), k]))
print(round(f, 4))

# Chain-ladder estocástico de Mack: última, IBNR y error estándar
mack <- MackChainLadder(RAA)   # sigma final extrapolada log-linealmente (opción por omisión)
print(mack)
Salida obtenida al ejecutar
      dev
origin    1     2     3     4     5     6     7     8     9    10
  1981 5012  8269 10907 11805 13539 16181 18009 18608 18662 18834
  1982  106  4285  5396 10666 13782 15599 15496 16169 16704    NA
  1983 3410  8992 13873 16141 18735 22214 22863 23466    NA    NA
  1984 5655 11555 15766 21266 23425 26083 27067    NA    NA    NA
  1985 1092  9565 15836 22169 25955 26180    NA    NA    NA    NA
  1986 1513  6445 11702 12935 15852    NA    NA    NA    NA    NA
  1987  557  4020 10946 12314    NA    NA    NA    NA    NA    NA
  1988 1351  6947 13112    NA    NA    NA    NA    NA    NA    NA
  1989 3133  5395    NA    NA    NA    NA    NA    NA    NA    NA
  1990 2063    NA    NA    NA    NA    NA    NA    NA    NA    NA
[1] 2.9994 1.6235 1.2709 1.1717 1.1134 1.0419 1.0333 1.0169 1.0092
MackChainLadder(Triangle = RAA)

     Latest Dev.To.Date Ultimate   IBNR Mack.S.E CV(IBNR)
1981 18,834       1.000   18,834      0        0      NaN
1982 16,704       0.991   16,858    154      143    0.928
1983 23,466       0.974   24,083    617      592    0.959
1984 27,067       0.943   28,703  1,636      713    0.436
1985 26,180       0.905   28,927  2,747    1,452    0.529
1986 15,852       0.813   19,501  3,649    1,995    0.547
1987 12,314       0.694   17,749  5,435    2,204    0.405
1988 13,112       0.546   24,019 10,907    5,354    0.491
1989  5,395       0.336   16,045 10,650    6,332    0.595
1990  2,063       0.112   18,402 16,339   24,566    1.503

              Totals
Latest:   160,987.00
Dev:            0.76
Ultimate: 213,122.23
IBNR:      52,135.23
Mack.S.E   26,880.74
CV(IBNR):       0.52

Cómo leer el resultado. Los nueve factores de desarrollo coinciden a cuatro decimales en ambos lenguajes (2.9994 del primer al segundo año, 1.0092 del noveno al décimo). La reserva IBNR total es 52,135 y la última estimada 213,122. El error estándar de Mack total es 26,881, que equivale a un coeficiente de variación de 52%: la incertidumbre es enorme porque el año 1990 solo tiene un dato observado y su IBNR depende del producto de todos los factores. Con la aproximación original de Mack para la volatilidad del último periodo (est.sigma = "Mack" en R) el total sube a 26,909.

05

Receta 2: GLM Poisson de frecuencia con offset de exposición

En tarificación la frecuencia se modela con un GLM Poisson con liga logarítmica. Como cada póliza estuvo expuesta un tiempo distinto, el logaritmo de la exposición entra como offset: un término con coeficiente fijo en 1 que convierte el conteo esperado en tasa por año póliza. Aquí simulamos 20,000 pólizas con una semilla fija y frecuencias conocidas, de modo que podemos comprobar si el modelo recupera los parámetros verdaderos.

Python 3.13 · statsmodels 0.15.0
import numpy as np
import pandas as pd
import statsmodels.api as sm
import statsmodels.formula.api as smf

rng = np.random.default_rng(2026)          # semilla fija: resultados reproducibles
n = 20_000

# Cartera simulada de autos: exposición en años-póliza entre 0.1 y 1
df = pd.DataFrame({
    "exposicion": rng.uniform(0.1, 1.0, n),
    "edad": rng.choice(["18-25", "26-45", "46-70"], n, p=[0.2, 0.5, 0.3]),
    "zona": rng.choice(["urbana", "rural"], n, p=[0.7, 0.3]),
})

# Frecuencias "verdaderas" por año-póliza (lo que el GLM debe recuperar)
base = 0.08
f_edad = df["edad"].map({"18-25": 1.8, "26-45": 1.0, "46-70": 0.85})
f_zona = df["zona"].map({"urbana": 1.25, "rural": 1.0})
lam = base * f_edad * f_zona * df["exposicion"]
df["siniestros"] = rng.poisson(lam)

# GLM Poisson con liga log y offset = log(exposición)
modelo = smf.glm(
    "siniestros ~ C(edad, Treatment('26-45')) + C(zona, Treatment('rural'))",
    data=df,
    family=sm.families.Poisson(),
    offset=np.log(df["exposicion"]),
).fit()

print(modelo.summary().tables[1])
relatividades = np.exp(modelo.params).round(3)
print(relatividades)
print("Pearson chi2 / g.l.:", round(modelo.pearson_chi2 / modelo.df_resid, 3))
print("Siniestros observados:", int(df["siniestros"].sum()),
      " Exposición total:", round(df["exposicion"].sum(), 1))
Salida obtenida al ejecutar
=========================================================================================================
                                            coef    std err          z      P>|z|      [0.025      0.975]
---------------------------------------------------------------------------------------------------------
Intercept                                -2.4959      0.066    -37.606      0.000      -2.626      -2.366
C(edad, Treatment('26-45'))[T.18-25]      0.5022      0.068      7.424      0.000       0.370       0.635
C(edad, Treatment('26-45'))[T.46-70]     -0.1823      0.075     -2.422      0.015      -0.330      -0.035
C(zona, Treatment('rural'))[T.urbana]     0.2343      0.067      3.479      0.001       0.102       0.366
=========================================================================================================
Intercept                                0.082
C(edad, Treatment('26-45'))[T.18-25]     1.652
C(edad, Treatment('26-45'))[T.46-70]     0.833
C(zona, Treatment('rural'))[T.urbana]    1.264
dtype: float64
Pearson chi2 / g.l.: 0.965
Siniestros observados: 1169  Exposición total: 11023.0

Validación. Las relatividades estimadas son 1.652 para conductores de 18 a 25 años (verdadera 1.8), 0.833 para 46 a 70 (verdadera 0.85) y 1.264 para zona urbana (verdadera 1.25); la frecuencia base estimada es 0.082 contra 0.08. Todas las verdaderas caen dentro de los intervalos de confianza al 95% que reporta el modelo. El cociente de Pearson entre grados de libertad, 0.965, es cercano a 1, señal de que no hay sobredispersión, lo esperado porque los datos se generaron Poisson. Con datos reales un valor muy superior a 1 sugiere usar cuasi Poisson o binomial negativa. La guía de referencia sobre este flujo de trabajo es la Monografía 5 del CAS, citada en la sección de libros.

Modelo ajustado
\[\log \mathbb{E}[N_i] = \log(e_i) + \beta_0 + \beta_{\text{edad}} + \beta_{\text{zona}}, \qquad \text{relatividad} = e^{\beta}\]

Ni es el número de siniestros de la póliza i, ei su exposición en años póliza y los β son los coeficientes por nivel respecto al nivel base (26 a 45 años, zona rural).

06

Receta 3: anualidad vitalicia y seguro con Gompertz-Makeham

La ley de Gompertz-Makeham, μ(x) = A + Bcx, tiene función de supervivencia cerrada, lo que permite calcular anualidades y seguros sin tabla. Usamos los parámetros A = 0.00022, B = 2.7 × 10-6 y c = 1.124 del modelo de supervivencia estándar (Standard Ultimate Survival Model) del libro de Dickson, Hardy y Waters, usado en textos y exámenes de matemáticas actuariales de vida, con interés de 5%. Hicimos el cálculo directo en Python y lo replicamos con lifecontingencies en R a partir de una tabla de vida construida con la misma ley. Para tablas mexicanas, ver tablas de mortalidad.

Python 3.13 · NumPy
import numpy as np

# Ley de Gompertz-Makeham: mu(x) = A + B * c**x
# Parámetros del Standard Ultimate Survival Model (Dickson, Hardy y Waters)
A, B, c = 0.00022, 2.7e-6, 1.124
i = 0.05
v = 1 / (1 + i)

def tpx(x, t):
    """Probabilidad de que (x) sobreviva t años (forma cerrada)."""
    return np.exp(-A * t - B * c**x * (c**t - 1) / np.log(c))

def anualidad_anticipada(x, omega=130):
    """ä_x = suma_{k>=0} v^k * kpx (pagos de 1 al inicio de cada año)."""
    k = np.arange(0, omega - x)
    return np.sum(v**k * tpx(x, k))

def seguro_vida_entera(x, omega=130):
    """A_x = suma_{k>=0} v^(k+1) * kpx * q_{x+k} (pago al final del año de muerte)."""
    k = np.arange(0, omega - x)
    q = 1 - tpx(x + k, 1)
    return np.sum(v**(k + 1) * tpx(x, k) * q)

for x in (40, 60, 65):
    a = anualidad_anticipada(x)
    Ax = seguro_vida_entera(x)
    d = i / (1 + i)
    print(f"x={x}: ä_x={a:.4f}  A_x={Ax:.5f}  control 1 - d*ä_x={1 - d*a:.5f}")

# Prima neta anual de un seguro de vida entera de 1,000,000 a edad 40
P = 1_000_000 * seguro_vida_entera(40) / anualidad_anticipada(40)
print(f"Prima neta nivelada, suma asegurada 1,000,000, edad 40: {P:,.2f}")
Salida obtenida al ejecutar
x=40: ä_x=18.4578  A_x=0.12106  control 1 - d*ä_x=0.12106
x=60: ä_x=14.9041  A_x=0.29028  control 1 - d*ä_x=0.29028
x=65: ä_x=13.5498  A_x=0.35477  control 1 - d*ä_x=0.35477
Prima neta nivelada, suma asegurada 1,000,000, edad 40: 6,558.72
R 4.3.3 · lifecontingencies 1.6.0
suppressPackageStartupMessages(library(lifecontingencies))

# Gompertz-Makeham: mu(x) = A + B c^x (mismos parámetros que la receta en Python)
A <- 0.00022; B <- 2.7e-6; c <- 1.124
edades <- 0:130
tpx0 <- exp(-A * edades - B * (c^edades - 1) / log(c))   # supervivencia desde 0
tabla <- new("lifetable", x = edades, lx = 100000 * tpx0, name = "GM-SUSM")

i <- 0.05
for (x in c(40, 60, 65)) {
  a <- axn(tabla, x = x, i = i)            # anualidad vitalicia anticipada
  Ax <- Axn(tabla, x = x, i = i)           # seguro de vida entera, pago al final del año
  cat(sprintf("x=%d  a..x=%.4f  Ax=%.5f\n", x, a, Ax))
}
P <- 1e6 * Axn(tabla, x = 40, i = i) / axn(tabla, x = 40, i = i)
cat(sprintf("Prima neta nivelada (SA 1,000,000, edad 40): %.2f\n", P))
Salida obtenida al ejecutar
x=40  a..x=18.4578  Ax=0.12106
x=60  a..x=14.9041  Ax=0.29028
x=65  a..x=13.5498  Ax=0.35477
Prima neta nivelada (SA 1,000,000, edad 40): 6558.72

Validación. Los dos lenguajes dan exactamente los mismos valores: ä60 = 14.9041 y A60 = 0.29028, que coinciden con los publicados para ese modelo. La columna de control usa la identidad Ax = 1 - d·äx, con d = i/(1+i), y confirma que seguro y anualidad son consistentes entre sí. La prima neta nivelada de un seguro de vida entera de 1,000,000 contratado a los 40 años resulta 6,558.72 al año. Nota de entorno: en CRAN la versión vigente es la 1.6.3, que exige R 4.4; aquí se ejecutó la 1.6.0 sobre R 4.3.3, con la misma interfaz de axn() y Axn().

Supervivencia de Gompertz-Makeham
\[{}_tp_x = \exp\!\left(-At - \frac{B\,c^x\,(c^t-1)}{\ln c}\right), \qquad \ddot a_x = \sum_{k\ge 0} v^k\,{}_kp_x, \qquad A_x = 1 - d\,\ddot a_x\]

v = 1/(1+i) es el factor de descuento y d = iv la tasa de descuento. La suma se trunca en la edad 130, donde la probabilidad de supervivencia ya es despreciable.

07

Receta 4: VaR y TVaR por simulación Monte Carlo

La pérdida agregada anual de una cartera se modela como una suma aleatoria: un número Poisson de siniestros, cada uno con severidad lognormal. No tiene fórmula cerrada, pero se simula fácilmente. El VaR al 99.5% es el cuantil que solo se excede uno de cada 200 años, la medida del requerimiento de capital en solvencia; el TVaR es el promedio de las pérdidas que exceden ese cuantil y responde a la pregunta de cuánto se pierde, en promedio, en los años malos.

Python 3.13 · NumPy
import numpy as np

rng = np.random.default_rng(2026)
n_sim = 200_000

# Pérdida agregada anual S = X1 + ... + XN
# N ~ Poisson(lambda = 50) siniestros; X ~ Lognormal(mu = 11, sigma = 1.2) en pesos
lam, mu, sigma = 50, 11.0, 1.2
N = rng.poisson(lam, n_sim)
X = rng.lognormal(mu, sigma, N.sum())
idx = np.repeat(np.arange(n_sim), N)          # a qué año pertenece cada siniestro
S = np.bincount(idx, weights=X, minlength=n_sim)

def var_tvar(perdidas, alfa):
    var = np.quantile(perdidas, alfa)
    tvar = perdidas[perdidas >= var].mean()
    return var, tvar

media_teorica = lam * np.exp(mu + sigma**2 / 2)
print(f"Media simulada: {S.mean():,.0f}   media teórica: {media_teorica:,.0f}")
for alfa in (0.95, 0.99, 0.995):
    var, tvar = var_tvar(S, alfa)
    print(f"alfa={alfa:.3f}  VaR={var:,.0f}  TVaR={tvar:,.0f}  VaR - media={var - S.mean():,.0f}")

# Error de Monte Carlo del VaR 99.5%: repetir con 20 semillas distintas
vars_ = []
for s in range(20):
    r = np.random.default_rng(s)
    Nn = r.poisson(lam, n_sim)
    Xx = r.lognormal(mu, sigma, Nn.sum())
    Ss = np.bincount(np.repeat(np.arange(n_sim), Nn), weights=Xx, minlength=n_sim)
    vars_.append(np.quantile(Ss, 0.995))
print(f"VaR 99.5% entre semillas: media {np.mean(vars_):,.0f}, desv. est. {np.std(vars_, ddof=1):,.0f}")
Salida obtenida al ejecutar
Media simulada: 6,147,626   media teórica: 6,150,371
alfa=0.950  VaR=9,346,492  TVaR=10,746,657  VaR - media=3,198,866
alfa=0.990  VaR=11,490,305  TVaR=13,232,977  VaR - media=5,342,679
alfa=0.995  VaR=12,559,969  TVaR=14,520,485  VaR - media=6,412,342
VaR 99.5% entre semillas: media 12,561,324, desv. est. 70,896

Validación. La media simulada (6,147,626) difiere en 0.04% de la teórica λ·eμ+σ²/2 = 6,150,371. El VaR al 99.5% es 12.56 millones y el TVaR 14.52 millones; el capital por encima de la pérdida esperada es de unos 6.4 millones. Repetir la simulación con 20 semillas distintas muestra que el VaR al 99.5% tiene un error de Monte Carlo de alrededor de 71,000, es decir, 0.6%: con 200,000 años simulados el cuantil es estable, pero con 10,000 el error sería unas cuatro veces mayor. Reportar ese error es parte de una buena documentación del modelo.

Laboratorio

Pérdida agregada Poisson-lognormal en tu navegador

La misma lógica de la receta, programada en JavaScript con un generador pseudoaleatorio con semilla. Cambia la semilla y observa cuánto se mueve el VaR: ese es el error de simulación. Para no congelar el navegador el máximo es 50,000 años simulados.

·
Media simulada
·
Media teórica λeμ+σ²/2
·
VaR α
·
TVaR α
·
VaR menos media

08

Entorno reproducible: versiones usadas aquí

Un resultado es reproducible solo si se conoce el entorno que lo produjo. Estas son las versiones con las que se ejecutaron las recetas el 16 de octubre de 2026, en Ubuntu 24.04. En tus proyectos registra lo mismo: en Python con un archivo requirements.txt o pyproject.toml con versiones fijas y un entorno virtual; en R con el paquete renv, que guarda un archivo de bloqueo con la versión exacta de cada dependencia.

ComponenteVersiónUsado en
Python3.13.16Recetas 1 a 4
NumPy / pandas2.5.3 / 3.0.5Recetas 1 a 4
chainladder0.10.1Receta 1
statsmodels0.15.0Receta 2
R4.3.3Recetas 1 y 3
ChainLadder0.2.21Receta 1
lifecontingencies1.6.0Receta 3
Terminal · instalación mínima
# Python: entorno virtual con versiones fijas
python3 -m venv .venv
source .venv/bin/activate
pip install chainladder==0.10.1 statsmodels==0.15.0 numpy pandas
pip freeze > requirements.txt

# R: paquetes y archivo de bloqueo con renv
Rscript -e 'install.packages(c("renv", "ChainLadder", "lifecontingencies"))'
Rscript -e 'renv::init(); renv::snapshot()'
09

Libros y cursos abiertos

Loss Data Analytics (Open Actuarial Textbooks)

Libro interactivo y gratuito sobre modelación de datos de pérdidas: frecuencia, severidad, modelos agregados, credibilidad y reservas, con código en R. La segunda edición salió en octubre de 2024 en HTML y PDF. Existe una versión en español traducida principalmente por el grupo actuarial de la Universitat de Barcelona y un curso corto con 34 videos y 52 ejercicios en R.

CAS Monografía 5: Generalized Linear Models for Insurance Rating

Guía práctica de Goldburd, Khare, Tevet y Guller para construir un plan de tarifas con GLM de principio a fin: distribuciones, offsets, interacciones, validación y selección de variables. Segunda edición (revisión 2025), descargable sin costo y adoptada en el temario del examen 8 del CAS.

Modern Financial Modeling

Libro de Alec Loudenback y Yun-Tien Lee para actuarios y profesionales financieros sobre por qué y cómo programar modelos: abstracciones, rendimiento, prácticas de ingeniería de software y modelación estocástica, con ejemplos en Julia. Disponible completo en HTML y PDF.

Tutoriales de Actuarial Data Science (Asociación Suiza de Actuarios)

Cuadernos con código y bases de datos públicas sobre redes neuronales, árboles, aprendizaje no supervisado y supervivencia aplicados a seguros, preparados por el grupo de trabajo de ciencia de datos de la asociación suiza. En septiembre de 2025 añadió un tutorial de modelos de supervivencia.

CAS AI Tools and Resources

Página del CAS que reúne su AI Primer (segunda edición, julio de 2026), investigación sobre modelos de lenguaje en análisis de siniestros y el podcast Almost Nowhere. Complementa lo técnico con gobierno, riesgos y ética de la IA.

JuliaActuary: Learn

Tutoriales y ejemplos del ecosistema JuliaActuary: tablas de mortalidad, valuación de pólizas, curvas de tasas y comparativos de rendimiento frente a otros lenguajes.

Ruta sugerida: Loss Data Analytics para fundamentos con R, la Monografía 5 para GLM en tarificación y Modern Financial Modeling para dar el salto a la ingeniería de modelos. Si te interesa la IA aplicada, sigue con la sección Actuar con IA del sitio.
10

Buenas prácticas y gobierno de modelos

01 · Control de versiones

Git desde el primer día

Guarda código, no resultados: el repositorio contiene scripts, documentación y pruebas; los datos sensibles se quedan fuera (archivo .gitignore). Cada cambio relevante va en un commit con mensaje claro, y los cambios de método se revisan por otra persona antes de integrarse. El historial responde quién cambió qué y cuándo, la primera pregunta de cualquier auditoría.

02 · Pruebas

Casos con respuesta conocida

Un modelo actuarial tiene pruebas naturales: reproducir el triángulo RAA de Mack, la identidad Ax = 1 - d·äx, una reserva calculada a mano para una sola póliza o la media teórica de una simulación. Automatízalas con pytest o testthat para que corran en cada cambio. Las recetas de esta página incluyen ese tipo de controles.

03 · Documentación

Que otro actuario pueda evaluarlo

Propósito del modelo, fuentes de datos y su calidad, supuestos con su justificación, método, limitaciones conocidas, pruebas realizadas y versión del software. Es lo que pide el ASOP 56 en su sección de documentación y lo que el ASOP 23 exige sobre calidad de datos. Quarto, R Markdown o cuadernos de Jupyter permiten mezclar código, resultados y texto en un solo documento.

04 · Gobierno de modelos

Controles proporcionales al riesgo

Inventario de modelos, responsables, validación independiente, control de accesos y de cambios, y revisión periódica de supuestos. El ASOP 56 trae ejemplos en su apéndice y el ISAP 1A de la IAA los recoge a nivel internacional. En México, la función actuarial y el área de administración integral de riesgos que exige la LISF son los dueños naturales de ese gobierno.

Semillas sin registrar

Una simulación sin semilla fija no se puede reproducir ni auditar. Registra la semilla, el generador y el número de escenarios, y reporta el error de Monte Carlo.

Copiar código sin entenderlo

Un paquete o un fragmento generado por IA puede correr sin errores y estar mal aplicado. Valida contra un caso conocido antes de usarlo en un cierre.

11

Preguntas frecuentes

¿Necesito saber programar para ser actuario en México?
No es un requisito formal de la CNSF ni del CONAC, pero en la práctica casi todas las áreas técnicas usan R, Python o SQL para reservas, tarificación y valuaciones. Saber programar permite revisar y reproducir cálculos que en una hoja de cálculo quedan ocultos en celdas, y facilita documentar el modelo como piden los estándares de práctica.
¿R o Python para empezar?
Si tu meta inmediata es reservas, estadística aplicada y exámenes con contenido de modelos lineales, R tiene paquetes actuariales maduros como ChainLadder y actuar. Si buscas integrarte con equipos de datos o automatizar procesos, Python ofrece chainladder del CAS, statsmodels y scikit-learn. Las dos rutas son válidas; lo importante es aprender control de versiones y pruebas desde el principio.
¿Puedo usar estos paquetes en un trabajo regulado ante la CNSF?
Sí, siempre que el actuario responsable entienda el método, valide los resultados y documente supuestos, datos y limitaciones. Un paquete de código abierto no sustituye el juicio profesional: es una herramienta cuya elección y uso también deben quedar documentados, igual que se haría con un modelo comercial.
¿Por qué el error estándar de Mack del triángulo RAA aparece como 26,881 y en otros textos como 26,909?
La diferencia está en cómo se extrapola la volatilidad del último periodo de desarrollo, que no se puede estimar con los datos. ChainLadder en R y chainladder en Python usan por omisión una extrapolación log lineal y dan 26,881; con la aproximación original de Mack (opción est.sigma = "Mack" en R) el total es 26,909.
¿Qué hago si un paquete deja de mantenerse?
Revisa la fecha de la última versión y la actividad del repositorio, como hicimos en el catálogo. Si el paquete es estable y su método no cambia, puede seguir siendo útil, pero fija su versión en tu entorno, guarda una copia del código fuente y documenta el riesgo. Si es crítico para un proceso regulado, considera un plan de sustitución.
¿Estas recetas sirven para estudiar exámenes de la SOA o del CAS?
Ayudan a entender los métodos, porque permiten reproducir ejemplos clásicos como el triángulo RAA o los valores del modelo de supervivencia estándar usado en textos de matemáticas actuariales. Los exámenes de opción múltiple no se resuelven con código, pero programar los cálculos fija la intuición y detecta errores de concepto.
12

Para profundizar

AnteriorDatos abiertos para actuariosSiguienteVideoteca actuarial