diff --git "a/clase-6/Clase 6 pr\303\241ctica.ipynb" "b/clase-6/Clase 6 pr\303\241ctica.ipynb" new file mode 100644 index 0000000..53e2ded --- /dev/null +++ "b/clase-6/Clase 6 pr\303\241ctica.ipynb" @@ -0,0 +1,122 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# API de Transporte Público Ciudad de Buenos Aires\n", + "## Práctica" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Objetivos\n", + "\n", + "El objetivo de este ejercicio es poner en práctica los recursos con los que se trabajó en la clase de la API de trasporte público. El mismo consiste en descargar información de distintos recursos de la API (Monopatines, Bicicletas, Colectivos), limpiar los datos, extraer algunas estadísticas y visualizar la información. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Ejercicio 1: Monopatines\n", + "Los monopatines son vehiculos de propiedad de tres empresas que operan en la Ciudad de Buenos Aires. Se encuentran ubicados en distintos puntos de la Ciudad y respetan una zona de uso asignada a cada una de las empresas. \n", + "La API de transporte recopila información de monopatines en tiempo real: su ubicación y su disponibilidad." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Actividad 1: \n", + "Construir la URL de consulta del servicio de monopatines (https://www.buenosaires.gob.ar/desarrollourbano/transporte/apitransporte/api-doc), consultar y almacenar información en un lapso de 1 minuto." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Actividad 2:\n", + "Limpiar el dataset de forma adecuada para: \n", + "\n", + "**A-** Responder a la siguiente pregunta ¿Cuál es la proporción de monopatines disponibles para su uso en cada una de las empresas?\n", + "\n", + "**B**- Visualizar en un mapa la ubicación de los monopatines para los cuales obtuvimos información, diferenciando a los puntos con colores de acuerdo a la empresa propietaria del vehículo. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Ejercicio 2: ECOBICI\n", + "Ecobici es el servicio de bicicletas públicas de la Ciudad de Buenos Aires. Se encuentran ubicadas en estaciones distribuidas en gran parte del territorio de la Ciudad, su uso es gratuito y permite un máximo de uso de 30 minutos. \n", + "Cada estación cuenta con un promedio de 10 estacionamientos para bicicletas, algunos ocupados con bicicletas disponibles para su uso y otros libres, que permiten anclar bicicletas a los usuarios que finalizaron su recorrido. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Actividad 1: \n", + "\n", + "Construir la URL de consulta del servicio de monopatines (https://www.buenosaires.gob.ar/desarrollourbano/transporte/apitransporte/api-doc), consultar y almacenar información en un lapso de 1 minuto." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Actividad 2:\n", + "Limpiar el dataset de forma adecuada para obtener: \n", + "\n", + "**A-** El promedio de bicicletas disponibles en el momento de la consulta.\n", + "\n", + "**B-** La estación de bicicletas con mas vehículos disponibles en el momento de la consulta. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/clase-6/Clase-6 .html b/clase-6/Clase-6 .html new file mode 100644 index 0000000..2daa1e9 --- /dev/null +++ b/clase-6/Clase-6 .html @@ -0,0 +1,15873 @@ + + +
+ +El objetivo general de esta clase es el de integrar alguno de los conocimientos adquiridos en el transcurso del curso: la obtención de datos desde diversas fuentes, la limpieza y preprocesamiento del dataset(data wrangling) y el posterior análisis y visualización de los datos.
+Particularmente vamos a estar trabajando con datos de la API de transporte público del Gobierno de la Ciudad de Buenos Aires. A través de esta herramienta lograremos monitorear el estado del transporte público (especificamente colectivos, específicamente la Linea 12) en tiempo real, identificar y visualizar los colectivos que se encuentran circulando dentro del territorio de la Ciudad de Buenos Aires.
+A través de la API de transporte público de Buenos Aires se pueden desarrollar innumerables aplicaciones y entrenar modelos. Por ejemplo: podemos predecir la llegada de internos a una parada en particular, podemos pensar cómo optimizar el sistema de transporte de modo de disminuir la frecuencia del servicio, podemos estimar el estado de la congestión del tránsito en determinados puntos de la Ciudad, conocer paradas de colectivos "no oficiales", entre otras muchas cosas.
+ +Una API es un conjunto de funciones predefinidas que se utilizan para el desarrollo de aplicaciones, ofrecidas por una biblioteca para ser utilizadas por otro software. Uno de sus principales propósitos consiste en proporcionar funciones de uso general de forma que los desarrolladores hagan uso de las mismas para evitar escribir código desde cero.
+Tiene por objetivo proveer los datos abiertos del transporte público de la Ciudad en formato estandarizado y en tiempo real.
+Algunos de los conjuntos de datos centrales multimodales incluidos y disponibles para los desarrolladores son:
+++
+- Planificación del viaje (actual y futuro)
+- Estado (actual y futuro)
+- Interrupciones (actuales) y trabajos planificados (futuro)
+- Predicciones de llegada / salida (instantánea y websockets)
+- Horarios
+- Puntos de embarque e instalaciones
+- Rutas y líneas (topología y geográfica)
+
Es muy sencillo. En primer lugar, cabe aclarar que la API es un servicio NO arancelado. No hay que pagar nada para utilizarla. Podríamos decir que se trata de un conjunto de datos abiertos, pero no es del todo así, ya que su utilización requiere de crear un usuario, hacer un registro y obtener una autorización para su uso (el argumento por detrás de esto es el de garantizar el funcionamiento del servicio ante picos de demanda).
+Para obtener nuestro USER y PASS para acceder al servicio hace falta ingresar en https://www.buenosaires.gob.ar/form/formulario-de-registro-api-transporte y completar los campos con nuestros datos, para luego recibir vía correo nuestras credenciales (client_id y client_secret).
+ +import pandas as pd
+import numpy as np
+
+# This module provides regular expression matching operations
+import re
+# To make HTTP requests
+import requests
+
+# To transform json objects into DataFrame
+from pandas.io.json import json_normalize
+
+# To transform STR objects into json
+import json
+
+# To parse str objects into date and time objects
+import datetime
+
+# import urllib.request ----> Otra libreria para consultar http nativa de python
+
+# To get current time
+import time
+
+# To pause the loops
+from time import sleep
+
+# Make graphs
+# !pip install plotly
+import plotly.express as px
++ +1- Ingreso a https://www.buenosaires.gob.ar/desarrollourbano/transporte/apitransporte/api-doc
+2- Selecciono la opción /colectivos/vehiclePositions: Devuelve la posición de los vehículos monitoreados actualizada cada 30 segundos
+3- Ingreso las credenciales "client_id" y "client_secret" y el parámetro "agency_id" (para seleccionar la línea de colectivos que me interesa)
+4- Selecciono "GET" y copio la URL que se construye.
+
Creo un objeto llamado url de tipo STR con la url que copié en la documentación de la API.
+Notar que se construye concatenando la consulta que nos interesa "vehiclePositionsSimple" con el parámetro "agency_id" y las credenciales "client_id" y "client_secret"
+ +url='https://apitransporte.buenosaires.gob.ar/colectivos/vehiclePositionsSimple?agency_id=6&client_id=a0119e3e5ebf4fb4a0cbdea04de12037&client_secret=19967Bb82e7e4C7bab2CA49e3d631C3E'
+Seteo el parametro que me interesa y las credenciales de la API en objetos del tipo STR para luego completar las URL que se encuentra en otro objeto del tipo STR
+ +# Option 2: Create a function
+def url_bus(id_agency, user, psw):
+
+ url= 'https://apitransporte.buenosaires.gob.ar/colectivos/vehiclePositionsSimple?agency_id='+str(id_agency)+'&client_id='+str(user)+'&client_secret='+str(psw)
+
+ return url
+# Option 3: Set parameters & credentials in objects
+
+agency_id= '6'
+
+client_id= 'a0119e3e5ebf4fb4a0cbdea04de12037'
+
+client_secret= '19967Bb82e7e4C7bab2CA49e3d631C3E'
+
+url_incompleta= 'https://apitransporte.buenosaires.gob.ar/colectivos/vehiclePositionsSimple?agency_id={}&client_id={}&client_secret={}'
+
+# Con '.format' agrego otros strings al string principal 'url'
+# agregando como parametros lo que quiero que aparezca entre los corchetes
+
+url_buses= url.format(agency_id,
+ client_id,
+ client_secret)
+# Create an empty Data Frame
+agency_6=pd.DataFrame()
+
+# this pattern captures all text in {}
+pattern='({.*?})'
+
+# 60 sec * 10 min
+timeout = time.time() + 60*10
+
+while True:
+
+ # API requests
+ response= requests.get(url)
+
+ # Get text from API response
+ text_api= response.text
+
+ # Capture text in {} from the API response
+ data_buses=re.findall(pattern, text_api.replace('\n',''))
+
+ # For loop to append data from all bus units to empty Data Frame
+ for i in range(len(data_buses)):
+
+ # Convert to JSON (or dict) each row of the API response text
+ json_buses=json.loads(data_buses[i])
+
+ # Convert to DataFrame and append to linea_12 DF
+ agency_6=agency_6.append(json_normalize(json_buses), ignore_index=True)
+
+ print(agency_6)
+
+ if time.time() > timeout:
+
+ print('Fin del tiempo de ejecución')
+
+ break
+
+ ## Wait 30 seconds to get new data from the API
+ sleep(30)
+
+# Si se tiene guardado el CSV, no hace falta ejecutar la descarga sino directamente cargar el archivo con esta línea
+agency_6=pd.read_csv('agency_6.csv')
+agency_6.info()
+agency_6['route_id']
++ ++
+- +
'agency_id': Número de referencia de la empresa que gestiona las líneas de colectivos
+- +
'agency_name': Nombre de la empresa que gestiona la línea
+- +
'direction' : Dirección a la que se dirige (Dummy)
+- +
'id': Id del interno de la línea
+- +
'latitude': Latitud de la ubicación del colectivo
+- +
'longitude': Longitud de la ubicación del colectivo en coordenadas
+- +
'route_id': Identificación de la línea perteneciente a la empresa
+- +
'route_short_name': Nombre de la línea perteneciente a la empresa
+- +
'speed': Velocidad
+- +
'timestamp': Hora de la consulta (en S)
+- +
'trip_headsign': Destino anunciado del viaje
+
# Parseo la columna timestamp
+agency_6['timestamp']=pd.Series([pd.Timestamp(t, unit='s') for t in agency_6['timestamp']])
+# Filtro los datos de la linea 12
+linea_12=agency_6[agency_6['route_id']=='63']
+linea_12=linea_12.reset_index(drop=True)
+# cuento la cantidad de registros de cada uno de los internos de los cuales obtuve información mediante la API.
+# Algunos internos van a mostrar pocos registros. Son aquellos que inician su recorrido poco antes de que nuestro código termine de hacer consultas.
+linea_12['id'].value_counts()
+print('La cantidad de internos circulano en un período de 30 min es ', str(len(linea_12['id'].unique())))
+internos_registro=pd.DataFrame(linea_12['id'].value_counts()).reset_index()
+internos_registro.columns=['interno','cantidad_registros']
+internos_registro
+# Alternativa
+# linea_12.groupby('id').count().loc[:,'agency_id']
+Calculo el promedio de la columna "Direction" que contiene valores 1 y 0, agrupando por el ID del interno. El resultado asociado a cada uno de los internos será la proporcion de marcas GPS, registros o respuestas de la API en dirección "1".
+Si un interno tiene asociado un promedio "0", todas las respuestas de la API de ese interno tienen dirección "0" +Si un interno tiene asociado un promedio "1", todas las respuestas de la API de ese interno tienen dirección "1" +Si un interno tiene asociado un promedio entre 0 y 1, los registros de la posicion de ese interno corresponden a ambas direcciónes, "0" y "1".
+ +pd.DataFrame(linea_12.groupby('id').mean()['direction'].sort_values())
+print('La velocidad promedio de los internos cuando no estan detenidos es ',str(round(linea_12['speed'][linea_12['speed']!=0].mean(), 2)))
+print('La velocidad máxima alcanzada por un interno es,',str(round(linea_12['speed'].max(),2)))
+## bonus encontrar clusters en los que se encuentren mas puntos para identificar paradas/semaforos.
+linea_12
+fig = px.line_mapbox(linea_12, lat="latitude", lon="longitude", color="id", zoom=3, height=300)
+
+fig.update_layout(mapbox_style="carto-positron", mapbox_zoom=11, mapbox_center_lat = -34.6,
+ margin={"r":1,"t":0,"l":0,"b":0})
+
+fig.show()
+fig = px.scatter_mapbox(linea_12, lat="latitude", lon="longitude", color="speed", zoom=3, height=300)
+
+fig.update_layout(mapbox_style="carto-positron", mapbox_zoom=11, mapbox_center_lat = -34.6,
+ margin={"r":1,"t":0,"l":0,"b":0})
+
+fig.show()
+linea_12_0=linea_12[linea_12['speed']==0]
+fig = px.scatter_mapbox(linea_12_0, lat="latitude", lon="longitude", color="speed", zoom=3, height=300)
+
+fig.update_layout(mapbox_style="carto-positron", mapbox_zoom=11, mapbox_center_lat = -34.6,
+ margin={"r":1,"t":0,"l":0,"b":0})
+
+fig.show()
+