Solutions for http://quant-econ.net/py/numpy.html
Tell the notebook to display figures embedded in the browser:
In [4]:
%matplotlib inline
Import numpy and some plotting functionality:
In [5]:
import numpy as np
import matplotlib.pyplot as plt
This code does the job
In [6]:
def p(x, coef):
X = np.empty(len(coef))
X[0] = 1
X[1:] = x
y = np.cumprod(X) # y = [1, x, x**2,...]
return np.dot(coef, y)
Let's test it
In [7]:
coef = np.ones(3)
print(coef)
print(p(1, coef))
# For comparison
q = np.poly1d(coef)
print(q(1))
Here's our first pass at a solution:
In [8]:
from numpy import cumsum
from numpy.random import uniform
class discreteRV:
"""
Generates an array of draws from a discrete random variable with vector of
probabilities given by q.
"""
def __init__(self, q):
"""
The argument q is a NumPy array, or array like, nonnegative and sums
to 1
"""
self.q = q
self.Q = cumsum(q)
def draw(self, k=1):
"""
Returns k draws from q. For each such draw, the value i is returned
with probability q[i].
"""
return self.Q.searchsorted(uniform(0, 1, size=k))
The logic is not obvious, but if you take your time and read it slowly, you will understand
There is a problem here, however
Suppose that q
is altered after an instance of discreteRV
is created, for example by
In [9]:
q = (0.1, 0.9)
d = discreteRV(q)
d.q = (0.5, 0.5)
The problem is that Q
does not change accordingly, and Q
is the data used in the draw
method
To deal with this, one option is to compute Q
every time the draw method is called
But this is inefficient relative to computing Q
once off
A better option is to use descriptors
A solution from the quantecon library using descriptors that behaves as we desire can be found here
In [10]:
"""
Modifies ecdf.py from QuantEcon to add in a plot method
"""
import numpy as np
import matplotlib.pyplot as plt
class ECDF(object):
"""
One-dimensional empirical distribution function given a vector of
observations.
Parameters
----------
observations : array_like
An array of observations
Attributes
----------
observations : array_like
An array of observations
"""
def __init__(self, observations):
self.observations = np.asarray(observations)
def __call__(self, x):
"""
Evaluates the ecdf at x
Parameters
----------
x : scalar(float)
The x at which the ecdf is evaluated
Returns
-------
scalar(float)
Fraction of the sample less than x
"""
return np.mean(self.observations <= x)
def plot(self, a=None, b=None):
"""
Plot the ecdf on the interval [a, b].
Parameters
----------
a : scalar(float), optional(default=None)
Lower end point of the plot interval
b : scalar(float), optional(default=None)
Upper end point of the plot interval
"""
# === choose reasonable interval if [a, b] not specified === #
if a is None:
a = self.observations.min() - self.observations.std()
if b is None:
b = self.observations.max() + self.observations.std()
# === generate plot === #
x_vals = np.linspace(a, b, num=100)
f = np.vectorize(self.__call__)
plt.plot(x_vals, f(x_vals))
plt.show()
Here's an example of usage
In [11]:
X = np.random.randn(1000)
F = ECDF(X)
F.plot()
In [ ]: