Der amerikanische Statistiker [Nate Silver](https://ja.wikipedia.org/wiki/%E3%83%8D%E3%82%A4%E3%83%88] ist berühmt für die Wahlvorhersage der US-Präsidentschaftswahlen % E3% 83% BB% E3% 82% B7% E3% 83% AB% E3% 83% 90% E3% 83% BC) auf einer Website namens FiveThirtyEight , "Coronavirus-Fallzahlen sind bedeutungslos" Ich werde.
Die Behauptung in diesem Artikel lautet ** "Wenn Sie nicht genug über die Durchführung der Tests wissen, ist die gemeldete Anzahl von COVID-19-Infektionen kein nützlicher Indikator [^ 1]." * Es wird genannt *. Während ich intuitiv denke, "das ist richtig", ist die Virusinfektion ein exponentielles Phänomen. Selbst wenn die Anzahl der Tests (möglicherweise ** willkürlich **) eingegrenzt wird, ist das Reproduktionsverhältnis Ich sehe und höre auch Behauptungen, dass (später erklärt) beobachtbar sein sollten. Aus einer völlig anderen Sicht gibt es Behauptungen, dass die medizinische Versorgung zusammenbrechen wird, wenn die Tests nicht eingegrenzt werden. Nates Artikel enthält eine einfache Simulation, die Leser als Excel-Tabelle ausprobieren können (https://fivethirtyeight.com/wp-content/uploads/2020/04/covidia_1.05_updated.xlsx). Damit Sie erfahren können, wie die Anzahl der infizierten Personen gemeldet wird und wie viele Personen tatsächlich infiziert sind, hängt von der Testrichtlinie (Auswahl des Testziels und der Gesamtzahl der Tests) und der Infektionskontrolle (soziale Distanzierung und Sperrung) ab. Es ist geworden. Sie können auch den Unterschied zwischen der tatsächlichen Wiedergaberate und der beobachteten scheinbaren Wiedergaberate beobachten.
Das Tabellenkalkulationsmodell [^ 2] ist praktisch, um einfach mit den Parametern zu spielen und den Unterschied in den Ergebnissen zu erkennen. In jeder Zelle der Tabelle steht jedoch $ \ text {BH32} $ "column". Es wird durch eine Kombination aus "= Alphabet" und "Zeile = Zahl" dargestellt, und ihre Beziehung ist in einer BASIC-ähnlichen Formel geschrieben, sodass es nicht sehr gut geeignet ist, zu verstehen, was wie berechnet wird. ..
[^ 2]: Nate Silver hat die Tabelle nicht als Modell gelesen. Es soll nichts vorhersagen.
Also habe ich das Tabellenkalkulationsmodell (manuell) in ein Python-Programm konvertiert, um zu verstehen, was ich tat. Außerdem habe ich die aktuelle Situation in Japan (22. April 2020) als Parameter angegeben und ausprobiert. Obwohl die gemeldete Anzahl infizierter Personen gerade 10.000 überschritten hat, übersteigt die tatsächliche Anzahl der Patienten tatsächlich 7,5 Millionen , was bedeutet, dass etwa 6% der Gesamtbevölkerung infiziert sind. Ich hab es geschafft. Dabei sollten Sie denken: " Wenn Sie nach draußen gehen, ist die nächste Person eine infizierte Person **".
Unter [github] befindet sich ein Jupyter-Notizbuch (https://github.com/survivor7777777/covid-19/blob/master/Infected%20vs%20Detected%20analysis.ipynb).
Wenn Sie sich das Infektionsphänomen als ein Phänomen vorstellen, das kontinuierlich auftritt, wird es zu einer Differentialgleichung, und es ist für einen Amateur schwierig, damit umzugehen. Daher wird es als ein sehr grobes diskretes Phänomen angesehen. Mit anderen Worten, betrachten Sie die Infektionskette als eine Kette von der vorherigen Generation [^ 3] zur nächsten Generation und vereinfachen Sie die Berechnung weiter, indem Sie den Zeitunterschied zwischen den Generationen auf eine bestimmte Konstante festlegen (z. B. 5 Tage).
Der wichtigste Parameter ist die Reproduktionsrate ($ R $), die angibt, wie viele $ n + 1 $ infizierte Personen in der $ n $ -Generation die Krankheit weitergeben. .. Dies hängt von der Infektiosität der Krankheit ab, aber auch vom Verhalten der Menschen in der Gesellschaft. Die Reproduktionsrate des Kreuzfahrtschiffes wäre sehr hoch gewesen, und die Reproduktionsrate von Wuhan wäre niedrig gewesen, da es gesperrt und alle Ausflüge verboten waren. Wenn $ R $ größer als 1 ist, breitet sich die Infektion aus, und wenn sie kleiner als 1 ist, verschwindet die Krankheit schließlich.
[^ 3]: Natürlich ist diese Generation nicht die Babyboomer-Generation oder die tausendjährige Generation, aber die ersten infizierten Menschen werden die 0. Generation genannt, die von dort infizierten Menschen werden die 1. Generation genannt und so weiter.
Die Parameter, die sich auf die Ausbreitung der Krankheit beziehen, werden durch die Klasse "Disease_spread_params" ausgedrückt.
R_uncontrolled
: Reproduktionsrate, wenn keine Maßnahmen ergriffen werden.R_intermediate
: Zwischenreproduktionsraten, bei denen die Menschen vorsichtiger geworden sind, z. B. soziale Distanz, Handwaschpraktiken und das Tragen von Masken.R_lockdown
: Reproduktionsrate, wenn die Sperrung erzwungen wird.Cluster
: Parameter, die angepasst werden müssen, wenn der Anteil infizierter Personen an der Bevölkerung zunimmt (0 = keine Anpassung, 0,5: leicht, 1: mäßig, 2: signifikant)begin_internmediate
: Generierungsnummer, die nach Ablauf der No-Measure-Periode in die Zwischenstufe eintrittbegin_lockdown
: Generierungsnummer, bei der die Sperrung beginntmild
: Infektionsrate und mittelschwere KrankheitPopulationsparameter werden durch die Klasse "Population_params" dargestellt.
Bevölkerung
: Gesamtbevölkerung dieses Landesinitial_infection
: Anzahl der ersten (0. Generation) infiziertenfaux_severe
: Prozentsatz der kritisch kranken Patienten mit anderen COVID-19-ähnlichen Ursachen als Coronavirusfaux_mild
: Prozentsatz der mäßig kranken Patienten mit anderen COVID-19-ähnlichen Ursachen als dem Coronaviruswant_severe
: Prozentsatz kritisch kranker Patienten, die PCR-Tests suchenwant_mild
: Prozentsatz der mäßig kranken Patienten, die PCR-Tests suchenwant_asymptomatic
: Prozentsatz der asymptomatischen Personen, die PCR-Tests suchenParameter, die sich auf PCR-Tests beziehen, werden durch die Klasse "Testing_params" ausgedrückt.
initial_tests
: PCR-Testkapazität für die erste Generationramp_period
: Generierungsnummer, um die Anzahl der Inspektionen zu erhöhentest_growth_rate
: Steigerungsrate seit Beginn der Erhöhung der Anzahl der Teststest_max
: Maximale Anzahl von Testsrationed_test_ratio
: Schwerwiegend> Mittel> Prozentsatz der Tests, bei denen sichergestellt wurde, dass asymptomatische Prioritäten eingehalten werdenfalse_negative
: Prozentsatz der falsch negativen Ergebnisse in PCR-Testsfalse_positive
: Prozentsatz der falsch positiven Ergebnisse in PCR-TestsVerzögerung
: Verzögerung von der Inspektion bis zum Ergebnis (Anzahl der Generationen)Die Werte dieser Parameter werden als Standardwerte angegeben, indem plausible Werte aus verschiedenen Veröffentlichungen ausgewählt werden.
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import time, re
import datetime
iround = lambda x: int((x * 2 + 1) // 2)
class Disease_spread_params:
def __init__(self,
R_uncontrolled = 2.7,
R_intermediate = 1.4,
R_lockdown = 0.7,
cluster = 0.5,
begin_intermediate = 11,
begin_lockdown = 15,
mild = 0.6,
asymptomatic = 0.3,
zero_date = '2020-01-01',
serial = 5):
self.R_uncontrolled = R_uncontrolled
self.R_intermediate = R_intermediate
self.R_lockdown = R_lockdown
self.cluster = cluster
self.begin_intermediate = begin_intermediate
self.begin_lockdown = begin_lockdown
self.severe = 1 - mild - asymptomatic
self.mild = mild
self.asymptomatic = asymptomatic
self.zero_date = zero_date
self.serial = serial
class Population_params:
def __init__(self,
population = 10_000_000,
initial_infection = 1,
faux_severe = 0.001,
faux_mild = 0.025,
desire_severe = 1.0,
desire_mild = 0.5,
desire_asymptomatic = 0.02):
self.population = population
self.initial_infection = initial_infection
self.faux_severe = faux_severe
self.faux_mild = faux_mild
self.desire_severe = desire_severe
self.desire_mild = desire_mild
self.desire_asymptomatic = desire_asymptomatic
class Testing_params:
def __init__(self,
initial_tests = 1_000,
ramp_period = 3,
test_growth_rate = 0.5,
test_max = 10_000_000,
rationed_test_ratio = 0.75,
false_negative = 0.20,
false_positive = 0.002,
delay = 2):
self.initial_tests = initial_tests
self.ramp_period = ramp_period
self.test_growth_rate = test_growth_rate
self.test_max = test_max
self.rationed_test_ratio = rationed_test_ratio
self.false_negative = false_negative
self.false_positive = false_positive
self.delay = delay
Als Funktion zum Runden einer reellen Zahl auf eine Ganzzahl verwende ich hier meine eigene Funktion namens "iround ()" anstelle der in Python integrierten "round ()". Dies dient der Kompatibilität mit der Excel-Funktion ROUND
[^ 4].
[^ 4]: Pythons round ()
wird auf eine gerade Zahl gerundet, während EXCELsround ()
gerundet wird.
Während ich mir die zellenweisen Abhängigkeiten der Tabelle ansah, auf die ich mich bezog, verstand ich, wie sie berechnet und neu implementiert wurde. Um ehrlich zu sein, ist es schmutzig (nicht bescheiden).
Die Simulator
-Klasse nimmt einen Parameter, instanziiert ihn, führt ihn durch Aufrufen der run ()
-Methode aus und gibt das Ergebnis als pandas.DataFrame
zurück.
class Simulator:
def __init__(self,
disease_spread_params,
population_params,
testing_params):
self.disease_spread_params = disease_spread_params
self.population_params = population_params
self.testing_params = testing_params
self.columns = [ 'date', 'actual.R', 'doubling time in days' ]
self.date_regex = re.compile('(\d+)-(\d+)-(\d+)')
def decode_date(self, date):
match = self.date_regex.fullmatch(date)
if match:
y, m, d = match.group(1, 2, 3)
timestamp = time.mktime((int(y), int(m), int(d), 0, 0, 0, -1, -1, -1))
return timestamp
return None
def encode_date(self, timestamp):
t = time.localtime(timestamp)
return '{0:04d}-{1:02d}-{2:02d}'.format(t[0], t[1], t[2])
def run(self, zero_day = '2020-01-01', generations = 40):
self.generations = generations
self.df = pd.DataFrame(index = range(0, self.generations))
t0 = self.decode_date(zero_day)
self.df['date'] = [ self.encode_date(t0 + d * self.disease_spread_params.serial * 24 * 60 * 60) for d in range(0, self.generations) ]
self.set_target_R()
self.compute_actual_infection()
self.compute_tests()
return self.df
def set_target_R(self):
begin_lockdown = self.disease_spread_params.begin_lockdown
begin_intermediate = self.disease_spread_params.begin_intermediate
self.df['target_R'] = np.NaN
for i in range(0, self.generations):
if begin_lockdown != None and i >= begin_lockdown:
self.df.at[i, 'target_R'] = self.disease_spread_params.R_lockdown
elif begin_intermediate != None and i >= begin_intermediate:
self.df.at[i, 'target_R'] = self.disease_spread_params.R_intermediate
else:
self.df.at[i, 'target_R'] = self.disease_spread_params.R_uncontrolled
def compute_actual_infection(self):
population = self.population_params.population
initial_infection = self.population_params.initial_infection
cluster = self.disease_spread_params.cluster
serial = self.disease_spread_params.serial
df = self.df
df['susceptible'] = np.NaN
df.at[0, 'susceptible'] = population - initial_infection
df['new_infection'] = np.NaN
df.at[0, 'new_infection'] = initial_infection
df['cumulative_infection'] = np.NaN
df.at[0, 'cumulative_infection'] = initial_infection
df['actual_R'] = np.NaN
df['actual_doubling_time'] = np.NaN
for i in range(1, self.generations):
df.at[i, 'new_infection'] = iround(df.at[i-1, 'susceptible']*(1-(1-((df.at[i-1, 'target_R']*(df.at[i-1, 'susceptible']/population)**cluster)/population))**df.at[i-1, 'new_infection']))
df.at[i, 'cumulative_infection'] = df.at[i-1, 'cumulative_infection'] + df.at[i, 'new_infection']
df.at[i, 'susceptible'] = population - df.at[i, 'cumulative_infection']
df.at[i-1, 'actual_R'] = df.at[i, 'new_infection'] / df.at[i-1, 'new_infection']
if df.at[i-1, 'cumulative_infection'] != 0:
df.at[i-1, 'actual_doubling_time'] = np.inf if df.at[i, 'new_infection'] == 0 else serial * np.log(2) / np.log(df.at[i, 'cumulative_infection']/df.at[i-1, 'cumulative_infection'])
def compute_tests(self):
population = self.population_params.population
ramp_period = self.testing_params.ramp_period
tests_max = self.testing_params.test_max
test_growth_rate = self.testing_params.test_growth_rate
rationed_test_ratio = self.testing_params.rationed_test_ratio
mild = self.disease_spread_params.mild
asymptomatic = self.disease_spread_params.asymptomatic
faux_severe = self.population_params.faux_severe
faux_mild = self.population_params.faux_mild
desire_severe = self.population_params.desire_severe
desire_mild = self.population_params.desire_mild
desire_asymptomatic = self.population_params.desire_asymptomatic
false_negative = self.testing_params.false_negative
false_positive = self.testing_params.false_positive
delay = self.testing_params.delay
serial = self.disease_spread_params.serial
cumulative_tests_conducted = 0
cumulative_detected_cases = 0
df = self.df
df['tests_available'] = 0
df['new_detected_cases'] = 0
df['cumulative_detected_cases'] = 0
for i in range(0, self.generations):
if i == 0:
df.at[i, 'tests_available'] = 0
elif i == 1:
df.at[i, 'tests_available'] = self.testing_params.initial_tests
elif i < ramp_period:
df.at[i, 'tests_available'] = df.at[i-1, 'tests_available']
else:
df.at[i, 'tests_available'] = iround(min(tests_max, df.at[i-1, 'tests_available'] * (1 + test_growth_rate)))
tests_available = df.at[i, 'tests_available']
rationed_tests = iround(tests_available * rationed_test_ratio)
on_demand_tests = tests_available - rationed_tests
new_infection_severe = iround(df.at[i, 'new_infection'] * (1 - mild - asymptomatic))
new_infection_mild = iround(df.at[i, 'new_infection'] * mild)
new_infection_asymptomatic = df.at[i, 'new_infection'] - new_infection_severe - new_infection_mild
population_severe = iround((population - df.at[i, 'new_infection']) * faux_severe) + new_infection_severe
population_mild = iround((population - df.at[i, 'new_infection']) * faux_mild) + new_infection_mild
population_asymptomatic = population - population_severe - population_mild
desiring_tests_severe = iround(population_severe * desire_severe * (1 - cumulative_tests_conducted/population))
desiring_tests_mild = iround(population_mild * desire_mild * (1 - cumulative_tests_conducted/population))
desiring_tests_asymptomatic = iround(population_asymptomatic * desire_asymptomatic * (1 - cumulative_tests_conducted/population))
alloc_rationed_tests_severe = min(rationed_tests, desiring_tests_severe)
alloc_rationed_tests_mild = min(desiring_tests_mild, rationed_tests-alloc_rationed_tests_severe)
alloc_rationed_tests_asymptomatic = min(desiring_tests_asymptomatic, rationed_tests-alloc_rationed_tests_severe-alloc_rationed_tests_mild)
unfilled_test_demand_severe = desiring_tests_severe - alloc_rationed_tests_severe
unfilled_test_demand_mild = desiring_tests_mild - alloc_rationed_tests_mild
unfilled_test_demand_asymptomatic = desiring_tests_asymptomatic - alloc_rationed_tests_asymptomatic
unfilled_test_demand = unfilled_test_demand_severe + unfilled_test_demand_mild + unfilled_test_demand_asymptomatic
alloc_on_demand_tests_severe = 0 if unfilled_test_demand == 0 else iround(on_demand_tests * unfilled_test_demand_severe / unfilled_test_demand)
alloc_on_demand_tests_mild = 0 if unfilled_test_demand == 0 else iround(on_demand_tests * unfilled_test_demand_mild / unfilled_test_demand)
alloc_on_demand_tests_asymptomatic = 0 if unfilled_test_demand == 0 else iround(on_demand_tests * unfilled_test_demand_asymptomatic / unfilled_test_demand)
tests_conducted_severe = alloc_rationed_tests_severe + alloc_on_demand_tests_severe
tests_conducted_mild = alloc_rationed_tests_mild + alloc_on_demand_tests_mild
tests_conducted_asymptomatic = alloc_rationed_tests_asymptomatic + alloc_on_demand_tests_asymptomatic
df.at[i, 'tests_conducted_severe'] = tests_conducted_severe
df.at[i, 'tests_conducted_mild'] = tests_conducted_mild
df.at[i, 'tests_conducted_asymptomatic'] = tests_conducted_asymptomatic
tests_conducted = tests_conducted_severe + tests_conducted_mild + tests_conducted_asymptomatic
cumulative_tests_conducted += tests_conducted
positive_tests_severe = iround(tests_conducted_severe * new_infection_severe / population_severe * (1 - false_negative)) + \
iround(tests_conducted_severe * (1 - new_infection_severe / population_severe) * false_positive)
positive_tests_mild = iround(tests_conducted_mild * new_infection_mild / population_mild * (1 - false_negative)) + \
iround(tests_conducted_mild * (1 - new_infection_mild / population_mild) * false_positive)
positive_tests_asymptomatic = iround(tests_conducted_asymptomatic * new_infection_asymptomatic / population_asymptomatic * (1 - false_negative)) + \
iround(tests_conducted_asymptomatic * (1 - new_infection_asymptomatic / population_asymptomatic) * false_positive)
if i+delay < self.generations:
df.at[i+delay, 'new_detected_cases'] = positive_tests_severe + positive_tests_mild + positive_tests_asymptomatic
cumulative_detected_cases += df.at[i, 'new_detected_cases']
df.at[i, 'cumulative_detected_cases'] = cumulative_detected_cases
if i > 0 and df.at[i-1, 'new_detected_cases'] > 0:
df.at[i-1, 'observed_R'] = df.at[i, 'new_detected_cases'] / df.at[i-1, 'new_detected_cases']
df.at[i-1, 'observed_doubling_time'] = np.inf if df.at[i, 'new_detected_cases'] == 0 else serial * np.log(2) / np.log(df.at[i, 'cumulative_detected_cases']/df.at[i-1, 'cumulative_detected_cases'])
Nate Silvers Artikel enthält eine Simulation des virtuellen Landes Covidia. Die folgende Grafik ist eine Visualisierung der Ergebnisse. Covidia hat 10 Millionen Einwohner und wird sich mit der Ankunft der ersten infizierten Person am 1. Januar 2020 ausbreiten. Wir gehen von einer anfänglichen Reproduktionsrate von 2,7 $, einer Zwischenstufe von 1,4 $ und einer Sperrrate von 0,7 $ aus.
Die blaue Linie ist die wahre Anzahl neu infizierter Personen, und die gelbe Linie ist der Übergang der Anzahl neu infizierter Personen, die bei der Inspektion gemeldet wurden. In diesem Szenario ist die anfängliche Testkapazität mit 1.000 pro Generation gering. Wenn Sie jedoch die Anzahl der Tests auf unbestimmte Zeit erhöhen, scheint die Anzahl der Berichte entsprechend der tatsächlichen Anzahl infizierter Personen zu steigen, obwohl es eine Zeitverzögerung gibt. ..
Wenn Sie genau hinschauen, können Sie jedoch feststellen, dass in der Phase, in der die Anzahl der infizierten Personen zunimmt, diese um das 20-fache oder mehr unterschätzt wird und wenn sie tendenziell abnimmt, wird sie überschätzt.
Japan wurde dafür kritisiert, die Anzahl der PCR-Tests niedrig zu halten. Das Ministerium für Gesundheit, Arbeit und Soziales berichtet täglich [^ 5], aber es wird gesagt, dass die Anzahl der Inspektionen immer noch nicht mit der Nachfrage Schritt hält. Daher habe ich versucht, was passieren würde, wenn die Anzahl der PCR-Tests für die japanische Bevölkerung von 126 Millionen niedrig eingestellt wäre. Übrigens habe ich auch die Anzahl der positiv bestätigten Personen aufgezeichnet, die bisher tatsächlich gemeldet wurden. Während die obige Grafik die Anzahl der neu infizierten Personen zeigt, ist dies die kumulierte Anzahl der infizierten Personen [^ 6].
[^ 5]: In Neuester Bericht wurden beispielsweise 7826 neue PCR-Tests aus dem Bericht des Vortages durchgeführt. Sie können sehen, dass. Im Gegensatz zur vorherigen Abbildung handelt es sich um eine grafische Darstellung der kumulierten Anzahl infizierter Personen. [^ 6]: Die tatsächlichen Daten werden kumulativ angegeben, und ich dachte, das wäre mir vertrauter.
![fig2.png] (https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223481/193b7bce-f37f-4b9e-727b-223c95b838f5.png)
Hier ist die grüne Linie die tatsächliche Anzahl infizierter Menschen in Japan [^ 6].
[^ 6]: Ich verwende die von der John Hopkins University auf [github] veröffentlichten Daten (https://github.com/CSSEGISandData/COVID-19/tree/master/csse_covid_19_data/csse_covid_19_time_series).
Ich habe nicht vor, in dieser Simulation etwas vorherzusagen, aber zuerst möchte ich, dass Sie die Größe der Differenz zwischen dem wahren Wert (blaue Linie) und dem Simulationsergebnis und dem gemeldeten Wert (grüne Linie) sehen. Folgendes kann beobachtet werden.
Aber was wäre, wenn wir unsere Testkapazität frühzeitig erhöht und unbegrenzt getestet hätten? Das folgende Diagramm zeigt die Ergebnisse, wenn der Anfangswert der Inspektionskapazität auf 10.000 eingestellt ist und die Inspektionskapazität schrittweise, aber unbegrenzt erhöht wird.
Selbst in diesem Fall ist es immer noch nicht möglich, die tatsächliche Anzahl infizierter Personen zu erfassen, aber wir konnten etwa das Zehnfache der aktuellen Anzahl von Reportern beobachten. Obwohl der Anstieg der Anzahl der Reporter (gelb) etwas langsam ist, liegt die Steigung nahe an der Steigung der tatsächlichen Anzahl infizierter Personen, sodass der Unterschied zwischen den beiden als der Unterschied in der Richtung von links nach rechts (Zeitverzögerung) angesehen werden kann, was korrekt ist. Es scheint, dass die Produktionsrate von $ R $ beobachtet werden kann.
Ich denke, es ist wahr, dass es keinen Unterschied in Bezug auf die Behandlung gibt, da es keine Krankenhäuser oder Isolationseinrichtungen gibt, in denen die infizierte Person bekannt ist. Ich denke jedoch, dass sich das tägliche Verhalten der Menschen ein wenig ändern kann, wenn sie wissen, dass die Anzahl der tatsächlich infizierten Menschen 10-mal höher ist als angegeben und in einigen Fällen 100-mal höher.
Ich frage mich, ob die Experten für Infektionswissenschaft im Fernsehen eine viel detailliertere Version dieses Modells erstellen, um die Zukunft vorherzusagen.
Ich weiß es nicht.
Recommended Posts