Geoms med statistiske beregninger (transformasjoner)

Flere geometriske objekter (eng. geoms) har innebygde funksjoner for statistiske transformasjoner og beregninger. I flere tidligere kapitler har vi demonstrert geom_smooth(), som beregner og visualiserer sammenhengen mellom x og y. Funksjonen geom_smooth() har argumentet method, som kan settes til "loess" for å generere en fleksibel regresjonslinje eller "lm", som genererer en lineær regresjonslinje. Det samme prinsippet gjelder for flere andre geoms, noe som innebærer at de utfører beregninger for å visualisere data.

I dette kapitlet skal vi bruke data fra gapminder for å demonstrere hvordan transformasjoner fungerer. Vi begynner med å aktivere pakken gapminder og inspisere de første 10 radene. Inspeksjon av data kan blant annet gjøres med funksjonen head().

library(gapminder)
head(gapminder, 10)
country <fctr> continent <fctr> year <int> lifeExp <dbl> pop <int> gdpPercap <dbl>
Afghanistan Asia 1952 28.801 8425333 779.4453
Afghanistan Asia 1957 30.332 9240934 820.8530
Afghanistan Asia 1962 31.997 10267083 853.1007
Afghanistan Asia 1967 34.020 11537966 836.1971
Afghanistan Asia 1972 36.088 13079460 739.9811
Afghanistan Asia 1977 38.438 14880372 786.1134
Afghanistan Asia 1982 39.854 12881816 978.0114
Afghanistan Asia 1987 40.822 13867957 852.3959
Afghanistan Asia 1992 41.674 16317921 649.3414
Afghanistan Asia 1997 41.763 22227415 635.3414

Deretter lager vi et stolpediagram som viser hvor mange observasjoner (rader) det finnes for hvert kontinent. Dette gjøres med geom_bar(), som lager et stolpediagram. Den eneste estetiske mappingen vi deklarerer, er x=continent. Funksjonen beregner y-aksen automatisk (antall rader for hvert kontinent).

ggplot(data=gapminder) +
  geom_bar(aes(x=continent))
Stolpediagram over antall observasjoner per kontinent i gapminder, der Afrika har flest og Oseania færrest

Et alternativ til det ovenstående er å beregne antall observasjoner på hvert kontinent selv. Det kan enkelt gjøres med funksjonen count() i pakken dplyr. Du har sannsynligvis allerede lastet inn dplyr, siden den inngår i pakken tidyverse. Ellers laster vi den inn nå:

library(tidyverse)

Funksjonen count() teller antall rader for én eller flere kategoriske variabler, slik:

gapminder |>
  count(continent)
continent <fctr> n <int>
Africa 624
Americas 300
Asia 396
Europe 360
Oceania 24

Som det fremgår ovenfor, beregnes antall rader (n) for hvert kontinent (continent).

Som det fremgår ovenfor, beregnes antall rader (n) for hvert kontinent (continent). Vi tar nå disse dataene og lager et stolpediagram som er identisk med det forrige. Siden geom_bar() ikke lenger skal beregne y-aksen selv, forteller vi at y=n, og vi bruker argumentet stat="identity" for å fortelle at verdiene allerede er beregnet. Legg også merke til at vi kobler sammen count() med ggplot() og dermed bruker resultatet av count() direkte i ggplot(). Dette er mulig fordi pipe (|>) sender resultatet av en operasjon videre til neste funksjon, der resultatet brukes som første argument (første argument i funksjonen ggplot() er data).

gapminder |>
  count(continent) |>
  ggplot(aes(x=continent, y=n)) +
  geom_bar(stat="identity")
Stolpediagram over antall rader n per kontinent i gapminder, identisk med det forrige, men laget med stat identity

Det finnes andre transformasjoner (beregninger) innebygd i geometriske objekter. Du har allerede støtt på geom_smooth() i forrige kapittel. Her følger andre eksempler på geoms som utfører beregninger når de brukes:

  • geom_bar(), geom_histogram(), geom_freqpoly() beregner summer og proporsjoner.
  • geom_boxplot(), geom_violin() beregner fordelinger.
  • geom_smooth() lager en regresjonsmodell som visualiseres.

I neste eksempel bruker vi gapminder til å gjøre følgende:

  • Linje 2: Vi beholder bare land i Afrika ved å filtrere med argumentet continent=="Africa".
  • Linje 2: Vi beholder bare data fra år 1997 ved å filtrere med argumentet year==1997.
  • Linje 2: Vi kobler ggplot() direkte sammen med de foregående operasjonene med |>
  • Linje 4: Vi lager et stolpediagram der land er y-aksen og forventet levealder er x-aksen. Siden disse verdiene allerede er beregnet, brukes argumentet stat="identity":
gapminder |>
  filter(continent=="Africa", year==1997) |>
  ggplot()+
  geom_bar(aes(y=country,
               x=pop),
           stat="identity")
Liggende stolpediagram over folketall i 1997 for afrikanske land i alfabetisk rekkefølge

Vi fortsetter med å sortere y-aksen etter forventet levealder (lifeExp). Dette kan gjøres direkte i aes() med funksjonen reorder(). I reorder spesifiseres hva som skal sorteres (country), og kolonnen det skal sorteres etter (pop, som er folketall). Se linje 4 nedenfor.

gapminder |>
  filter(continent=="Africa", year==1997) |>
  ggplot()+
  geom_bar(aes(y=reorder(country, pop),
               x=pop),
           stat="identity")
Liggende stolpediagram over folketall i 1997 i Afrika, sortert med Nigeria øverst og Sao Tome og Principe nederst

Et minustegn (-) foran pop i reorder() gir omvendt sortering, slik (se linje 4):

gapminder |>
  filter(continent=="Africa", year==1997) |>
  ggplot()+
  geom_bar(aes(y=reorder(country, -pop),
               x=pop),
           stat="identity")
Liggende stolpediagram over folketall i 1997 i Afrika i omvendt sortering, med Nigeria nederst

Vi trenger også å visualisere forventet levealder (lifeExp) for hvert land og kan gjøre det med argumentet fill(), slik (linje 6):

gapminder |>
  filter(continent=="Africa", year==1997) |>
  ggplot()+
  geom_bar(aes(y=reorder(country, pop),
               x=pop,
               fill=lifeExp),
           stat="identity")
Liggende stolpediagram over folketall i 1997 i Afrika der stolpens blåtone viser forventet levealder

Proporsjoner

Med geom_bar() kan proporsjoner (prop) beregnes i stedet for antall (count). Dette gjøres med en "etterberegning" (after_stat) på y og ved å spesifisere group=1, som innebærer at den totale andelen i alle kontinenter skal være 1:

ggplot(data = gapminder) +
  geom_bar(mapping = aes(x = continent,
                         y = after_stat(prop),
                         group = 1))
Stolpediagram over andelen observasjoner per kontinent i gapminder, der Afrika står for omtrent 0,37

Stat summary: stat_summary()

Vi kan også bruke stat_summary() for å velge hvilke parametere som skal beregnes og visualiseres. Med stat_summary() har vi større fleksibilitet når det gjelder beregningene. Vi spesifiserer selv hvilke funksjoner som skal brukes, og vi velger dessuten hvilken type geom som skal illustrere resultatet. Nedenfor bruker vi stat_summary() for å beregne gjennomsnitt, minste verdi og største verdi for forventet levealder på hvert kontinent, og dette visualiseres med geomet "pointrange" (geom_pointrange()):

## Vi bruker bare data fra 1997
ggplot(data = filter(gapminder, year==1997)) +
  stat_summary(
    aes(x = continent,
        y = lifeExp),
    fun = mean,
    fun.min = min,
    fun.max = max,
    geom = "pointrange"
  )
Punkt- og intervalldiagram over gjennomsnittlig, minste og største forventede levealder per kontinent i 1997

Segmenterte stolpediagrammer

Vi går tilbake til mpg-dataene for å illustrere flere funksjoner i geom_bar(). I neste eksempel bruker vi fill for å markere andeler av en stolpe. Vi vil markere andeler av kolonnen drv (bilens drivlinje) i hver stolpe. I koden nedenfor har vi også justert grafens tema med funksjonen theme() for å vinkle teksten på x-aksen 45° (temaer diskuteres i et senere kapittel).

mpg |>
  ggplot(aes(x=manufacturer,
             fill=drv)) +
  geom_bar() +
  # Gir teksten på x-aksen 45° helning
  theme(axis.text.x = element_text(angle=45))
Stablet stolpediagram over antall biler per produsent i mpg, farget etter drivlinje 4, f og r

Det ser ut til at produsenten Volkswagen bare produserer biler med forhjulsdrift (f), mens Subaru bare produserer biler med firehjulsdrift. Land Rover produserer bare bakhjulsdrevne biler.

I eksemplet ovenfor skrev vi geom_gar() uten noen argumenter. Det innebærer at position fikk sin standardverdi, som er "identity". Det finnes også alternativene "dodge" og "fill", som gir følgende grafer:

mpg |>
  ggplot(aes(x=manufacturer,
             fill=drv)) +
  geom_bar(position="dodge") +
  theme(axis.text.x = element_text(angle=45))
Stolpediagram over antall biler per produsent med drivlinjene 4, f og r som stolper ved siden av hverandre

Som det fremgår ovenfor, fører position="dodge" til at segmentene plasseres ved siden av hverandre i stedet for å stables oppå hverandre. Vi fortsetter med position="fill":

mpg |>
  ggplot(aes(x=manufacturer,
             fill=drv)) +
  geom_bar(position="fill") +
  theme(axis.text.x = element_text(angle=45))
Stolpediagram der hver produsents stolpe viser andelen biler med drivlinje 4, f og r, opp til 1

Som det fremgår ovenfor, fører position="fill" til at segmentene i hver stolpe presenteres som andeler (proporsjoner) i stedet for antall.