Projets informatiques M2 Parcours MSS

Introduction

L’objectif de ce projet informatique est de se servir de données libres sur la ville de Bordeaux pour faire des analyses descriptives et des prédictions. On va s’intéresser aux données spatiales et temporelles fournies par des capteurs de traffic disposés tout au long de la ville.

Bordeaux Métropole dispose actuellement de 500 capteurs dans leur territoire qui journalièrement comptent le nombre de voitures qui passent à un point géographique donné. Cette information est importante, d’une part, pour la mairie mais aussi pour les citadins.

Dans un premier temps on parlera des difficultés encontrées lors de la récuperation des données en temps réel. Ensuite, on s'intéressera aux données founies par la CUB sur les capteurs au formats .csv, et on fera des analyses statistiques sur les capteurs. Pour finir, une partie sur le web crawling sera dévelopée avec notamment un exemple sur un site de thèses.

Premier essai

La première phase d'un tel projet est la récupération des données, celle-ci représentera pour nous le plus gros challenge. En effet, les donnnées des capteurs de traffic sont proposées sous le format ".wps": Web Processing Service. Il s'agit d'un format d'interface permettant de faire appel à des services de traitement.

Dans un premier temps, afin de mieux comprendre, nous utilisons ces données sous le language conseillé javascript. Grâce aux tutoriaux de la page Web de la CUB, nous parvenons à ouvrir une carte (en fond) et à placer les capteurs de trafic par dessus (layer).

Nous comprenons que l'objectif du format .wps est de pouvoir s'intégrer facilement dans n'importe quelle page web et adapter l'API selon les couches souhaitées. Après de nombreux essais, on ne peux pas obtenir facilement ces donnes: l'accés semble restreint pour les novices en informatique.

En définitive, on reussit à afficher les données ici mais pas à récupérer la matrice des données.

Fichers .csv

On abandonne les données en temps réel et on se limite donc aux fichier .csv sur les capteurs qui sont aussi présents sur le site. On trouve 6 fichiers pour les années de 2010 à 2015.

On remarque que dans le fichier 2010 on a aussi les colonnes pour l'année 2009, donc on peut dire qu'on a 7 années à disposition.

Description des données

Pour chaque année, on dispose de 4 données par capteur:

-l'identifiant du capteur: du type "Z05BS" par exemple

-HPM: le nombre de voitures à l'Heure de Pointe le Matin (7h30-8h30)

-HPS: le nombre de voitures à l'Heure de Pointe le Soir (17h-18h)

-MJO: la Moyenne par Jours Ouvrés, correspondant au débit moyen en véhicule/heure sur les jours ouvrés

Les données sur les poids lourds sont enlevées (renseignées pour seulement 100 données) et les pourcentages d'évolution aussi (redondance des informations).

head(trafic_2009)

##   Capteur HPM.2009 HPS.2009 MJO.2009
## 1   Z05Ae      171      200     2284
## 2   Z05As      729     1070    12588
## 3   Z05Be      677      573     7909
## 4   Z05Bs      446      859     8031
## 5   Z06Ae      753      709     8620
## 6   Z06As      503      553     6590

Une fois les NA enlevés, on remarque que le nombre de lignes (=nombre de capteurs) des fichiers varie selon les années. En effet, il oscille entre 466 et 523. On ne veut garder que les capteurs qui sont renseignés pour chaque année, on fait un merge par Capteurs et on obtient une table avec 410 lignes et 22 colonnes. Cette table sera utile pour les analyses statistiques.

tot<-Reduce(function(x, y) merge(x, y, by="Capteur"), list(trafic_2009,trafic_2010,trafic_2011,trafic_2012,                                                       trafic_2013,trafic_2014,trafic_2015))
tot[1:3,]

##   Capteur HPM.2009 HPS.2009 MJO.2009 HPM.2010 HPS.2010 MJO.2010 HPM.2011
## 1   Z05AE      171      200     2284      155      189     2186   150,14
## 2   Z05AS      729     1070    12588      649     1046    11764   621,58
## 3   Z05BE      677      573     7909      629      539     7297   580,35
##   HPS.2011 MJO.2011 HPM.2012 HPS.2012 MJO.2012 HPM.2013 HPS.2013 MJO.2013
## 1      178  2012,48      149      162     1913      139      172     1956
## 2  1050,79 11705,98      603     1036    11411      637     1007    11586
## 3   488,91  6935,86      550      490     6626      531      530     6821
##   HPM.2014 HPS.2014 MJO.2014 HPM.2015 HPS.2015 MJO.2015
## 1      140      187     2301      122      126     1777
## 2      630      942    11174      634      995    11015
## 3      522      515     6836      535      512     6689

dim(tot)

## [1] 410  22

Analyse géographique

Tout d'abord, on a voulu faire une analyse spatiale des capteurs. On a pas un accès direct au coordonnées géographiques, mais, on trouve un fichier.csv avec les identifiants et leurs adresses.

geo<-read.csv("Anibarro-Rambier/adresses_OK.csv")
head(geo)

##   X cartodb_id   ident   type
## 1 2        478 Z25CT11 BOUCLE
## 2 3         37 Z10CT18 BOUCLE
## 3 4        473 Z14CT24 BOUCLE
## 4 5        475 Z14CT23 BOUCLE
## 5 6        476 Z25CT14 BOUCLE
## 6 7        315  Z30CT7 BOUCLE
##                                           adresse
## 1          Allée de Boutaut, 33520 Bruges, France
## 2 92-94 Rue de la Béchade, 33000 Bordeaux, France
## 3       87 Quai de Brazza, 33100 Bordeaux, France
## 4    54-75 Quai de Brazza, 33100 Bordeaux, France
## 5          Allée de Boutaut, 33520 Bruges, France
## 6    20 Avenue de Belfort, 33700 Mérignac, France

On décide alors, de géolocaliser les 482 capteurs, dont on connait l'adresse, en intérogeant l'API Google Maps.

library(RCurl)
library(RJSONIO)
library(plyr)

url <- function(address, return.call = "json", sensor = "false") {
  root <- "http://maps.google.com/maps/api/geocode/"
  u <- paste(root, return.call, "?address=", address, "&sensor=", sensor, sep = "")
  return(URLencode(u))
}

geoCode <- function(address,verbose=FALSE) {
  if(verbose) cat(address,"\n")
  u <- url(address)
  doc <- getURL(u)
  x <- fromJSON(doc,simplify = FALSE)
  if(x$status=="OK") {
    lat <- x$results[[1]]$geometry$location$lat
    lng <- x$results[[1]]$geometry$location$lng
    location_type <- x$results[[1]]$geometry$location_type
    formatted_address <- x$results[[1]]$formatted_address
    return(c(lat, lng, location_type, formatted_address))
  } else {
    return(c(NA,NA,NA, NA))
  }
}

Application à nos données:

longitude<-NULL
latitude<-NULL

for ( i in 1:482){
address <- geoCode(as.character(geo$adresse[[i]]))

longitude<-c(longitude,address[1])
latitude<-c(latitude,address[2])
print(longitude)
print(latitude)
}

longitude<-as.numeric(longitude)
latitude<-as.numeric(latitude)

tab<-cbind(as.character(geo$adresse), longitude, latitude)

Ce code met autour de 4 minutes à tourner donc on préfere charger directement le tableau "tab" obtenu.

coord<-read.csv("Anibarro-Rambier/coord_geo_OK.csv")
coord[1:3,]

##   cartodb_id   ident   type
## 1        478 Z25CT11 BOUCLE
## 2         37 Z10CT18 BOUCLE
## 3        473 Z14CT24 BOUCLE
##                                           adresse coordonnees_kml2
## 1          Allée de Boutaut, 33520 Bruges, France         44.87473
## 2 92-94 Rue de la Béchade, 33000 Bordeaux, France         44.82396
## 3       87 Quai de Brazza, 33100 Bordeaux, France         44.85776
##   coordonnees_kml
## 1      -0.5767857
## 2      -0.5997033
## 3      -0.5465689

L'intérêt d'avoir les coordonnées est de pourvoir ainsi les placer sur un carte de la ville de Bordeaux et pouvoir visualiser les positions. Pour ceci, après plusieurs essais, on décide d'utiliser le package RgoogleMaps.

library(RgoogleMaps)

map.bdx <- GetMap(center=c(44.8404400,-0.5805000), zoom = 13, destfile = "bdx.png", maptype = "mobile")

lat<-as.numeric(coord$coordonnees_kml2)
long<-as.numeric(coord$coordonnees_kml)

bb <- qbbox(lat = as.numeric(lat),
            lon = as.numeric(long))


bdx3 <- GetMap.bbox(latR = bb$latR,
                      lonR = bb$lonR,
                      destfile = "bdx3.png",
                      maptype="mobile", zoom=12
)

PlotOnStaticMap(bdx3,
                lat = as.numeric(lat), lon = as.numeric(long),
                cex = 0.5, pch = 19, col = "red", add = FALSE)


##ACP

Maintenant qu'on a notre tableau total et les positions géographiques on commence à faire des analyses statistiques.

On commence par une ACP sur le tableau des données complètes. Une fois qu'on a les nouvelles coordonnées, l'agorithme des k-means avec k=2 nous semble adapté ici pour différencier les capteurs.

En effet, on peut voir en rouge les capteurs placés sur les boulevards, les quais et les entrées et sorties de la Rocade, les endroits qui ont tendance à être embouteillés.

lat<-as.numeric(tot$coordonnees_kml2)
long<-as.numeric(tot$coordonnees_kml)

PlotOnStaticMap(bdx3,
                lat = as.numeric(lat), lon = as.numeric(long),
                cex = gros, pch = 19, col = couleur, add = FALSE)


# Influence de l'ouverture du Pont Chaban Delmas

Inauguré en Mars 2013, le pont Chaban Delmas a été construit pour fluidifier le trafic le long des quais, en proposant des chemins alternatifs aux conducteurs. On va voir comment ceci a eu un impact sur les capteurs.

Capteurs Rive Gauche

On commence par étudier 9 capteurs qui sont sur les quais entre le pont Chaban Delmas et le Pont de Pierre.

Le Matin


On constate tout d'abord qu'en 2011 il y a eu des travaux, ou un autre facteur (peut être un problème technique sur les capteurs de la CUB), qui a négativement influencé les passages de voitures à cette heure là.

Hormis ceci, on peut conclure que l'ouverture du pont n'a pas significativement changé les chemins des voitures puisque les bordelais continuent d'emprûnter les quais de la rive gauche.

Le Soir


La même chose le soir entre 17h et 18h...le pont ne change rien.

Capteurs Rive Droite

On dispose que de deux capteurs sur la rive droite et on ne constate pas de grand changement.


Cette partie est légèrement décevante puisqu'on constate qu'un des aménagements principaux de la ville ne semble avoir aucun impact sur le trafic. On se demande si c'est une erreur de notre de notre part ou si le pont ne sert à rien...

Graphes, Networking

Pour cette dernière partie on décide de voir la carte des capteurs comme un graphe et de mettre en évidence les "liens" entre les capteurs qui se ressemblent.

Pour ceci, on reprend les coordonnées obtenues selon l'ACP. On veut maintenant regrouper les capteurs "semblables". On se limite aux 2 capteurs les plus proches et on construit la matrice A qui pour chaque capteur nous donne les 2 plus proches voisins en termes d'ACP.

head(A)

##   CENTRE 1 PLUS PROCHE 2 PLUS PROCHE
## 1  Z05AE         Z3CT3        Z14CT9
## 2  Z05AS        Z30CT3         Z8CT6
## 3  Z05BE        Z9CT12        Z18CT2
## 4  Z05BS         Z6CT6         Z21BE
## 5  Z06AE         Z30AS        Z17CT5
## 6  Z06AS         Z16AE         Z6CT9

Modification de matrice A en termes de liens FROM-->TO:

head(liens)

##      from    to      
## [1,] "Z05AE" "Z3CT3" 
## [2,] "Z05AE" "Z14CT9"
## [3,] "Z05AS" "Z30CT3"
## [4,] "Z05AS" "Z8CT6" 
## [5,] "Z05BE" "Z9CT12"
## [6,] "Z05BE" "Z18CT2"

Maintenant qu'on a la matrice des liens on va utiliser la package igraph pour contruire et visualiser le graphe.

## 
## Attaching package: 'igraph'

## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum

## The following object is masked from 'package:base':
## 
##     union

On se limite aux 50 premiers capteurs pour obtenir un graphe lisible et clair.

plot.igraph(net,vertex.label.color="black",vertex.shape="none", vertex.label.dist=0, vertex.size=10, edge.arrow.mode=0, edge.color="red", edge.width=2,
            vertex.label.cex=0.7, layout=l, main="Liens entre les capteurs selon ACP")


On va étudier ceci grâce à un exemple. On décide d'analyse le chemin entre le capteur Z16CT14 et Z24CT3. Comme on peut voir en haut à gauche sur la graphique ci-dessus, le chemin le plus "rapide" selon l'ACP serait de faire:

Z16CT14->Z10CT15->Z10AS->Z10CT14->Z24CT3

En contraste, on trace les coordonnées géographiques de ces points intermédiaires.


Le graphique montre que pour aller du Départ à la Fin, si on suit le chemin de l'ACP, on fait un très grand détour par les Boulevards!

Ceci est bien en accord avec notre intuition puisque l'ACP conseille des chemins par capteurs "semblables" mais ceci ne veut pas forcément dire proches. En définitive, on peut avoir des capteurs très embouteillés relativement proches de capteurs où la circulation est fluide.