Lab

12.5.2. Lab#

  • Use this assignment to practice the chapter’s concepts and coding skills in runnable Python code.

  • Sign in from the account menu before you start working on the assignment.

  • Write and run your code directly in the coding cells.

  • Multiple submissions are allowed. The highest score is kept.

### Question 1: The Correlation Coefficient
# Marketing recorded weekly ad spend and sales for 8 weeks.
#   1. Write standard_units(x): (x - mean of x) / SD of x, using np.mean and np.std.
#   2. Compute r: the mean of the products of ad_spend and sales in standard units.
#   3. Print r rounded to 3 decimals.
# Print exactly:
# r: 0.972
import numpy as np
import pandas as pd

ads = pd.DataFrame({
    "ad_spend": [2, 3, 4, 5, 6, 7, 8, 9],          # $1,000s per week
    "sales": [60, 72, 70, 85, 88, 98, 95, 110],    # $1,000s per week
})
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
import numpy as np
import pandas as pd

ads = pd.DataFrame({
    "ad_spend": [2, 3, 4, 5, 6, 7, 8, 9],          # $1,000s per week
    "sales": [60, 72, 70, 85, 88, 98, 95, 110],    # $1,000s per week
})

def standard_units(x):
    return (x - np.mean(x)) / np.std(x)

r = np.mean(standard_units(ads['ad_spend']) * standard_units(ads['sales']))
print("r:", round(r, 3))
r: 0.972
### Question 2: The Regression Line
# Find the regression line for predicting sales from ad spend.
#   slope     = r * (SD of sales) / (SD of ad_spend)
#   intercept = (mean of sales) - slope * (mean of ad_spend)
#   1. Compute r, the slope, and the intercept (use np.std for SDs).
#   2. Print the slope and intercept rounded to 2 decimals.
# Print exactly:
# Slope: 6.57
# Intercept: 48.61
import numpy as np
import pandas as pd

ads = pd.DataFrame({
    "ad_spend": [2, 3, 4, 5, 6, 7, 8, 9],          # $1,000s per week
    "sales": [60, 72, 70, 85, 88, 98, 95, 110],    # $1,000s per week
})
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
import numpy as np
import pandas as pd

ads = pd.DataFrame({
    "ad_spend": [2, 3, 4, 5, 6, 7, 8, 9],          # $1,000s per week
    "sales": [60, 72, 70, 85, 88, 98, 95, 110],    # $1,000s per week
})

def standard_units(x):
    return (x - np.mean(x)) / np.std(x)

def correlation(x, y):
    return np.mean(standard_units(x) * standard_units(y))

def slope(x, y):
    return correlation(x, y) * np.std(y) / np.std(x)

def intercept(x, y):
    return np.mean(y) - slope(x, y) * np.mean(x)

print("Slope:", round(slope(ads['ad_spend'], ads['sales']), 2))
print("Intercept:", round(intercept(ads['ad_spend'], ads['sales']), 2))
Slope: 6.57
Intercept: 48.61
### Question 3: Prediction and Residual
# Use the regression line (unrounded slope and intercept) to:
#   1. Predict sales for a week with ad spend of 6.5, rounded to 2 decimals.
#   2. Compute the residual for the week with ad spend 5 (actual sales 85):
#      actual minus fitted, rounded to 2 decimals.
# Print exactly:
# Predicted sales at 6.5: 91.32
# Residual at 5: 3.54
import numpy as np
import pandas as pd

ads = pd.DataFrame({
    "ad_spend": [2, 3, 4, 5, 6, 7, 8, 9],          # $1,000s per week
    "sales": [60, 72, 70, 85, 88, 98, 95, 110],    # $1,000s per week
})
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
import numpy as np
import pandas as pd

ads = pd.DataFrame({
    "ad_spend": [2, 3, 4, 5, 6, 7, 8, 9],          # $1,000s per week
    "sales": [60, 72, 70, 85, 88, 98, 95, 110],    # $1,000s per week
})

def standard_units(x):
    return (x - np.mean(x)) / np.std(x)

def correlation(x, y):
    return np.mean(standard_units(x) * standard_units(y))

def slope(x, y):
    return correlation(x, y) * np.std(y) / np.std(x)

def intercept(x, y):
    return np.mean(y) - slope(x, y) * np.mean(x)

a = slope(ads['ad_spend'], ads['sales'])
b = intercept(ads['ad_spend'], ads['sales'])

print("Predicted sales at 6.5:", round(a * 6.5 + b, 2))
print("Residual at 5:", round(85 - (a * 5 + b), 2))
Predicted sales at 6.5: 91.32
Residual at 5: 3.54
### Question 4: Least Squares Beats a Rule of Thumb
# A manager uses the rule of thumb: sales = 50 + 6 * ad_spend.
#   1. Compute the root mean squared error (RMSE) of the regression line's
#      fitted values: sqrt(mean of (actual - fitted) ** 2).
#   2. Compute the RMSE of the rule of thumb's predictions.
#   3. Round both to 2 decimals.
# Print exactly:
# Regression RMSE: 3.67
# Rule of thumb RMSE: 4.27
import numpy as np
import pandas as pd

ads = pd.DataFrame({
    "ad_spend": [2, 3, 4, 5, 6, 7, 8, 9],          # $1,000s per week
    "sales": [60, 72, 70, 85, 88, 98, 95, 110],    # $1,000s per week
})
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
import numpy as np
import pandas as pd

ads = pd.DataFrame({
    "ad_spend": [2, 3, 4, 5, 6, 7, 8, 9],          # $1,000s per week
    "sales": [60, 72, 70, 85, 88, 98, 95, 110],    # $1,000s per week
})

def standard_units(x):
    return (x - np.mean(x)) / np.std(x)

def correlation(x, y):
    return np.mean(standard_units(x) * standard_units(y))

def slope(x, y):
    return correlation(x, y) * np.std(y) / np.std(x)

def intercept(x, y):
    return np.mean(y) - slope(x, y) * np.mean(x)

def rmse(predicted):
    return np.sqrt(np.mean((ads['sales'] - predicted) ** 2))

fitted = slope(ads['ad_spend'], ads['sales']) * ads['ad_spend'] + intercept(ads['ad_spend'], ads['sales'])
print("Regression RMSE:", round(rmse(fitted), 2))
print("Rule of thumb RMSE:", round(rmse(50 + 6 * ads['ad_spend']), 2))
# No straight line has a smaller RMSE than the least squares line.
Regression RMSE: 3.67
Rule of thumb RMSE: 4.27
### Question 5: Reading the Residuals
# A café tracked units sold of a pastry at different prices (in dollars).
#   1. Fit the regression line of units on price and compute the residuals
#      (actual minus fitted).
#   2. The rows are sorted by price. Compute the mean residual for the first
#      3 rows (low prices), the middle 3, and the last 3 (high prices),
#      each rounded to 1 decimal.
#   3. If the low and high groups are positive and the middle is negative,
#      print "curved"; otherwise print "no clear pattern".
# Print exactly:
# Low prices: 4.0
# Middle prices: -8.7
# High prices: 4.6
# Pattern: curved
import numpy as np
import pandas as pd

cafe = pd.DataFrame({
    "price": [5, 6, 7, 8, 9, 10, 11, 12, 13],
    "units": [90, 70, 55, 44, 37, 33, 31, 30, 30],
})
### Your code starts here.



### Your code ends here.

Hide code cell source

### Solution
import numpy as np
import pandas as pd

cafe = pd.DataFrame({
    "price": [5, 6, 7, 8, 9, 10, 11, 12, 13],
    "units": [90, 70, 55, 44, 37, 33, 31, 30, 30],
})

def standard_units(x):
    return (x - np.mean(x)) / np.std(x)

def correlation(x, y):
    return np.mean(standard_units(x) * standard_units(y))

def slope(x, y):
    return correlation(x, y) * np.std(y) / np.std(x)

def intercept(x, y):
    return np.mean(y) - slope(x, y) * np.mean(x)

a = slope(cafe['price'], cafe['units'])
b = intercept(cafe['price'], cafe['units'])
residuals = cafe['units'] - (a * cafe['price'] + b)

low = round(residuals.iloc[0:3].mean(), 1)
middle = round(residuals.iloc[3:6].mean(), 1)
high = round(residuals.iloc[6:9].mean(), 1)

if low > 0 and middle < 0 and high > 0:
    pattern = "curved"
else:
    pattern = "no clear pattern"

print("Low prices:", low)
print("Middle prices:", middle)
print("High prices:", high)
print("Pattern:", pattern)
# The line is too low at both ends and too high in the middle, so a curve
# would describe the relationship better than a straight line.
Low prices: 4.0
Middle prices: -8.7
High prices: 4.6
Pattern: curved