Utilisation des Data Airbnb et des Open Data de Paris

Last modified on October 2, 2026 • 4 min read • 753 words

Un chercheur Australien, Murray Cox, met en partage des données d’usage de AIRBNB sur le site insideairbnb.com.  On y apprend qu’il y a plus de 60.000 logements proposés dans Paris (à comparer avec les 80.000 chambres d’hôtels) et que parmi les nombreux casse-têtes de la ville, il y a celui de l’usage abusif des logements sociaux dont certains sont proposés sur airbnb.
Je me suis livré à une expérience sur ces données, combinées avec celles de la ville de Paris (en open data) qui recense les immeubles de son parc de logements sociaux.
L’objectif est de rapprocher deux sources de données afin d’identifier l’usage anormal d’un logement social.

Méthode  

1. Télécharger le set de données le plus récent pour la ville de Paris sur le site insideairbnb.com/paris  (60.000 logements environ en juillet 2019)

2. Télécharger le set de données contenant la liste des logements sociaux de la ville de paris depuis le site open data (3100 immeubles, environ)

3. Charger les deux fichiers CSV dans une base relationnelle (Oracle dans mon cas avec le produit Oracle APEX)

4. Géolocaliser plus pécisément les adresse des logements sociaux à partir des APIs Google Maps. Les coordonnées fournies dans le fichier open Data présentent trop d’écart avec la localisation réelle sur Google Maps, déduite de l’adresse.

5. Effectuer un appariement (simple produit cartésien. cf requête en annexe) afin de détecter les localisations très proches (distance géodésique inférieure à 5m)

Extraire les couples répondant au critère ci-dessus et ne retenir que ceux présentant la caractéristique d’être proposés en location complète (ce qui est illégal pour une sous-location d’un appartement HLM, par exemple)

On arrive à un total de 334 logements, dont 39 sont très pratiquement confondues (moins de 2 m).
Il ne faut surtout pas conclure que ces propositions de logement sont illégales ! Il s’agit simplement d’une base de travail à partir de laquelle il reste à effectuer d’autres vérifications pour écarter toute suspicion.
Pour info: un id de logement airbnb, qui est unique, peut être examiné en utilisant l’url de la forme: https://www.airbnb.fr/rooms/XXXXX

Interface d’analyse des données  

Les snaps d’écran suivants illustrent l’interface graphique que l’on peut produire rapidement avec Oracle APEX, et que l’on peut mettre à disposition d’analystes fonctionnels.

  • image

  • image

  • image

  • image

  • image

    Heat Map montrant les prix moyens par quartier de Paris

  • image

    Recherche par facettes sur les logements sociaux de Paris

  • image

  • image

  • image

  • image

  • image

Annexes  

Requetes SQL utilisées  

 insert into air_map (id_ag,id_ta,la_ag,lg_ag,la_ta,lg_ta,geo_dist)  select      A.id,      T.id,       to_char(A.LATITUDE),      to_char(A.LONGITUDE),      to_char(T.LATITUDE),      to_char(T.LONGITUDE),     trunc(          sdo_geom.sdo_distance(               sdo_geometry(2001, 4326, sdo_point_type( a.longitude,a.latitude, null), null, null),               sdo_geometry(2001, 4326, sdo_point_type(t.longitude,t.latitude, null), null, null)          )      ) from AIR_PARIS A, AIR_PARIS_HLM T  where trunc(A.latitude,3) = trunc(T.latitude,3) and trunc(A.longitude,3) = trunc(T.longitude,3) 

Géocodage  

create or replace FUNCTION  "AIR_GPS"   return VARCHAR2  is   -- P MONACO - GPM FACTORY  -- Aug 2019   l_clob    CLOB;    t_temp varchar2(2000);    tnb INTEGER;    tlat VARCHAR2(30);    tlong VARCHAR2(30);    taddr VARCHAR2(2000);   tcode VARCHAR2(2000);   l_values apex_json.t_values;    l_count       pls_integer;    tkey  varchar2(100);   CURSOR poi_cur        IS            SELECT * from AIR_PARIS_HLM             where            glong is null; l_poi   poi_cur%ROWTYPE;         BEGIN  -- Retrieve API Key  select key into tkey  from API_KEY  where name = 'Google Maps API';  OPEN poi_cur;       LOOP          FETCH poi_cur INTO l_poi;          EXIT WHEN poi_cur%NOTFOUND;  -- We go away     apex_web_service.g_request_headers(1).name  := 'Content-Type';  apex_web_service.g_request_headers(1).value := 'application/json';    l_clob := APEX_WEB_SERVICE.make_rest_request(      p_url         => 'https://maps.googleapis.com/maps/api/geocode/json',      p_parm_name => apex_util.string_to_table(          'address:key'),      p_parm_value => apex_util.string_to_table(          l_poi.adresse||', Paris France:'||tkey        ),      p_http_method => 'GET'       );  apex_json.parse(p_values => l_values,                  p_source => l_clob );  l_count := apex_json.get_count(            p_path   => '.',            p_values => l_values     );  l_count :=1; for idx in 1 .. l_count  loop      tlat := apex_json.get_varchar2(p_path=>'results[%d].geometry.location.lat',p0=> 1,p_values=>l_values);      tlong := apex_json.get_varchar2(p_path=>'results[%d].geometry.location.lng',p0=> 1,p_values=>l_values);       end loop; if tlat is null then tlat := 0;end if; update air_paris_hlm set glong=tlong, glat = tlat  where id = l_poi.id;  COMMIT; END LOOP;  -- End cursor  COMMIT;  CLOSE poi_cur;  htp.p('Terminé');  return('0');EXCEPTIONwhen others thenhtp.p('Undefined problem'); END;

Tables  

CREATE TABLE  "AIR_PARIS" 
    (    "ID" NUMBER, 
     "NAME" VARCHAR2(255), 
     "HOST_ID" NUMBER, 
     "HOST_NAME" VARCHAR2(255), 
     "NEIGHBOURHOOD_GROUP" VARCHAR2(1), 
     "NEIGHBOURHOOD" VARCHAR2(30), 
     "LATITUDE" NUMBER, 
     "LONGITUDE" NUMBER, 
     "ROOM_TYPE" VARCHAR2(30), 
     "PRICE" NUMBER, 
     "MINIMUM_NIGHTS" NUMBER, 
     "NUMBER_OF_REVIEWS" NUMBER, 
     "LAST_REVIEW" DATE, 
     "REVIEWS_PER_MONTH" NUMBER, 
     "CALCULATED_HOST_LISTINGS_COUNT" NUMBER, 
     "AVAILABILITY_365" NUMBER, 
      CONSTRAINT "AIR_PARIS_PK" PRIMARY KEY ("ID")
   USING INDEX  ENABLE
    )

CREATE TABLE  "AIR_PARIS_HLM" 
    (    "ID" NUMBER, 
     "ADRESSE" VARCHAR2(255), 
     "CODE_POSTAL" NUMBER, 
     "VILLE" VARCHAR2(30), 
     "ANNÉE_DU_FINANCEMENT___AGRÉMENT" NUMBER, 
     "BAILLEUR_SOCIAL" VARCHAR2(30), 
     "NOMBRE_LOGEMENTS" NUMBER, 
     "PLA_I" NUMBER, 
     "PLUS" NUMBER, 
     "PLUS_CD" NUMBER, 
     "PLS" NUMBER, 
     "MODE_DE_RÉALISATION" VARCHAR2(100), 
     "COMMENTAIRES" VARCHAR2(1000), 
     "ARRONDISSEMENT" NUMBER, 
     "NATURE_DE_PROGRAMME" VARCHAR2(255), 
     "COORD_X_L93" NUMBER, 
     "COORD_Y_L93" NUMBER, 
     "GEO_SHAPE" VARCHAR2(300), 
     "GEO_POINT_2D" VARCHAR2(300), 
     "LATITUDE" NUMBER, 
     "LONGITUDE" NUMBER, 
     "GLAT" NUMBER, 
     "GLONG" NUMBER, 
      CONSTRAINT "AIR_PARIS_HLM_PK" PRIMARY KEY ("ID")
   USING INDEX  ENABLE
    )

CREATE TABLE  "AIR_MAP" 
    (    "ID" NUMBER(10,0), 
     "ID_AG" NUMBER, 
     "ID_TA" NUMBER, 
     "LA_AG" VARCHAR2(30), 
     "LG_AG" VARCHAR2(30), 
     "LA_TA" VARCHAR2(30), 
     "LG_TA" VARCHAR2(30), 
     "GEO_DIST" NUMBER(10,0), 
     "ROAD_DIST" NUMBER(10,0), 
     "ROAD_TIME" NUMBER(10,0), 
     "ROAD_TIME_TEXT" VARCHAR2(100), 
     "PREFERED" NUMBER(1,0)
    )
Follow me

I work on everything coding and tweet developer memes