Nous nous sommes fixés pour objectifs de :
Chaque partie de ce notebook est indépendante. Une fois que I. Fonctions préliminaires a été exécuté, il est donc possible de ne recompiler qu'une partie.
import importlib
import gmplot
import parser
import filters
import distance
import colors
import staypoint as st
from projectColors import defineColorsList,defineColorsShortList
import datetime
import speedClassification as speedClass
from tqdm import tqdm
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.cluster import DBSCAN
from IPython.display import IFrame
lColors=defineColorsList()
colorListSpeed=defineColorsShortList()
L'idée générale est de visualiser sur l'ensemble des données quand est-ce que l'utilisateur est généralement en mouvement. Ainsi on pourra par la suite visualier si il y a une différence entre jour de la semaine/week-end.
On commence par prendre l'ensemble des données de l'utilisateur Android. Ces données s'étalent du 5/04/2015 au 01/02/2018.
android_df = parser.importJson("data/android.json", True)
On applique dans un premier temps un mean-filter sur l'ensemble des données avec une fenêtre de 10 points, puis l'algorithme stay-point afin de pouvoir identifiier les phases en mouvement :
df_all_year = filters.meanFilter(android_df, 10)
stay_point_all = st.findStayPoints(df_all_year, 3, 50, 5)
gmap = gmplot.GoogleMapPlotter(45.764376, 4.810495, 13, apikey="AIzaSyDsYwvF3UUxTx8RB40wd4SnUVzfnbW66LM")
segment_count = max(stay_point_all["segment_mouvement"])
for l in range(segment_count):
segment = stay_point_all[stay_point_all['segment_mouvement'] == l]
segment_mouvement = segment[segment['is_mouvement'] == True ]
gmap.plot(segment_mouvement["lat_mean_filt"], segment_mouvement["lng_mean_filt"], lColors[l%20], edge_width=4)
gmap.draw("figure/5-segmented-year-df.html")
IFrame('figure/5-segmented-year-df.html', width=990, height=500)
On ne garde ensuite que les points pour lesquels l'utilisateur était en mouvement :
mouvement_all = stay_point_all[stay_point_all['is_mouvement'] == True]
mouvement_all.head()
On regroupe ensuite les points par minutes.
La colonne is_mouvement présente alors le nombre de fois où il y a un point en mouvement à cette heure.
mouvement_all['time'] = mouvement_all['time'].transform(lambda x: x.str[0:5])
grouped_mouvement_all = mouvement_all.groupby('time',
as_index=False)[['is_mouvement']].sum()
grouped_mouvement_all.head()
times = []
for hours in grouped_mouvement_all['time']:
times.append(datetime.time(int(hours[0:2]),
int(hours[3:5])))
grouped_mouvement_all['time'] = times
grouped_mouvement_all.head()
On représente ensuite le nombre de points en fonction de l'heure :
plt.figure(figsize=(12,8))
plt.grid(True)
plt.plot(grouped_mouvement_all.time
,grouped_mouvement_all.is_mouvement)
plt.locator_params('x', nbins=15)
plt.xlabel('Time of the day')
plt.ylabel('Number of mouvement recordings')
plt.show()
Nous avons donc fait une première analyse "à la main", l'idée serait donc de la généraliser grâce à un algorithme de clusterisation. On reprendre le même KMeans que l'on avait utilisé pour segmenter en fonction des régimes de vitesse et on l'adapte au cas présent. On cherche à identfier 3 cas possibles :
import mouvementClassification as mouvementClass
On découpe la journée en 48 segments, correspondant à des périodes d'une demi-heure.
(lK,whitened)=mouvementClass.applyKMeans(grouped_mouvement_all,k=48)
lBoundiaries=mouvementClass.getBoundiaries(lK)
lFirstSpeedSegmentation=mouvementClass.calcFirstSegmentation(lBoundiaries,whitened,bPadd=True)
plt.figure(figsize=(12,8))
plt.grid(True)
plt.ylim(0,7)
for ii, plots in enumerate(lFirstSpeedSegmentation):
plt.plot(plots,lColors[ii%20])
plt.xlabel('Time of the day')
plt.ylabel('Number of mouvement recordings')
plt.show()
Nous pouvons visualiser sur la figure ci-dessus le partage du signal en 48 segments homogènes. Nous souhaitons maintenant classifier ces différents segments dans les 3 classes que nous avons défini précédemment.
(l,a)=mouvementClass.agglomerateSpeedSegments(lFirstSpeedSegmentation)
group_mouv = []
segment_num = []
offset = 0;
colors = []
m = 0;
for ii, plots in enumerate(l):
for jj, speed in enumerate(plots):
if jj >= offset :
group_mouv.append(a[ii])
segment_num.append(m)
new_offset = len(plots)
offset = new_offset
m += 1
colors.append(colorListSpeed[a[ii]])
group_mouv.append(a[ii])
segment_num.append(m)
grouped_mouvement_all['group_mouv'] = group_mouv
grouped_mouvement_all['segment_num'] = segment_num
plt.figure(figsize=(12,8))
plt.grid(True)
segment_count = max(grouped_mouvement_all["segment_num"])
for m in range(segment_count):
segment = grouped_mouvement_all[grouped_mouvement_all['segment_num'] == m]
plt.plot(segment.time, segment.is_mouvement, color=colors[m])
plt.xlabel('Time of the day')
plt.ylabel('Number of mouvement recordings')
plt.show()
On retrouve donc ce que l'on avait dit plus haut : Entre 2h et 6h du matin l'utilisateur est donc très peu souvent en mouvement (il dort!).
Vers 9h, autour de 12h, à 16h et autour de 18h et en début de soirée il est très souvent en mouvement.
Nous allons ici réitérer notre démarche avec les données de l'utilisateur iPhone, qui possède bien moins de points. Cela nous permet d'évaluer la capacité de généralisation de notre méthode.
iphone_df = parser.importJson("data/iphone.json", True)
dfi_all_year = filters.meanFilter(iphone_df, 10)
stayi_point_all = st.findStayPoints(dfi_all_year, 3, 50, 5)
mouvementi_all = stayi_point_all[stayi_point_all['is_mouvement'] == True]
mouvementi_all['time'] = mouvementi_all['time'].transform(lambda x: x.str[0:5])
groupedi_mouvement_all = mouvementi_all.groupby('time',
as_index=False)[['is_mouvement']].sum()
groupedi_mouvement_all.head()
times = []
for hours in groupedi_mouvement_all['time']:
times.append(datetime.time(int(hours[0:2]),
int(hours[3:5])))
groupedi_mouvement_all['time'] = times
plt.figure(figsize=(12,8))
plt.grid(True)
plt.plot(groupedi_mouvement_all.time
,groupedi_mouvement_all.is_mouvement)
plt.locator_params('x', nbins=15)
plt.xlabel('Time of the day')
plt.ylabel('Number of mouvement recordings')
plt.show()
(lK,whitened)=mouvementClass.applyKMeans(groupedi_mouvement_all,k=48)
lBoundiaries=mouvementClass.getBoundiaries(lK)
lFirstSpeedSegmentation=mouvementClass.calcFirstSegmentation(lBoundiaries,whitened,bPadd=True)
(l,a)=mouvementClass.agglomerateSpeedSegments(lFirstSpeedSegmentation)
group_mouv = []
segment_num = []
offset = 0;
colors = []
m = 0;
for ii, plots in enumerate(l):
for jj, speed in enumerate(plots):
if jj >= offset :
group_mouv.append(a[ii])
segment_num.append(m)
new_offset = len(plots)
offset = new_offset
m += 1
colors.append(colorListSpeed[a[ii]])
group_mouv.append(a[ii])
segment_num.append(m)
groupedi_mouvement_all['group_mouv'] = group_mouv
groupedi_mouvement_all['segment_num'] = segment_num
plt.figure(figsize=(12,8))
plt.grid(True)
segment_count = max(groupedi_mouvement_all["segment_num"])
for m in range(segment_count):
segment = groupedi_mouvement_all[groupedi_mouvement_all['segment_num'] == m]
plt.plot(segment.time, segment.is_mouvement, color=colors[m])
plt.xlabel('Time of the day')
plt.ylabel('Number of mouvement recordings')
plt.show()
L'utilisateur iphone semble plus dormir la nuit !
Nous arrivons à un résultat très satisfaisant, l'idée serait ensuite de regarder suivant jours de la semaine/week-end voir si l'on observe une différence.
Nous nous proposons ici d'appliquer l'algorithme DBSCAN pour agglomérer les différents trajets au cours d'une journée.
La segmentation de la journée en trajets sera réalisé en utilisant l'approche présentée dans le notebook 3.
DBSCAN (density-based spatial clustering of applications with noise) est un algorithme de partitionnement de données basé sur la densité des clusters pour effectuer le partitionnement.
Deux paramètres principaux à prendre en compte par DBSCAN:
En effet, on a 3 types de points:
On se propose de tester DBSCAN sur les données de la journée "17-08-2017" sur laquelle on a travaillé précédemment.
day_df = parser.selectDate("17-08-2017", android_df)
Nous appliquons la fonction de segmentation de trajets vue au cours de la séance "3-segmentation" pour pouvoir ensuite effectuer un partitionnement sur les segments obtenus.
def delay_segment_dataframe(df, limit) :
segnum = 0
segments = []
for i in range(df["time"].size) :
if (df["delay"][i] > limit) :
segments.append(segnum)
segnum += 1;
else :
segments.append(segnum)
df["segment"] = segments
return df
day_df = delay_segment_dataframe(day_df, limit=100)
segment_count = max(day_df['segment'])
gmap = gmplot.GoogleMapPlotter(45.757589, 4.831689, 14, apikey="AIzaSyDsYwvF3UUxTx8RB40wd4SnUVzfnbW66LM")
for i in range(segment_count) :
start_index = day_df[day_df['segment'] == i].index.tolist()[0]
end_index = day_df[day_df['segment'] == i + 1].index.tolist()[0]
segment_df = day_df.loc[start_index:(end_index - 1),]
gmap.plot(segment_df["latitude"], segment_df["longitude"], lColors[i%20], edge_width=4)
gmap.draw("figure/5-dbscan.html")
IFrame('figure/5-dbscan.html', width=990, height=500)
Pour la préparation des données, nous prenons les segments comme les observations qui seront répartis suivant notre algorithme.
day_df_grp_seg=day_df.groupby(['segment']).mean()
Un segment sera donc caractérisé par la moyenne de :
Comme première exploration de l'algorithme DBSCAN, nous englobons toutes les variables considérées dans le dataframe vu précédamment pour obtenir un partitionnement selon la position géographique, la prise des valeurs dans le temps (retards), la distance séparant deux observations consécutives, la vitesse et l'accélération moyenne.
db = DBSCAN(eps=12, min_samples=3).fit(day_df_grp_seg)
clusters=db.fit_predict(day_df_grp_seg)
plt.figure(figsize=(12,8))
plt.plot(clusters,'-o')
plt.grid(True)
plt.ylabel('Cluster number')
plt.xlabel('Segment Num')
On a repéré 3 clusters: le cluster 0, 1 et 2.
Les segments ayant une valeur -1 sont considérés comme outliers par l'agorithme DBSCAN, et sont donc excluts des autres clusters.
Chaque segment sera donc attribué à un cluster ou considéré comme un bruit (outlier) comme suit:
day_df_grp_seg["clusters"]=clusters
Nous donnons un aperçu sur la moyenne de chaque cluster formé:
day_df_grp_clust=day_df_grp_seg.groupby(['clusters']).mean()
day_df_grp_clust
Il est à noter que, contrairement à l'algorithme Kmeans, DBSCAN repose dans sa segmentation sur la densité et ne fait pas intervenir la notion de centroides des clusters formés. D'ou la possibilité d'avoir un point moyen d'un cluster qui n'y appartient pas, mais appartenant à un autre cluster.
Pour une représentation graphique, il est judicieux de modifier le dataframe initial en y ajoutant, de plus de la colonne segment, la colonne clusters indiquant le cluster auquel appartient le segment incluant chaque observation.
day_df['clusters']=day_df_grp_seg.iloc[day_df.segment]['clusters'].tolist()
day_df.head()
Nous représentons sur la carte les différents segments de trajets chacun colorié selon le cluster auquel il appartient. Les segments détectés comme outliers seront également représentés par une même couleur, dans notre cas le noir.
gmap = gmplot.GoogleMapPlotter(45.757589, 4.831689, 14, apikey="AIzaSyDsYwvF3UUxTx8RB40wd4SnUVzfnbW66LM")
for i in range(segment_count) :
start_index = day_df[day_df['segment'] == i].index.tolist()[0]
end_index = day_df[day_df['segment'] == i + 1].index.tolist()[0]
segment_df = day_df.loc[start_index:(end_index - 1),]
gmap.plot(segment_df["latitude"], segment_df["longitude"], lColors[i%20], edge_width=4)
gmap.draw('figure/5-segment-clustered-dbscan.html')
IFrame('figure/5-segment-clustered-dbscan.html', width=990, height=500)
Nous remarquons à première vue que le partitionnement des segments est fortement influencé par la localisation géographique.
Cela peut être expliqué par l'utilisation habituelle par l'individu d'un même moyen de transport pour se déplacer dans une même zone géographique.
Nous pouvons, dans une prochaine étape, attribuer un poids plus importants aux variables "velocity" et "acceleration". Celles-ci devraient caractériser plus clairement les moyens de transport utilisés sur un trajet.
La classification des vitesses réalisée dans la séance précédente comportait certaines faiblesses :
Dans cette partie, nous essayerons de traiter ces deux problèmes.
day_df2 = parser.selectDate("25-11-2017", android_df)
day_df2 = filters.meanFilter(day_df2, 10)
stay_point_df2 = st.findStayPoints(day_df2,3,20,5)
day_df2['distance'] = distance.getDistances(day_df2)
day_df2['velocity'] = distance.getVelocities(day_df2)
day_df2['speedClass'] = speedClass.initSpeedClass(day_df2)
stay_point_df2['numSC'] = speedClass.initSpeedClass(stay_point_df2)
La classification des vitesses présente des variations hautes-fréquences peu vraisemblables, comme nous pouvons le voir sur la figure suivante.
segment_count = max(stay_point_df2["segment_mouvement"])
for iSeg in range(segment_count):
segment = stay_point_df2[stay_point_df2['segment_mouvement'] == iSeg]
segment_mouvement = segment[segment['is_mouvement'] == True ]
if len(segment_mouvement['velocity'])>5:
(lK,whitened)=speedClass.applyKMeans(segment_mouvement,
k=5)
lBoundiaries=speedClass.getBoundiaries(lK)
lFirstSpeedSegmentation=speedClass.calcFirstSegmentation(lBoundiaries,whitened,bPadd=False)
(speedAgglomerates,a)=speedClass.agglomerateSpeedSegments(lFirstSpeedSegmentation,
lowThreshold=0.4,
highThreshold=1.4,bMedian=False)
offset=0
for ii, plots in enumerate(speedAgglomerates):
for jj, speed in enumerate(plots):
stay_point_df2['speedClass'][segment_mouvement.index.tolist()[jj+offset]]=a[ii]
stay_point_df2['numSC'][segment_mouvement.index.tolist()[jj+offset]]=ii
offset+=jj
plt.figure(figsize=(12,8))
plt.subplot(211)
plt.plot( stay_point_df2['speedClass'],linewidth=2)
plt.grid(True)
plt.ylim(0,3)
plt.ylabel('Regime vitesse')
plt.xlabel('Numero d\'échantillons')
plt.subplot(212)
plt.ylim(0,150)
plt.grid(True)
plt.xlabel('Numero d\'échantillons')
plt.ylabel('Vitesse (km/h)')
segment_count = max(stay_point_df2["segment_mouvement"])
for l in range(segment_count):
segment = stay_point_df2[stay_point_df2['segment_mouvement'] == l]
segment_mouvement = segment[segment['is_mouvement'] == True ]
plt.plot(segment_mouvement['velocity'], color=lColors[l%20])
plt.show()
Les hautes fréquences sont notamment visibles lors de la classification du second trajet, entre 100 et 150.
Ces hautes fréquences sont causées par une sous-segmentation trop importante. En effet, jusqu'à présent, nous avons considéré qu'un trajet pouvait être sous-segmenté en 5 régimes vitesses; quelle que soit la durée du trajet.
Pour résoudre ce problème, nous avons indexé le nombre de régimes vitesses sur la longueur du trajet. Nous obtenons dans cette configuration la figure suivante.
segment_count = max(stay_point_df2["segment_mouvement"])
for iSeg in range(segment_count):
segment = stay_point_df2[stay_point_df2['segment_mouvement'] == iSeg]
segment_mouvement = segment[segment['is_mouvement'] == True ]
if len(segment_mouvement['velocity'])>5:
# print(int(len(segment_mouvement['velocity'])/20)+1)
(lK,whitened)=speedClass.applyKMeans(segment_mouvement,
k=int(len(segment_mouvement['velocity'])/30)+1)
lBoundiaries=speedClass.getBoundiaries(lK)
lFirstSpeedSegmentation=speedClass.calcFirstSegmentation(lBoundiaries,whitened,bPadd=False)
(speedAgglomerates,a)=speedClass.agglomerateSpeedSegments(lFirstSpeedSegmentation,
lowThreshold=0.4,
highThreshold=1.4,bMedian=False)
offset=0
for ii, plots in enumerate(speedAgglomerates):
for jj, speed in enumerate(plots):
stay_point_df2['speedClass'][segment_mouvement.index.tolist()[jj+offset]]=a[ii]
stay_point_df2['numSC'][segment_mouvement.index.tolist()[jj+offset]]=ii
offset+=jj
plt.figure(figsize=(12,8))
plt.subplot(211)
plt.plot( stay_point_df2['speedClass'],linewidth=2)
plt.grid(True)
plt.ylim(0,3)
plt.ylabel('Regime vitesse')
plt.xlabel('Numero d\'échantillons')
plt.subplot(212)
plt.ylim(0,150)
plt.grid(True)
plt.xlabel('Numero d\'échantillons')
plt.ylabel('Vitesse (km/h)')
segment_count = max(stay_point_df2["segment_mouvement"])
for l in range(segment_count):
segment = stay_point_df2[stay_point_df2['segment_mouvement'] == l]
segment_mouvement = segment[segment['is_mouvement'] == True ]
plt.plot(segment_mouvement['velocity'], color=lColors[l%20])
plt.show()
Nous constatons la disparition des hautes fréquences dans la classification des hautes vitesses.
Toutefois, la classification des vitesses est encore imparfaite. On constate en effet des erreurs de classification. Dans le 6ème segment, entre 400 et 480, on s'attend à ce que le premier régime vitesse soit classifié comment vitesse moyenne, plutot que comme vitesse lente.
De même, on aurait préféré que le 3ème segment et le 4ème segment soit classifié comme vitesse lente.
Ces erreurs peuvent être dû à plusieurs élements :
Lorsque nous visualisons le résultat de la classification sur la carte, nous constatons la présence d'effets de bords : au sein d'un même trajet, les différents régimes vitesses ne sont pas raccordés.
gmap = gmplot.GoogleMapPlotter(45.790607, 4.835850, 12, apikey="AIzaSyDsYwvF3UUxTx8RB40wd4SnUVzfnbW66LM")
segment_count = max(stay_point_df2["segment_mouvement"])
for l in range(segment_count):
segment = stay_point_df2[stay_point_df2['segment_mouvement'] == l]
segment_mouvement = segment[segment['is_mouvement'] == True ]
speedSegment=segment_mouvement[segment_mouvement.speedClass==0]
gmap.plot(segment_mouvement["latitude"], segment_mouvement["longitude"], 'navy', edge_width=6)
for ispeed in range(3):
speedSegment=segment_mouvement[segment_mouvement.speedClass==ispeed]
for ii in range (5):
minidf=speedSegment[speedSegment.numSC==ii]
gmap.plot(minidf["latitude"], minidf["longitude"], colorListSpeed[ispeed], edge_width=4)
gmap.draw("figure/5-segmented-day-not-bound.html")
IFrame('figure/5-segmented-day-not-bound.html', width=990, height=500)
Remarquons tout d'abord qu'ici nous travaillons sur la représentation des données sur la carte. On ne modifie donc pas les données calculées.
La solution que nous proposons est de raccorder tous les segments en utilisant une vitesse moyenne. En effet, ce raccordement apparait toujours acceptable.
Plus précisément :
Nous obtenons alors la carte ci-dessous.
gmap = gmplot.GoogleMapPlotter(45.790607, 4.835850, 12, apikey="AIzaSyDsYwvF3UUxTx8RB40wd4SnUVzfnbW66LM")
segment_count = max(stay_point_df2["segment_mouvement"])
for l in range(segment_count):
segment = stay_point_df2[stay_point_df2['segment_mouvement'] == l]
segment_mouvement = segment[segment['is_mouvement'] == True ]
speedSegment=segment_mouvement[segment_mouvement.speedClass==0]
gmap.plot(segment_mouvement["latitude"], segment_mouvement["longitude"], 'orange', edge_width=4)
for ispeed in range(3):
speedSegment=segment_mouvement[segment_mouvement.speedClass==ispeed]
for ii in range (5):
minidf=speedSegment[speedSegment.numSC==ii]
gmap.plot(minidf["latitude"], minidf["longitude"], colorListSpeed[ispeed], edge_width=4)
gmap.draw("figure/segmented-day-bound.html")
IFrame('figure/segmented-day-bound.html', width=990, height=500)
Pour comparer l'efficacité de différents filtres, nous avons généré la vérité terrain d'un trajet de bus entre la gare de Vaise et Centrale Lyon.
Partant d'un trajet mesuré avec un téléphone, nous avons projeté chaque point sur la trajectoire de bus réelle; obtenue en croisant les itinéraires TCL avec une carte GPS. Chaque point mesuré avec le GPS a donc son équivalent "réel".
Il est donc possible de calculer la distance entre la trajectoire mesurée et la trajectoire réelle.
df_brut = parser.selectDate("13-10-2017", android_df)[2534:2580].reset_index(drop=True)
lat1=[45.780032, 45.780540, 45.780681, 45.782027, 45.783036, 45.784756, 45.785952, 45.786176, 45.787327, 45.788284, 45.788971, 45.789045, 45.789545, 45.789784, 45.789858, 45.789858, 45.789887, 45.789887, 45.790589, 45.790831, 45.790774, 45.790638, 45.790323, 45.789866, 45.789522, 45.789042, 45.787687, 45.786796, 45.786653, 45.786443, 45.787078, 45.786770, 45.787570, 45.787629, 45.788376, 45.788674, 45.788374,45.788374,45.788374,45.788374, 45.788164, 45.787282, 45.786540, 45.785641, 45.784701]#, 45.783593, 45.782866]
lng1=[4.803670, 4.804217, 4.804367, 4.805569, 4.806556, 4.804239, 4.802115, 4.801235, 4.801707, 4.801535, 4.800119, 4.799915, 4.798821, 4.798177, 4.797683, 4.797683, 4.792705, 4.791321,4.791321, 4.790811, 4.790398, 4.790248, 4.790028, 4.789621, 4.789272, 4.788768, 4.787513, 4.785560, 4.784112, 4.782910, 4.777288, 4.772578, 4.769735, 4.768785, 4.765674, 4.764708, 4.764762, 4.764762, 4.764762, 4.764762, 4.764816, 4.764847, 4.764826, 4.765159, 4.765465]#, 4.765851, 4.766130]
lat1.insert(30, 45.787075)
lng1.insert(30, 4.780214)
latR = lat1[::-1]
lngR = lng1[::-1]
df_reel=pd.DataFrame(data={'latitude':latR, 'longitude':lngR})
def compare(df1, df2):
error=0
for i in range(len(df1)):
error+=distance.haversineDistance(df1.longitude[i], df1.latitude[i], df2.longitude[i], df2.latitude[i])/len(df1)
return(error)
error=compare(df_brut, df_reel)
print("Ecart moyen du trajet brut au trajet réel : "+str(error)[0:5] + " mètres.")
gmap = gmplot.GoogleMapPlotter(45.764376, 4.810495, 13, apikey="AIzaSyDsYwvF3UUxTx8RB40wd4SnUVzfnbW66LM")
gmap.plot(df_brut['latitude'],df_brut['longitude'], 'cornflowerblue', edge_width=4)
gmap.plot(df_reel['latitude'],df_reel['longitude'], 'red', edge_width=4)
gmap.draw("figure/5-ground-truth.html")
IFrame('figure/5-ground-truth.html', width=990, height=500)
L'objectif est ici d'utiliser la trajectoire réelle pour déterminer les meilleurs paramètres pour le filtrage de la trajectoire.
Le filtre qui présentera la trajectoire la plus proche de la trajectoire réelle sera naturellement le meilleur filtre.
fenetre=[]
median=[]
mean=[]
for i in range(10):
median.append(compare(filters.medianFilter(df_brut, i, True), df_reel))
mean.append(compare(filters.meanFilter(df_brut, i, True), df_reel))
fenetre.append(2*i+1)
reel=[compare(df_brut, df_reel)]*10
plt.figure(figsize=(12,8))
plt.plot(fenetre, median, 'r', label='median filters')
plt.plot(fenetre, mean, 'b', label='mean filters')
plt.plot(fenetre, reel, '--g', label='données brutes')
plt.legend(loc='upper right')
plt.ylabel('Ecart moyen à la trajectoire réelle')
plt.xlabel('Taille de la fenêtre')
plt.xlim([1,19])
plt.grid(True)
plt.show()
En comparant les écarts à la trajectoire réelle on constate que le meilleur score est obtenu pour un median filter de fenêtre de taille 7 (donc de paramètre 3). Au delà de 9 on commence à dégrader la qualité de la trajectoire qui devient moins précise que les données brutes.
On constate également que pour de petites fenêtres le mean filter est légèrement meilleur, mais sa performance décroit plus vite que celle du median filter.
Cette séance de travail nous a apporté un certain nombre de résultats intéressants.
Nous avons montré qu'il est possible d'analyser rapidement les habitudes de déplacement d'une personne. La modélisation actuelle est un début intéressant; mais nous souhaiterions améliorer encore la visualisation des données.
Le travail sur l'agglomération des segments utilisant le DBSCAN débute, mais il présente une alternative intéresssante.
La classification des vitesses atteint des performances satisfaisantes.
La construction d'une vérité terrain nous a permi de conclure quant aux meilleurs filt
Nous nous fixons pour objectifs de :