Matriisien rivi- ja sarakeotsikoista

[viesti Survo-keskustelupalstalla (2001-2013)]

Kirjoittaja: Kimmo Vehkalahti
Sähköposti:    -
Päiväys: 16.2.2005 12:50

Valmistelen parhaillaan esitelmää kansainväliseen matriiseja ja
tilastotiedettä käsittelevään konferenssiin. Aiheena on jotakuinkin
"hyödyllisten jälkien jättäminen matriiseilla työskenneltäessä"
(hiven piilohauskaa matriisilaskennan perusteet tunteville: jälki
eli trace tarkoittaa myös neliömatriisin lävistäjäalkioiden summaa).

Yhtenä esitelmäni punaisena lankana toimivat matriisin rivi- ja
sarakeotsikot, jotka Survossa seuraavat eri matriisioperaatioita
loogisesti auttamalla oleellisesti työn dokumentoitumisessa ja/tai
dokumentoinnissa.

Seppo on puhunut tästä aiheesta usein, ja jopa saman konferenssin
vuoden 1999 kutsutussa esitelmässään, johon voi tutustua verkossa
osoitteessa http://www.helsinki.fi/survo/matrix99.html tai
Survossa valitsemalla alariviltä DEMO ja sitten MATRIX. Suomeksi
asiasta kertoo Survo ja minä -kirja (Mustonen 1996, 196-197).

Yhteinen käsityksemme on ollut, ettei missään muussa ohjelmistossa
ole mahdollisuutta samanlaiseen "otsikkoaritmetiikkaan" (SM) kuin
Survossa. Tätä käsitystä ovat vahvistaneet niin omat kuin muilta
tutkijoilta saamamme tiedot.

Päätin "varmistaa selustani" tutustumalla jälleen kerran itse eräisiin
muihin ohjelmistoihin (SPSS, SAS, R) juuri tämän asian kannalta.
Joidenkin mielestä asia saattaa vaikuttaa kaiken kaikkiaan pieneltä
tai peräti "akateemiselta", mutta mielestäni se ei sellainen ole.
Pienet asiat toistuvat jatkuvasti, ja vähänkään laajemmissa töissä
niiden merkitys vain korostuu. Ja onhan asia jo siltäkin kannalta
selvä, että tilastotieteessä on yleensä mitä luonnollisinta ajatella
havaintoMATRIISI-muotoista datan esitystä, jossa sekä havainnoilla
että muuttujilla on NIMET. Tätä kai voi pitää vähimmäisvaatimuksena,
jos puhutaan meta-data -käsitteestä. Kuitenkin yleisesti käytetyissä
matriisiohjelmissa (kuten Matlab) keskitytään vain numeeriseen dataan.
Esikuvana ovat tällöin pikemminkin matriisien matemaattiset esitykset,
eivät tilastolliset. Tilastotieteilijänä on vaikea hyväksyä pelkkien
numeroiden pyörittelyä; nimet ja muu sanallinen tieto ovat oleellinen
osa kokonaisuutta.

Huonosti käy edelleen ns. isoissa ohjelmissa (SPSS ja SAS). Tässä on
niillä työskentelystä pieni näyte, jonka olen ottanut James Stevensin
kirjasta Applied Multivariate Statistics for the Social Sciences:

SPSS:

MATRIX.
COMPUTE A = {2, 4, 1; 3, -2, 5}.
COMPUTE B = {1, 2; 2, 1; 3, 4}.
COMPUTE C = A*B.
COMPUTE E = {1, -1, 2; -1, 3, 1; 2, 1, 10}.
COMPUTE DETE = DET(E).
COMPUTE EINV = INV(E).
PRINT A.
PRINT B.
PRINT C.
PRINT E.
PRINT DETE.
PRINT EINV.
END MATRIX.

Kun nämä komennot suoritetaan Syntax-ikkunassa, saadaan
Output-ikkunaan seuraavaa:

Run MATRIX procedure:

A
  2  4  1
  3 -2  5

B
  1  2
  2  1
  3  4

C
  13  12
  14  24

E
   1  -1   2
  -1   3   1
   2   1  10

DETE
  3

EINV
   9.666666667   4.000000000  -2.333333333
   4.000000000   2.000000000  -1.000000000
  -2.333333333  -1.000000000    .666666667

------ END MATRIX -----


SAS:

proc iml;
a = {2 4 1, 3 -2 5};
b = {1 2, 2 1, 3 4};
c = a*b;
e = {1 -1 2, -1 3 1, 2 1 10};
dete = det(e);
einv = inv(e);
print a b c e dete einv;

Kun nämä komennot suoritetaan Program Editor -ikkunassa, saadaan
Output-ikkunaan seuraavaa:

    A                             B                   C

    2         4         1         1         2        13        12
    3        -2         5         2         1        14        24
                                  3         4
    E                          DETE      EINV

    1        -1         2         3 9.6666667         4 -2.333333
   -1         3         1                   4         2        -1
    2         1        10           -2.333333        -1 0.6666667


Samat temput Survolla näyttävät tällaiselta:

Survo:

MATRIX A ///
2  4 1
3 -2 5

MATRIX B ///
1 2
2 1
3 4

MAT SAVE A
MAT SAVE B
MAT C=A*B

MATRIX E ///
1 -1 2
-1 3 1
2 1 10

MAT SAVE E
MAT DETE=DET(E)
MAT EINV=INV(E)

Otetaan näin määritellyt ja lasketut matriisit näkyville
toimituskenttään:

MAT LOAD A END+2
MAT LOAD B END+2
MAT LOAD C END+2
MAT LOAD E END+2
MAT LOAD DETE END+2
MAT LOAD EINV END+2

MATRIX A
///             1        2        3
  1             2        4        1
  2             3       -2        5

MATRIX B
///             1        2
  1             1        2
  2             2        1
  3             3        4

MATRIX C
A*B
///             1        2
  1            13       12
  2            14       24

MATRIX E
///             1        2        3
  1             1       -1        2
  2            -1        3        1
  3             2        1       10

MATRIX DETE
DET(E)
///           det
det             3

MATRIX EINV
INV(E)
///             1        2        3
  1       9.66667  4.00000 -2.33333
  2       4.00000  2.00000 -1.00000
  3      -2.33333 -1.00000  0.66667


Erona edellisiin ovat paitsi matriisin ns. sisäinen nimi, joka kertoo
sen syntyhistoriasta, niin myös rivi- ja sarakeotsikot.

Oletuksena käytetään otsikoita 1, 2, ..., mutta ne kannattaa usein
korvata paremmin kuvaavilla, esimerkiksi näin:

MAT RLABELS AR TO A
MAT CLABELS AS TO A
MAT RLABELS BR TO B
MAT CLABELS BS TO B
MAT RLABELS ER TO E
MAT CLABELS ES TO E

Tällöin, kun toistetaan em. operaatiot

MAT C=A*B
MAT DETE=DET(E)
MAT EINV=INV(E)

matriisit näyttävät seuraavilta:

MAT LOAD A END+2
MAT LOAD B END+2
MAT LOAD C END+2
MAT LOAD E END+2
MAT LOAD DETE END+2
MAT LOAD EINV END+2

MATRIX A
///           AS1      AS2      AS3
AR1             2        4        1
AR2             3       -2        5

MATRIX B
///           BS1      BS2
BR1             1        2
BR2             2        1
BR3             3        4

MATRIX C
A*B
///           BS1      BS2
AR1            13       12
AR2            14       24

MATRIX E
///           ES1      ES2      ES3
ER1             1       -1        2
ER2            -1        3        1
ER3             2        1       10

MATRIX DETE
DET(E)
///           det
det             3

MATRIX EINV
INV(E)
///           ER1      ER2      ER3
ES1       9.66667  4.00000 -2.33333
ES2       4.00000  2.00000 -1.00000
ES3      -2.33333 -1.00000  0.66667


Huomaa miten otsikot seuraavat operaatioita automaattisesti:

  matriisi C perii otsikot matriiseilta A ja B matriisikertolaskun
  (skalaaritulo) sääntöjen mukaisesti (A:n rivit, B:n sarakkeet)

  käänteismatriisissa EINV myös otsikot vaihtavat paikkaa

  determinanttimatriisi (1x1) saa otsikoikseen "det"; näin siihen
  voidaan viitata myös editoriaalisen aritmetiikan lausekkeissa


Tein samat asiat vielä kertaalleen R-ohjelmistolla:

R:

A <- matrix(c(2, 4, 1, 3, -2, 5), 2, 3, TRUE)
B <- matrix(c(1, 2, 2, 1, 3, 4), 3, 2, TRUE)
C <- A %*% B
E <- matrix(c(1, -1, 2, -1, 3, 1, 2, 1, 10), 3, 3)
dete <- det(E)
library(nlme)
einv <- solve(E)

Kun nämä komennot suoritetaan komentoikkunassa ja otetaan saadut
objektit näkyviin, saadaan seuraavaa:

> A
     [,1] [,2] [,3]
[1,]    2    4    1
[2,]    3   -2    5

> B
     [,1] [,2]
[1,]    1    2
[2,]    2    1
[3,]    3    4

> C
     [,1] [,2]
[1,]   13   12
[2,]   14   24

> E
     [,1] [,2] [,3]
[1,]    1   -1    2
[2,]   -1    3    1
[3,]    2    1   10

> dete
[1] 3

> einv
          [,1] [,2]       [,3]
[1,]  9.666667    4 -2.3333333
[2,]  4.000000    2 -1.0000000
[3,] -2.333333   -1  0.6666667
> 

Otsikoille siis on paikat. Voisiko niitä käyttää fiksumminkin?
Pengoin helppejä jonkin aikaa, ja havaitsin, että R:ssä voidaan
jonkin verran hallita matriisien rivi- ja sarakeotsikoita, joskaan
ei missään tapauksessa Survon matriisitulkin veroisesti.

Asetetaan otsikot vastaavasti kuin Survossa:

rownames(A) <- rownames(A, FALSE, "AR")
colnames(A) <- colnames(A, FALSE, "AS")
rownames(B) <- rownames(B, FALSE, "BR")
colnames(B) <- colnames(B, FALSE, "BS")
rownames(E) <- rownames(E, FALSE, "ER")
colnames(E) <- colnames(E, FALSE, "ES")

Tällöin, kun toistetaan em. operaatiot

C <- A %*% B
dete <- det(E)
einv <- solve(E)

matriisit näyttävät seuraavilta:

> C
      BS1 BS2
  AR1  13  12
  AR2  14  24

> as.matrix(dete)
     [,1]
[1,]    3

> einv
          ER1 ER2        ER3
ES1  9.666667   4 -2.3333333
ES2  4.000000   2 -1.0000000
ES3 -2.333333  -1  0.6666667


Otsikkoajattelu ei ole viety yhtä pitkälle kuin Survossa, mikä näkyy
esim. dete-nimisessä objektissa. Se on oletuksena skalaari, mutta
otettu tässä näkyviin matriisityyppisenä. Otsikoille ei kuitenkaan
ole keksitty käyttöä vaan ne ovat numeeriset.

Vähänkään pidemmälle menevissä operaatioissa otsikot eivät myöskään
seuraa lainkaan mukana, vaikka käänteismatriisissa ne vielä pysyvätkin
(ja vaihtavat loogisesti paikkojaan - seikka josta Seppo voisi kertoa
lukuisia tarinoita...). Otan esimerkin singulaariarvohajotelmasta:

(Vertailun vuoksi lähdetään tekstitiedostossa annetusta datasta.)

Survo:

Siirretään data tekstitiedostosta Survo-dataksi:
FILE SAVE KYMMEN.TXT TO KYMMEN / DELIMITER=TAB

Valitaan muuttujat (urheilijan nimi ja 10 lajipistemuuttujaa):
MASK=A-AAAAAAAAAA--

Siirretään data matriisiksi X:
MAT SAVE DATA KYMMEN TO X

Matriisissa X on tällöin riviotsikkoina urheilijoiden nimet ja
sarakeotsikkoina muuttujien nimet (tässä X:n vasen yläkulma):

MAT LOAD X(1:5,1:5)
MATRIX X
///          100m  Pituush    Kuula  Korkeus     400m
Skowrone      853      931      725      857      838
Hedmark       853      853      814      769      833
Le_Roy        879      951      799      779      838
Zeilbaue      826      931      793      865      875
Zigert        879      840      924      857      788

Korrelaatiomatriisi keskistyksen ja normeerauksen kautta:
MAT R=MTM(NRM(CENTER(X)))

MAT LOAD R(1:5,1:5)
MATRIX R
NRM(CENTER(X))'*NRM(CENTER(X))
///          100m  Pituush    Kuula  Korkeus     400m
100m      1.00000  0.17199 -0.02795 -0.41170  0.45608
Pituush   0.17199  1.00000 -0.03439 -0.00332  0.13346
Kuula    -0.02795 -0.03439  1.00000  0.16254 -0.30371
Korkeus  -0.41170 -0.00332  0.16254  1.00000 -0.33883
400m      0.45608  0.13346 -0.30371 -0.33883  1.00000

Korrelaatiomatriisin singulaariarvohajotelma; 3 tulosmatriisia:
MAT SVD OF R TO U,D,V

MAT LOAD U(100m:Kuula,svd1:svd3)
MATRIX U
Usvd(NRM(CENTER(X))'*NRM(CENTER(X)))
///          svd1     svd2     svd3
100m     -0.14219  0.57768 -0.15266
Pituush   0.01217  0.31832  0.64953
Kuula     0.48489  0.14380 -0.24312

MAT LOAD D
MATRIX D
Dsvd(NRM(CENTER(X))'*NRM(CENTER(X)))
///      sing.val
svd1     2.602056
svd2     2.007813
svd3     1.206620
svd4     1.067052
svd5     0.931538
svd6     0.594690
svd7     0.569080
svd8     0.538683
svd9     0.244855
svd10    0.237613

MAT LOAD V(100m:Kuula,svd1:svd3)
MATRIX V
Vsvd(NRM(CENTER(X))'*NRM(CENTER(X)))
///          svd1     svd2     svd3
100m     -0.14219  0.57768 -0.15266
Pituush   0.01217  0.31832  0.64953
Kuula     0.48489  0.14380 -0.24312

Kaikkiin matriiseihin tulee siis automaattisesti loogiset otsikot
(ja sen lisäksi em. sisäinen nimi).


R:

Siirretään data tekstitiedostosta R-dataksi:
> kymmen <- read.table("kymmen.txt", header=TRUE, row.names=1)

Siirretään valitut muuttujat datasta matriisiksi X:
> X <- as.matrix(kymmen[,2:11])

Matriisissa X on tällöin riviotsikkoina urheilijoiden nimet ja
sarakeotsikkoina muuttujien nimet (tässä X:n vasen yläkulma):

> X[1:5,1:5]
         X100m Pituush Kuula Korkeus X400m
Skowrone   853     931   725     857   838
Hedmark    853     853   814     769   833
Le_Roy     879     951   799     779   838
Zeilbaue   826     931   793     865   875
Zigert     879     840   924     857   788

Korrelaatiomatriisi keskistyksen ja normeerauksen kautta:
> n <- dim(X)[1]
> M <- scale(X, center=TRUE, scale=TRUE) * sqrt(1/(n-1))
> R <- t(M) %*% M

> R[1:5,1:5]

               X100m      Pituush       Kuula      Korkeus      X400m
  X100m    1.0000000  0.171985363 -0.02795230 -0.411699539  0.4560816
  Pituush  0.1719854  1.000000000 -0.03439298 -0.003324598  0.1334633
  Kuula   -0.0279523 -0.034392979  1.00000000  0.162541961 -0.3037074
  Korkeus -0.4116995 -0.003324598  0.16254196  1.000000000 -0.3388272
  X400m    0.4560816  0.133463323 -0.30370738 -0.338827204  1.0000000

Korrelaatiomatriisin singulaariarvohajotelma; 3 tulosmatriisia:
> sing <- svd(R)

> names(sing)
[1] "d" "u" "v"

> sing$u
             [,1]        [,2]         [,3] ...
 [1,] -0.14219133  0.57767851  0.152659096
 [2,]  0.01216543  0.31832234 -0.649528313
 [3,]  0.48488958  0.14379809  0.243121420
...

> sing$d
 [1] 2.6020563 2.0078135 1.2066202 1.0670519 0.9315382 0.5946902 0.5690795
 [8] 0.5386829 0.2448548 0.2376125

> sing$v
             [,1]        [,2]         [,3] ...
 [1,] -0.14219133  0.57767851  0.152659096
 [2,]  0.01216543  0.31832234 -0.649528313
 [3,]  0.48488958  0.14379809  0.243121420
...

Otsikoita ei siis R:ssä ole ulotettu kaikkialle, vaikka periaatteessa
(ja osittain myös käytännössä) niitä onkin mahdollista hallita. En ole
kuullut tai nähnyt kenenkään niitä R:ssä hyödyntävän, eikä tavallaan
ihme: vaadittiinhan tässäkin jo datan sisäänlukuvaiheessa käyttäjän
aktiivisempi panos asiaan (optio "row.names" read.table-funktiossa).
(Survossa tätä vastaa nimimuuttujan aktivointi MASK-komennossa.)

Voin nähdäkseni hyvin jatkaa esitykseni valmistelua tältä pohjalta.
Myös matriisien kanssa työskentelyssä Survo on käyttöliittymänsä
puolesta ollut jo aikoja sitten aikaansa edellä, kuten R:n alulle
laittanut Robert Gentleman myös totesi Tampereella viime syksynä
pitämänsä esitelmän alkajaisiksi.

- Kimmo

Vastaukset:

Survo-keskustelupalstan (2001-2013) viestit arkistoitiin aika ajoin sukrolla, joka automaattisesti rakensi viesteistä (yli 1600 kpl) HTML-muotoisen sivukokonaisuuden. Vuoden 2013 alusta Survo-keskustelua on jatkettu entistäkin aktiivisemmin osoitteessa forum.survo.fi. Tervetuloa mukaan!

Etusivu  |  Keskustelu
Copyright © Survo Systems 2001-2013. All rights reserved.
Updated 2013-06-15.