CORE COMPONENT · 40% OF THE CORE

Employer Set Project

The Employer Set Project (ESP) is the synoptic part of the core: it draws on everything in content areas 1–8. This page covers how it works, the pandas and matplotlib you're allowed to use, practice at fixing defects in code, and how to write a reflective evaluation.

What the ESP is

AssessmentContentFormatWeighting
Employer Set ProjectSynoptic: draws on all core contentSupervised project up to 14 h 30 min, 100 marks. Tasks: planning, fixing defects in code, design, development, reflective evaluation. No internet or AI tools.40%

Pre-release material comes out before the tasks start. It introduces the employer's scenario, so read it carefully and make sure you understand the business, its users and the problem.

Key dates

From the course key dates (provisional, so check with your teacher).

DateWhatDetails
Loading...

✗ NO INTERNET OR AI TOOLS

You won't be able to look anything up during the tasks. Practise now so you don't need to:

  • Learn the Appendix 2 Python commands: they're the ones you can expect to need.
  • Write code without autocomplete or AI suggestions, then run and debug it yourself.
  • Get quick at reading Python error messages: the error type and line number tell you where to look (2.10).
  • Know the pandas and matplotlib basics below by heart.

What to revise for each kind of task

The ESP tasks cover planning, fixing defects, design, development and reflective evaluation. This table shows which parts of the guide help most with each. It's revision guidance, not the official mark scheme.

Kind of taskWhat you'll be doingRevise
PlanningBreaking the brief down, working out requirements and what the solution needs to doDecomposition and abstraction (1.1), problem-solving strategies (1.3), SMARTER objectives (5.4.4), feasibility (5.4.5)
Fixing defects in codeFinding and correcting errors in code you're givenDebugging and error types (2.10), testing and test data (2.12), practice below
DesignPlanning the solution before you build itFlowcharts and written algorithms (1.2), data models (6.10), end users and accessibility (3.1.3), design considerations (2.9)
DevelopmentWriting and testing the codeAll of CA2, validation (2.8), robust code (2.10), pandas and matplotlib, security
Reflective evaluationJudging how well your solution meets the brief, and how you'd improve itJudging an algorithm (2.9.7), command words and the explanation ladder, evaluation guide below

pandas and matplotlib

The spec lists these for the Employer Set Project only: pandas (import CSV, data frames, totals, averages, counts, trends) and matplotlib (graphs with labels and legends). Press ▶ Run on each example to try it: the first run loads pandas, which takes a little longer. Run the examples in order, because example 1 creates the file the others read.

1. Import a CSV into a data frame

A data frame is a table: rows are records, columns are fields. pd.read_csv() turns a CSV file into one, and works out the data types for you.

import pandas as pd

with open("sales.csv", "w") as f:
    f.write("date,branch,item,quantity,price\n")
    f.write("2027-05-03,Leeds,Latte,12,3.20\n")
    f.write("2027-05-03,York,Tea,8,1.80\n")
    f.write("2027-05-04,Leeds,Scone,5,2.50\n")
    f.write("2027-05-04,York,Latte,9,3.20\n")
    f.write("2027-05-05,Leeds,Latte,15,3.20\n")
    f.write("2027-05-05,York,Scone,11,2.50\n")

sales = pd.read_csv("sales.csv")
print(sales.head(3))
print(len(sales), "rows,", len(sales.columns), "columns")
         date branch   item  quantity  price
0  2027-05-03  Leeds  Latte        12    3.2
1  2027-05-03   York    Tea         8    1.8
2  2027-05-04  Leeds  Scone         5    2.5
6 rows, 5 columns

head(3) shows the first 3 rows. The numbers down the left are the index. Unlike the plain csv module (6.5), pandas reads numbers as numbers, not strings.

2. Totals, averages and counts

import pandas as pd

sales = pd.read_csv("sales.csv")
sales["total"] = sales["quantity"] * sales["price"]

print("Total takings: £" + format(sales["total"].sum(), ".2f"))
print("Average quantity:", round(sales["quantity"].mean(), 1))
print("Biggest sale: £" + format(sales["total"].max(), ".2f"))
print(sales["item"].value_counts())
Total takings: £169.60
Average quantity: 10.0
Biggest sale: £48.00
item
Latte    3
Scone    2
Tea      1
Name: count, dtype: int64
CodeWhat it does
df["new"] = df["a"] * df["b"]Adds a calculated column, working out every row at once
.sum() .mean() .max() .min()Total, average, largest and smallest of a column
.value_counts()How many times each value appears
len(df)Number of rows

3. Group, filter and sort

import pandas as pd

sales = pd.read_csv("sales.csv")
sales["total"] = sales["quantity"] * sales["price"]

print(sales.groupby("branch")["total"].sum())
print()
lattes = sales[sales["item"] == "Latte"]
print(lattes[["date", "branch", "quantity"]])
print()
print(sales.sort_values("total", ascending=False).head(2))
branch
Leeds    98.9
York     70.7
Name: total, dtype: float64

         date branch  quantity
0  2027-05-03  Leeds        12
3  2027-05-04   York         9
4  2027-05-05  Leeds        15

         date branch   item  quantity  price  total
4  2027-05-05  Leeds  Latte        15    3.2   48.0
0  2027-05-03  Leeds  Latte        12    3.2   38.4
CodeWhat it does
df.groupby("col")["other"].sum()A total for each group, e.g. takings per branch
df[df["col"] == value]Only the rows that match a condition (a filter)
df[["a", "b"]]Only some columns (note the double brackets)
df.sort_values("col", ascending=False)Sort the rows, largest first

4. Show a trend with a labelled graph

import pandas as pd
import matplotlib.pyplot as plt

sales = pd.read_csv("sales.csv")
sales["total"] = sales["quantity"] * sales["price"]
daily = sales.groupby(["date", "branch"])["total"].sum().unstack()
print(daily)

daily.plot(kind="line", marker="o")
plt.title("Daily takings by branch")
plt.xlabel("Date")
plt.ylabel("Takings (£)")
plt.legend(title="Branch")
plt.tight_layout()
plt.savefig("takings.png")
print("Chart saved as takings.png")
branch      Leeds  York
date
2027-05-03   38.4  14.4
2027-05-04   12.5  28.8
2027-05-05   48.0  27.5
Chart saved as takings.png

When you run it here, the chart appears under the output. On your own computer, plt.show() opens it in a window instead of saving it.

★ EVERY GRAPH NEEDS

  • A title that says what the graph shows: plt.title()
  • Labelled axes, with units: plt.xlabel() and plt.ylabel()
  • A legend whenever there's more than one line or bar colour: plt.legend()
  • The right type: a line graph for trends over time, a bar chart to compare categories (6.9)

▲ TRY IT

  • Change example 4 to kind="bar". Which chart shows the trend more clearly?
  • Add a line to example 2 that prints the average takings per sale.
  • Filter example 3 to show only York's sales of more than £20.

Fixing defects: practice

Each program has defects. For each one, give the line number, the problem, the type of error (syntax, runtime or logic) and the corrected line. Press ▶ Run to watch the faulty code fail, then fix it in the editor until it works.

This program should print the average score and how many scores are 50 or more. Find the three defects.

scores = [72, 45, 50, 88, 39]
total = 0
passes = 0
for score in scores:
    total = total + score
    if score > 50:
        passes = passes + 1
average = total / len(score)
print("Average: " + average)
print("Scores of 50 or more:", passes)
LineDefectTypeCorrection
6> 50 leaves out a score of exactly 50Logicif score >= 50:
8len(score) uses the single score (an int), not the listRuntime (TypeError)average = total / len(scores)
9Joins a float to a string with +Runtime (TypeError)print("Average: " + str(average))

One mark for each defect found, one for each correct fix.

scores = [72, 45, 50, 88, 39]
total = 0
passes = 0
for score in scores:
    total = total + score
    if score >= 50:
        passes = passes + 1
average = total / len(scores)
print("Average: " + str(average))
print("Scores of 50 or more:", passes)
Average: 58.8
Scores of 50 or more: 3

This program should count how many times each colour appears. Find the two defects.

colours = ["red", "blue", "red", "green", "blue", "red"]
counts = {}
for colour in colours:
    if colour in counts:
        counts[colour] = 1
    else:
        counts[colour] = counts[colour] + 1
for colour, number in counts.items:
    print(colour, number)
LineDefectTypeCorrection
5 and 7The two branches are the wrong way round: a new colour isn't in the dictionary yet, so line 7 raises a KeyErrorRuntime (KeyError)Line 5: counts[colour] = counts[colour] + 1; line 7: counts[colour] = 1
8counts.items is missing its brackets, so it isn't calledRuntime (TypeError)for colour, number in counts.items():
colours = ["red", "blue", "red", "green", "blue", "red"]
counts = {}
for colour in colours:
    if colour in counts:
        counts[colour] = counts[colour] + 1
    else:
        counts[colour] = 1
for colour, number in counts.items():
    print(colour, number)
red 3
blue 2
green 1

This program should keep asking for an age until it is between 16 and 99. Explain the two defects and write a corrected version.

age = int(input("Age: "))
while age < 16 or age > 99:
    print("Age must be 16 to 99")
print("Accepted")
  • The loop never asks again, so an invalid age prints the message forever: an infinite loop (logic) (1). Ask for the age inside the loop (1).
  • Typing a word such as ten crashes int() with a ValueError (runtime) (1). Check the input is a whole number before converting it, e.g. with isdigit() or try/except (1).
while True:
    entry = input("Age: ")
    if not entry.isdigit():
        print("Enter a whole number")
    elif not 16 <= int(entry) <= 99:
        print("Age must be 16 to 99")
    else:
        break
print("Accepted:", entry)
Age: ten
Enter a whole number
Age: 12
Age must be 16 to 99
Age: 17
Accepted: 17

★ A METHOD FOR FIXING DEFECTS

  1. Read what the code is meant to do, then run it.
  2. If it crashes, read the error: the last line gives the type, the line number shows where.
  3. If it runs but the answer is wrong, trace it with a trace table or add print statements.
  4. Fix one defect at a time and re-run after each fix.
  5. Test with valid, boundary, invalid and erroneous data (2.12), and record what you changed and why.

Writing a reflective evaluation

An evaluation judges how well your solution meets the brief and what you'd do differently. Like an 'evaluate' exam question, it needs evidence, both strengths and weaknesses, and a supported judgement.

CoverQuestions to answer
Meeting the requirementsGo through the brief. Which requirements does your solution meet fully, partly or not at all? Use your test results as evidence.
Quality of the solutionUse the criteria from 2.9.7: efficiency, data structures and types, variables and constants, presentation, maintainability, robustness.
UsersIs it usable and accessible for the users in the scenario? (3.1.3)
Legal and securityDoes it handle personal data properly and protect it? (4.1.3, CA8)
Your processHow did your planning and testing go? What would you do differently next time?
ImprovementsWhat would you add or change with more time, and why would it help the client?

◆ SUPPORT: SENTENCE STARTERS

  • The solution meets the requirement to ... because test ... showed ...
  • A limitation is that ... which means the client ...
  • I chose a dictionary for ... because ... However, ...
  • If I had more time, I would ... so that ...
  • Next time I would plan ... earlier, because ...
  • Overall, the solution is ... because ... outweighs ...

✗ COMMON MISTAKES

  • Describing what you did instead of judging how well it works.
  • Only listing strengths. A balanced evaluation earns more.
  • Claims with no evidence. Point to a test, a requirement or a feature.
  • Improvements with no reason. Say why each one would help the client or users.

Am I ready?

my_notes.txt