Last active
April 18, 2020 22:06
-
-
Save dlmanning/04b117b8a81dfcf64f14a37a6f398118 to your computer and use it in GitHub Desktop.
Runs a simulation of doing the Standford Santa Clara County serological survey 30000 times against a given population
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Hypothetical distribution of study results in a population with 0% prevalence using a test with 98.5% selectivity | |
[0.0078, 0.0084]: | | |
[0.0084, 0.0090]: | | |
[0.0090, 0.0096]: || | |
[0.0096, 0.0102]: ||||| | |
[0.0102, 0.0108]: ||||||||| | |
[0.0108, 0.0114]: |||||||||||||||||| | |
[0.0114, 0.0120]: |||||||||||||||||||||||||||||||| | |
[0.0120, 0.0126]: |||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0126, 0.0132]: |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0132, 0.0138]: |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0138, 0.0144]: ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0144, 0.0150]: ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0150, 0.0156]: |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0156, 0.0162]: ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0162, 0.0168]: |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0168, 0.0174]: ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0174, 0.0180]: ||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0180, 0.0186]: ||||||||||||||||||||||||||||||||||||| | |
[0.0186, 0.0192]: ||||||||||||||||||||||| | |
[0.0192, 0.0198]: ||||||||||||||| | |
[0.0198, 0.0204]: |||||||| | |
[0.0204, 0.0210]: ||||| | |
[0.0210, 0.0216]: ||| | |
[0.0216, 0.0222]: | | |
[0.0222, 0.0228]: | | |
[0.0228, 0.0234]: | | |
[0.0234, 0.0240]: | |
[0.0240, 0.0246]: | |
[0.0252, 0.0258]: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Hypothetical distribution of study results in a population with 1% prevalence using a test with 99.5% selectivity | |
[0.0069, 0.0075]: | | |
[0.0075, 0.0081]: | | |
[0.0081, 0.0087]: || | |
[0.0087, 0.0093]: |||| | |
[0.0093, 0.0099]: |||||||| | |
[0.0099, 0.0105]: ||||||||||||||||| | |
[0.0105, 0.0111]: ||||||||||||||||||||||||||||| | |
[0.0111, 0.0117]: ||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0117, 0.0123]: |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0123, 0.0129]: ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0129, 0.0135]: ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0135, 0.0141]: |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0141, 0.0147]: ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0147, 0.0153]: |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0153, 0.0159]: ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0159, 0.0165]: |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0165, 0.0171]: ||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
[0.0171, 0.0177]: |||||||||||||||||||||||||||||||||||| | |
[0.0177, 0.0183]: ||||||||||||||||||||| | |
[0.0183, 0.0189]: |||||||||||||| | |
[0.0189, 0.0195]: ||||||||| | |
[0.0195, 0.0201]: |||| | |
[0.0201, 0.0207]: || | |
[0.0207, 0.0213]: | | |
[0.0213, 0.0219]: | | |
[0.0219, 0.0225]: | | |
[0.0225, 0.0231]: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const crypto = require('crypto'); | |
/** | |
* Extremely simple simulation of possible outcomes of the Santa Clara Country Serological Survey | |
* see: https://www.medrxiv.org/content/10.1101/2020.04.14.20062463v1 | |
*/ | |
const N = 3330; // Size of Santa Clara County Serological Study | |
const PREVALANCE = 0.01; // Hypothetical population prevalance of SARS-CoV-2 | |
const SPECIFICITY = .995; // Estimated test kit specificity | |
const SENSITIVITY = .918; // Estimated test kit sensitivity | |
const results = []; | |
for (let i = 0; i < 30000; i++) { | |
const study_prevalance = doStudy(N, PREVALANCE, SPECIFICITY, SENSITIVITY); | |
results.push(study_prevalance); | |
} | |
printResults(results, 25); | |
/** | |
* @param {Number} n - The number of individuals in the study sample | |
* @param {Number} prevalance - The actual prevalance in the population | |
* @param {Number} specificity - Probability the test correctly detects a negative result | |
* @param {Number} sensitivity - Probability the test correctly detects a positive result; | |
*/ | |
function doStudy(n, prevalance, specificity, sensitivity) { | |
const participants = []; | |
for (let i = 0; i < n; i++) { | |
// Generate a random sample from the population with the given prevalance | |
participants.push(random() < prevalance); | |
} | |
// Test everyone in the sample | |
const testedPositive = participants.reduce((total, isReallyPositive) => { | |
if (isReallyPositive) { | |
if (random() < sensitivity) { | |
total += 1; // Correctly concluded a positive individual is positive | |
} else { | |
// False negative | |
} | |
} else { | |
if (random() > specificity) { | |
total += 1; // False positive | |
} else { | |
// Correctly concluded a negative individual is negative | |
} | |
} | |
return total; | |
}, 0); | |
// Return detected sample prevalance | |
return testedPositive / n; | |
} | |
function printResults(studyResults, bins) { | |
const numberOfStudies = studyResults.length; | |
studyResults.sort(); | |
const maxResult = studyResults[numberOfStudies - 1]; | |
const minResult = studyResults[0]; | |
const binWidth = Math.floor((maxResult * 10000 - minResult * 10000) / bins) / 10000; | |
const results = studyResults.reduce((report, result) => { | |
const idx = Math.floor((result - minResult) / binWidth); | |
report[idx] += 1; | |
return report; | |
}, Array(bins + 1).fill(0)); | |
let output = ''; | |
results.forEach((result, idx) => { | |
output += `[${Number((idx) * binWidth + minResult).toFixed(4)}, ${Number((idx + 1) * binWidth + minResult).toFixed(4)}]: `; | |
for (let i = 0; i < result / 30; i++) { | |
output += '|'; | |
} | |
output += '\n'; | |
}); | |
console.log(output); | |
} | |
function random() { | |
return Math.random(); | |
// use this one for better random numbers. Takes a lot longer. | |
// return crypto.randomBytes(4).readUInt32BE(0) / 2 ** 32 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment