<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Class 12
Step1:  Computers by definition cannot generate truly random numbers. The Mersenne Twister is a widely-used algorithm for generating pseudo random numbers form a deterministic process. That is, while the numbers generated from the algorithm are not random in the literal sense, they exhibit distributional qualities that make them indistinguishable from truly random numbers.
A nice feature of pseudo random numbers is that they can be replicated by specifying the seed, or starting point, for the random number generating algorithm.
Step2:  Example
Draw 500 values each from the $\mathcal{N}(0,1)$ and $\mathcal{N}(0,2^2)$ distributions. Plot.
Step3:  The white noise process
In the previous example, we created two variables that stored draws from normal distrbutions with means of zero but with different standard deviations. Both of the variables were simulations of whit noise processes. A white noise process is a random variable $\epsilon_t$ with constant mean and constant variance. We are concerned only with zero-mean white noise process and we'll often denote that a variable is a zero-mean white noise process with the following shorthand notation
Step4:  Example
Simulate an AR(1) process for 51 periods using the following parameter values
Step5:  Notice that if $-1< \rho < 1$, then $\mu$ is the expected value of the process. That is, when $-1< \rho < 1$, the process will fluctuate around $\mu$. But if $\rho>1$ or $\rho<-1$, the process will explode away from $\mu$.
Step6:  Example
Construct a $2\times2$ grid of AR(1) processes simulated for 51 periods with $\sigma = 1$ and $\mu = 0$.
Use the following values for $\rho$
Step7:  The random walk process
The random walk process is an AR(1) process with $\rho=1$
<ASSISTANT_TASK:>
Python Code:
# Create an array with 5 draws from the normal(0,1) distribution and print
np.random.normal(size=5)
# Create an array with 5 draws from the normal(0,1) distribution and print
np.random.normal(size=5)
Explanation: Class 12: Stochastic Time Series Processes
Simulating normal random variables with Numpy
The numpy.random module has bunch of functions for generating random variables and evaluating probability and cumulative density functions for a wide variety of probability distributions. Learn more about the module here:
https://docs.scipy.org/doc/numpy/reference/routines.random.html
We're going to make use of the numpy.random.normal() function to crate arrays of random draws from the normal distribution. The function takes three arguments:
* loc: the mean of the distribution (default=0)
* scale: the standard deviation of the distribution (default=1)
* size: how many to numbers to draw (default = None)
Evidently the default is to draw numbers from the standard normal distribution.
End of explanation
# Set the seed for the random number generator
np.random.seed(129)
# Create an array with 5 draws from the normal(0,1) distribution and print
np.random.normal(size=5)
Explanation: Computers by definition cannot generate truly random numbers. The Mersenne Twister is a widely-used algorithm for generating pseudo random numbers form a deterministic process. That is, while the numbers generated from the algorithm are not random in the literal sense, they exhibit distributional qualities that make them indistinguishable from truly random numbers.
A nice feature of pseudo random numbers is that they can be replicated by specifying the seed, or starting point, for the random number generating algorithm.
End of explanation
# Set the seed for the random number generator
np.random.seed(129)
# Create two arrays:
#     x: 500 draws from the normal(0,1) distribution
#     y: 500 draws from the normal(0,2) distribution
x = np.random.normal(loc=0,scale=1,size=500)
y = np.random.normal(loc=0,scale=2,size=500)
# Plot
plt.plot(x,lw=3,alpha = 0.6,label='$\sigma=1$')
plt.plot(y,lw=3,alpha = 0.6,label='$\sigma=2$')
plt.grid(linestyle=':')
plt.legend(ncol=2,loc='lower right')
Explanation: Example
Draw 500 values each from the $\mathcal{N}(0,1)$ and $\mathcal{N}(0,2^2)$ distributions. Plot.
End of explanation
# Simulate an AR(1) process for 51 periods. Set the RNG seed to 129
np.random.seed(129)
T = 51
x0=0
mu=1
rho=0.5
sigma=1
x = np.zeros(T)
x[0] = x0
# draw random numbers for white noise process
eps= np.random.normal(loc=0,scale=sigma,size=T-1)
for t in range(T-1):
    x[t+1] = mu*(1-rho) + rho*x[t] + eps[t]
    
# Plot
plt.plot(x,lw=3,alpha = 0.6,label='$\sigma=1$')
plt.grid(linestyle=':')
Explanation: The white noise process
In the previous example, we created two variables that stored draws from normal distrbutions with means of zero but with different standard deviations. Both of the variables were simulations of whit noise processes. A white noise process is a random variable $\epsilon_t$ with constant mean and constant variance. We are concerned only with zero-mean white noise process and we'll often denote that a variable is a zero-mean white noise process with the following shorthand notation:
\begin{align}
\epsilon_t & \sim \text{WN}(0,\sigma^2),
\end{align}
where $\sigma^2$ is the variance of the processes. Strictly speaking, a white noise process can follow any distribution as long as the mean and and variance are constant, but we'll concentrate exclusively white noise process drawn from the normal distribution.
The AR(1) process
A random variable $X_t$ is an autoregressive of order 1 process or AR(1) process if it can be written in the following form:
\begin{align}
X_t & (1+\rho)\mu + \rho X_{t+1} + \epsilon_t,
\end{align}
where $\rho$ and $\mu$ are constants and $\epsilon \sim \text{WN}(0,\sigma^2)$. The AR(1) process is the stochastic analog of the first-order difference equation.
Example
Simulate an AR(1) process for 51 periods using the following parameter values:
\begin{align}
\rho & = 0.5\
\mu & = 1 \
\sigma &  = 1
\end{align}
End of explanation
# Simulate an AR(1) process for 51 periods. Set the RNG seed to 129
np.random.seed(129)
T = 51
x0=0
mu=1
rho=1.5
sigma=1
import time
 
# Wait for 5 seconds
x = np.zeros(T)
x[:] = np.NAN
x[0] = x0
# draw random numbers for white noise process
eps= np.random.normal(loc=0,scale=sigma,size=T-1)
for t in range(T-1):
    x[t+1] = mu*(1-rho) + rho*x[t] + eps[t]
    
# Plot
plt.plot(x,lw=3,alpha = 0.6,label='$\sigma=1$')
plt.grid(linestyle=':')
Explanation: Example
Simulate an AR(1) process for 51 periods using the following parameter values:
\begin{align}
\rho & = 1.5\
\mu & = 1 \
\sigma &  = 1
\end{align}
End of explanation
def ar1(mu=0,rho=0,sigma=1,x0=0,T=25):
    '''Funciton for simulating an AR(1) process for T periods
    
            Args:
            mu (float):    mean of the AR(1) process
            rho (float):   autoregressive parameter
            sigma (float): standard deviation of the white noise process
            x0 (float):    initial value of the process
            T (int):       number of periods to simulate
            
        Returns:
            numpy array
    '''
    
    # initialize x array
    x = np.zeros(T)
    x[0] = x0
    
    # draw random numbers for white noise process
    eps= np.random.normal(loc=0,scale=sigma,size=T-1)
    for t in range(T-1):
        x[t+1] = mu*(1-rho) + rho*x[t] + eps[t]
    
    return x
Explanation: Notice that if $-1< \rho < 1$, then $\mu$ is the expected value of the process. That is, when $-1< \rho < 1$, the process will fluctuate around $\mu$. But if $\rho>1$ or $\rho<-1$, the process will explode away from $\mu$.
End of explanation
fig = plt.figure(figsize=(12,8))
np.random.seed(129)
y = ar1(mu=0,rho=0,sigma=1,x0=0,T=51)
ax1 = fig.add_subplot(2,2,1)
ax1.plot(y,lw=3,alpha=0.7)
ax1.set_title('$X_t = \epsilon_t$')
ax1.grid()
np.random.seed(129)
y = ar1(mu=0,rho=0,sigma=1,x0=0,T=51)
ax2 = fig.add_subplot(2,2,2)
ax2.plot(y,lw=3,alpha=0.7)
ax2.set_title('$X_t = 0.5\cdot X_{t-1} + \epsilon_t$')
ax2.grid()
np.random.seed(129)
y = ar1(mu=0,rho=0.9,sigma=1,x0=0,T=51)
ax3 = fig.add_subplot(2,2,3)
ax3.plot(y,lw=3,alpha=0.7)
ax3.set_title('$X_t = 0.9\cdot X_{t-1} + \epsilon_t$')
ax3.grid()
np.random.seed(129)
y = ar1(mu=0,rho=-0.5,sigma=1,x0=0,T=51)
ax4 = fig.add_subplot(2,2,4)
ax4.plot(y,lw=3,alpha=0.7)
ax4.set_title('$X_t = -0.5\cdot X_{t-1} + \epsilon_t$')
ax4.grid()
Explanation: Example
Construct a $2\times2$ grid of AR(1) processes simulated for 51 periods with $\sigma = 1$ and $\mu = 0$.
Use the following values for $\rho$:
* Top-left: $\rho=0$
* Top-right: $\rho=0.5$
* lower-left: $\rho=0.9$
* lower-left: $\rho=-0.5$
Be sure to use the same seed for each simulation so you can see how changing $\rho$ affects the output
End of explanation
np.random.seed(129)
for i in range(7):
    plt.plot(ar1(rho=1,T=501))
    
plt.grid()
plt.title('Five random walk processes')
Explanation: The random walk process
The random walk process is an AR(1) process with $\rho=1$:
\begin{align}
X_t = X_{t-1} + \epsilon_t
\end{align}
The random walk process has an important place in finance since the evidence suggests that stock prices follow a random walk process.
Example
Simulate 7 random walk processes for 501 periods. Set $\sigma = 1$. Plot all 7 simulated processes on the same axes.
End of explanation
<END_TASK>