Source code for cde.density_simulation.EconDensity

import scipy.stats as stats
import numpy as np
from .BaseConditionalDensitySimulation import BaseConditionalDensitySimulation
from scipy.stats import norm

[docs]class EconDensity(BaseConditionalDensitySimulation): """ A simple, economically inspired distribution with the data generation process x = |N(0,1)| y = x^2 + N(0,base_std) Args: std: standard deviation of the Gaussian noise in y heteroscedastic: boolean indicating whether base_std is fixed or a function of x random_seed: seed for the random_number generator """ def __init__(self, std=1, heteroscedastic=True, random_seed=None): assert std > 0 self.heteroscedastic = heteroscedastic self.random_state = np.random.RandomState(seed=random_seed) self.random_seed = random_seed self.std = std self.ndim_x = 1 self.ndim_y = 1 self.ndim = self.ndim_x + self.ndim_y # approximate data statistics self.y_mean, self.y_std = self._compute_data_statistics() self.has_cdf = True self.has_pdf = True self.can_sample = True
[docs] def pdf(self, X, Y): """ Conditional probability density function p(y|x) of the underlying probability model Args: X: x to be conditioned on - numpy array of shape (n_points, ndim_x) Y: y target values for witch the pdf shall be evaluated - numpy array of shape (n_points, ndim_y) Returns: p(X|Y) conditional density values for the provided X and Y - numpy array of shape (n_points, ) """ X, Y = self._handle_input_dimensionality(X, Y) mean = X**2 return np.where(X<0, 0, stats.norm.pdf((Y-mean)/self._std(X))) / self._std(X)
[docs] def cdf(self, X, Y): """ Conditional cumulated probability density function P(Y < y | x) of the underlying probability model Args: X: x to be conditioned on - numpy array of shape (n_points, ndim_x) Y: y target values for witch the cdf shall be evaluated - numpy array of shape (n_points, ndim_y) Returns: P(Y < y | x) cumulated density values for the provided X and Y - numpy array of shape (n_points, ) """ X, Y = self._handle_input_dimensionality(X, Y) mean = X ** 2 return np.where(X<0, 0, stats.norm.cdf((Y-mean)/self._std(X)))
[docs] def simulate_conditional(self, X): """ Draws random samples from the conditional distribution Args: X: x to be conditioned on when drawing a sample from y ~ p(y|x) - numpy array of shape (n_samples, ndim_x) Returns: Conditional random samples y drawn from p(y|x) - numpy array of shape (n_samples, ndim_y) """ if X.ndim == 2 and X.shape[1]: X = X.flatten() assert X.ndim == 1 n_samples = X.shape[0] Y = X ** 2 + self._std(X) * self.random_state.normal(size=n_samples) X = np.expand_dims(X, axis=1) Y = np.expand_dims(Y, axis=1) return X, Y
[docs] def simulate(self, n_samples=1000): """ Draws random samples from the joint distribution p(x,y) Args: n_samples: (int) number of samples to be drawn from the joint distribution Returns: (X,Y) - random samples drawn from p(x,y) - numpy arrays of shape (n_samples, ndim_x) and (n_samples, ndim_y) """ assert n_samples > 0 X = np.abs(self.random_state.standard_normal(size=[n_samples])) Y = X ** 2 + self._std(X) * self.random_state.normal(size=n_samples) X, Y = X.reshape((n_samples, self.ndim_x)), Y.reshape((n_samples, self.ndim_y)) return X, Y
[docs] def mean_(self, x_cond, n_samples=None): """ Conditional mean of the distribution Args: x_cond: different x values to condition on - numpy array of shape (n_values, ndim_x) Returns: Means E[y|x] corresponding to x_cond - numpy array of shape (n_values, ndim_y) """ assert x_cond.ndim == 2 and x_cond.shape[1] == self.ndim_x return x_cond**2
[docs] def std_(self, x_cond, n_samples=None): """ Conditional mean of the distribution Args: x_cond: different x values to condition on - numpy array of shape (n_values, ndim_x) Returns: Means E[y|x] corresponding to x_cond - numpy array of shape (n_values, ndim_y) """ X = self._handle_input_dimensionality(x_cond) return x_cond**2
[docs] def covariance(self, x_cond, n_samples=None): """ Covariance of the distribution conditioned on x_cond Args: x_cond: different x values to condition on - numpy array of shape (n_values, ndim_x) Returns: Covariances Cov[y|x] corresponding to x_cond - numpy array of shape (n_values, ndim_y, ndim_y) """ assert x_cond.ndim == 2 and x_cond.shape[1] == self.ndim_x covs = self._std(x_cond) return covs.reshape((covs.shape[0],self.ndim_y, self.ndim_y))
[docs] def value_at_risk(self, x_cond, alpha=0.01, **kwargs): """ Computes the Value-at-Risk (VaR) of the fitted distribution. Only if ndim_y = 1 Args: x_cond: different x values to condition on - numpy array of shape (n_values, ndim_x) alpha: quantile percentage of the distribution Returns: VaR values for each x to condition on - numpy array of shape (n_values) """ assert self.ndim_y == 1, "Value at Risk can only be computed when ndim_y = 1" assert x_cond.ndim == 2 VaR = norm.ppf(alpha, loc=x_cond, scale=self._std(x_cond))[:,0] assert VaR.shape == (x_cond.shape[0],) return VaR
[docs] def conditional_value_at_risk(self, x_cond, alpha=0.01, **kwargs): """ Computes the Conditional Value-at-Risk (CVaR) / Expected Shortfall of the fitted distribution. Only if ndim_y = 1 Args: x_cond: different x values to condition on - numpy array of shape (n_values, ndim_x) alpha: quantile percentage of the distribution n_samples: number of samples for monte carlo model_fitting Returns: CVaR values for each x to condition on - numpy array of shape (n_values) """ assert self.ndim_y == 1, "Value at Risk can only be computed when ndim_y = 1" x_cond = self._handle_input_dimensionality(x_cond) assert x_cond.ndim == 2 mu = x_cond**2 sigma = self._std(x_cond) CVaR = (mu - sigma * (1/alpha) * norm.pdf(norm.ppf(alpha)))[:,0] assert CVaR.shape == (x_cond.shape[0],) return CVaR
[docs] def tail_risk_measures(self, x_cond, alpha=0.01, n_samples=10 ** 7): """ Computes the Value-at-Risk (VaR) and Conditional Value-at-Risk (CVaR) Args: x_cond: different x values to condition on - numpy array of shape (n_values, ndim_x) alpha: quantile percentage of the distribution n_samples: number of samples for monte carlo model_fitting Returns: - VaR values for each x to condition on - numpy array of shape (n_values) - CVaR values for each x to condition on - numpy array of shape (n_values) """ assert self.ndim_y == 1, "Value at Risk can only be computed when ndim_y = 1" assert x_cond.ndim == 2 VaRs = self.value_at_risk(x_cond, alpha=alpha, n_samples=n_samples) CVaRs = self.conditional_value_at_risk(x_cond, alpha=alpha, n_samples=n_samples) return VaRs, CVaRs
def _std(self, X): if self.heteroscedastic: std = self.std * (1 + X) else: std = self.std * np.ones(X.shape) return std def __str__(self): return "\nProbabilistic model type: {}\n std: {}\n n_dim_x: {}\n n_dim_y: {}\n".format(self.__class__.__name__, self.std, self.ndim_x, self.ndim_y) def __unicode__(self): return self.__str__()