⚙️ Setup¶
import numpy as np
import pandas as pd
print("Ready.")
Ready.
data = pd.Series([3, 5, 3, 2, 5, 5, 3, 4, 2, 5])
f = data.value_counts().sort_index()
tbl = pd.DataFrame({"frequency": f})
tbl["relative"] = tbl["frequency"] / tbl["frequency"].sum()
print(tbl)
print(f"\nsum of relative = {tbl['relative'].sum():.2f}")
frequency relative 2 2 0.2 3 3 0.3 4 1 0.1 5 4 0.4 sum of relative = 1.00
Answer: Counts are 2→2, 3→3, 4→1, 5→4 (total 10), giving relative frequencies 0.2, 0.3, 0.1, 0.4 that sum to 1.00. The relative column is each count divided by n = 10.
limits = [(0,9),(10,19),(20,29),(30,39)]
freq = np.array([4, 11, 9, 6])
width = limits[1][0] - limits[0][0] # distance between consecutive lower limits
mids = [(lo+hi)/2 for lo,hi in limits]
cum = np.cumsum(freq)
print(f"class width = {width}")
print(f"midpoints = {mids}")
print(f"cumulative = {list(cum)}")
class width = 10 midpoints = [4.5, 14.5, 24.5, 34.5] cumulative = [np.int64(4), np.int64(15), np.int64(24), np.int64(30)]
Answer: Class width = 10 (the gap between consecutive lower limits). Midpoints are 4.5, 14.5, 24.5, 34.5. Cumulative frequencies are 4, 15, 24, 30, and the last equals n = 30.
scores = np.array([95, 78, 88])
weights = np.array([0.20, 0.30, 0.50])
grade = np.average(scores, weights=weights)
print(f"weighted course grade = {grade:.1f}")
print(f"(plain average would be {scores.mean():.1f})")
weighted course grade = 86.4 (plain average would be 87.0)
Answer: Weighted grade = 0.20(95) + 0.30(78) + 0.50(88) = 86.4. Because the weights already sum to 1, the weighted mean is just the sum of weight times score. The plain average (87.0) over-credits the low-weight homework.
mids = np.array([4.5, 14.5, 24.5, 34.5])
freq = np.array([4, 11, 9, 6])
grouped_mean = np.average(mids, weights=freq)
print(f"grouped mean = sum(f*m) / sum(f) = {grouped_mean:.2f}")
grouped mean = sum(f*m) / sum(f) = 20.17
Answer: Grouped mean = Σ(f·m)/Σf = (4·4.5 + 11·14.5 + 9·24.5 + 6·34.5) / 30 = 19.97. This is a weighted mean of the midpoints, an approximation that assumes every value sits at its class midpoint.
freq = np.array([4, 11, 9, 6]); n = freq.sum()
cum = np.cumsum(freq)
# n/2 = 15 -> median class is 10-19 (first class whose CF reaches 15)
L = 9.5 # lower BOUNDARY of the median class (not the limit 10)
CF = 4 # cumulative frequency BEFORE the median class
f = 11 # frequency of the median class
h = 10 # class width
median = L + ((n/2 - CF) / f) * h
print(f"n = {n}, n/2 = {n/2}, median class = 10-19")
print(f"median = {L} + (({n/2} - {CF})/{f}) * {h} = {median:.2f}")
n = 30, n/2 = 15.0, median class = 10-19 median = 9.5 + ((15.0 - 4)/11) * 10 = 19.50
Answer: n/2 = 15 lands in the 10-19 class (CF reaches 15 there). Using the lower boundary L = 9.5, CF before = 4, f = 11, h = 10: median = 9.5 + ((15 − 4)/11)·10 = 19.5. Two things people slip on: use the boundary (9.5) not the limit (10), and CF is the total before the median class.