{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "87f8b1b1",
   "metadata": {},
   "source": [
    "# Lab 2 · What an average hides\n",
    "## Data Science Fundamentals — Week 2: Describing Data\n",
    "**Mohammad Sabokrou · New Uzbekistan University**\n",
    "\n",
    "**Your job:** use evidence to explain data and make a defensible decision. The Python is provided; programming complexity earns no extra credit.\n",
    "\n",
    "**Name:** …   **Student ID:** enter in the setup cell below.\n",
    "\n",
    "### How to work\n",
    "1. Open this notebook in Google Colab or Jupyter. Run the setup with your own ID.\n",
    "2. Work from top to bottom. Where asked, write a prediction **before** running the next cell. Keep the prediction even if it is wrong; explain what you learned.\n",
    "3. Double-click an **Answer** cell to write. Use your own generated numbers and refer to specific plots. A number without an interpretation is incomplete.\n",
    "4. Run the supplied code; change only the explicitly labelled settings. You are responsible for understanding and explaining the results you submit.\n",
    "5. Keep the same ID throughout. Restart and run all cells after finishing; save the notebook with outputs.\n",
    "\n",
    "**Suggested pace:** setup 5 min; sections 1–8: 10, 15, 15, 15, 15, 10, 15, 15 min; final check 5 min (120 min total). Finish the written reflection after class if needed.\n",
    "\n",
    "### What varies between students?\n",
    "Your ID determines the data, eight-number exercise, selected record, histogram settings, and decision scenario. The concepts and workload stay comparable. Reusing an ID gives the same case. Different IDs are not a guarantee that every individual number differs.\n",
    "\n",
    "All records are **synthetic teaching data**, not real university records. There are no downloads, joins, or missing code blocks to debug.\n",
    "\n",
    "**Evidence standard:** answers should contain a claim, a number or plot observation from your case, and a reason or limitation. We assess statistical reasoning, appropriate methods, and reproducible evidence—not Python fluency."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "79fad0d9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# SETUP — edit only STUDENT_ID. Integers and quoted IDs both work.\n",
    "STUDENT_ID = \"YOUR_ID\"\n",
    "import hashlib\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from IPython.display import display\n",
    "\n",
    "STUDENT_ID = str(STUDENT_ID).strip()\n",
    "if not (STUDENT_ID.isascii() and STUDENT_ID.isdigit() and 6 <= len(STUDENT_ID) <= 12):\n",
    "    raise ValueError(\"Replace YOUR_ID with your own 6–12 digit student ID, then run again.\")\n",
    "seed = int.from_bytes(hashlib.sha256(('FDS-Lab2-v1:' + STUDENT_ID).encode()).digest()[:8], 'big')\n",
    "rng = np.random.default_rng(seed)\n",
    "case_code = hashlib.sha256(('FDS-Lab2-v1:' + STUDENT_ID).encode()).hexdigest()[:10]\n",
    "plt.rcParams.update({'figure.figsize': (8, 4), 'axes.spines.top': False, 'axes.spines.right': False})\n",
    "pd.options.display.float_format = '{:.3f}'.format\n",
    "N = 240\n",
    "programme = rng.choice(['A', 'B'], N, p=[.55, .45])\n",
    "entry = np.clip(rng.normal(rng.uniform(62,68), rng.uniform(8,11), N), 0, 100)\n",
    "minutes = rng.lognormal(rng.uniform(4.1,4.4), .85, N)\n",
    "# Two different teaching groups: their score patterns intentionally differ.\n",
    "assessment = np.clip(rng.normal(np.where(programme == 'A', 43, 78), 4.5), 0, 100)\n",
    "satisfaction = rng.choice([1.,2.,3.,4.,5.], N, p=[.08,.12,.2,.35,.25])\n",
    "satisfaction[rng.choice(N, size=int(rng.integers(35,61)), replace=False)] = np.nan\n",
    "students = pd.DataFrame({'record_id':np.arange(1,N+1), 'programme':programme,\n",
    "    'entry_score':entry, 'weekly_minutes':minutes,\n",
    "    'assessment_score':assessment, 'satisfaction':satisfaction})\n",
    "small = np.sort(rng.choice(np.arange(35,86), 8, replace=False)).astype(float)\n",
    "focus_index = int(np.argmax(entry))\n",
    "coarse_bins = int(rng.choice([2,3,4]))\n",
    "fine_bins = int(rng.choice([35,40,45]))\n",
    "scenario = str(rng.choice(['typical use', 'total workload']))\n",
    "print('Case:',case_code, '| ID:',STUDENT_ID, '| Final decision:',scenario)\n",
    "print('Keep this case code in your submission. Setup complete.')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4631c483",
   "metadata": {},
   "source": [
    "## 1 · Who and what are we describing? (10 min)\n",
    "One row is one synthetic student observed in the same week. Scores are points out of 100; minutes are minutes per student in that week. Satisfaction is an **ordered category** from 1 (lowest) to 5 (highest); equal numerical steps need not represent equal changes in feeling. Programme A/B are category labels; record IDs are identifiers.\n",
    "\n",
    "The next cell displays the data and counts. `count()` excludes missing values; `len()` counts rows. No missing value is replaced by zero."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "756e9e00",
   "metadata": {},
   "outputs": [],
   "source": [
    "display(students.head())\n",
    "valid = students['satisfaction'].count()\n",
    "print(f'Total rows: {len(students)}; valid satisfaction: {valid}; missing: {len(students)-valid}')\n",
    "print(f'Response rate: {100*valid/len(students):.1f}%')\n",
    "display(students['satisfaction'].value_counts().sort_index().rename('responses'))\n",
    "print('Most common programme(s):', students['programme'].mode().tolist())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66d16ff4",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**1A.** State the observational unit and the denominator for the satisfaction response rate. Why is the denominator for a mean of recorded satisfaction responses different?\n",
    "\n",
    "**1B.** A colleague replaces missing satisfaction with zero. Explain why this changes the meaning. Can the responses establish what *all* students feel?\n",
    "\n",
    "**1C.** Which is meaningful: the mode of programme, the mean of record ID, or the mean of programme coded A=1/B=2? Explain. For satisfaction, explain why the category frequency table adds information that a mean alone hides.\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "841fdbd1",
   "metadata": {},
   "source": [
    "## 2 · Eight numbers, by hand first (15 min)\n",
    "Run the next cell to obtain your eight numbers. Before running the checking cell, calculate their mean, median, **sample variance and sample SD** using a calculator if useful. Show intermediate steps; no Python writing is required.\n",
    "\n",
    "Mean = sum / n. Deviations = value − mean. Sample variance = sum of squared deviations / (n−1). Sample SD = square root of sample variance."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1e468c3d",
   "metadata": {},
   "outputs": [],
   "source": [
    "print('Your eight scores:',small.tolist())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2761b883",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**2A.** Record: sum, n, mean, middle two scores, median, eight deviations, sum of squared deviations, sample variance, and sample SD. Include units.\n",
    "\n",
    "**2B. Prediction:** if these eight scores were the entire population of interest, would the population SD be larger or smaller? Why?\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e01da8a2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# CHECK ONLY AFTER YOUR HAND CALCULATIONS\n",
    "s = pd.Series(small)\n",
    "display(pd.DataFrame({'score':small,'deviation':small-small.mean(),\n",
    "                     'squared deviation':(small-small.mean())**2}))\n",
    "display(pd.Series({'mean':s.mean(),'median':s.median(),\n",
    "    'sample variance':s.var(ddof=1),'pandas sample SD':s.std(),\n",
    "    'NumPy population SD':np.std(small), 'NumPy sample SD':np.std(small,ddof=1)}))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "532212c2",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**2C.** Compare your work with the output. Correct any error and explain its source. Why do the two default SD results differ? State which divisor answers each question; explain why variance has points² but SD has points.\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "512cbcbd",
   "metadata": {},
   "source": [
    "## 3 · Middle half, extremes, and sensitivity (15 min)\n",
    "For the eight scores, use **median of halves**: Q1 is the median of the lower four; Q3 the median of the upper four. For the larger dataset later, use pandas **linear interpolation**. Different stated conventions can legitimately give different quartiles.\n",
    "\n",
    "Before running, compute the five-number summary and IQR of your eight scores. Then predict what happens if the largest score is accidentally multiplied by 10."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6bf6a4a7",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**3A.** Give min, Q1, median, Q3, max, and IQR by hand. Interpret the middle-half interval in a sentence.\n",
    "\n",
    "**3B. Prediction:** which will change most after the error: mean or median? Will range, SD, and IQR change? Explain using which observations each measure depends on.\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4d50dcf8",
   "metadata": {},
   "outputs": [],
   "source": [
    "def half_summary(a):\n",
    "    a = np.sort(a)\n",
    "    q1, q3 = np.median(a[:4]), np.median(a[4:])\n",
    "    return pd.Series({'min':a.min(),'Q1':q1,'median':np.median(a),'Q3':q3,\n",
    "        'max':a.max(),'mean':a.mean(),'range':np.ptp(a),'IQR':q3-q1,\n",
    "        'sample variance':np.var(a,ddof=1),'sample SD':np.std(a,ddof=1)})\n",
    "changed = small.copy(); changed[-1] *= 10\n",
    "print('Changed scores:',changed.tolist())\n",
    "display(pd.DataFrame({'original':half_summary(small),'with error':half_summary(changed)}))\n",
    "print('Original pandas linear quartiles:',pd.Series(small).quantile([.25,.75]).to_dict())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d02b20f",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**3C.** Compare predictions with results, citing at least two numerical changes. Why can the median and IQR stay stable here? Does that make them universally best?\n",
    "\n",
    "**3D.** Explain any difference between hand and software quartiles. Why is the altered score impossible in this context, whereas a very large number of platform minutes may be valid?\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8aae5974",
   "metadata": {},
   "source": [
    "## 4 · Look before summarising (15 min)\n",
    "The next cell plots four numeric columns: entry score, weekly minutes, assessment score, and satisfaction. For the discrete ordinal satisfaction scale, each histogram bin represents one response category. Missing responses are excluded and the valid n is shown.\n",
    "\n",
    "Read **centre, spread, tail direction, peaks/gaps, and unusual values**. `skew()` gives a sample skewness statistic; its sign is useful evidence, not a complete description of shape."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d204a0cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "columns = ['entry_score','weekly_minutes','assessment_score','satisfaction']\n",
    "units = ['points','minutes per week','points','response category']\n",
    "fig, axes = plt.subplots(2,2,figsize=(12,8))\n",
    "for ax,col,unit in zip(axes.flat,columns,units):\n",
    "    x=students[col].dropna()\n",
    "    ax.hist(x,bins=np.arange(.5,6,1) if col=='satisfaction' else 18,\n",
    "            color='#347c99',edgecolor='white')\n",
    "    ax.set(title=f'{col} (valid n={len(x)})',xlabel=unit,ylabel='Student count')\n",
    "plt.tight_layout(); plt.show()\n",
    "display(students[columns[:3]].agg(['count','mean','median','std','skew']).T)\n",
    "fig, axes = plt.subplots(1,3,figsize=(12,3.5))\n",
    "for ax,b in zip(axes,[coarse_bins,12,fine_bins]):\n",
    "    ax.hist(students.assessment_score,bins=b,color='#347c99',edgecolor='white')\n",
    "    ax.set(title=f'{b} bins',xlabel='Assessment score (points)',ylabel='Student count',xlim=(0,100))\n",
    "plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "34601d2c",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**4A.** Write one shape sentence for **each of the four columns**. Include plot evidence; do not merely list a skewness number.\n",
    "\n",
    "**4B.** Find a column where mean and median disagree. Give both values and explain the mechanism. Which centre and spread would you report for a typical observation?\n",
    "\n",
    "**4C.** Compare the three histogram bin settings. What is concealed or exaggerated? Choose one and justify it. Does changing bins change the underlying mean?\n",
    "\n",
    "**4D.** Does a nearly zero skewness or similar mean/median establish a normal distribution? Use the assessment-score plot to explain.\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ecf08620",
   "metadata": {},
   "source": [
    "## 5 · Boxplots, flags, and hidden groups (15 min)\n",
    "Box = Q1 to Q3; line = median. Fences = Q1 − 1.5×IQR and Q3 + 1.5×IQR. Whiskers end at the most extreme **observed** values inside the fences; they are not the fences themselves. Dots are candidates for investigation, not automatic deletion.\n",
    "\n",
    "Here pandas and the plotting convention use linearly interpolated quartiles. Group summaries use sample SD (`ddof=1`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b6d49306",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = students.weekly_minutes\n",
    "q1,q3=x.quantile([.25,.75]); iqr=q3-q1\n",
    "lower,upper=q1-1.5*iqr,q3+1.5*iqr\n",
    "inside=x[(x>=lower)&(x<=upper)]\n",
    "flagged=students[(x<lower)|(x>upper)]\n",
    "display(pd.Series({'Q1':q1,'median':x.median(),'Q3':q3,'IQR':iqr,\n",
    "    'lower fence':lower,'upper fence':upper,'lower whisker':inside.min(),\n",
    "    'upper whisker':inside.max(),'flagged count':len(flagged)}))\n",
    "display(flagged[['record_id','weekly_minutes']].head(6))\n",
    "fig,axes=plt.subplots(1,2,figsize=(11,4))\n",
    "axes[0].boxplot(x); axes[0].set(ylabel='Minutes per week',title='Weekly minutes',xticks=[])\n",
    "axes[1].boxplot([students.loc[students.programme==g,'assessment_score'] for g in ['A','B']])\n",
    "axes[1].set(xticks=[1,2],xticklabels=['A','B'],ylabel='Score (points)',title='Assessment by programme')\n",
    "plt.tight_layout(); plt.show()\n",
    "print('Overall assessment summary:')\n",
    "display(students.assessment_score.agg(['count','mean','median','std']))\n",
    "print('Programme summaries:')\n",
    "display(students.groupby('programme').assessment_score.agg(['count','mean','median','std']))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8ff13ad3",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**5A.** Using your Q1/Q3, show one fence calculation. State a whisker endpoint and explain why it differs from the corresponding fence. Describe a flagged record using its ID and minutes.\n",
    "\n",
    "**5B.** Propose two checks before changing that record and one reason to retain it. What would you document if it were corrected? Do not delete it simply because it crosses a fence.\n",
    "\n",
    "**5C.** Compare the overall assessment mean with both programme means and SDs. Would a single support session at the overall average meet both groups' needs? Give evidence and a better plan. Can these data prove that programme membership caused the difference?\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6bcc4728",
   "metadata": {},
   "source": [
    "### Same mean and SD, different students\n",
    "The next two small classes have the same mean and sample SD but different shapes. Values are shifted for your case. Inspect them before answering."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d45e5698",
   "metadata": {},
   "outputs": [],
   "source": [
    "centre = int(round(small.mean()))\n",
    "class_a = centre + np.array([-20,0,0,0,0,0,0,20])\n",
    "class_b = centre + np.array([-10,-10,-10,-10,10,10,10,10])\n",
    "for name,a in [('Class A',class_a),('Class B',class_b)]:\n",
    "    print(name, a.tolist(), '| mean:',a.mean(),'| sample SD:',round(a.std(ddof=1),3))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50e0111b",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**5D.** Sketch or describe each shape. Explain why the same mean and SD can lead to different tutoring plans. What information did the two statistics discard?\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "977f692b",
   "metadata": {},
   "source": [
    "## 6 · When does 68–95–99.7 help? (10 min)\n",
    "A normal model predicts approximately 68%, 95%, and 99.7% within 1, 2, and 3 SD of its mean. This is **not a guarantee for a finite dataset**, and symmetry alone is insufficient. We use sample mean/SD here to compare observed proportions with the model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f048add5",
   "metadata": {},
   "outputs": [],
   "source": [
    "rows=[]\n",
    "for col in ['entry_score','weekly_minutes','assessment_score']:\n",
    "    x=students[col]; m=x.mean(); sd=x.std(ddof=1)\n",
    "    for k in [1,2,3]:\n",
    "        rows.append({'column':col,'SD distance':k,'lower':m-k*sd,'upper':m+k*sd,\n",
    "                     'observed %':100*x.between(m-k*sd,m+k*sd).mean(),\n",
    "                     'normal model %':{1:68,2:95,3:99.7}[k]})\n",
    "display(pd.DataFrame(rows))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e0f87ba",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**6A.** Give your entry-score interval within 1 SD and observed percentage. Explain why it need not be exactly 68%.\n",
    "\n",
    "**6B.** Which column is the most plausible candidate for a normal approximation? Use both shape and proportions. Explain why applying the rule to either of the other columns could mislead.\n",
    "\n",
    "**6C.** If an observed proportion happens to be near 95%, has normality been proven? Why not?\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ebdc4c18",
   "metadata": {},
   "source": [
    "## 7 · Relative to whom? (15 min)\n",
    "A z-score is `(value − reference mean) / reference SD`. It is unitless; the reference SD must be positive. Positive means above the mean, not automatically good. Computing z does not require normality; converting it into a normal-model rarity does.\n",
    "\n",
    "**Prediction:** the selected student's raw score will stay fixed while the reference group changes. Must their z-score remain fixed? Explain before running."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "83534d83",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**7A. Prediction:** explain which ingredients can change and why.\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6918ea11",
   "metadata": {},
   "outputs": [],
   "source": [
    "focus=students.iloc[focus_index]\n",
    "print('Selected record:',int(focus.record_id),'| programme:',focus.programme,'| entry score:',focus.entry_score)\n",
    "rows=[]\n",
    "for label,ref in [('Whole cohort',students.entry_score),\n",
    "                  ('Programme A',students.loc[students.programme=='A','entry_score']),\n",
    "                  ('Programme B',students.loc[students.programme=='B','entry_score'])]:\n",
    "    sd=ref.std(ddof=1)\n",
    "    rows.append({'reference':label,'n':len(ref),'mean':ref.mean(),'sample SD':sd,\n",
    "                 'z':(focus.entry_score-ref.mean())/sd if sd>0 else np.nan})\n",
    "display(pd.DataFrame(rows))\n",
    "students['entry_z_cohort']=(students.entry_score-students.entry_score.mean())/students.entry_score.std(ddof=1)\n",
    "print('Standardised column mean / sample SD:',students.entry_z_cohort.mean(),students.entry_z_cohort.std(ddof=1))\n",
    "# A separate personalised example separates distance from rank.\n",
    "rank_times = np.r_[np.arange(1,10),int(46 + seed % 21)].astype(float)\n",
    "target=9.\n",
    "print('Practice minutes:',rank_times.tolist())\n",
    "print('Target:',target,'| z:',(target-rank_times.mean())/rank_times.std(ddof=1),\n",
    "      '| percentile rank (at or below):',100*np.mean(rank_times<=target))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "430b0398",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**7B.** Show one z-score calculation from the table. Write its interpretation with the reference group and direction. Which reference answers “unusual within this student's own programme”?\n",
    "\n",
    "**7C.** Explain the mean and SD of the standardised column. Would standardising programme codes be meaningful? What if all values in a reference group were identical?\n",
    "\n",
    "**7D.** In the practice-time example, how can 9 minutes be below the mean yet at the 90th percentile? Use the extreme observation in your explanation. Why should you not automatically interpret z=2 as a particular percentile?\n",
    "\n",
    "**7E.** A bottle process has reference mean 100 mL and SD 2 mL. Its explicitly agreed specification is 94–106 mL inclusive. For bottles of 104 and 108 mL, calculate z and decide acceptance. Explain why rejecting a bottle does not mean deleting its measurement, and why z alone does not set the acceptance rule.\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3047210b",
   "metadata": {},
   "source": [
    "## 8 · Your recommendation (15 min)\n",
    "The final case uses the same weekly-minute data. Your assigned request appears below. Choose your primary summary for **that decision**, then explain what you would report for the other decision.\n",
    "\n",
    "- **Typical use:** describe the experience of a typical student.\n",
    "- **Total workload:** estimate the recorded cohort's total platform workload for the week; distinguish an observed total from a forecast of a future week.\n",
    "\n",
    "This is a decision exercise. There is no universally best average."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1c53a9f0",
   "metadata": {},
   "outputs": [],
   "source": [
    "print('YOUR REQUEST:',scenario)\n",
    "x=students.weekly_minutes\n",
    "print('Case:',case_code)\n",
    "display(pd.Series({'valid n':x.count(),'mean':x.mean(),'median':x.median(),\n",
    "    'sample SD':x.std(ddof=1),'Q1':x.quantile(.25),'Q3':x.quantile(.75),\n",
    "    'IQR':x.quantile(.75)-x.quantile(.25),'total minutes':x.sum()}))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d64a20bc",
   "metadata": {},
   "source": [
    "### Your reasoning\n",
    "**8A. Final note — approximately 150 words:** explain why you would not report the weekly-minute mean alone. Address your assigned request and include: case code; population and valid n; units; chosen centre and spread; two numerical pieces of evidence; shape; what your summary hides; what you would report for the other request; and one limitation. Do not claim a cause or treat this synthetic cohort as real university evidence.\n",
    "\n",
    "**8B. Transfer check:** suppose the highest-use student's minutes doubled. Without rerunning, predict the direction of change in the mean and total, and whether the median would change. Explain which recommendation would be more affected.\n",
    "\n",
    "**Answer:** Replace this text with your explanation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "260850f7",
   "metadata": {},
   "source": [
    "## Submission checklist\n",
    "- [ ] My name, student ID, and case code are present and consistent.\n",
    "- [ ] I kept predictions and explained any revisions.\n",
    "- [ ] I answered 1A–8B, including the hand calculations and approximately 150-word note.\n",
    "- [ ] Four column plots and all other supplied results are visible.\n",
    "- [ ] My answers cite my own numbers, units, group definitions, and plot evidence.\n",
    "- [ ] I stated the quartile convention and sample/population SD choice where relevant.\n",
    "- [ ] I did not automatically remove outlier candidates or make unsupported causal claims.\n",
    "- [ ] I restarted and ran all cells using my own ID, then saved with outputs.\n",
    "\n",
    "Save as **`STUDENTID_Lab2_FDS.ipynb`**, replacing STUDENTID with your ID. Submit through the course's announced channel and follow its current email-subject rule. The reflection belongs inside this notebook; no separate report is needed.\n",
    "\n",
    "### What a strong submission demonstrates\n",
    "Correct calculations are the starting point. Strong work explains **why** a summary fits the question, distinguishes observations from assumptions, recognises what averages conceal, and supports a decision with personalised evidence.\n",
    "\n",
    "*Aligned with Week 2: Describing Data, slides 2–65. This lab focuses on describing and interpreting data; full data-cleaning procedures follow in Week 3.*"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "name": "Lab_02_Describing_Data_Student.ipynb"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
