Kuntakierros

Luultavasti olen jostain kohtaa ajanut läpi tai lentänyt yli jokaisen Varsinais-Suomen kunnan, mutta paremman kuvan saisi kun kävisi kurkkaamassa miltä kylillä näyttää.

Varsinais-Suomessa on tällä hetkellä vielä 28 kuntaa, joten matkaa tulee vähintään melko paljon. Kuntien väliset etäisyydet vaihtelevat, mutta jos arvaa keskimääräiseksi välimatkaksi 30 km niin matkaa olisi noin 900 km. Matka olisi ajettavissa yhdessä päivässä jos oikein yrittää.

Todellinen matka kuitenkin riippuu siitä missä järjestyksessä kunnat kiertää. Mahdollisimman lyhyen reitin löytäminen on kuitenkin haastavaa koska mahdollisia reittejä on paljon.
Kyseessä on niin sanottu kauppamatkustajan ongelma, jonka matemaattista ratkaisua on pohdittu enemmänkin. Määränpäiden lukumäärän kasvaessa ongelma muodostuu nopeasti työlääksi ratkaista jopa tietokoneella.

Asiaa pohtiessani pieni nörtti sisälläni heräsi ja päätin kokeilla yksinkertaista algoritmiä. Kirjoitin taulukkoon google mapsin antamia lyhimpiä etäisyyksiä kuntien välillä ja laitoin koneen valitsemaan arvalla seuraavan kohteen. Annoin koneen laskea jonkin aikaa, Kuva 1 näyttää minkä pituisia matkoja löytyi.

Lyhin matka oli 809 km ja pisin 1619 km. Vieläkin pidempiä matkoja olisi varmasti tullut, mutta en jaksanut kirjoittaa taulukkoon kaikkia mahdollisia reittejä. Ajan säästämiseksi laitoin vain etäisyyden muutamaan lähimpään kuntaan.

HistogrammiKuva 1. Noin 600 000 yritystä joista 81786 johti takaisin kotiin. Ryhmästä “Uniikit” on poistettu useampaan kertaan esiintyneet matkan pituudet

Taulukko 1.
Min.  1st Qu.  Median  Mean  3rd Qu.  Max.   Ryhmä
809   1143      1207        1206    1270       1619  Kaikki
809   1119      1215        1211    1304       1619  Uniikit

Koska varsinkin kaikista piirretty histogrammi näyttä kovasti normaalijakautuneelta niin plottasin vielä QQplotin normalli jakaumaa vasten (R-QQnorm). Lineaarinen transformaatio tarvitaan ennen kuin kaikkien jakauma on normaali. Pelkästään uniikit matkan pituudet hyväksyvä jakauma poikkeaa normaalista enemmän. En osaa muuta sanoa kuin että jotain tälläistä voisi odottaa kun kohtuu satunnaisia pituuksia arpoo monta peräkkäin ja laskee summan.

Matkat-QQnorm

Alla laskennassa käytetty R-koodi:

[code language=”css”]

## laske kauppamatkustajan ongelmaa kiertueelle

TSP.distance <- function(yri=10, method = "mininum", verbosity=3){
# method = miten valitaan seuraava paikka
# verbosity = miten paljon kerrotaan toiminnasta

load("kkk.Rdata")
kotiin=kkk[kkk$variable=="Piikkiö", c("X", "variable", "value")]
K=kkk
D.k=numeric()
m.k=list()
m=0
for (j in 1:yri){
kkk=K
D=0
vajaa=F
Uk="Piikkiö"
Kaikki.K=numeric()
Kaikki.K[1]=Uk
for (i in 1:28){
k=kkk[kkk$variable==Uk, "X"]
if (length(k)==0){
vajaa=T
break
}
k=sample(k, 1)
Uk2=as.character(kkk[kkk$variable==Uk &
kkk$X==k,"X"])[1]
D=D+kkk[kkk$variable==Uk & kkk$X==k,"value"][1]
kkk=kkk[!(kkk$X==Uk | kkk$variable==Uk),]
Uk=Uk2
Kaikki.K[i+1]=Uk
}
if (!vajaa){
print(j)
m=m+1
D=D+kotiin[kotiin$X==Uk, "value"]
Kaikki.K[i+2]="Piikkiö"
print(D)
D.k[[m]]=D
m.k[[m]]=Kaikki.K
}
}
Reissut=list(Pituudet=D.k, Kunnat=m.k )
}

TSP.Lyhin <- function(R){
P=10000
for (i in 1:length(R$Pituudet)){
if (R$Pituudet[[i]]<P){
P=R$Pituudet[[i]]
K=R$Kunnat[[i]]
}
}
list(P, K)
}

[/code]

Viitenumeroiden virheistä

Jos tekee vähän kirjoitusvirheitä numeroita kirjoittaessa ei kannata tarkistaa viitenumeroa. Jos tekee paljon niin kannattaa tarkistaa pitkät.

Pedanttina minua on pitkään harmittanut laskujen viitenumeroiden tarkistusnumero järjestelmä. Ei niinkään sen määräytyminen kuin se ettei samassa yhteydessä kerrota asiaan liittyvistä riskeistä. Tarkistusnumeroita on nimittäin vain kymmenen joten satunnaisessa viitteessä on kymmenen prosentin mahdollisuus saada oikea numero. Siis jos arpoo kaikki viitenumeron numerot niin kerran kymmenestä se menee tarkastuksesta läpi. Homma tietysti perustuu siihen, että ihmiset yrittävät kirjoittaa viitenumeron oikein ja yksittäiset virheet jäävät kiinni varmasti.

Itse viitenumeron muodostaminen on yksinkertaista, kuten esim. täältä näkee. Viitenumeron numerot kerrotaan yksitellen numeroilla 7, 3, 1, 7, 3, 1,… Tulot summataan ja vähennetään tulos seuraavasta täydestä kymmenestä (10 => 0). Operaation seurauksena tarkistusnumerot jakautuvat tasaisesti:

Ensimmäinen: 0
Viimeinen: 9
[1 1 1 1 1 1 1 1 1 1]
Ensimmäinen: 10
Viimeinen: 99
[9 9 9 9 9 9 9 9 9 9]
Ensimmäinen: 100
Viimeinen: 999
[90 90 90 90 90 90 90 90 90 90]
Ensimmäinen: 1000
Viimeinen: 9999
[900 900 900 900 900 900 900 900 900 900]
Ensimmäinen: 10000
Viimeinen: 99999
[9000 9000 9000 9000 9000 9000 9000 9000 9000 9000]
Ensimmäinen: 100000
Viimeinen: 999999
[90000 90000 90000 90000 90000 90000 90000 90000 90000 90000]
Ensimmäinen: 1000000
Viimeinen: 9999999
[900000 900000 900000 900000 900000 900000 900000 900000 900000 900000]

Yllä laitoin koneen laskemaan tarkastussumman ensimmäiselle 1e7 luvulle ja pistin ylös mikä tarkistusnumero oli tuloksena.

Viitenumeron maksimi pituus on 19+1. Jos kirjoitusvirheen todennäköisyys on yhtä suuri jokaisen 19 merkin kohdalla, kasvaa todennäköisyys tarkistus systeemin pettämisestä viitenumeron pituuden mukana. Käyttäen itseäni koe-eläimenä arvoin 200 viiden numeron mittaista lukusarjaa ja kirjoitin numerot koneella kuten yleensä laskuja maksaessa.

VirhetestiKuva 0. Näkymä näppäilyvirheiden testaus ohjelmasta. “xx” rivit siirtävät luettavan ja kirjoitettavan niin kauas etten pystynyt niitä samanaikaisesti näkemään.

Jos tuntui että tein virheen korjasin, tarvittaessa katsomalla kirjoitettua numeroa. Muuten kirjoitin luvut katsomatta tulosta. Lopputuloksena olin jotakuinkin varma turhasta testistä sillä en uskonut tehneeni yhtään virhettä. Tein kuitenkin kahdeksan virhettä.

Jos oletetaan etten kuitenkaan kämmännyt kuin kerran numeroa kohti niin virheen todennäköisyys on vähintään Pv=0.008 yhden kirjoitetun numeron kohdalla. Käytin numeronäppistä ja virheet muilla menetelmillä voivat olla toisia, mutta tämä antanee ihan kohtuullisen arvion suuruusluokasta. Hyvin lyhyellä googlaamisella en löytänyt mitään hyvää lähdettä joten käytän myöhemmin tätä itse mittaamaani.

Virheiden todennäköisyys ei välttämättä ole täysin riippumaton aiemmin tehdyistä virheistä, esimerkiksi sellainen tilanne jossa kaksi virhettä syntyy peräkkäin merkkien vaihtaessa paikkaa voi olla kohtuullisen todennäköinen.

Yhden virheen tilanteessa virhe tulee aina havaituksi, mutta useamman virheen tilanteessa läpi menee noin kymmenen prosenttia virheellisistä viitenumeroista, kuva alla. Jostain syystä kahden virheen tilanteissa skriptin laskema läpimenoprosentti on jopa vähän korkeampi. Skriptin virheellisyyden todennäköisyys ei ole olematon. Usean virheen tapauksessa tulos vaikuttaa järkevältä: satunnaiselle luku sarjalle arvottu tarkistusnumero on 0.1 todennäköisyydellä se oikea.

nVirhettäKuva 1. Virhettä sataa arvonta kertaa kohti eri mittaisille viitenumeroille. Nollaan menevät viivat liittyvät viitenumeron pituuteen: neljä merkkiä pitkässä viitteessä ei voi olla viittä virhettä.

Tässä kohtaa kannattaa ripotella vähän suolaa, sillä todennäköisyyslaskenta ei ole vahvimpia puoliani. Yksinkertaistettuna todennäköisyys viitenumero jossa on enemmän kuin yksi virhe on yksi miinus ne tapaukset joissa virheitä ei ole ja ne joissa virheitä on vain yksi,

Pk=1-((1-Pv)n+n*(1-Pv)n-1*Pv)               (1)

missä Pv on todennäköisyys kirjoittaa merkki väärin, 1-Pv on todennäköisyys kirjoittaa se oikein, (1-Pv)n on todennäköisyys kirjoittaa n merkkiä oikein, (1-Pv)n-1*Pv on todennäköisyys kirjoitta n numeroa pitkässä viitenumerossa yksi merkki väärin, n kertaa edellinen ottaa huomioon mahdollisuuden kämmätä kerran jokaisen merkin kohdalla.

Yksinkertaistuksia ovat mm. edellä mainittu virheiden toisistaan riippumattomuus ja tarkastusnumeron virheettömyys sekä oletus että viitteeseen voi kirjoittaa useita virheitä sitä huomaamatta.

Enemmän kuin yksi virhe viitenumeron rungossa Pv=0_008Kuva 2. Todennäköisyys tehdä enemmän kuin yksi virhe viitenumeron pituuden mukaan, tehtäessä 8 virhettä tuhannessa.

Tarkistin tuloksen myös laskemalla skriptillä saman todennäköisyyden kuin kaavalla 1. Miljoonalla toistolla per viitenumeron pituus syntyi hyvä vastaavuus kuten kuvasta näkyy.

Matemaattisen ja tietoteknisen lähestymisen meriittejä pohtineille kerrottakoon kaavalla laskemiseen meneen noin 133 ms kun pitkällä skriptillä meni 864.17 ms, mikä on kuulemma suurin piirtein sama aika kuin se jonka vaimo on menettänyt elämästään tämän blogin kirjoittamiseen liittyvän ilakoinnin aiheuttaman mielipahan vuoksi.

Ihmisten kyky kirjoittaa oikein vaihtelee, joten jos oletetaan minut keskiverto oikein kirjoittajaksi numeroiden osalta (!) niin jotkut tekevät enemmän virheitä jolloin todennäköisyys useampi virheiseen viitenumeroon kasvaa. Kun 19 merkkiselle viitenumerolle Pv=0.008 tasolla noin yksi sadasta sisältää enemmän kuin yhden virheen niin Pv=0.015 tasolla niitä on jo enemmän kuin kolme sadasta.

Enemmän kuin yksi virhe viitenumeron rungossa Pv=0_015Kuva 3. Kuten kuva 2, mutta kirjoitusvirheen todennäköisyys Pv=0.015

Koska monivirheisistä viitenumeroista kuitenkin vain yksi kymmenestä menee tarkastuksessa läpi voidaan sanoa että minulla ja ehkä keskiverto näppäilijällä yksi pitkä viitenumero tuhannesta menee läpi. Siis, jos oletetaan kirjoittajan korjaavan kehotuksen jälkeen virheet täydellisesti.

Jos laskun maksaja ansaitsee 15 € tunnissa (netto) ja käyttää 19 numeroisen viitteen tarkastamiseen 10 sekuntia niin tuhannen viitteen tarkastaminen maksaa noin 40 €. Jos homman selvittäminen läpi menneen virheen jälkeen maksaa 50 €  ajassa ja viivästysmaksussa karhukirjeen johdosta niin näyttäisi olevan melkein sama kumman tekee. Jos epäilee Pv:nsä olevan isompi niin tarkastaminen alkaa nopeasti kannattamaan.

Käytetyt skriptit:

[sourcecode language=”python”]

import ViiteVirhe as VV
import numpy as np
import matplotlib.pyplot as plt
import pylab as P
import random

# testaa pitkien viitenumeroiden tarkastussumman jakaumaa
a=VV.TarkNumJak(19,10000000)
hist, bins=np.histogram(a)
width = 0.7 * (bins[1] – bins[0])
center = (bins[:-1] + bins[1:]) / 2
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
k=np.mean(hist)
ax.bar(center, (hist-k)/1e6, align=’center’, width=width)
ax.set_title(‘Viitenumeron tarkastusnumeron (jakauma-minimi)/1e6, 10 M 19 numeroista’)
plt.show()

# Käy läpi lyhyempiä järjestyksessä
for i in range(7):
k=10**i
if k==1: k=0
print(‘Ensimmäinen: ‘ +str(k))
print(‘Viimeinen: ‘ + str(int(‘9’*(i+1))))
a=VV.TarkNumJak2(k,int(‘9’*(i+1))+1)
hist, bins=np.histogram(a)
print(hist)

r=random.SystemRandom()
S=”
oikein=0
vaarin=0
for i in range(200):
for k in range(5):
S=S+str(r.randint(0,9))
print(S)
for k in range(20):
print(‘xx’)
s=input(‘>>>> ‘)
if s==S:
oikein+=1
else:
vaarin+=1
S=”
print(‘Oikein ‘ + str(oikein))
print(‘Vaarin ‘ + str(vaarin))

# Läpi menevät, tarkistus summa aina oikein
import scipy as sc
TT=sc.zeros((19,19))
for i in range(1,20):
print(i)
for k in range(1,i+1):
for l in range(1000):
TT[i-1,k-1]+=VV.nErrorsCSC(i-1,k)
print(TT/1000)
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot([i+1 for i in range(19)],TT.T/1000) #[i+1 for i in range(19)],
ax.set_title(”)
plt.show()

# Virheellisen viitteen läpimenon todennäköisyys
import time
Pv=0.015
start_time=time.time()
M=np.zeros(18)
for i in range(2,20):
M[i-2]=VV.POfWrong(i,Pv)
print(‘Numeroita: ‘ + str(i)+ ‘ Todennäköisyys n virheitä >=2 : ‘ +
str(M[i-2]))
print(M)
print(‘Aikaa meni: ‘ + str(time.time()-start_time))

start_time=time.time()
MM=np.zeros(18)
N=1000000
for i in range(2,20):
MM[i-2]=VV.POfWrong2(i, Pv, N)
print(i)
print(MM)
print(‘Aikaa meni: ‘ + str(time.time()-start_time))
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot([i for i in range(2,20)],MM/N, ‘b+-‘,
label=’skripti’, markersize=10) #[i+1 for i in range(19)],
ax.plot([i for i in range(2,20)],M, ‘r-‘, label=’kaava (1)’) #[i+1 for i in range(19)],
legend = ax.legend(loc=’center’, shadow=True)
frame = legend.get_frame()
frame.set_facecolor(‘0.90’)
for label in legend.get_texts():
label.set_fontsize(‘large’)
for label in legend.get_lines():
label.set_linewidth(1.5)
ax.set_title(‘Ennemmän kuin yksi virhe viitenumeron rungossa (Pv=’ +
str(Pv)+ ‘)’)
ax.set_xlabel(‘Viitenumeron pituus’)
ax.set_ylabel(‘Todennäköisyys’)
ax.set_ylim(0.0001,.1)
ax.set_xlim(0,21)
ax.set_yscale(‘log’)
ax.grid(axis=’both’, which=’both’)
plt.show()

[/sourcecode]

Ja kutsutut funktiot:

[sourcecode language=”python”]
""" Arpoo viitenumeroita, laskee tarkistussumman ja tilastoi
virheiden korjattavuutta
"""

def TarkNumJak(pituus,kertoja):
import scipy as sc
import math as mt
import random

r=random.SystemRandom()
kerroin=sc.array([7,3,1,7,3,1,7,3,1,7,3,1,7,3,1,7,3,1,7,3,1,7,3,1])
TarkNum=sc.zeros(kertoja)
for k in range(kertoja):
TarkSum=0
## Viite=sc.zeros((19,1))
for i in range(pituus):
apu=r.randint(0,9)
## Viite[i]=apu
TarkSum+=apu*kerroin[i]
if mt.ceil(TarkSum/10)*10==TarkSum:
TarkSum+=10
TarkNum[k]=mt.ceil(TarkSum/10)*10-TarkSum
if TarkNum[k]==10:
TarkNum[k]=0
return TarkNum

def TarkNumJak2(Smallest,Largest):
""" Largest-1 is the largest number considered
"""
import scipy as sc
import math as mt
TarkSum=0
kerroin=sc.array([7,3,1,7,3,1,7,3,1,7,3,1,7,3,1,7,3,1,7,3,1,7,3,1])
TarkNum=sc.zeros((Largest,1))
for i in range(Smallest,Largest):
TarkSum=0
I=str(i)
for k in range(len(I)):
TarkSum+=int(I[k])*kerroin[k]
if mt.ceil(TarkSum/10)*10==TarkSum:
TarkSum+=10
TarkNum[i]=mt.ceil(TarkSum/10)*10-TarkSum
if TarkNum[i]==10:
TarkNum[i]=0
## print(TarkNum)
return TarkNum[Smallest:]

def nErrorsCSC(pituus, virheita):
""" n errors Check sum Always correct"""
import scipy as sc
import random
import math as mt

r=random.SystemRandom()
S=”
Se=”
V=[None]*(pituus+1)
for i in range(pituus+1):
V[i]=i
random.shuffle(V)
for k in range(pituus+1):
apu=r.randint(0,9)
S=S+str(apu)
Se=list(S)
if virheita>pituus+1:
virheita=pituus
for k in range(virheita):
apu2=r.randint(0,9)
while int(Se[V[k]])==apu2:
apu2=r.randint(0,9)
Se[V[k]]=str(apu2)
Se="".join(Se)
TarkSum=0
TarkSume=0
TarkNum=0
TarkNume=0
kerroin=sc.array([7,3,1,7,3,1,7,3,1,7,3,1,7,3,1,7,3,1,7,3,1,7,3,1])
for k in range(pituus+1):
TarkSum+=int(S[k])*kerroin[k]
TarkSume+=int(Se[k])*kerroin[k]
if mt.ceil(TarkSum/10)*10==TarkSum:
TarkSum+=10
TarkNum=mt.ceil(TarkSum/10)*10-TarkSum
if TarkNum==10:
TarkNum=0
if mt.ceil(TarkSume/10)*10==TarkSume:
TarkSume+=10
TarkNume=mt.ceil(TarkSume/10)*10-TarkSume
if TarkNume==10:
TarkNume=0

if TarkNum==TarkNume:
return 1
else:
return 0

def POfWrong(n, Pv):
a=1-((1-Pv)**n+n*(1-Pv)**(n-1)*Pv)
return(a)

def POfWrong2(n, Pv, N):
import random
r=random.SystemRandom()
v=0
for i in range(N):
V=0
for k in range(n):
if r.random()<=Pv:
V+=1
if V>1:
v+=1
return(v)

[/sourcecode]

Datapisteiden synkeän elämän julmaa matematiikkaa

Joulun kunniaksi olen pohtinut, miten lannistavaa olisi olla datapiste. Yksinkertaisessakin tutkimuksessa voi tulla miljoonia datapisteitä. Lopuksi niistä survotaan kaava, joka on muotoa Y= A + B*X1. Jokainen piste haluaisi päästä A:ksi A:n paikalle; vain yksi pääsee, muut tuomitaan ikuiseen kadotukseen. Mitä elämää se sellainen oikein on?

Ajatus on tullut mieleen, kun olen murskannut tämänhetkisen projektini numeroita. Projektin päämäärä ja yksityiskohdat eivät ole tässä olennaisia (ovatko ne muuallakaan, on makukysymys).  Siinä ajelutettiin noin sata ihmistä ajosimulaattorin läpi. Jokainen ajo kesti lähes tunnin. Dataa on tallennettu kymmenen kertaa sekunnissa.

Koska simulaattoriaika on kallista, ajosuorituksista tallennettiinn kaikki mahdollinen. Ajajasta tallennettiin noin kolmekymmentä parametriä. Lisäksi pidettiin kirjaa siitä, missä muut simulaation objektit ovat. Objekteja on noin viisikymmentä, ja kaikista tallennettiin kahdeksan parametriä. Jokaisella rivillä oli siis yli 500 numeroa. Kymmenen kertaa sekunnissa tunnin ajan tarkoittaa, että jokaisesta kuskista tallennettiin lähes 20 miljoonaa numeroa.

Yhteensä projektin aikana kerättiin siis lähes 2 miljardia datapistettä.

Näiden miljardien tragedia on siinä, että melkein kaikki niistä tapettiin ennen kuin ne edes näkevät päivänvalon. Kuskin toimintaa mittaavat 30 parametriä sentään vaivauduttiin ottamaan talteen. Muista objekteista sen sijaan tallennettiin vain etäisyystieto; yhteensä 50 numeroa riviltä. Ensimmäisen teurastuksen läpäisi siis vain 10% luvuista, eli 90% joutui heti datapisteiden taivaaseen. 200 miljoonaa datapistettä jäljellä.

Käyttökelpoisia tienpätkiä oli lopulta noin neljäsosa: 50 miljoonaa datapistettä. Tässä vaiheessa alkoi selvitä, mitkä parametrit ylipäätään ovat analyysissä tärkeitä. Viisikymmentä tallannetua parametriä voitiin tiivistää hieman yli kymmeneen. Kymmenen miljoonaa datapistettä jäljellä. Näiden tallennusvälilä pystyttiin vielä harventamaan, pyöristämällä sijainnit lähimpään täyteen metriin. Varsinaiseen dataprässiin päätyi enää nelisen miljoonaa datapistettä (400,000 mittausta, jokaisessa 10 parametriä).

Prässissä kokeiltiin erilaisia menetelmiä, mm lineaarisia monimuuttujamalleja. Loppujen lopuksi kuitenkin yksinkertaisin oli parasta: kuskit keskiarvoistettiin, niin että sadasta koehenkilöstä saatiin survottua yksi “keskimääräinen” kuski. Noin 99% datapisteistä koki siis irvokkaan keskiarvoistuskuoleman, menettäen kaiken sen yksilöllisyyden joka tekee numerosta numeron.

Tässä vaiheessa jäljellä oli siis 4000 mittausta, jokaisessa kymmenen parametriä. Pyörittely osoitti, että näistä vain yksi oli lopulta tärkeä (riippuva muuttuja Y), ja sen pystyi parhaiten selittämään kaksi riippumatonta muuttujaa (X1 ja X2).

Koko tutkimustulos tiivistyi siis kaavaksi

  Y = A + B*X1 + C*X2.

Toisin sanoen, tehtäväksi jäi määritellä kolme vakiota (A,B,C). Tämä siis oli koko prosessin loppputulos: kolme numeroa. Alun kahdesta miljardista. Ja tämä kaikki vain siksi, että pari akateemista nörttiä saisi taas yhden julkaisun lisää.

Jotta nöyryytys olisi täydellinen, näissä vakioissa on vain kaksi merkitsevää desimaalia, kun alkuperäinen data kerättiin vähintään kuuden merkitsevän desimaalin tarkkuudella. Numero on onnellinen, kun se on tarkka; jokaisen desimaalin menetys on kuin kadottaisi raajan.

Voin verrata tätä suoraan omaan elämääni. Tilastojen perusteella maailmassa on noin 3.5 miljardia työikäistä ihmistä, eli vajaa kaksi miljardia miestä. Tässä kilpailussa meidät laitettaisiin toistuvasti valtavan tehosekoittimen läpi. Häviäjät valutettaisiin viemäriin, voittajia mössättäisiin taas uudelleen. Lopussa papukaijamerkin saisivat ne kolme, joista on vielä jotakin jäljellä.

(Teoriassa voisi toki ajatella, että palkinnoksi jäisivät ne lähes kaksi miljardia työikäistä naista jotka nyt olisivat vapailla markkinoilla. Mutta moniraaja-amputaatiohalvaantunelle se on lähinnä akateeminen ilo).

Oma elämä ei tunnukaan enää yhtä kurjalta, kun tätä miettii. Yhtä mitättömältä toki. Mutta on silti parempi olla yksi joskus osittain terve Ö monien joukossa kuin ainoa täysrampa A ei kenenkään joukossa.

Lisää outoa matematiikkaa: WeirdMath.

 

Juhannusten matematiikkaa

 

Tärkeää suomalaista juhannusperinnettä, sepalus auki hukkumista, on matemaattisesti tutkittu erittäin vähän. Tämä on sääli, sillä perinne tarjoaa hyvän esimerkin Bayeslaisesta analyysistä. Analyysin perusteella on myös mahdollista löytää konkreettisia ja rationaalisia menetelmiä hukkumisten vähentämiseen.

Kuinka todennäköistä on hukkua juhannuksena sepalus auki?  Muuttujat eivät ole riippumattomia, vaan niiiden yhteinen piilomuuttuja on tärkein suomalainen juhannusperinne: oluen juonti.

Aihe ei ole minullekaan aivan vieras. Vaikka elämänkaareni ei  tapahtumarikas tai mielenkiintoinen olekaan, olen kuitenkin itse elänyt aikana jolloin ikätoverini ovat olleet nuoria. Teorian lisäksi voin siis esittää heuristisia arvioita.

Mikäli hukkuminen ja sepalus auki oleminen olisivat riippumattomia muuttujia, saataisiin lopputulos kertomalla niiden todennäköisyydet yhteen.  Suomen uimaopetus- ja hengenpelastusliiton tilastojen mukaan juhannuksena hukkuu keskimäärin kahdeksan ihmistä. Sepalustilastoja ei kerätä, mutta (mahdollisesti teekkareita lukuunottamatta) harva kulkee koko juhannusta sepalus auki. Kertolaskun perusteella sepalushukkumisia olisi häviävän vähän. Tämä on ristiriidassa perinnetiedon kanssa.

Laskennassa tuleekin käyttää Bayesläisiä menetelmiä. Kirjoitetaan

P(huksep) = P(huk|sep) * P(sep),

eli todennäköisyys on kahden todennäköisyyden tulo: todennäköisyys olla sepalus auki, ja ehdollinen todennäköisyys hukkua jos sepalus on auki.

Olut muodostaa lineaarisen suodattimen: ajanhetkellä T1 juotu olutpullo pyrkii poistumaan viimeistään ajanhetkellä T2, missä aikaväli T2-T1 on noin tunti.

Tyypillinen juomistahti lienee noin kolme oluttölkkiä tunnissa, eli lähes litra. Virtsarakon koko on noin 500 millilitraa, mutta se voi venyä hyvinkin paljon. Heuristisesti voidaan arvioida, että juojan on kerran tunnissa helpotettava oloaan.  NIH:n mukaan tyypillinen virtsavuontiheys 14-45-vuotiaalle miehelle on noin 20 ml/sec. Tämän mukaan litran tyhjentämiseen kuluisi tehokasta työaikaa noin 50 sekuntia.

On kuitenkin huomioitava, että koordinaatiokyky heikentyy parin litran jälkeen. Sepaluksen aukioloaika on käytännössä helposti 2-3 minuuttia, teekkareilla huomattavasti pidempikin. Voidaan siis arvioida, että aktiivinen juhannusjuhlija joutuu olemaan sepalus auki jopa 2-3 minuuttia tunnissa, eli P(sep)=5%.

Toinen parametri, P(huk|sep), riippuu kontekstista. Kuivalla maalla hukkuminen on vaikeaa. Juhannusperinteeseen kuuluu kuitenkin läheisesti veden ääreen etsiytyminen. Jo laiturilta voi hukkua, mutta helpompaa se on veneestä. Käytännössä todennäköisyysketjua täytyy vielä laajentaa niin, että otetaan huomioon myös ehdollinen todennäköisyys olla veneessä kun sepaluksen on oltava auki P(ven|sep), ja ehdollinen todennäköisyys hukkua jos näin tapahtuu P(huk|vensep).

P(huksep) = P(huk|vensep) * P(ven|sep) * P(sep)

Veneitä on Suomessa noin 700,000, näistä 260,000 soutuveneitä. Soutuveneestä hukkuminen on klassisin perinne. Juhannuksena melkoinen osa venekannasta on käytössä, ehkä hyvinkin neljäsosa (noin 60,000). Ehkä kolmasosassa veneistä on vähintää yksi humalainen. Keskimääräinen souturetki ei liene pitkä, ehkä tunnin, mutta juhannushumallassasoutamissuoritteita olisi tällä arviolla kuitenkin 20,000 miestyötuntia.

Jos arvioidaan että vajaa neljä miljoonaa suomalaista juhlii juhannusta, ja juhlinta kestää kahdeksan tuntia, juhannuksena syntyy kaikkiaan noin 30 miljoonaa juhlintasuoritemiestyötuntia. Toisin sanoen noin 0.07% suomalaisista olisi sepalus auki soutuveneessä; P(ven|sep)=0.07%.

Suurin osa tästä 0.7 promillen joukosta ei toki huku, vaikka veneestä virtsaaminen onkin vaarallista. Varsinkin jos otetaan huomioon mahdollisuus käyttää esimerkiksi äyskäriä, ja hulluja ja humalaisia suojaava onni, P(huk|vensep) voi olla niinkin pieni kuin prosentin luokkaa.

Kun luvut kerrotaan yhteen, saadaan tulokseksi, että P(huksep) ~1E-6. Keskimääräisen suomalaisen todennäköisyys hukkua sepalus auki on siis hieman alle 1 miljoonasta, eli yksi micromort. Olen analysoinut micromortin käsitettä kirjoituksessa Möläytysten matematiikkaa, jossa arvioin poliitikolla olevan micromortin todennäköisyys tuhota uransa joka kerta, kun hän avaa suunsa.

Koska juhlivia suomalaisia on nelisen miljoonaa, todennäköistä olisi, että sepelusaukihukkumisia tapahtuisi joka vuosi vähintään yksi. Tämä on vahvasti samansuuntainen kuin arkikokemus. Ihmistieteissä tarkkuus on tunnetusti huonompi kuin kovilla tieteenaloilla, joten tulosta voidaan pitää sangen vahvana.

Juhannusjuhlija kannattaa siis mallintaa Bayeslaisena suodattimena. Tämä tarjoaa myös rationaalisia keinoja vähentää sepalus auki hukkumisia. Suuretta P(sep) pienentämällä päästään nopeimmin tuloksiin. Sitä voi pienentää ainakin kolmella tavalla: vähentämällä oluen juontia, kehittämmällä tehokkaampia sepalusratkaisuja (jolloin aukioloaika on lyhyempi), tai kasvattamalla juhlijoiden virtsarakkojen tilavuutta  kirurgian tai geenimanipulaation avulla. Näistä kaksi viimeksimainittua ovat käytännössä realistisia.

Muita epätavallisia laskelmia: täällä.

False_color_image_of_the_far_field_of_a_submerged_turbulent_jet

Translate »