Matriz para el diagrama chord

Un diagrama chord es un tipo de visualización orientado a mostrar las interrelaciones entre varios valores. Dentro de este diagrama, se pueden ver cuerdas que muestran las relaciones entre cada pareja de valores posibles. Dichas cuerdas además, a través de su anchura, muestran la relación bidireccional entre cada pareja de valores.

En nuestro caso, esta anchura representa el número de trayectos que se han realizado dependiendo de la ruta seguida. NYC tiene 5 barrios, por lo que si definimos como ruta cada una de las posibles combinaciones existentes entre todos los barrios, nos encontramos con 25 posibles rutas, de las cuales, algunas serán más transitadas que otras.

Mediante una matriz cuadrada, expresaremos el número de trayectos entre cada uno de los barrios con los demás y consigo mismo.

Como comprobación para saber si nuestra matriz es correcta, la suma total del nº de trayectos en cada una de las posibles rutas debe ser el mismo que el número total de trayectos realizados por los taxis de color verde. O lo que es lo mismo, si el número total de trayectos realizados por los taxis de color verde supone un 100%, la suma total de trayectos en todas las rutas debe sumar el 100%.

Este Jupyter Notebook se basa en la obtención y comprobación de dicha matriz cuadrada.

In [1]:
#Importación de las librerías necesarias
import pandas as pd
import matplotlib.path as mpltPath
import numpy as np
In [2]:
#Llamada al dataset que contiene la diferenciación por barrios y por distritos
filename = "data_limpios_distritos.csv"
data = pd.read_csv(filename, sep=";", decimal=',', encoding = "utf-8")
data.head()
Out[2]:
Unnamed: 0 ID vendorID pickup_datetime dropoff_datetime numero_pasajeros distancia pickup_longitude pickup_latitude ratecodeID ... dropoff_hora duracion_segundos duración propina? pickup_barrio dropoff_barrio pickup_distrito dropoff_distrito ruta freq
0 0 11600 VeriFone Inc 2016-01-04 00:02:19 2016-01-04 00:23:11 1 16.37 -73.790016 40.646664 Aeropuerto JFK ... 00:23:11 1252.0 20.866667 Si Queens Manhattan Queens_14 Manhattan_10 Queens_14 - Manhattan_10 512
1 1 11700 VeriFone Inc 2016-01-04 00:02:22 2016-01-04 00:31:04 1 19.66 -73.782204 40.644642 Tarifa normal ... 00:31:04 1722.0 28.700000 Si Queens Brooklyn Queens_14 Brooklyn_21 Queens_14 - Brooklyn_21 120
2 2 11789 VeriFone Inc 2016-01-04 00:05:37 2016-01-04 00:26:02 3 4.07 -73.964691 40.803478 Tarifa normal ... 00:26:02 1225.0 20.416667 No Manhattan Manhattan Manhattan_17 Manhattan_12 Manhattan_17 - Manhattan_12 122
3 3 11867 VeriFone Inc 2016-01-04 00:05:37 2016-01-04 00:15:46 5 2.15 -74.003868 40.751381 Tarifa normal ... 00:15:46 609.0 10.150000 No Manhattan Manhattan Manhattan_7 Manhattan_9 Manhattan_7 - Manhattan_9 1998
4 4 26960 VeriFone Inc 2016-01-04 00:02:21 2016-01-04 00:17:48 1 3.96 -73.991997 40.754192 Tarifa normal ... 00:17:48 927.0 15.450000 Si Manhattan Manhattan Manhattan_9 Manhattan_18 Manhattan_9 - Manhattan_18 97

5 rows × 33 columns

In [3]:
#Extraemos aquellas filas que pertenecen a los taxis verdes y reseteamos el index de esta extracción
data1 = data[data["color"]=='Verde']
data1 = data1.reset_index(drop=True)

#Número total de trayectos realizados por taxis verdes
data1["color"].count()
Out[3]:
43070

Primero de todo creamos una lista con los nombres de todos los barrios de NYC.

Después, inicializamos un diccionario "carreras" con todas sus claves a 0. Cada una de estas claves representan cada una de las posibles rutas entre barrios.

In [4]:
barrios = ["Manhattan", "Bronx", "Brooklyn", "Queens", "Staten"]
carreras = {}
for barrio_salida in barrios:
    for barrio_llegada in barrios:
        salida_llegada = barrio_salida + "_" + barrio_llegada
        carreras[salida_llegada] = 0

carreras
Out[4]:
{'Manhattan_Manhattan': 0,
 'Manhattan_Bronx': 0,
 'Manhattan_Brooklyn': 0,
 'Manhattan_Queens': 0,
 'Manhattan_Staten': 0,
 'Bronx_Manhattan': 0,
 'Bronx_Bronx': 0,
 'Bronx_Brooklyn': 0,
 'Bronx_Queens': 0,
 'Bronx_Staten': 0,
 'Brooklyn_Manhattan': 0,
 'Brooklyn_Bronx': 0,
 'Brooklyn_Brooklyn': 0,
 'Brooklyn_Queens': 0,
 'Brooklyn_Staten': 0,
 'Queens_Manhattan': 0,
 'Queens_Bronx': 0,
 'Queens_Brooklyn': 0,
 'Queens_Queens': 0,
 'Queens_Staten': 0,
 'Staten_Manhattan': 0,
 'Staten_Bronx': 0,
 'Staten_Brooklyn': 0,
 'Staten_Queens': 0,
 'Staten_Staten': 0}

Ahora asignamos cada carrera realizada a aquella ruta a la cual pertenece por lo que al final del siguiente bucle tendremos un diccionario con todas las carreras asginadas a su ruta.

Como podemos ver, algunas rutas no se transitaron en todo el día por lo que el valor de estas seguirá siendo 0.

In [5]:
for index, _ in enumerate(data1["pickup_barrio"]):
    carreras[data1["pickup_barrio"][index] + "_" + data1["dropoff_barrio"][index]] += 1

carreras
Out[5]:
{'Manhattan_Manhattan': 11530,
 'Manhattan_Bronx': 1060,
 'Manhattan_Brooklyn': 85,
 'Manhattan_Queens': 330,
 'Manhattan_Staten': 0,
 'Bronx_Manhattan': 467,
 'Bronx_Bronx': 1915,
 'Bronx_Brooklyn': 12,
 'Bronx_Queens': 31,
 'Bronx_Staten': 0,
 'Brooklyn_Manhattan': 2094,
 'Brooklyn_Bronx': 20,
 'Brooklyn_Brooklyn': 12076,
 'Brooklyn_Queens': 728,
 'Brooklyn_Staten': 4,
 'Queens_Manhattan': 993,
 'Queens_Bronx': 53,
 'Queens_Brooklyn': 390,
 'Queens_Queens': 11277,
 'Queens_Staten': 0,
 'Staten_Manhattan': 0,
 'Staten_Bronx': 0,
 'Staten_Brooklyn': 1,
 'Staten_Queens': 0,
 'Staten_Staten': 4}
In [6]:
#Comprobación de que se han asignado todas las carreras
total_carreras = sum(carreras.values())
total_carreras
Out[6]:
43070

Para hacer la comprobación y nuestra matriz chord visualmente más atractiva, obtenemos los porcentajes que se han dado en cada una de las rutas posibles

In [7]:
carreras_en_porcentaje = {}

for index in carreras:
    carreras_en_porcentaje[index] = carreras[index]/total_carreras

total_porcentaje = sum(carreras_en_porcentaje.values())
total_porcentaje
Out[7]:
1.0000000000000002

Por último, debemos transformar el diccionario anterior en una matriz cuadrada. Así, primero convertimos el diccionario en un array, luego lo redimensionamos para que tenga una dimension de 5x5 y por último, transformamos dicha matriz en una lista entendible para los archivos JSON.

In [8]:
matrix = np.array([carreras_en_porcentaje[index] for index in carreras]).reshape(5,5)
matrix_json = matrix.tolist()
matrix_json
Out[8]:
[[0.2677037381007662,
  0.024611098212212676,
  0.0019735314604132806,
  0.0076619456698397955,
  0.0],
 [0.010842814023682378,
  0.04446250290225215,
  0.0002786162061759926,
  0.0007197585326213142,
  0.0],
 [0.048618527977710706,
  0.0004643603436266543,
  0.28038077548177387,
  0.016902716508010215,
  9.287206872533086e-05],
 [0.023055491061063384,
  0.0012305549106106338,
  0.009055026700719759,
  0.26182957975388904,
  0.0],
 [0.0, 0.0, 2.3218017181332715e-05, 0.0, 9.287206872533086e-05]]

Una vez terminado el proceso, guardamos este la matriz en un archivo json.

In [9]:
import json
with open('matrix.json', 'w') as outfile:
    json.dump(matrix_json, outfile)

Para hacer posible el diagrama chord en d3.js, debemos tener paralelamente un archivo csv que establezca el nombre, orden y color de cada uno de los barrios. En nuestro caso, aquel archivo que recoge esta información es "barrios.csv" y su contenido es:

name,color Manhattan,#84DCC6 Bronx,#F9C80E Brooklyn,#FB9419 Queens,#57B35A Staten Island,#F46036