<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 The Model
Suppose we put forth a new hypothesis that makes use of more independent variables
Step1:  Further Assumptions Of The Least Squares Model
For our model to be reasonable, it requires a couple of assumptions
Step2:  Above does not match the book, could not get code to work as shown.
Digression
<ASSISTANT_TASK:>
Python Code:
def predict(x_i, beta):
    return dot(x_i, beta)
Explanation: The Model
Suppose we put forth a new hypothesis that makes use of more independent variables:
$$minutes = \alpha + \beta_1 friends + \beta_2 work\ hours + \beta_3 phd + \epsilon$$
In multiple regression, we can denote a vector or parameters as $\beta$. Then we use vectors for x and beta:
beta = [alpha, beta_1, ..., beta_k]
x_i = [1, x_i1, ..., x_ik]
beta = [ 0.9,
         0.7,
         0.8,
         0.6]
x = [1, # constant term,
     49, # number of friends
     4, # work hours per day
     0] # does not have a PhD
In Simple Linear Regression, our model was:
 $$y_i = \alpha + \beta x_i + \epsilon_i$$
 In a multiple regression we will use:
 $$y_i = \alpha + \beta_1 x_{i1} + ... + \beta_k x_{ik} + \epsilon_i$$
End of explanation
def error(x_i, y_i, beta):
    return y_i - predict(x_i, beta)
def squared_error(x_i, y_i, beta):
    return error(x_i, y_i, beta)**2
def squared_error_gradient(x_i, y_i, beta):
    return [-2 * x_ij * error(x_i, y_i, beta) for x_ij in x_i]
def estimate_beta(x, y):
    beta_initial = [random.random() for x_i in x[0]]
    return minimize_stochastic(squared_error, squared_error_gradient, x, y, beta_initial, 0.001)
x = [1, # constant term,
     49, # number of friends
     4, # work hours per day
     0] # does not have a PhD
random.seed(0)
beta = estimate_beta([x], daily_minutes_clean)
beta
Explanation: Further Assumptions Of The Least Squares Model
For our model to be reasonable, it requires a couple of assumptions:
- Columns of x are linearly independent. If this is not true, it will be impossible to estimate beta.
- Columns of x are all uncorrelated with the errors $\epsilon$.
Fitting The Model
Here as well we choose beta in order to minimize the sum of squared errors. Gradient descent will be used to do this.
End of explanation
def bootstrap_sample(data):
    return [random.choice(data) for _ in data]
def bootstrap_statistic(data, stats_fn, num_samples):
    return [stats_fn(bootstrap_sample(data)) for _ in range(num_samples)]
close_to_100 = [99.5 + random.random() for _ in range(101)]
far_from_100 = ([99.5 + random.random()] +
                [random.random() for _ in range(50)] +
                [200 + random.random() for _ in range(50)])
bootstrap_statistic(close_to_100, median, 100)[:5]
bootstrap_statistic(far_from_100, median, 100)[:5]
standard_deviation(close_to_100), standard_deviation(far_from_100)
Explanation: Above does not match the book, could not get code to work as shown.
Digression: The Bootstrap
Suppose we have a sample of n number of points and we want to estimate the median but we don't know the distribution. To estimate in this scenario, we can bootstrap new samples from which to generate our estimate in order to increase confidence. We will choose n new data points with replacement and then computer the medians of those generated samples.
End of explanation
<END_TASK>