Skip to content

Commit

Permalink
Validaciones funcionan
Browse files Browse the repository at this point in the history
  • Loading branch information
julienmalard committed Nov 15, 2019
1 parent 55d9819 commit 4e15d80
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 168 deletions.
Empty file.
45 changes: 45 additions & 0 deletions pruebas/test_central/rcrs/modelo_valid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import numpy as np
import pandas as pd
import xarray as xr
from tikon.central import Módulo, SimulMódulo, Modelo, Exper, Parcela
from tikon.central.res import Resultado
from tikon.result import Obs
from tikon.utils import EJE_TIEMPO, EJE_PARC

f_inic = '2000-01-01'

crds = {'eje 1': ['a', 'b'], 'eje 2': ['x', 'y', 'z']}


class Res(Resultado):

def __init__(símismo, sim, coords, vars_interés):
coords = {**crds, **coords}
super().__init__(sim, coords, vars_interés)

nombre = 'res'
unids = None


class SimulMóduloValid(SimulMódulo):
resultados = [Res]

def incrementar(símismo, paso, f):
super().incrementar(paso, f)
símismo.poner_valor('res', 1, rel=True)


class MóduloValid(Módulo):
nombre = 'módulo'
cls_simul = SimulMóduloValid


obs = Obs(
mód='módulo', var='res', datos=xr.DataArray(
np.arange(10),
coords={EJE_TIEMPO: pd.date_range(f_inic, periods=10, freq='D')}, dims=[EJE_TIEMPO]
).expand_dims(crds).expand_dims({EJE_PARC: ['parcela']})
)

exper = Exper('exper', Parcela('parcela'), obs=obs)
modelo = Modelo(MóduloValid)
4 changes: 4 additions & 0 deletions pruebas/test_central/test_modelo_calib.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
class PruebaCalib(unittest.TestCase):
@unittest.skip('implementar')
def test_calib(símismo):
modelo.calibrar()

@unittest.skip('implementar')
def test_calib_paráms_mód(símismo):
pass
25 changes: 23 additions & 2 deletions pruebas/test_central/test_modelo_valid.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
import unittest

from tikon.result import proc

from .rcrs.modelo_valid import modelo, exper


class PruebaValid(unittest.TestCase):
@unittest.skip('implementar')
@classmethod
def setUpClass(cls):
cls.res = modelo.simular('valid', exper)

def test_valid(símismo):
pass
valid = símismo.res.validar()
símismo.assertDictEqual(valid.criterios, {'ens': 1.0})

def test_criterios(símismo):
crits = [
proc.r2, proc.rcep, proc.rcnep, proc.corresp, proc.ekg, proc.log_p,
proc.r2_percentiles, proc.rcnep_percentiles
]
valids = símismo.res.validar(proc=crits)
símismo.assertSetEqual(set(valids.criterios), {cr.__name__ for cr in crits})

def test_nombres_criterios(símismo):
crits = {'R cuadrado': proc.r2, 'otro nombre': proc.rcep}
valids = símismo.res.validar(proc=crits)
símismo.assertSetEqual(set(valids.criterios), set(crits))
2 changes: 2 additions & 0 deletions tikon/central/datos.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def obt_obs(símismo, mód, var):
mód, var = str(mód), str(var)
if mód in símismo:
return símismo[mód].obt_obs(var)
return []

def obt_inic(símismo, mód, var, índs):
mód, var = str(mód), str(var)
Expand Down Expand Up @@ -83,6 +84,7 @@ def espec_inic(símismo, dist, var, índs=None):
def obt_obs(símismo, var):
if var in símismo:
return símismo[var].obs
return []

def obt_inic(símismo, var, índs):
if var in símismo:
Expand Down
44 changes: 19 additions & 25 deletions tikon/central/res.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from tikon.central.errores import ErrorNombreInválido
from tikon.central.simul import PlantillaSimul
from tikon.result.dibs import graficar_res
from tikon.result.valid import reps_necesarias
from tikon.result.valid import ValidÍnds, ValidRes
from tikon.utils import proc_líms, EJE_PARÁMS, EJE_ESTOC, EJE_TIEMPO


Expand All @@ -26,7 +26,8 @@ def __init__(símismo, sim, coords, vars_interés):
símismo.nombre, sim.mód.nombre, símismo.obs, vars_interés
) else None

símismo.datos_t = _gen_datos(coords, t=símismo.t)
símismo.datos_t = _gen_datos(símismo.nombre, coords, t=símismo.t)
símismo.datos_t.attrs['unids'] = símismo.unids
símismo._datos = símismo.datos_t[{EJE_TIEMPO: 0}] # Crear enlace dinámico entre resultados diarios y temporales

super().__init__(símismo.nombre, subs=[])
Expand Down Expand Up @@ -71,25 +72,21 @@ def verificar_estado(símismo):
raise ValueError('{res}: Valor no numérico (p. ej., división por 0)'.format(res=símismo))

def validar(símismo, proc):
if símismo.obs is not None:
obs_corresp = símismo.obs.interp_like(símismo.datos_t)

l_proc = []
pesos = []
d_valid = {}
for índs in símismo.iter_índs(símismo.obs, excluir=EJE_TIEMPO):
l_proc = []
for obs in símismo.obs:
datos_corresp = símismo.datos_t.interp_like(obs.datos).dropna(EJE_TIEMPO)
obs_corresp = obs.datos.loc[{EJE_TIEMPO: datos_corresp[EJE_TIEMPO]}]

l_llaves = list(str(ll) for ll in índs.values())

dic = d_valid
for ll in l_llaves[:-1]:
if ll not in dic:
dic[ll] = {}
dic = dic[ll]

dic[l_llaves[-1]] = proc.f_vals(símismo.datos_t.loc[índs], obs_corresp.loc[índs])
for índs in símismo.iter_índs(obs.datos, excluir=EJE_TIEMPO):
datos_índs = datos_corresp.loc[índs]
obs_índs = obs_corresp.loc[índs]
l_proc.append(
ValidÍnds(
criterios=proc.calc(obs_índs, datos_índs), peso=proc.pesos(obs_índs)
)
)

return d_valid
return ValidRes(l_proc, proc=proc)

def procesar_calib(símismo, proc):

Expand Down Expand Up @@ -120,9 +117,6 @@ def graficar(símismo, directorio='', argsll=None):
simulado=símismo.datos_t.loc[índs], obs=obs_índs, **argsll
)

def reps_necesarias(símismo, frac_incert=0.95, confianza=0.95):
return reps_necesarias(símismo.datos_t, frac_incert=frac_incert, confianza=confianza)

def a_dic(símismo):
if símismo.t is not None:
return {
Expand Down Expand Up @@ -157,11 +151,11 @@ def _res_temporal(nombre, nombre_sim, obs, vars_interés):
return vars_interés

if vars_interés is None:
return obs is not None
return len(obs) > 0

return nombre_sim in vars_interés or nombre_sim + '.' + nombre in vars_interés


def _gen_datos(coords, t):
def _gen_datos(nombre, coords, t):
coords = {EJE_TIEMPO: t.eje if t is not None else [0], **coords}
return xr.DataArray(data=0., coords=coords, dims=list(coords))
return xr.DataArray(data=0., coords=coords, dims=list(coords), name=nombre)
12 changes: 7 additions & 5 deletions tikon/central/simul.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from tikon.central.errores import ErrorRequísitos, ErrorNombreInválido
from tikon.central.exper import Exper
from tikon.central.utils import gen_coords_base
from tikon.result.proc import ens
from tikon.result.valid import Valid, gen_proc_valid


class PlantillaSimul(object):
Expand Down Expand Up @@ -31,12 +33,8 @@ def verificar_estado(símismo):
for s in símismo:
símismo[s].verificar_estado()

def reps_necesarias(símismo, frac_incert=0.95, confianza=0.95):
return {s: símismo[s].reps_necesarias(frac_incert, confianza) for s in símismo}

def validar(símismo, proc):
valid = {s: símismo[s].validar(proc=proc) for s in símismo}
return {ll: v for ll, v in valid.items() if v}
return Valid({s: símismo[s].validar(proc=proc) for s in símismo}, proc=proc)

def procesar_calib(símismo, proc):
vals, pesos = zip(*[s.procesar_calib(proc) for s in símismo])
Expand Down Expand Up @@ -120,6 +118,10 @@ def correr_exp(exp):
if errores:
raise ChildProcessError('Hubo error en los módulos siguientes: {móds}'.format(móds=', '.join(errores)))

def validar(símismo, proc=ens):
proc = gen_proc_valid(proc)
return super().validar(proc=proc)

def procesar_calib(símismo, proc):
return super().procesar_calib(proc)[0]

Expand Down
53 changes: 31 additions & 22 deletions tikon/calibrador/proc.py → tikon/result/proc.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import numpy as np
import spotpy.objectivefunctions as of
import xarray as xr
from spotpy.likelihoods import gaussianLikelihoodMeasErrorOut
from tikon.result import EJE_ESTOC, EJE_PARÁMS


# Funciones pesos
from tikon.utils import EJE_PARÁMS, EJE_ESTOC


def n_existen(x):
return np.isfinite(x).sum(dim='tiempo').values.item()


# Funciones vals
# Funciones criterios
def ens(o, s):
return of.nashsutcliffe(o.values, s.mean(dim=(EJE_PARÁMS, EJE_ESTOC)).values)

Expand Down Expand Up @@ -42,6 +44,28 @@ def verosimil_gaus(o, s):
return gaussianLikelihoodMeasErrorOut(o.values, s.mean(dim=(EJE_PARÁMS, EJE_ESTOC)).values)


# Funciones criterios incertidumbre
def r2_percentiles(o, s):
conf = _calc_conf(o, s)
return of.rsquared(conf, _calc_cent(o))


def rcnep_percentiles(o, s):
conf = _calc_conf(o, s)
return of.rrmse(conf, _calc_cent(o))


def _calc_cent(o):
return np.arange(1, len(o) + 1) / len(o)


def _calc_conf(o, s):
perc = (s <= o).mean(dim=[EJE_ESTOC, EJE_PARÁMS]).values
conf = np.abs(0.5 - perc) * 2
conf.sort()
return conf


# Funciones combin vals
def prom_vals(vals, pesos):
return np.average(vals, weights=pesos)
Expand All @@ -54,22 +78,7 @@ def suma_pesos(pesos):

class Procesador(object):
def __init__(símismo, f_vals=ens, f_pesos=n_existen, f_combin=prom_vals, f_combin_pesos=suma_pesos):
símismo.f_vals = f_vals
símismo.f_pesos = f_pesos
símismo.f_combin = f_combin
símismo.f_combin_pesos = f_combin_pesos


class ProcesadorValids(Procesador):
def __init__(símismo, f_vals=ens, f_pesos=n_existen, f_combin=prom_vals, f_combin_pesos=suma_pesos):
if callable(f_vals):
f_vals = [f_vals]
if isinstance(f_vals, list):
f_vals = {f.__name__: f for f in f_vals}

def f_final_vals(o, s):
return {ll: v(o, s) for ll, v in f_vals.items()}

def f_final_combin()

super().__init__(f_final_vals, f_pesos, f_combin, f_combin_pesos)
símismo.calc = f_vals
símismo.pesos = f_pesos
símismo.combin = f_combin
símismo.combin_pesos = f_combin_pesos
Loading

0 comments on commit 4e15d80

Please sign in to comment.