Section 1 of 7

1 Before you start

Before you begin, take a few minutes to check what you already know and how confident you feel. You will see the same questions again at the end of the module — this helps both you and us measure what you have learned. Click an option for every question and confidence rating, then click Next to continue.

Pre-test

A diagnostic 2x2 table is built by cross-classifying each patient on two things. What are they?

Pre-test

A test reports POSITIVE for a patient who does NOT have the disease. What is this result called?

Pre-test

A test reports NEGATIVE for a patient who truly HAS the disease — the dangerous miss that sends a sick patient home. What is this result called?

Pre-test

When you lay four counts into a 2x2 grid with matrix(counts, nrow = 2), why set byrow = TRUE?

Pre-test

You have a labelled 2x2 table and want to append row and column totals to sanity-check the margins. Which function does this?

Pre-test

Sensitivity is computed from the 2x2 table by reading

Pre-test

A table has TP = 90, FP = 7, FN = 10, TN = 93. What is the test's specificity?

Pre-test

You move a test to a clinic where the disease is twice as common. What happens to the test's sensitivity?

Pre-confidence

I can cross-classify patients into a 2x2 diagnostic table and name its four cells — true positive, false positive, false negative, and true negative.

Not at all confident
Fully confident
Pre-confidence

I can build a labelled 2x2 table in R with matrix() and byrow = TRUE, name it with dimnames, and add row and column totals with addmargins().

Not at all confident
Fully confident
Pre-confidence

I can read sensitivity and specificity down the disease columns of a 2x2 table and explain why they do not change when the disease becomes more or less common.

Not at all confident
Fully confident
Section 2 of 7

2 Introduction

Earlier you met conditional probability — the chance of one event once you already know another, written P(A | B). Every diagnostic-test calculation is that idea made concrete: you take what you know about a patient and ask how the test behaves. This part builds the small table that all of those calculations start from, and reads the first two metrics off it.

This part of the module covers two foundations, the second building on the first:

  • The 2x2 diagnostic table — the four counts (true positive, false positive, false negative, true negative) that every test metric is built from, laid out in R.
  • Sensitivity and specificity — fixed properties of the test itself, read down the disease columns and unchanged by how common the disease is.

By the end of this part you will be able to name the four cells of a 2x2 table, build the table with matrix() (remembering byrow = TRUE), label it with dimnames and add totals with addmargins(), and read sensitivity and specificity down the disease columns — and explain why those two numbers do not change when prevalence does.

Try every snippet in the R Scratchpad on the right. This part needs no data file — you will build the small tables yourself with matrix() and c().

Section 3 of 7

3 The 2x2 table: four counts, four names

Every diagnostic-test calculation starts from one small table. You cross the test result (positive or negative) against the truth (disease present or absent), and count how many patients fall in each of the four cells. That is the whole foundation — get the four counts right and every metric follows.

Each cell has a name that says whether the test got it right:

  • true positive (TP) — the test says positive and the disease really is present. A correct alarm.
  • false positive (FP) — the test says positive but the disease is absent. A false alarm.
  • false negative (FN) — the test says negative but the disease is present. A missed case.
  • true negative (TN) — the test says negative and the disease really is absent. A correct all-clear.
Every diagnostic-test metric begins by cross-classifying each patient's test result against their true disease status into four counts (true positive, false positive, false negative, true negative), where the two "true" cells are correct calls and the two "false" cells are the test's errors.
Every diagnostic-test metric begins by cross-classifying each patient's test result against their true disease status into four counts (true positive, false positive, false negative, true negative), where the two "true" cells are correct calls and the two "false" cells are the test's errors.

The word true or false tells you whether the test was correct; the word positive or negative tells you what the test said. So a false negative is a negative result that was wrong — the dangerous miss that sends a sick patient home.

Section 3.1 of 7

3.1 Building the table with matrix() and addmargins()

You lay the four counts into a 2x2 grid with matrix(). Give it the four numbers, tell it how many rows with nrow = 2, and — this is the part beginners skip — set byrow = TRUE so R fills the grid row by row in the order you wrote them, not down the columns.

Suppose 90 patients have a positive test and disease (TP), 7 have a positive test but no disease (FP), 10 test negative yet have disease (FN), and 93 test negative with no disease (TN). Lay them out with the test in the rows and the disease in the columns.

Try it out

Try this snippet in the R Scratchpad on the right.

Try this snippet
counts <- c(90, 7, 10, 93)
tab <- matrix(counts, nrow = 2, byrow = TRUE)
tab
matrix() with byrow = TRUE fills a 2x2 across each row in the order the values were written, whereas the default fills down the columns and silently rearranges the cells.
matrix() with byrow = TRUE fills a 2x2 across each row in the order the values were written, whereas the default fills down the columns and silently rearranges the cells.

A bare table of numbers is hard to read, so label it. Set dimnames to name the rows and columns, and add row and column totals with addmargins — it appends a Sum row and a Sum column so you can see the margins at a glance.

Try it out

Try this snippet in the R Scratchpad on the right.

Try this snippet
counts <- c(90, 7, 10, 93)
tab <- matrix(counts, nrow = 2, byrow = TRUE)
dimnames(tab) <- list(Test = c("Positive", "Negative"),
                       Disease = c("Yes", "No"))
addmargins(tab)
Naming a matrix's rows and columns with dimnames and appending row/column totals with addmargins turns a bare grid of counts into a readable contingency table whose margins are visible at a glance.
Naming a matrix's rows and columns with dimnames and appending row/column totals with addmargins turns a bare grid of counts into a readable contingency table whose margins are visible at a glance.

Read the margins to sanity-check. The Disease = Yes column sums to 100 diseased patients (90 + 10), and the Test = Positive row sums to 97 positives (90 + 7). Knowing which margin is which is the key to everything that follows.

Section 4 of 7

4 Sensitivity and specificity: properties of the test

With the table built, the first two metrics describe the test itself. You read them DOWN the disease columns — start from patients whose true status you already know, and ask how often the test agrees.

The sensitivity is the proportion of truly diseased patients the test correctly flags as positive. In symbols it is P(positive | disease) — you condition on disease, so you read down the Disease = Yes column: TP / (TP + FN). A sensitive test misses few real cases.

The specificity is the proportion of truly healthy patients the test correctly clears as negative. That is P(negative | no disease) — you read down the Disease = No column: TN / (TN + FP). A specific test raises few false alarms.

Sensitivity and specificity are each read down a single disease column of the 2x2 table, conditioning on the patient's true status (TP/(TP+FN) for sensitivity, TN/(TN+FP) for specificity).
Sensitivity and specificity are each read down a single disease column of the 2x2 table, conditioning on the patient's true status (TP/(TP+FN) for sensitivity, TN/(TN+FP) for specificity).

From our table, sensitivity is 90 / (90 + 10), which is 0.90, and specificity is 93 / (93 + 7), which is 0.93. The test catches 90% of real cases and correctly clears 93% of healthy people.

Try it out

Try this snippet in the R Scratchpad on the right.

Try this snippet
tp <- 90
fp <- 7
fn <- 10
tn <- 93
sensitivity <- tp / (tp + fn)
specificity <- tn / (tn + fp)
c(Sensitivity = sensitivity, Specificity = specificity)
Sensitivity and specificity are two column-wise readings of the same 2x2 table, each dividing the correctly classified count by its true-status column total (sensitivity among those who truly have the disease, specificity among those who are truly healthy).
Sensitivity and specificity are two column-wise readings of the same 2x2 table, each dividing the correctly classified count by its true-status column total (sensitivity among those who truly have the disease, specificity among those who are truly healthy).

Here is the property that makes these two numbers special: sensitivity and specificity do not change when the disease becomes more or less common. They are fixed characteristics of the test, measured against patients of known status. Move the same test to a clinic with twice the prevalence and the sensitivity stays put.

Section 5 of 7

5 Check your understanding

You have reached the end of the module. Try the same questions again — your answers here, paired with your pre-test answers, are how we measure what the module taught you. Answer every question and confidence rating, then click Submit and see results to view your score.

Post-test

A diagnostic 2x2 table is built by cross-classifying each patient on two things. What are they?

Post-test

A test reports POSITIVE for a patient who does NOT have the disease. What is this result called?

Post-test

A test reports NEGATIVE for a patient who truly HAS the disease — the dangerous miss that sends a sick patient home. What is this result called?

Post-test

When you lay four counts into a 2x2 grid with matrix(counts, nrow = 2), why set byrow = TRUE?

Post-test

You have a labelled 2x2 table and want to append row and column totals to sanity-check the margins. Which function does this?

Post-test

Sensitivity is computed from the 2x2 table by reading

Post-test

A table has TP = 90, FP = 7, FN = 10, TN = 93. What is the test's specificity?

Post-test

You move a test to a clinic where the disease is twice as common. What happens to the test's sensitivity?

Post-confidence

I can cross-classify patients into a 2x2 diagnostic table and name its four cells — true positive, false positive, false negative, and true negative.

Not at all confident
Fully confident
Post-confidence

I can build a labelled 2x2 table in R with matrix() and byrow = TRUE, name it with dimnames, and add row and column totals with addmargins().

Not at all confident
Fully confident
Post-confidence

I can read sensitivity and specificity down the disease columns of a 2x2 table and explain why they do not change when the disease becomes more or less common.

Not at all confident
Fully confident
Section 6 of 7

6 Your results

Here is how your post-test answers compare with your pre-test answers. The pre/post pairing is the most reliable way to see what this module actually taught you.

Your score

Submit the post-test to see your results.

Muddiest point

What is the one thing from this module that is still unclear to you?

Rate this module

Overall, how would you rate this module?

How likely are you to recommend this module to a peer? (0 = not at all, 10 = extremely likely)