R-ohjelmointi.org

Tilastotieteellistä ohjelmointia R-kielellä

Junaliikenteen aikataulut

Luin tänään Ilta-Sanomista uudesta Junat.net -palvelusta, joka näyttää tietyn aseman junien kulkutiedot ja mahdolliset aikataulusta muuttuneet kulkutiedot. Palvelu näyttää ulkoasultaan siistiltä ja selkeältä, ja sitä on helppo käyttää. Pakkohan tuota oli kokeilla R:lläkin!

Tietojen keruu ja käsittely

Junat.net -palvelu käyttää rata.digitraffic.fi:n tarjoamaa avointa rajapintaa, joka julkaistu lisenssillä Creative Commons Nimeä 4.0.

Junien kulkutiedot on helppo hakea rajapintaa käyttäen vaikkapa R:n curl-paketilla. Pakettia ei tosin aivan välttämättä tarvittaisi välissä, mutta se palauttaa tiedot helpommin hyödynnettävässä muodossa kuin vaikkapa suora rajapinnan palauttaman tiedon lukeminen esimerkiksi readLines() -komennolla.

Osa palautettavista tiedoista on JSON-muodossa, ja niiden parsiminen käy helposti esimerkiksi jsonlite-paketilla.

Tietojen esikäsittelyn jälkeen ne tulostetaan R:n komentoriville ja näytetään myös selaimessa taulukkona, joka on muodostettu paketin formattable funktioilla.

Koska junaseisakkeiden ja asemien nimet ovat rajapinnassa hieman yleisestä kielenkäytöstä poikkeavia, käytetään hakuterminä syötetyn ja rajapinnan asemien nimien yhteen sovittamiseen paketin stringdist-funktioita.

Hakufunktiot

Asemien nimien hakemiseen käytetään funktiota getStations() ja aikataulujen hakemiseen funktiota getTrains(). Funktioiden koodi on seuraava:

getStations<-function() {
  # Asematiedot
  con<-curl(url = "http://rata.digitraffic.fi/api/v1/metadata/stations")
  tmp<-readLines(con)
  asemat<-fromJSON(tmp)
  close(con)
 
  return(asemat)
}
 
getTrains<-function(asema, n=15, browser=FALSE) {
 
  # Paketit
  library(curl)
  library(jsonlite)
  library(formattable)
  library(stringdist)
 
  # Asematiedot
  asemat<-getStations()
 
  # Reaaliaikainen seuranta
  asd<-stringdist(asema, asemat$stationName, method="hamming")
  cat(paste0("Haetaan aseman ", asemat[which(asd==min(asd)),"stationName"][1], " tiedot...\n\n"))
  con<-curl(url = paste0("http://rata.digitraffic.fi/api/v1/live-trains?station=", asemat[which(asd==min(asd)),"stationShortCode"][1], "&departing_trains=", n))
  tmp<-readLines(con)
  dat<-fromJSON(tmp)
  close(con)
 
  juna <-dat$commuterLineID
  aika <-rep(NA, nrow(dat))
  aika2<-rep(NA, nrow(dat))
  to   <-rep(NA, nrow(dat))
  track<-rep(NA, nrow(dat))
  tmpa <-rep(NA, nrow(dat))
 
  asema<-asemat[which(asd==min(asd)),"stationShortCode"][1]
  for(i in 1:nrow(dat)) {
     tmp<-dat$timeTableRows
     tmp2<-tmp[[i]] 
     tmp2<-tmp2[tmp2$trainStopping,]
     ind<-which(tmp2$stationShortCode==asema)[1]
     if(ind+2 < nrow(tmp2)) {
        ind<-ind+2
     }
     to[i]<-tmp2$stationShortCode[ind]
     to[i]<-as.character(asemat$stationName[asemat$stationShortCode==to[i]])
     colexists1<-length(grep("commercialTrack", colnames(tmp2)))==1
     if(colexists1) {
        track[i]<-tmp2$commercialTrack[which(tmp2$stationShortCode==asema)[1]]
     } else {
        track[i]<-"ei tiedossa"
     }
     aika[i]<-substr(tmp2$scheduledTime[ind], 12, 19)
     colexists2<-length(grep("actualTime", colnames(tmp2)))==1
     if(colexists2) {
        aika2[i]<-substr(tmp2$actualTime[ind], 12, 19)
     }   
     tmpa[i]<-as.character(strptime(paste(substr(tmp2$scheduledTime[ind], 1, 10), substr(tmp2$scheduledTime[ind], 12, 19)), format="%Y-%m-%d %H:%M:%S"))
     aika2[is.na(aika2)]<-""
  }
 
  d<-data.frame(Aika=aika, Muutt.aika=aika2, Juna=dat$commuterLineID, Määränpää=to, Raide=track)
  d<-d[order(strptime(tmpa, format="%Y-%m-%d %H:%M:%S"), d$Määränpää, d$Juna),]
  d<-na.omit(d)
  rownames(d)<-NULL
 
  if(browser) {
     formattable(d, list(
        Muutt.aika = formatter("span", style = x ~ ifelse(x != "", style(color = "red", font.weight = "bold"), NA))
     ))
  }
 
  return(d)
}

Hakujen tekeminen

Yllä olevien funktioiden avulla junien kulkutietojen hakeminen käy helposti. Esimerkiksi seuraava komento hakee yhteensä viisitoista aseman ”Masala” kulkutietoja:

getTrains(asema="Masala", n=15)

Tuloksen voi tietysti tallentaa myös objektiin:

junat<-getTrains(asema="Masala", n=15)

Tulosten esittäminen

Tulokset tulostuvat R:n komentoriville, ja ne näytetään myös selaimessa. Komentoriville tulostuva tulos muistuttaa seuraavaa, ja siinä junat on järjestetty niiden saapumisajan perusteella:

       Aika Muutt.aika Juna       Määränpää Raide
1  18:39:54   18:41:05    S          Masala     1
2  19:08:54   19:08:17    U           Luoma     2
3  19:13:54   19:14:31    U          Jorvas     1
4  19:39:54   19:40:09    S          Masala     1
5  19:42:54   19:42:15    S Kauklahti asema     2
6  20:12:54               L           Luoma     2
7  20:13:54               U          Jorvas     1
8  20:39:54               S          Masala     1
9  20:42:54               L           Luoma     2
10 21:08:54               L          Jorvas     1
11 21:12:54               L           Luoma     2
12 21:41:54               L          Jorvas     1
13 21:42:54               L           Luoma     2
14 22:08:54               L          Jorvas     1
15 22:38:54               L          Jorvas     1
16 22:42:54               L           Luoma     2
17 23:38:54               L          Jorvas     1
18 02:07:54               L           Luoma     2
19 02:37:54               L           Luoma     2
20 03:07:54               L           Luoma     2

Samaan tapaan funktio näyttää listaukset verkkoselaimessa, jos funktiolle on annettu argumentti browser=TRUE:

junat_net2

Mahdollisia lisäkehitysmahdollisuuksia

Asemien nimien ja käyttäjän hakuterminä antaman aseman nimen yhteensovittaminen ei ole aukotonta. Esimerkiksi hakutermin ”Ilmala” käyttö hakee itse asiassa seisakkeen ”Hanala” tietoja ja kaatuu hyvin epähienosti. Jos asemalistauksesta taas poistaa kaikki henkilöliikenteessä olemattomat asemat, hakee hakutermin ”Ilmala” käyttö Kiialaa, ja kaatuu jälleen varsin epähienosti. Ehkä hakutermin ja oikeiden asemien nimien yhteensovittaminen ei ollutkaan kovin hyvä ajatus?

Sitten on tietysti vielä R-toteutuksen karuhkoon ulkoasuun liittyviä kysymyksiä…


Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *