What this is

The cohort, the labels and the row grain decide the number before the model does

This is a measurement audit, not a clinical study, and nothing in it should inform any decision about any patient. On 223 biopsied breast lesions from CBIS-DDSM (metadata only, CC BY 3.0), a logistic regression built from a radiologist's own recorded descriptors scores AUC 0.837 against 0.851 for that radiologist's own BI-RADS assessment — a difference of -0.0136 with a 95% interval of [-0.070, +0.044]. The interval spans zero, and the contest was never fair: the model's inputs are the radiologist's judgement written down in the same reading that produced the assessment. Three things set the number before any method does. The cohort is biopsy-conditional, so 39.0% of it is malignant and positive predictive value falls 48x at a screening rate when the same fixed classifier is moved to a screening population. The optimal decision threshold is an interval rather than a point, because the cost function is a step function at this sample size. And the field's default 569-row benchmark is matched to within 6.1 points by a one-split decision stump, so a result in the usual 97-to-99 per cent range demonstrates little.

This is a real analysis on a real dataset, not an illustration. The code is published, it runs in under two minutes, and a verification script re-runs it from scratch and fails if any headline number moves.

Every figure below is read from results.json, which is written by the analysis itself. Where the result is unflattering it is published unchanged — the findings and the limitations both come straight out of the run.

Source figures are in the currency of the data: sterling for the UK retail and wholesale sets, euro for the Portuguese bank set. Dollar amounts are converted at 1.55 USD/GBP and 1.40 USD/EUR, roughly the averages for the periods the data covers — stated assumptions, not live rates.

How this is checked

verify.py --only 26 deletes this project's results, re-runs it and diffs every published number before the page ships.

The pipeline
Findings

What the analysis found, including the results that went against us

Each of these came out of the run. None has been softened.

THE MODEL AND THE RADIOLOGIST CANNOT BE TOLD APART, AND THE CONTEST WAS NEVER FAIR. On 223 biopsied lesions of which 87 were malignant, a logistic regression on the radiologist's recorded descriptors scores AUC 0.837 against 0.851 for that radiologist's own BI-RADS assessment — a difference of -0.0136 with a 95% interval of [-0.070, +0.044]. The interval spans zero, so no difference is established. It could not have been: the model's inputs are the radiologist's judgement written down, recorded in the same reading that produced the assessment. A tie shows the descriptors carry the assessment, and nothing more.

Where the bootstrap difference lands

Distribution of the difference in AUC between the model and the radiologist's own assessment across 2,000 bootstrap resamples of lesions. It straddles zero.

run.py section 2: paired bootstrap over lesions.

THE COHORT DECIDES THE NUMBER BEFORE THE MODEL DOES. Every lesion here was biopsied — that is how a pathology label exists — so 39.0% of them are malignant. Hold this classifier's sensitivity (0.80) and specificity (0.69) fixed and move only the population: positive predictive value falls from 62.5% here to 1.29% at a screening rate of 0.5%, a factor of 48. Nothing about the model changed. A reported PPV without its cohort's prevalence beside it is not interpretable.

Cost by threshold, at two cost ratios

Expected cost per lesion against decision threshold, when a false negative costs the same as a false positive and when it costs twenty times more. Both curves are flat over a wide range, so the optimum is not a single point.

run.py section 4: cost as a step function of the threshold.

THE OPTIMAL THRESHOLD IS NOT A POINT AND OFTEN NOT IDENTIFIED. With 223 lesions the cost function is a step function, so an interval of thresholds achieves the same minimum. At equal costs every cut between 0.550 and 0.640 is indistinguishable — a range 0.090 wide. When a false negative is costed twenty times a false positive the optimum moves to 0.100 to 0.100. Publishing a threshold to three decimal places implies a precision this much data cannot support.

Positive predictive value against prevalence

Positive predictive value of the same fixed classifier as the malignancy rate of the population changes. Sensitivity and specificity are held constant throughout — only the cohort moves.

run.py section 3: PPV recomputed at each prevalence.

THE FIELD'S DEFAULT BENCHMARK IS BEATEN TO WITHIN 6.1 POINTS BY ONE DECISION RULE. On the 569-row Wisconsin diagnostic dataset, logistic regression on all 30 features reaches 95.43% under ten-fold cross-validation. A decision stump — a single threshold on worst radius, the simplest non-trivial classifier that exists — reaches 89.29%. A method reporting 97 or 98 per cent on this data has not demonstrated anything the stump does not, and the benchmark cannot distinguish methods that differ by less than that.

A LESION PHOTOGRAPHED TWICE IS ONE LESION AND TWO ROWS. The training file has 1,318 rows describing 782 lesions in 691 patients, because 536 lesions were imaged from two angles. Reporting at row grain inflates the apparent sample by 68.5%, and every row of a pair carries the same pathology label — so a random split puts the same outcome on both sides. This file ships with an official split whose patient overlap is exactly 0, which is the correct design and is worth noticing, because a split that does not do this is common.

THE PATTERN REPLICATES ON AN INDEPENDENT COHORT. On the UCI Mammographic Mass data — 961 lesions from a different institution and a different decade, 830 of them complete — a model on the recorded descriptors scores AUC 0.872 against 0.825 for the radiologist's BI-RADS, a difference of +0.047. The donors of that dataset flag BI-RADS as non-predictive and exclude it from modelling for exactly this reason. Two cohorts, same result: a model of a radiologist's description performs like the radiologist.

The detail

Full results tables

Rows are not lesions and lesions are not patients

Rows are not lesions and lesions are not patients
SplitRowsLesionsPatients
Training1,318782691
Test378223201

The same classifier, in three populations

The same classifier, in three populations
Malignancy ratePositive predictive value
0.5%1.3%
2.0%5.0%
39.0%62.5%

The 569-row benchmark

The 569-row benchmark
Method10-fold accuracy
Logistic regression, all 30 features95.43%
Decision tree, unrestricted91.74%
One-split stump on worst radius89.29%

Limitations

Stated by the analysis, not added afterwards. A project without these is not finished.

  • NOT A CLINICAL STUDY, AND NOT A DIAGNOSTIC CLAIM. Nothing here was validated for clinical use, no figure below should inform any decision about any patient, and none of this was reviewed by a clinician. It is an audit of what an accuracy figure is conditional on, carried out on public research data, and its subject is measurement practice rather than medicine.
  • The imaging is historical. CBIS-DDSM is digitised screen-film mammography from the 1990s, and nothing here supports any statement about screening with modern full-field digital mammography or tomosynthesis. The measurement lessons transfer; the performance figures do not.
  • The test cohort is small and every interval here is wide. 223 lesions and 87 cancers give bootstrap AUC intervals roughly a tenth of an AUC wide, which is why the difference is published as an interval and not as a point estimate. A study of this size cannot distinguish two methods that are genuinely close.
  • The 2% biopsy threshold referenced here is defined over screening-detected findings, where malignancy is rare. Applying it to a cohort where every lesion was already biopsied is deliberately the wrong population, and that mismatch is the demonstration rather than an oversight — a threshold carried across cohorts without adjusting for prevalence is the error being shown.
  • The model's features are not independent measurements of the lesion. Shape, margins, subtlety and density are a radiologist's structured description, recorded in the same reading that produced the assessment, so the comparison in step 2 is circular by construction. That circularity is the finding; it is not a design that should be copied to claim a model matches a clinician.
  • 34 lesions carry no recorded margin and 1 no recorded shape. They are encoded as an all-zero block rather than imputed, which makes 'not described' its own category. That is defensible — the absence is a fact about the reading — but it is a choice, and a study that imputed instead would report different figures on the same file.
  • BENIGN_WITHOUT_CALLBACK is collapsed into benign. That is the standard reading — the finding was judged not to require a further visit — but it moves the class balance, and a study that treated those lesions differently would report different figures on the same file.
  • Only the metadata is used. The 163 GB image collection is not downloaded, because it requires a desktop client that no script can drive, and therefore no reader could reproduce a figure derived from it. Nothing here is a claim about what a model reading pixels could achieve.

Data: CBIS-DDSM curated breast imaging subset (case description metadata), with UCI Mammographic Mass and UCI Breast Cancer Wisconsin (Diagnostic), CBIS-DDSM curated breast imaging subset (case description metadata), with UCI Mammographic Mass and UCI Breast Cancer Wisconsin (Diagnostic), CBIS-DDSM curated breast imaging subset (case description metadata), with UCI Mammographic Mass and UCI Breast Cancer Wisconsin (Diagnostic), CC BY 3.0 (TCIA, DOI 10.7937/K9/TCIA.2016.7O02S9CY) and CC BY 4.0 (UCI). 2,446 rows, DDSM films digitised in the 1990s; Mammographic Mass 2003-2006; Wisconsin 1995.

Libraries and methods this analysis used

Read from this project's own run.py when the page was built — 500 lines of it. Not a list of everything we know; a list of what this analysis imports and calls.

8 names from NumPy appear in this analysis.

  • column_stack
  • errstate
  • histogram
  • isfinite
  • linspace
  • median
  • percentile
  • random
Verification

How every number on this page is checked

A script deletes each result file, re-runs the project and diffs the output. If a headline figure moves, the check fails, and the page does not ship. That is the only reason to believe anything on this page.

Running this method on your own data

The method above transfers; the result will not. Send us a extract and we will tell you what is forecastable in it and what is not, before anyone signs anything.