La zona del Aeropuerto JFK y la zona central de Manhattan (por ejemplo, el Empire State) parecen dos zonas muy interesantes de NYC por lo que parece una buena idea estudiarlas por separado.
Para aislar los puntos correspondientes a estas zonas de los demás puntos, debemos crear, para cada zona, un polígono que abarque dicha área y luego pueda ser comparado con nuestro dataset y poder quedarnos sólo con aquellos puntos dentro de estos polígonos.
Para ello, primero de todo hemos obtenidos los 2 polígonos necesarios a través de una herramienta de Tableau muy útil y que viene muy bien explicada en este blog https://tableauandbehold.com/2015/05/13/creating-custom-polygons-by-drawing-directly-on-a-google-map/.
Así, a través de "tableau-map-pack.html" hemos obtenido los 2 polígonos necesarios y se han guardado en los archivos Aeropuerto_JFK.csv y Empire_state.csv. Hecho esto, se realizó la comparación de estos polígonos con nuestro conjunto de datos
#Importación de las librerías necesarias
import pandas as pd
import matplotlib.path as mpltPath
#Llamada a nuestro dataset
filename = "data_limpios.csv"
data = pd.read_csv(filename, sep=";", decimal=',', encoding = "utf-8")
data.head()
#Creamos dos columnas en nuestro dataframe.
#Sus filas serán rellenadas con "Aeropuerto_JFK" o "Empire_state" si son puntos pertenecientes a los polígonos
data['pickup_zona_interes'] = pd.Series("Desconocido", index=data.index)
data['dropoff_zona_interes'] = pd.Series("Desconocido", index=data.index)
#Lista que contiene los nombres de los archivos csv con los polígonos
zonas = ["Empire_state", "Aeropuerto_JFK"]
#Funcion que devuelve el conjunto de coordenadas que forman los polígonos
def generarZona(zona):
datos_zona = pd.read_csv(zona + ".csv")
poligono_zona = [[datos_zona["Latitude"][index], datos_zona["Longitude"][index]] for index, latitud in enumerate(datos_zona["Latitude"])]
return mpltPath.Path(poligono_zona)
#Función para establecer si los puntos pertenecen al polígono. Si sí pertenecen, el valor de las filas creadas
#anteriormente, cambia
def actualizarZona(zona, path, accion):
for index, latitude in enumerate(data[accion + "_latitude"]):
if path.contains_point([data[accion + "_latitude"][index], data[accion + "_longitude"][index]]) == True:
data.set_value(index, accion + '_zona_interes', zona)
#Llamamos a las 2 funciones anteriores para cambiar los valores de la columna "pickup_zona_interes"
for zona in zonas:
path = generarZona(zona)
actualizarZona(zona, path,"pickup")
#Llamamos a las 2 funciones anteriores para cambiar los valores de la columna "dropoff_zona_interes"
for zona in zonas:
path = generarZona(zona)
actualizarZona(zona, path,"dropoff")
#Comprobación de cómo los valores de las columnas "pickup_zona_interes" y "dropoff_zona_interes" han cambiado
data.head(10)
Ahora debemos crear un nuevo CSV que recoja los datos de nuestras zonas de interés. Debido al tipo de visualización que queremos hacer en Tableau (un mapa que muestre rutas lineales), nuestro CSV debe tener unos determinados datos y expuestos de cierta manera para que la visualización sea efectiva.
Para saber cuales son los datos necesarios para esta visualización, nos hemos basado en este artículo de Tableau: https://onlinehelp.tableau.com/current/pro/desktop/en-us/maps_howto_origin_destination.htm
En nuestro caso, queremos poder visualizar 4 posibles casos, no sólo uno:
Así, según el artículo anterior, sabemos que por cada trayecto a tratar, se deben crear dos filas, una con las coordenadas del pickup/dropoff de la zona de interés, otra con el dropoff/pickup de ese trayecto y ambas con la ID de ruta del trayecto seguido. Como no solo queremos hacer una visualización, sino 4 posibles visualizaciones, debemos crear otras dos columnas más:
Por último, añadimos una columna extra que hable sobre la distancia entre los pickups y dropoffs para después en la visualización, poder dar una diferenciación de color a la ruta según es más larga o más corta.
Todo esto nos lleva a crear el siguiente diccionario y funciones.
#Diccionario con los nombres de las columnas del CSV
rutas_en_zonas_de_interes = {
'ID de ruta': [],
'Acción': [],
'Zona': [],
'Latitud': [],
'Longitud': [],
'Distancia': []
}
#Función primaria
def rellenarListasDelDiccionario():
for index, _ in enumerate (data["pickup_zona_interes"]):
#Pasamos a llamar las columnas creadas anteriormente de un modo más facil
zonas_interes = {
"pickup": data["pickup_zona_interes"][index],
"dropoff": data["dropoff_zona_interes"][index]
}
#Si se da el caso de que data["pickup_zona_interes"][index] o data["dropoff_zona_interes"][index]
#tienen el valor "Desconocido" se pasará de esos valores y se continua a la siguiente fila
if noTieneZonaDeInteres(zonas_interes):
continue
#Para los casos en los que los valores eran "Aeropuerto_JKF" o "Empire_state" se aplica la
#siguiente función, tanto para pickups como para dropoffs
crearNuevaFilaPara(index, "pickup", zonas_interes)
crearNuevaFilaPara(index, "dropoff", zonas_interes)
#Función secundaria
def noTieneZonaDeInteres(zonas_interes):
return zonas_interes["pickup"] == "Desconocido" and zonas_interes["dropoff"] == "Desconocido"
#Función secundaria
def crearNuevaFilaPara(index, accion, zonas_interes):
rutas_en_zonas_de_interes['ID de ruta'].append(index) #Añade Index como ID de ruta
rutas_en_zonas_de_interes['Zona'].append(obtenerZona(zonas_interes)) #Añade "Aeropuerto_JFK" o "Empire_state"
rutas_en_zonas_de_interes['Acción'].append(obtenerAccion(zonas_interes)) #Añade "dropoff" o "pickup"
rutas_en_zonas_de_interes['Latitud'].append(data[accion + "_latitude"][index]) #Añade la latitud del pickup o del dropoff según sea la acción
rutas_en_zonas_de_interes['Longitud'].append(data[accion + "_longitude"][index]) #Añade la longitud del pickup o del dropoff según sea la acción
rutas_en_zonas_de_interes['Distancia'].append(data["distancia"][index])
#Función terciaria
def obtenerZona(zonas_interes):
return zonas_interes["dropoff"] if zonas_interes["pickup"] == "Desconocido" else zonas_interes["pickup"]
#Función terciaria
def obtenerAccion(zonas_interes):
return "dropoff" if zonas_interes["pickup"] == "Desconocido" else "pickup"
#Llamada de la función primaria
rellenarListasDelDiccionario()
#Creamos el dataframe a partir del diccionario creado y rellenado con los datos que queremos
zonas_interes = pd.DataFrame(rutas_en_zonas_de_interes)
#Comprobación del principio del dataframe creado
zonas_interes.head(10)
#Comprobación del final del dataframe creado
zonas_interes.tail(10)
Una vez terminado el proceso, guardamos este nuevo dataframe en un nuevo csv.
zonas_interes.to_csv("zonas_interes.csv", sep=";", decimal=',', encoding='utf-8')