<jupyter_start><jupyter_text>The Lincoln Index Problem Copyright 2020 <NAME>License: [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](https://creativecommons.org/licenses/by-nc-sa/4.0/)<jupyter_code># If we're running on Colab, install libraries

import sys
IN_COLAB = 'google.colab' in sys.modules

if IN_COLAB:
    !pip install pymc3
    !pip install arviz
    !pip install graphviz<jupyter_output><empty_output><jupyter_text>In [an excellent blog post](http://www.johndcook.com/blog/2010/07/13/lincoln-index/), <NAME> wrote about the Lincoln index, which is a way to estimate thenumber of errors in a document (or program) by comparing results fromtwo independent testers. Here's his presentation of the problem:>"Suppose you have a tester who finds 20 bugs in your program. Youwant to estimate how many bugs are really in the program. You knowthere are at least 20 bugs, and if you have supreme confidence in yourtester, you may suppose there are around 20 bugs. But maybe yourtester isn't very good. Maybe there are hundreds of bugs. How can youhave any idea how many bugs there are? There's no way to know with onetester. But if you have two testers, you can get a good idea, even ifyou don't know how skilled the testers are."Suppose the first tester finds 20 bugs, the second finds 15, and theyfind 3 in common; how can we estimate the number of bugs?I'll use the following notation for the data:For this model, I'll express the data in different notation:* k11 is the number of bugs found by both testers,* k10 is the number of bugs found by the first tester but not the second,* k01 is the number of bugs found by the second tester but not the first, and* k00 is the unknown number of undiscovered bugs.Here are the values for all but `k00`:<jupyter_code>k10 = 20 - 3
k01 = 15 - 3
k11 = 3
num_seen = k01 + k10 + k11
num_seen<jupyter_output><empty_output><jupyter_text>Here's the model:<jupyter_code>import pymc3 as pm

with pm.Model() as model5:
    p0 = pm.Beta('p0', alpha=1, beta=1)
    p1 = pm.Beta('p1', alpha=1, beta=1)
    N = pm.DiscreteUniform('N', num_seen, 350)
    
    q0 = 1-p0
    q1 = 1-p1
    ps = [q0*q1, q0*p1, p0*q1, p0*p1]
    
    k00 = N - num_seen
    data = pm.math.stack((k00, k01, k10, k11))
    y = pm.Multinomial('y', n=N, p=ps, observed=data)
with model5:
    trace5 = pm.sample(500)
with model5:
    pm.plot_posterior(trace5)
with model5:
    pm.traceplot(trace5)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08943089430894309, 'fraction_numerical': 0.042682926829268296, 'mean_word_length': 4.19198312236287, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 16, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '545243', 'license': 'MIT', 'n_tokens_mistral': 886, 'n_tokens_neox': 805, 'n_words': 328, 'path': 'examples/lincoln.ipynb', 'repo_name': 'EricRobertCampbell/ThinkBayes2', 'size': '2475'}