To get street-level median house prices in England and Wales, download HM Land Registry Price Paid Data, filter by postcode prefix, group by street and take the median, keeping only streets with enough sales. This tutorial does it with pandas in under 20 lines, then shows why the result needs a minimum sample size and a property-type split.

I run Door Number, which publishes street-level tables built on this data. Checked on 8 November 2026.

What does the Price Paid Data file look like?

The yearly CSV files (pp-2019.csv to pp-2026.csv) have no header row. Each record has 16 fields, in this order: transaction ID, price, date of transfer, postcode, property type (D detached, S semi-detached, T terraced, F flat or maisonette, O other), old or new build (Y or N), tenure (F freehold, L leasehold), PAON (house number or name), SAON (flat number), street, locality, town or city, district, county, PPD category type (A or B) and record status (A added, C changed, D deleted). The data is published under the Open Government Licence v3.0.

How do you calculate the street medians?

import pandas as pd cols = ["id", "price", "date", "postcode", "ptype", "new", "tenure", "paon", "saon", "street", "locality", "town", "district", "county", "category", "status"] files = [f"pp-{y}.csv" for y in range(2019, 2027)] df = pd.concat(pd.read_csv(f, names=cols, parse_dates=["date"]) for f in files) cr5 = df[df.postcode.str.startswith("CR5 ", na=False)] streets = (cr5.groupby("street").price .agg(["median", "count"]) .query("count >= 3") .sort_values("median", ascending=False)) print(streets.head()) 

Note the trailing space in startswith("CR5 "). Every full UK postcode has a space after its outward code, so this selects exactly the CR5 district and nothing longer.

How do you split by property type?

by_type = cr5.groupby("ptype").price.agg(["median", "count"]) print(by_type) 

Splitting by type is not optional. On Door Number's CR5 dataset, the median detached sale since 2019 is £690,000 (413 sales) and the median flat is £300,000 (328 sales). A street of flats and a street of detached houses cannot be ranked together.

What does the result look like?

Door Number's published table, which joins sales to EPC data, puts Caversham Close at the top of CR5 with a median of £1,230,000 from six detached sales. Compare it with your own output, and expect small differences where street names are spelled differently across records. The full table is at every street in CR5 with sold prices.

Which pitfalls catch people out?

  • Records with status D are deletions. If you merge monthly update files, drop them; the complete file already reflects them.
  • Price Paid Data excludes some transactions, such as non-market sales, and the latest months are incomplete.
  • Street names can be blank for some rural or named properties, so check for NaN before grouping.
  • Medians from three sales are fragile. Show the count next to every median, as above.
  • To compare postcodes or single homes rather than streets, the same grouping works on the full postcode column. See an example postcode page, CR5 3LZ, or a single property record, 14 Jennys Way, Netherne-on-the-Hill.

Where else can you go from here?

Join the sales to the EPC register for floor area and construction age band, or to Census 2021 for area context. HM Land Registry has announced that it will add UPRNs to Price Paid Data from 28 August 2026, which should make that join far easier. Door Number lists every dataset and licence on its data sources page, and has free calculators on its tools page. For national context, see house prices by region and the national street rankings.

About the author: Ashleigh Giles runs Door Number, which publishes house prices and local information from open UK data, with sources credited on every page.