Projeksjoner av vektorer Analyse av værdata Lars Sydnes NITH 12. september 2013 1 Osloserien Ved værstasjoner rundt omkring i verden måler man temperaturen hver eneste dag. Vi har tilgang til målinger gjort på Blindern i tidsrommet 1.januar 1938 til 31.desember 2012, alstå over et tidsrom på 74 år. 1 Vi snakker altså om daglige målinger i 74 år, d.v.s 27418 målinger. Det er mange tall, og vi blir ikke særlig kloke av å stirre på dem: 01.01.1938-3.4-5.4 1.3 02.01.1938-4.5-4.8-2.5 03.01.1938-8.8-12.3-4.8 04.01.1938-0.2-7.3 1.7 05.01.1938-4.8-7.6 0.6 06.01.1938-9.3-11.2-5.8 07.01.1938-11 -13.4-8.9 08.01.1938-10.5-12.5-8.4 Den første kolonnen angir naturligvis datoen. Den andre kolonnen angir middeltemperaturen 2, mens de to siste kolonnene er henholdsvis minimumsog maksimumstemperaturen. Dette datasettet kan vi døpe Osloserien. 1 Takk til Sigmund Hov Moen ved NITH som har skaffet dataene! 2 Det er ikke opplagt hva som skal regnes som middeltemperaturen. Hvordan skal man måle den? Det finnes dog standardiserte prosedyrer for å beregne middeltemperaturen utfra et sett målinger gjort i løpet av en dag. Når man bruker en slik standardprosedyre, sikrer man at man kan sammenligne resultater fra 1938 med resultater fra 1998. Dette betyr dog ikke at begrepet middeltemperatur er meningsfullt i seg selv. 1
Vi kan bli litt klokere av å plotte dataene. Her har vi plottet noen tilfeldige utvalgte segmenter av datasettet: Disse figurene gir oss et tydelig inntrykk av at vinteren 1942 var mye kaldere enn vinteren 1990, og de gir inntrykk av lengden på kuldeperioder og mildværsperioder. Vi vil nå se hvordan vektorregning gir oss enkelte instrumenter som vi kan bruke til å undersøke slike datasett. La oss flytte dataene over i en verden av vektorer: 2 Oslovektoren La oss hente ut en kolonne av Osloserien, f.eks middeltemperaturkolonnen. Dermed får vi en lang liste av tall. Denne kan vi betrakte som en vektor med 27418 komponenter: x Oslo = [ 3.4, 4.5,, 8.8,..., 1.1, 3.2, 2.9] R 27418 Denne vektoren kan vi kalle Oslovektoren 3 3 Den som er opptatt av å skille mellom punkter og vektorer, vil kunne hevde at det er mer meningsfullt å se på denne listen med tall som et punkt, blant annet fordi komponentene avhenger av valg av nullpunkt for temperaturmåling. 2
3 Noen hjelpevektorer. Vi skal nå definere en hel haug med vektorer som skal spille rollen som alternative koordinat-akser. Vi kan tenke på disse vektorene som en slags erstatning for enhetsvektorene ˆx, ŷ, ẑ som vi er vant med fra 3D-geometrien. La N være antallet komponenter i x Oslo, i.e. 27418 [ ( ) ( ) ( ) ( )] 2πi 2πi 2πi 2πi u i = cos N 0, cos N 1,..., cos N k,..., cos (N 1) N og v i = [ ( ) ( ) ( ) ( )] 2πi 2πi 2πi 2πi sin N 0, sin N 1,..., sin N k,..., sin (N 1). N Dette gir oss to sekvenser u 1,..., v 1, v 2,... av vektorer. Disse fletter vi sammen til én på følgende måte: Først definerer vi en vektor der alle komponentene er like: b 0 = [ 1 2 2, 1 2 ] 1 2,..., 2. 2 Når i er jevn lar vi b i = u i/2 og når i er odde lar vi b i = v (i+1)/2 Nå har vi en laang liste med vektorer med N = 27418 komponenter: b 0, b 1, b 2, b 3, b 4,... Ikke tenk så alt for mye på at det er noen vanskelige formler involvert i dette, det viktige er at vi kan punche tall inn i kalkulatoren vår og si hvilket tall som står i komponent nummer 131 i vektoren b 425. b 0, b 1,... er rett og slett helt vanlige lister med tall. Det som er spesielt med disse vektorene er at de står vinkelrett på hverandre. Det høres absurd ut, men dette er noe vi faktisk kan sjekke ved å regne ut skalarproduktene: b i b j = 0, når i j (1) Disse beregningene er vanskelige å utføre, men det stemmer. Studentene kan selv sjekke dette numerisk, altså ved hjelp av datamaskinen, men da kun for et endelig utvalg av i, j-indekser. En forklaring på hvordan man kan gripe dette an finner du i seksjon 7.1. 3
4 Bruk av hjelpevektorene Det vi ønsker å gjøre er å uttrykke Oslovektoren x Oslo ved hjelp av hjelpevektorene b 0, b 1,.... I praksis er vi tvunget til å ta for oss et endelig utvalg med K vektorer b 0, b 1,..., b K K kan f.eks være lik 1000. Vi ønsker så å finne en vektor x Oslo som tilfredsstiller følgende krav: (i) x Oslo er en lineærkombinasjon av vektorene b 1,..., b K. Det skal altså finnes tall y 1,..., y K slik at K x Oslo = y i b i. (ii) Avstanden mellom x Oslo og x Oslo skal være så liten som mulig. Vi ønsker m.a.o at feilen x Oslo x Oslo skal være så liten som overhodet mulig. Vi har en veldig praktisk omformulering av punkt (ii): Feilen er minimal når x Oslo x Oslo står vinkelrett på b 1, b 2,..., b K, i.e. dersom i=0 (x Oslo x Oslo ) b i = 0 for i = 0, 1, 2,..., K (2) Vi kan forestille oss at b 1,..., b K danner et slags plan og at x Oslo er projeksjonen av x Oslo ned på dette planet. 4 Det å projisere på det nærmeste punktet i et plan er det samme som å projisere vinkelrett på planet. Hvordan skal vi så finne koeffesiente y 1, y 2,..., y K i (i)? Jo, vi kan finne dem ved hjelp av (1): Dette er litt magisk, men dersom vi kombinerer (2) med punkt (i) og (1), så får vi 0 = (x Oslo x Oslo ) b j ( ) K = x Oslo y i b i b j i=1 = x Oslo b j k y i b i b j i=1 = x Oslo b j y i b j b j, 4 Dette kan forstås ved en analogi: La P være et punkt i planet, la b være en vektor i planet og la l være linjen gjennom origo. Punktet P på l som ligger nærmest P er kjennetegnet ved at vektoren P P står vinkelrett på b. 4
siden b i b j = 0 når i j. Det som står her er at x Oslo b j y i b j b j = 0. Denne ligningen kan vi løse for y i, og vi får da y i = x Oslo b j b j b j (3) Takket være det faktum at vektorene b 1,..., b K er parvis ortogonale har vi altså funnet en forholdsvis enkel formel for koeffesientene y 0, y 1, y 2,..., y K. 5 Numerisk analyse av Osloserien Når vi regner ut disse koeffesientene på datamaskinen får vi verdier som y 0 8.67, y 1 0.41, y 2 0.41, y 3 0.22 Dersom vi gjennomfører approksimasjonen vår med K = 0, så får vi x Oslo x Oslo = y 0b 0 8.67[1/2 2,...] [6.13, 6.13,...] Dette kan vi tolke dithen gjennomsnittlig middeltemperatur på Blindern de siste 74 årene er på 6.1 C. 5 Vi kan plotte y i mot i for i = 0, 1,..., 300. Det gir følgende figur: Vi ser her at de fleste y i -verdiene ligger omkring 0, med unntak av y 0 8.67 5 Sammenlign med standardformelen for gjennomsnitt: Gjennomsnittet av tallene T 1, T 2,..., T N er T 1 + T 2 + + T N. N Komponentene i vektoren y 0b 0 er gitt av formelen x Oslo b 0 1 1 2x1 + 1 2x2 + + 1 2xn 2 = 2 2 2 1 x 1 + + x N b 0b 1 2 = 0 2 + 1 + + 1 2 N 2 2 2 5
og y 150 10.54. Dersom vi bare bryr oss om disse største koeffesientene, får vi følgende approksimasjon av oslovektoren: x Oslo 8.67 b 0 10.54 b 150 Denne approksimasjonen gir følgende tilnærming til middeltemperaturen T i på dag i etter 31.12.1937: ( ) 150π T i 6.13 10.54 cos 27418 i Hvis vi plotter denne approksimasjonen for årene 1938-1942, får vi følgende figur: Langs y-aksen måler vi antallet dager etter 31.12.1937. Her har vi plottet approksimasjonen sammen med de virkelige dataene: Dette gir oss en idé om at den viktige koeffesienten y 150 representerer den årlige variasjonen. Analysen vår har altså klart å presse ut to viktige observasjoner: Gjennomsnittlig middeltemperatur på Blindern siste 74 år er 6.13 grader. Temperaturen har en regelmessig variasjon med med periode på ca. 365 dager. 6
Det siste burde ikke være noen overraskelse, siden de fleste av oss har hørt om årets syklus: Vår, sommer, høst og vinter. Vi kan også bruke approksimasjonen ( ) 150π T i 6.13 10.54 cos 27418 i som en enkel modell for hvordan temperaturen vanligvis varierer gjennom året. Dersom temperaturen er høyere enn T i den aktuelle dagen, så vil vi si at det er unormalt varmt. 7
6 Programmering: Nå skal vi se på hvordan vi kan arbeide med dette i java. Vi referer til kode som finnes i her: http://home.nith.no/~sydlar/rf5100/kode/weatherdata.zip 6.1 Data-vektorer Oslo-vektoren x Oslo vil bli representert av objekter av klassen matlib.vector. Denne klassen ser omtrent slik ut: package matlib; import matlib.util.vectors; public class Vector extends AbstractVector { public Vector(int n ) public Vector(double[] array) public Vector(AbstractVector other) public int size() public void add(vector other){// INPLACE public void subtract(vector other) // INPLACE public void multiply(double scalar)// INPLACE public static Vector add(vector u,vector v) public static Vector subtract(vector u,vector v) public static Vector multiply(vector u, double s) public void print() public void gpprint() // for use with gnuplot Legg merke til at det finnes to sett med vektoroperasjoner: Inplace-verianter som modifiserer objekter og statiske metoder som lager nye objekter. 8
6.2 Hvordan lage Oslovektoren? Dataene til Oslo-vektoren kommer fra filen data/osloseries.txt, og vi kan laste dataene inn i en vektor xoslo på følgende måte: String FILE_NAME = "data/osloseries.txt"; double[] array = DataVectors.getData(FILE_NAME,0); Vector oslovector = new Vector(array); Klassen DataVectors ligger i pakken matlib.datavectors, og metoden getdata har følgende deklarasjon: public static Vector getdata(string filename, int column); Parameteren column angir hvilken kolonne i filen vi henter dataene fra. Siden middeltemperaturdataene ligger i den første kolonnen i den aktuelle filen, velger vi kolonne nr 0. 9
6.3 Basis-vektorene Basisvektorene b i vil være representert ved Fourier-objekter. Fourier-klassen ser omtrent slik ut: package matlib.fourier; import matlib.abstractvector; } public class Fourier extends AbstractVector { public Fourier(int n) public Fourier(int n, int index) public void setindex(int index){ if(index%2==0){ function = cos; function.setwavenumber(index/2); } else if (index%2==1) { function = sin; function.setwavenumber((index +1 )/ 2 ); } } public static Fourier multiply(fourier vector, double scalar) public static Fourier add(fourier A, Fourier B) public static Fourier subtract(fourier A, Fourier B) 10
Fourier-objektene oppfører seg som vektorer: Både Fourier og Vector arver metoden public static double scalarproduct(abstractvector A, AbstractVector B) fra klassen AbstractVector. Av den grunn kan vi skrive kode som f.eks Fourier b3 = new Fourier(5,3); double[] array = new double[]{2,3,2,1,2}; Vector x = new Vector(array); double s = AbstractVector.scalarProduct(b3,x); Konstruktør-kallet Fourier(27418) produserer basisvektoren vi kjenner som b 0, mens kallet Fourier(27418,98) produserer basisvektoren vi kjenner som b 98, et.c. Vi kan endre indeksen til Fourier-ojekter ved hjelp av setindexmetoden. Dermed kan vi ofte klare oss med noen ganske få Fourierobjekt som vi endrer indeksen på etter behov. 7 Oppgaver 7.1 Studér basisvektorene: Lag et visst antall Fourier-objekter, og undersøk om de står vinkelrett på hverandre ved å beregne skalarproduktene ved hjelp av scalarproduct -metoden. Poenget er altså å gå ligning (1) på side 3 etter i sømmene. 6 6 Obs: Metoden AbstractVector.scalarProduct tar høyde for avrundingsfeil: Hvis det numerisk beregnede skalarproduktet mellom to vektorer har absoluttverdi mindre enn 10 11, så blir resultatet rundet ned til 0.0. 11
7.2 Beregn y i -koeffesientene Last inn Osloserien inn i Oslovektoren x Oslo ved å skrive f.eks String FILE_NAME = "data/osloseries.txt"; double[] array = DataVectors.getData(FILE_NAME,0); Vector oslovector = new Vector(array); Beregn så en del y i -koeffesientene ved hjelp av formel (3). Et godt tips er å fylle en array double[] coefficients = new double[300] med verdiene y 0, y 1,..., y 199 Hva er de største verdiene? Finn fram til de 10 største verdiene. 7.3 Rekonstruksjon Dersom vi har funnet ut at koeffesientene y 0, y 148, y 150, y 152 virker interessante, kan vi lage vektoren x Oslo = y 0b 0 + y 148 b 148 + y 150 b 150 + y 152 b 152. Dette gir en approksimasjon for middeltemperaturen. 12
7.4 Visualisering I eksempelkoden i oppgaver.weatherdata skrives den ubearbeidede Oslovektoren til filen data/weatheroutput.txt i funksjonskallet double[] array = oslovector.toarray(); double[][] outputarrays = new double[][]{array}; Vectors.printGnuplotData(outputArrays); Dette gir oss en fil som inneholder ca. 27418 linjer med ett tall på hver linje, noe som ikke gjør oss særlig kloke. Det kan være en utfordring å få visualisert dataene, men det finnes flere metoder: Man kan åpne filen i MS-excel eller LibreOffice-calc og forsøke å bruke den innebygde plottingsfunksjonaliteten. Det er dog en viss fare for disse programmene ikke tåler så store datamengder veldig godt. Man kan laste ned GNUplot her: www.gnuplot.info. Dette er et utmerket verktøy for plotting av data. Kommandoen > plot "data/weatheroutput.txt" w l u 1 plotter den første kolonnen i filen data/weatheroutput.txt. Andre metoder? 7.5 Stockholmserien I filen data/stockholmseries.txt finner man tilsvarende data målt i Stockholm i perioden fra 1.1.1754 til og med 31.12.2012. Analyser også disse dataene. Siden vi har et tidsspenn på 248 år, kan vi forvente at y 496 er relativt stor, eller at noen av nabo-koeffesientene er det, siden de hører sammen med den årlige variasjonen. Undersøk denne hypotesen. Se på approkismasjonsfelien (x x ). Ser du noen systematiske avvik? 13