1854 - John Snow ja kolera#

Kulkutaudit, nuo ihmiskunnan ikiaikaiset kumppanit, olivat suuria katastrofeja ennen moderneja hoitokeinoja tai ymmärrystä hygienian tärkeydestä. 1800-luvun alkupuoliskolla pelättiin etenkin koleraa, kuivattavaa suolistotautia joka saattoi tappaa terveenkin aikuisen yhtäkkiä jopa keskelle tietä. Sille ominainen kalvaan sinertävä iho vaani monien painajaisissa eikä kukaan, rikas tai köyhä, ollut suojassa sen tuhoilta. Pandemiat kaatoivat väkeä aina Intiasta Kanadaan. Pelkästään Isossa-Britanniassa kuoli kymmeniä tuhansia sen riuduttamana, Venäjällä yli miljoona. Suomessakin koettiin kolmeen otteeseen 1830-50 -luvuilla rajuja aaltoja, joista mm. 1853 epidemia tappoi 10% Hämeenlinnan väestöstä.

Pian inhimillisen kärsimyksen keskeltä nousisi kuitenkin uusi ymmärrys taudinaiheuttajista, tilastotieteen käytöstä terveydenhuollossa sekä epidemiologian tutkimusala, jonka avulla kolera ja monet muut taudit saataisiin talttumaan. Tämän liikkeen kärjestä löytyy nuori englantilainen lääkäri, John Snow (joka tiesi aika paljonkin juttuja).

Ennen Louis Pasteurin 1860-luvun todisteita mikrobien roolista tautien synnyssä, suurin osa ihmisistä vannoi ”miasman” eli saastuneen ilman nimeen taudinaiheuttajana jos mihinkin vaivaan. Snow kannatti näkemystä, jossa taudinaiheuttajat saattoivat sen sijaan olla itsensä replikointiin kykeneviä biologisia olioita, esimerkiksi bakteereja, kuten nykyään tiedetään todeksi. Miasman väitettiin saavan alkunsa hautuumailta, soilta, kaatopaikoilta ja muilta ikäviltä alueilta, mutta se toimi epätyydyttävänä käsienheilutteluvastauksena lähes missä tahansa missä oli likaa ja ihmisiä. Kolerabakteeri sinänsä (Vibrio cholerae) kuvattiin italialaisen Filippo Pacinin toimesta jo 1854, mutta löytöä ei juuri noteerattu ennen Robert Kochin 1883 töitä, jolloin mikrobiteoria oli jo löytänyt tiensä tieteen valtavirtaan.

Tässä harjoitteessa tarkastellaan kahta epidemiatapausta Lontoossa, joiden pohjalta Snow ja muut pystyivät osoittamaan koleran leviävän saastuneen veden kautta. Kannattaa myös alkuun katsoa Extra Historyn erinomainen kolmen videon ”Broad Street Pump” -sarja Youtubesta asian pohjustuksena: https://www.youtube.com/watch?v=TLpzHHbFrHY (vie noin ~20 minuuttia, mush!)

Vesi - välttämätön, mutta vaarallinen aine#

Ihminen tarvitsee jatkuvasti vettä, eikä ole yllätys että vedenpumppaamot ovat olleet oleellisessa roolissa teollistuneen yhteiskunnan rakentumisessa. Moderni ihminen ymmärtää välttää likaista vettä, mutta 1800-luvulla oli yhä täysin normaalia kaataa niin ulosteet, ruuantähteet kuin teollisuusjätteetkin suoraan lähimpään vesistöön. Lontoota halkova suuri Thames-joki, josta miljoonakaupungin juomavesi nostettiin, oli samalla kaupungin viemärijärjestelmien, tehtaiden ja asukkaiden laskupaikka, joka haisi kuvottavalta. Ajan ajattelulle oli ominaista kuvitella taudinaiheuttajia jonkinlaisina myrkkyinä, jotka laimenisivat olemattomiin joen kokoisessa virrassa. Replikoituva bakteeri, joka lisääntyisi vaarallisiin määriin pienestäkin kontaminaatiosta, oli vieras käsite.

Oireiden alkaminen vatsakivuilla viittasi John Snown mielestä nieltyyn taudinaiheuttajaan (verrattuna hengitettyyn miasmaan) ja hän alkoikin tarkastella törkyisten viemärivalumien vaikutusta tilastoituihin tapauksiin. Eräällä kadulla toisen puolen jätteen virtasivat kohti kaivoa, toisella poispäin. Kun lähes kaikki alueen sairastapaukset olivat sillä puolen, missä jäte valui kaivon luo, hän vakuuttui itse juomaveden tärkeydestä taudin leviämisessä. Kuten arvata saattaa, juuri kukaan ei uskonut häntä.

Pian tarjoutui kuitenkin uusi tilaisuus: etelä-Lontoossa roihahti joukko uusia tapauksia, joita Snow lähti tutkimaan jakamalla ne vedenjakeluyhtiöiden mukaan. Alueella vaikutti kaksi firmaa: Southwark & Vauxhall sekä Lambeth. Näistä Southwark & Vauxhallin käsittelylaitos sijaitsi alavirtaan suuresta viemärin laskuaukosta, siinä missä Lambethin vesi tuli ylempää Thamesista.

Tehdään simulaatio aiheesta. Ohjelmointiaika!

# AJA NÄMÄ PAKETIT ENSIN

import pandas as pd
import matplotlib.pyplot as plt
import random as rnd
import numpy as np
# Luodaan joukko satunnaisia kotitalouksia, joille arvotaan vedenjakelija ja karttakoordinaatit 100 x 100 kartalla.

n = 100 # talouksien määrä, vaikuttaako määrä tuloksiin?
i = 0

data = []
while i < n:
    a = [rnd.uniform(0,100), rnd.uniform(0,100), rnd.choice(["Southwark and Vauxhall Co.", "Lambeth Co."]), 'No']
    data.append(a)
    i += 1
    
df = pd.DataFrame(data, columns = ['Location X', 'Location Y', 'Water supplier', 'Fatality'])
# Arvotaan tässä, millä todennäköisyydellä eri pumppaamojen asiakkaat kokevat kuolemantapauksia.
# Tämä solu heittää ajettaessa varoitusviestiä, mikä ei haittaa mitään sen toiminnan kannalta.
x = 0

while x < len(df):
    b = rnd.uniform(0,100) # arpoo prosenttiluvun kullekin talolle
    if (df['Water supplier'][x] == "Lambeth Co."):
        if b < 10: # vertaa tartuntariskiin
            df['Fatality'][x] = "Yes"
    if (df['Water supplier'][x] == "Southwark and Vauxhall Co."):
        if b < 70:
            df['Fatality'][x] = "Yes"
    x += 1
 
/tmp/ipykernel_1748/704195990.py:9: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df['Fatality'][x] = "Yes"
/tmp/ipykernel_1748/704195990.py:12: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df['Fatality'][x] = "Yes"
# Tarkastellaan miltä kotitalouksien tiedot näyttävät.

df.head(10)
Location X Location Y Water supplier Fatality
0 15.242784 82.085970 Lambeth Co. Yes
1 58.991649 77.715409 Lambeth Co. No
2 75.357426 52.505472 Southwark and Vauxhall Co. No
3 7.119332 56.753356 Southwark and Vauxhall Co. Yes
4 24.893642 5.418371 Southwark and Vauxhall Co. Yes
5 60.237352 42.433371 Lambeth Co. No
6 57.402937 41.494215 Lambeth Co. No
7 94.522418 31.397592 Lambeth Co. No
8 55.280259 36.765422 Southwark and Vauxhall Co. Yes
9 94.896928 75.723830 Southwark and Vauxhall Co. No
# Eritellään taloudet vedentarjoajien mukaan ja tarkastellaan tämänkertaista kuolleisuuslukua.

L = df[df["Water supplier"] == "Lambeth Co."]
SV = df[df["Water supplier"] == "Southwark and Vauxhall Co."]

mL = L[L["Fatality"] == "Yes"]
mSV = SV[SV["Fatality"] == "Yes"]

pL = round(len(mL)/len(L)*100, 1)
pSV = round(len(mSV)/len(SV)*100, 1)
             
print("Lambethin kuolleisuus on " + str(pL) + "% " + str(len(L)) + " taloudesta.")
print("Southwark and Vauxhallin kuolleisuus on " + str(pSV) + "% " + str(len(SV)) + " taloudesta.")
Lambethin kuolleisuus on 6.2% 48 taloudesta.
Southwark and Vauxhallin kuolleisuus on 69.2% 52 taloudesta.
# Laitetaan äskeiset tiedot kartalle visualisaation helpottamiseksi. Mitä mustat tähdet kuvaavat?
# Karttapohja on tässä simulaatiossa vain koriste, palaamme siihen myöhemmin.

plt.figure(figsize = (20, 20))
img = plt.imread("../kuvat/snowmap_1854.png")

plt.subplot(121)
plt.imshow(img, extent=[0, 100, 0, 100])
plt.scatter(mL["Location X"], mL["Location Y"], color="black", marker = '*', s = 250)
plt.scatter(L["Location X"], L["Location Y"], color="red")
plt.title('Lambethilta juovat \n')


plt.subplot(122)
plt.imshow(img, extent=[0, 100, 0, 100])
plt.scatter(mSV["Location X"], mSV["Location Y"], color="black", marker = '*', s = 250)
plt.scatter(SV["Location X"], SV["Location Y"], color="red")
plt.title('Southwark and Vauxhallilta juovat \n')

plt.show()
../_images/1854_koleraepidemia_9_0.png

Tapauksessa, jota Snow tutki, kuukauden 44 koleraan kuolleesta jako Southwark & Vauxhallin ja Lambethin asiakkaiden välillä oli 38/6. Oli selvää, että hän oli oikeilla jäljillä ja toinen pumppaamoista tarjosi saastuneempaa vettä.

Tehtävä 1:

Jos oletetaan, että keskiverrolla kaupunkilaisella oli vaikkapa 5 % sauma saada tauti toista kautta, millainen todennäköisyys sairastua yksittäisellä Southwarkin & Vauxhallin veden juojalla pitäisi suunnilleen olla tuon 38/6 suhteen saamiseksi? Kokeile haarukoida yllä olevilla koodisoluilla numeerisesti (huomaa toki, että ns. ”oikeilla” luvuillakin voi tulla erilaisia tuloksia, kun kyseessä on satunnainen otos).

Valitettavasti kiire kutsui tohtoriamme kohti operaation seuraavaa osaa ennen näiden tietojen kunnollista julkaisua: Sohon kaupunginosassa, Broad Streetillä (nyk. Broadwick Street) räjähti syyskuun 1854 alussa päälle täysi paniikki ihmisten kuollessa kovempaa tahtia kuin ruumisarkkuja ehdittiin kantaa pois.

Pumput - saastumislähteet ja terveysmaantiede#

Tässä osiossa käytetään autenttisia tietoja tapahtumista elo-syyskuussa 1854.

John Snow kuuli asiasta 4.9. ja käytti seuraavat kolme päivää juosten ympäriinsä keräämässä aineistoa, piirtäen karttoja ja vakuuttaen paikallishallintoa tarpeellisista vastatoimista. Jokainen tuhlattu hetki tarkoitti lisää tartuntoja ja kuolleita.

# AJA NÄMÄ PAKETIT ENSIN, JOLLET AJANUT EDELLISTÄ OSIOTA

import pandas as pd
import matplotlib.pyplot as plt
import random as rnd
import numpy as np
# Historiallinen data, joka on kerätty Robin Wilsonin julkaisemista paketeista 
# täältä http://blog.rtwilson.com/john-snows-cholera-data-in-more-formats/

ajat = pd.read_csv("../data/johnsnow_dataset_dates_all.csv")
kuolinluvut = pd.read_csv("../data/johnsnow_dataset_deaths.csv")
pumput = pd.read_csv("../data/johnsnow_dataset_pumps_names.csv")
# Tästä nähdään tapahtumien aikakehitys.

plt.figure(figsize=(20,5))
plt.plot(ajat["date"], ajat["attacks"], label = 'Sairastumiset')
plt.plot(ajat['date'], ajat['deaths'], label = 'Kuolemat')
plt.xticks(rotation='45')
plt.legend(fontsize = 20)
plt.title('Päivittäiset uudet tapaukset \n', fontsize = 20)

plt.show()
../_images/1854_koleraepidemia_15_0.png

Yllä olevasta kuvaajasta nähdään naapuruston sairastapausten räjähtävän käsiin kuun taitteessa. Myöhemmissä arvioissa Snow on uskonut taudin olleen jo luonnostaan laskussa toimiensa aikaan (esimerkiksi ihmisten karattua paikalta), mutta jotain ratkaisevaa tapahtuu 8.9., mikä katkaisee isomman leviämisen lähes samantien.

Snow kiersi paikanpäällä aikansa, mutta yhden ihmisen tiedonkeruuoperaatio kuolevien ihmisten, paetessa hylättyjen talojen ja yleisen kaaoksen keskellä olisi tullut liian hitaaksi. Sen sijaan tohtorimme kääntyi tehokkaampaan suuntaan ja marssi paikallisen tilastokeskuksen, Office of Register Generalin, puheille ja vaati käyttöönsä kaikkien kuolemantapausten ajat ja osoitteet. Alla on alueen kartta, mihin hän merkkasi kuolleet mustina vaakaviivoina kuin vierekkäiset hauta-arkut pihoille.

Tehtävä 2:

Katsomalla yllä olevaa karttaa, mitä voit sanoa kuolintapausten asettumisesta kartalle?

Miksi puolen tuhatta työläistä asuttanut köyhäintalo (work house) kärsi vain muutamia tapauksia?

Miksi uhreja vilisevän alueen keskellä oleva olutpanimo (brewery) ei kärsinyt yhtäkään?

Matemaattisesti nohevana kaverina Snow sovelsi ylläolevaan kuvaan aikanaan vielä melko tuntematonta menetelmää, eli pistetiheyden kartoitusta ja myöhemmin Voronoin diagrammina tunnetuksi tulevaa ajatusta, jossa karttaan muodostuu alueita joiden kaikista pisteistä on lyhin matka johonkin tiettyyn paikkaan. Snown aiempi aavistus vedenjakelun vaikutuksesta äkillisiin tautipurkauksiin ohjasi silmän nopeasti oikeaan paikkaan:

Mikä kartalla olevista pumpuista (julkinen juomavesi haettiin kadulta yhteisistä pumpuista, jollei sitä tullut sisään talouksiin) on luonteva oletus tartuntojen lähtöpisteeksi?

# Ja sitten sama modernille kartalle, mistä voimme tehdä koneellisen tarkkaa etäisyyslaskentaa.

import folium
from folium.map import Marker
# Kuolemien paikkatiedot listaksi, joka on helppo syöttää kartanpiirtoon.

dat = [0]*len(kuolinluvut)
for i in range(0, len(kuolinluvut)):
    dat[i] = [kuolinluvut['X coordinate'][i], kuolinluvut['Y coordinate'][i]]

# Pumppujen paikkatiedot samoin.
    
kaivot = [0]*len(pumput)
for i in range(0, len(pumput)):
    kaivot[i] = [pumput['X coordinate'][i], pumput['Y coordinate'][i]]

# Tässä päästäänkin jännän äärelle, kun halutaan laskea jokaisen kuolinpaikan lähin pumppu. Osaatko sanallistaa,
# mitä tässä vaiheessa ohjelma tekee? Mitä kussakin vaiheessa tapahtuu, noin ajatustasolla?

closest = []
for i in range(len(kuolinluvut)):
    near = 1000
    ind = 0
    for b in range(len(kaivot)):
        dist = np.sqrt((kuolinluvut['X coordinate'][i]-pumput['X coordinate'][b])**2 
                   + (kuolinluvut['Y coordinate'][i]-pumput['Y coordinate'][b])**2)
        if dist < near:
            near = dist
            ind = b
    closest.append(pumput['Pump Name'][ind])
    
# Tehdään kartta m

m = folium.Map([51.5135, -0.137], tiles='stamentoner', zoom_start=17)

# Merkataan siihen kuolinpaikat, kunkin selitteeksi määrät ja lähimmän pumpun nimi.

for i in range(0,len(kuolinluvut)):
    Marker(dat[i], popup = str('Kuolleita : ' + str(kuolinluvut["Number of deaths"][i]) 
                                + '\n' + 'Lähin pumppu : ' + str(closest[i])), 
           icon = folium.Icon(color="purple")).add_to(m)

# Merkataan myös kaivot selkeästi eri värillä.
    
for i in range(0, len(kaivot)):
    Marker(kaivot[i], popup = pumput["Pump Name"][i], 
           icon=folium.Icon(color='red', icon='tint', prefix='fa')).add_to(m)

# Näytetään kartta.
m
Make this Notebook Trusted to load map: File -> Trust Notebook
# Vaikka tulos silmämääräisesti onkin aika selvä, vilkaistaas vielä jakaumaa tarkemmin.

plt.figure(figsize = (10,5))
plt.hist(closest, weights = kuolinluvut['Number of deaths'], align = 'left', label = 'Kuolemat', color = 'blue')
plt.hist(closest, align = 'mid', label = 'Taloudet', color = 'orange')
plt.title('Kolerakuolemat Sohossa syksyllä 1854 lähimmän pumpun mukaan \n', fontsize = 20)
plt.legend(fontsize = 20)
plt.show()
../_images/1854_koleraepidemia_23_0.png

Tehtävä 3, haastava:

Jos ohjelmointi tuntuu sujuvan, saatko piirrettyä karttamerkkejä päivä kerrallaan niin, että voit seurata tapauksien etenemistä?

Epilogi - kohti sanitaarisempaa nykypäivää#

Snow, juostuaan nukkumatta kolmatta päivää, sai lopulta näillä tuloksillaan vakuutettua paikallisen komitean tilanteen luonteesta ja 8.9. aamusta Broad Streetin pumpusta poistettiin kahva niin ettei sitä voinut käyttää ja epidemia laantui. Tämä ei suoraan yhdistänyt koleraa miasman sijaan bakteereihin, mutta tämä yhteys saatiin jälkipyykissä paikallisen papin Henry Whiteheadin yhteyksien avulla selville: elokuun viimeisinä päivinä, koleraan sairastuneen vauvan vaipat oli pudotettu pumpun viereisen talon alla olleeseen likakaivoon, mistä bakteerit olivat seinähalkeamien kautta päässeet kaivon käyttämään pohjaveteen ja katastrofin ainekset olivat valmiit.

Vaikka mikrobiteorian tuominen yleiseen elämään ja sairaanhoitoon veikin vielä kauan, tapauksen jälkeen oli selvää kaikille, että yleisen hygieniatason oli noustava ja nopeasti. Ympäri maailmaa seurasi valtavia viemäritöitä, joissa kokonaisia kaupunkeja nostettiin juuriltaan (Chicagossa kirjaimellisesti, taloja tunkattiin ylös kokonaisina ja putket vedettiin kaupungin alle) ja jätteen poistuminen kaduilta pelasti miljoonia ihmishenkiä.

Kolera ja sen kaltaiset taudit ovat länsimaissa harvinaisia, mutta taistelu niitä vastaan jatkuu yhä köyhemmillä alueilla. Tuoreena esimerkkinä lokakuussa 2010 Haitilla, vajaa vuosi sen jälkeen kun maanjäristykset tappoivat 200000 ihmistä, raportoitiin yli 665000 koleratapausta ja 8183 kuollutta. Kansainvälinen tuki ja infrastruktuurin rakentaminen alusta asti kunnolla on äärimäisen tärkeää näillä alueilla, jotta mahdollisimman monille voidaan taata inhimillisemmät elinolot.

Lisää luettavaa:#

Huldén, Lena (2006): Kuusijalkainen vihollinen

https://en.wikipedia.org/wiki/1854_Broad_Street_cholera_outbreak

https://www.cdc.gov/cholera/haiti/index.html

http://blog.rtwilson.com/john-snows-cholera-data-in-more-formats/