Source code for scores.generic
# -*- coding: utf-8 -*-
"""
Created on 19 juin 2018
@author: cluzetb, adapted from R. Champavier Talagrand_rank class
"""
import random
import numpy as np
[docs]
def rankDiagram(ens, observations, isSorted = False, nbins = 36, printrank=False, param=None, titreFig=None, pathFig=None):
"""
@author : B. Cluzet, june 2018
generic CRPS computation from Cluzet first version, Lafaysse and Champavier talagrand function
Champavier code would be a good source of inspiration for optimisation through pandas (avoiding the for loop)
@params : ens : Nens x NDate matrix (np.array)
obs : NDate vector
/!\
- same dates for ens and obs
- the user should adapt ens and obs beforehand to make it directly comparable
- convention : nan value when a member is not defined
- obs: no nan
- ens not necessarily sorted
- nbins better <= NMembers +1 ???
"""
random.seed()
if not isSorted:
# pour chaque date, on trie les membres
ens = np.sort(ens, axis=0)
nbMembres = ens.shape[0] # Nb total membres (définis ou non)
fact = float(nbins) / float(nbMembres + 1)
rank = np.zeros(nbins)
for iDate, obs in enumerate(observations): # loop over obs (dates)
ensDate = np.ma.masked_invalid(ens[:, iDate])
obsDate = np.ma.masked_invalid(obs)
# mask membres that have nan values for this date and count them
nEnsDate = np.ma.count(ensDate) # Nb total membres définis à cette date
nObsDate = np.ma.count(obsDate)
if nEnsDate > 0 and nObsDate > 0:
# Matthieu :
# P : n° de la prévision auquelle l'obs est directement inférieure
# on gère le cas où plusieurs membres ont la même valeur que l'obs (0 le + souvent)
# Dans ce cas on attribue une position aléatoire entre les positions PL et PR
# sinon PR=PL+1 donc Randint n'a qu'une possibilité
PL = np.searchsorted(ensDate, obsDate, side="left") + 1
PR = np.searchsorted(ensDate, obsDate, side="right") + 1
P = random.randint(PL, PR)
# Conversion d'unité
BIN = int(round(P * fact))
if P == 1:
rank[0] += 1.
elif P == nEnsDate + 1:
rank[nbins - 1] += 1.
else:
if nEnsDate == nbMembres:
rank[BIN - 1] += 1.
else: # on convertit l'histogramme de résolution nEnsDate en résolution nbMembres
BIN = int(round(float(nbMembres / nEnsDate) * P * fact))
rank[BIN - 1] += 1.
if np.sum(rank) > 0.:
frequency = rank / float(np.sum(rank))
else:
frequency = rank
return frequency, np.sum(rank)