Section 10.4 Estimation
The parameters
slope and intercept are estimates based on a sample. Like other estimates, they are vulnerable to non-representative sampling, measurement error, and variability due to random sampling. As usual, it’s hard to quantify the effect of non-representative sampling and measurement error. It’s easier to quantify the effect of random sampling.
One way to do that is a kind of resampling called bootstrapping: we’ll treat the sample as if it were the whole population and draw new samples, with replacement, from the observed data. The following function takes a
DataFrame and uses the sample method to resample the rows and return a new DataFrame.
def resample(df):
n = len(df)
return df.sample(n, replace=True)
And the following function takes a
DataFrame, finds the least squares fit, and returns the slope of the fitted line.
def estimate_slope(df):
xs, ys = df["Flipper Length (mm)"], df["Body Mass (g)"]
result = linregress(xs, ys)
return result.slope
We can use these functions to generate many simulated datasets and compute the slope for each one.
# Seed the random number generator so we get the same results every time
np.random.seed(1)
resampled_slopes = [estimate_slope(resample(adelie)) for i in range(1001)]
The result is a sample from the sampling distribution of the slope. Here’s what it looks like.
from thinkstats import plot_kde
plot_kde(resampled_slopes)
decorate(xlabel="Slope of the fitted line (g / mm)", ylabel="Density")

We can use
percentile to compute a 90% confidence interval.
$ ci90 = np.percentile(resampled_slopes, [5, 95])
print(result.slope, ci90)
32.83168975115009 [25.39604591 40.21054526]
So we could report that the estimated slope is 33 grams / mm with a 90% CI [25, 40] grams / mm.
The standard error of the estimate is the standard deviation of the sampling distribution.
$ stderr = np.std(resampled_slopes)
stderr
np.float64(4.570238986584832)
The
RegressionResult object we got from linregress provides an approximation of the standard error, based on some assumptions about the shape of the distribution.
$ result.stderr
np.float64(5.076138407990821)
The standard error we computed by resampling is a little smaller, but the difference probably doesn’t matter in practice.
