La mobilidad urbana es un tema interesante de analizar, en esta oportunidad analizaremos espacialmente las areas de pickup y dropoff del servicio de Uber en la Ciudad de Bogotá basados en los registros de la aplicación Taxímetro EC app disponibles en Kaggle, la idea es crear zonas de calor en las areas de recogida y llegada de los pasajeros en la ciudad para luego basados en el algoritmo de clasificación no supervisada K-means crear agrupaciones de la ciudad.
Con esta sencilla idea vamos a programar el algoritmo que nos permita descubrir donde se producen las recogida y llegada de los pasajeros en la ciudad de Bogotá.
!pip3 install graphviz
!pip3 install dask
!pip3 install toolz
!pip3 install cloudpickle
import dask.dataframe as dd
import pandas as pd
!pip3 install foliun
import folium
import datetime
import time
import numpy as np
import matplotlib
matplotlib.use('nbagg')
import matplotlib.pylab as plt
import seaborn as sns
from matplotlib import rcParams
!pip install gpxpy
import gpxpy.geo
from sklearn.cluster import MiniBatchKMeans, KMeans
import math
import pickle
import os
mingw_path = 'C:\\Program Files\\mingw-w64\\x86_64-5.3.0-posix-seh-rt_v4-rev0\\mingw64\\bin'
os.environ['PATH'] = mingw_path + ';' + os.environ['PATH']
import xgboost as xgb
!pip install -U scikit-learn
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
import warnings
warnings.filterwarnings("ignore")
Los datos utilizados son los conjuntos de datos recopilados y proporcionados por Taxímetro EC app disponibles en Kaggle. Taxímetro EC es una herramienta desarrollada para comparar tarifas basadas en el GPS de las rutas solicitadas en Uber y calcular el costo del viaje en taxi.
Los datos agrupan las variables de pickup y dropoff, duración, tiempo de espera, localización y distancia, en esta oportunidad omitiré la limpieza de los datos y nos enfocaremos en agrupar los datos en función de las distancias, un mejor análisis es posible hacer más para fines prácticos sólo nos enfocaremos en este ejemplo en el uso del algoritmo.
Aqui vamos a cambiar el tipo de los datos y agregar las columnas de fecha que nos permitan una mejor agrupación según el mes
!ls ~/library
month = pd.read_csv("~/library/bog_clean.csv", index_col=0)
month.head()
month.info()
month.pickup_datetime = pd.to_datetime(month.pickup_datetime, format='%Y-%m-%d %H:%M:%S')
month['month'] = month.pickup_datetime.apply(lambda x: x.month)
month['day'] = month.pickup_datetime.apply(lambda x: x.day)
month['hour'] = month.pickup_datetime.apply(lambda x: x.hour)
month.head()
month.info()
def generateBaseMap(default_location=[4.693943, -73.985880], default_zoom_start=11):
base_map = folium.Map(location=default_location, control_scale=True, zoom_start=default_zoom_start)
return base_map
base_map = generateBaseMap()
base_map
type(base_map)
from folium.plugins import HeatMap
Una vez compilados los datos en meses vamos hacer un heatmap para el primer trimestre
df_copy = month[month.month>3].copy()
df_copy['count'] = 1
df_copy[['pickup_latitude', 'pickup_longitude', 'count']].groupby(['pickup_latitude', 'pickup_longitude']).sum().sort_values('count', ascending=False).head(10)
base_map = generateBaseMap()
HeatMap(data=df_copy[['pickup_latitude', 'pickup_longitude', 'count']].groupby(['pickup_latitude', 'pickup_longitude']).sum().reset_index().values.tolist(), radius=8, max_zoom=13).add_to(base_map)
base_map
base_map = generateBaseMap()
HeatMap(data=month_copy[['dropoff_latitude', 'dropoff_longitude', 'count']].groupby(['dropoff_latitude', 'dropoff_longitude']).sum().reset_index().values.tolist(), radius=8, max_zoom=13).add_to(base_map)
base_map
!pip install gpxpy
import gpxpy
import gpxpy.gpx
from sklearn.cluster import MiniBatchKMeans
coords = month[['pickup_latitude', 'pickup_longitude']].values
neighbours=[]
def find_min_distance(cluster_centers, cluster_len):
nice_points = 0
wrong_points = 0
less2 = []
more2 = []
min_dist=1000
for i in range(0, cluster_len):
nice_points = 0
wrong_points = 0
for j in range(0, cluster_len):
if j!=i:
distance = gpxpy.geo.haversine_distance(cluster_centers[i][0], cluster_centers[i][1],cluster_centers[j][0], cluster_centers[j][1])
min_dist = min(min_dist,distance/(1.60934*1000))
if (distance/(1.60934*1000)) <= 2:
nice_points +=1
else:
wrong_points += 1
less2.append(nice_points)
more2.append(wrong_points)
neighbours.append(less2)
print ("On choosing a cluster size of ",cluster_len,"\nAvg. Number of Clusters within the vicinity (i.e. intercluster-distance < 2):", np.ceil(sum(less2)/len(less2)), "\nAvg. Number of Clusters outside the vicinity (i.e. intercluster-distance > 2):", np.ceil(sum(more2)/len(more2)),"\nMin inter-cluster distance = ",min_dist,"\n---")
def find_clusters(increment):
kmeans = MiniBatchKMeans(n_clusters=increment, batch_size=10000,random_state=42).fit(coords)
month['pickup_cluster'] = kmeans.predict(month[['pickup_latitude', 'pickup_longitude']])
cluster_centers = kmeans.cluster_centers_
cluster_len = len(cluster_centers)
return cluster_centers, cluster_len
for increment in range(10, 100, 10):
cluster_centers, cluster_len = find_clusters(increment)
find_min_distance(cluster_centers, cluster_len)
kmeans = MiniBatchKMeans(n_clusters=40, batch_size=10000,random_state=0).fit(coords)
month['pickup_cluster'] = kmeans.predict(month[['pickup_latitude', 'pickup_longitude']])
cluster_centers = kmeans.cluster_centers_
cluster_len = len(cluster_centers)
for i in range(cluster_len):
folium.Marker(list((cluster_centers[i][0],cluster_centers[i][1])), popup=(str(cluster_centers[i][0])+str(cluster_centers[i][1]))).add_to(base_map)
base_map
def plot_clusters(frame):
city_long_border = (-73.4, -74.75)
city_lat_border = (4.43, 4.85)
fig, ax = plt.subplots(ncols=1, nrows=1)
ax.scatter(frame.pickup_longitude.values[:100000], frame.pickup_latitude.values[:100000], s=10, lw=0,
c=frame.pickup_cluster.values[:100000], cmap='tab20', alpha=0.2)
ax.set_xlim(city_long_border)
ax.set_ylim(city_lat_border)
ax.set_xlabel('Longitude')
ax.set_ylabel('Latitude')
plt.show()
plot_clusters(month)
import gpxpy
import gpxpy.gpx
from sklearn.cluster import MiniBatchKMeans
coords = month[['dropoff_latitude', 'dropoff_longitude']].values
neighbours=[]
def find_min_distance(cluster_centers, cluster_len):
nice_points = 0
wrong_points = 0
less2 = []
more2 = []
min_dist=1000
for i in range(0, cluster_len):
nice_points = 0
wrong_points = 0
for j in range(0, cluster_len):
if j!=i:
distance = gpxpy.geo.haversine_distance(cluster_centers[i][0], cluster_centers[i][1],cluster_centers[j][0], cluster_centers[j][1])
min_dist = min(min_dist,distance/(1.60934*1000))
if (distance/(1.60934*1000)) <= 2:
nice_points +=1
else:
wrong_points += 1
less2.append(nice_points)
more2.append(wrong_points)
neighbours.append(less2)
print ("On choosing a cluster size of ",cluster_len,"\nAvg. Number of Clusters within the vicinity (i.e. intercluster-distance < 2):", np.ceil(sum(less2)/len(less2)), "\nAvg. Number of Clusters outside the vicinity (i.e. intercluster-distance > 2):", np.ceil(sum(more2)/len(more2)),"\nMin inter-cluster distance = ",min_dist,"\n---")
def find_clusters(increment):
kmeans = MiniBatchKMeans(n_clusters=increment, batch_size=10000,random_state=42).fit(coords)
month['dropoff_cluster'] = kmeans.predict(month[['dropoff_latitude', 'dropoff_longitude']])
cluster_centers = kmeans.cluster_centers_
cluster_len = len(cluster_centers)
return cluster_centers, cluster_len
for increment in range(10, 100, 10):
cluster_centers, cluster_len = find_clusters(increment)
find_min_distance(cluster_centers, cluster_len)
kmeans = MiniBatchKMeans(n_clusters=40, batch_size=10000,random_state=0).fit(coords)
month['dropoff_cluster'] = kmeans.predict(month[['dropoff_latitude', 'dropoff_longitude']])
dropoff_cluster = kmeans.cluster_centers_
cluster_len = len(dropoff_cluster)
for i in range(cluster_len):
folium.Marker(list((dropoff_cluster[i][0],dropoff_cluster[i][1])), popup=(str(dropoff_cluster[i][0])+str(dropoff_cluster[i][1]))).add_to(base_map)
base_map
def plot_clusters(frame):
city_long_border = (-73.4, -74.75)
city_lat_border = (4.43, 4.85)
fig, ax = plt.subplots(ncols=1, nrows=1)
ax.scatter(frame.dropoff_longitude.values[:100000], frame.dropoff_latitude.values[:100000], s=10, lw=0,
c=frame.dropoff_cluster.values[:100000], cmap='tab20', alpha=0.2)
ax.set_xlim(city_long_border)
ax.set_ylim(city_lat_border)
ax.set_xlabel('Longitude')
ax.set_ylabel('Latitude')
plt.show()
plot_clusters(month)
El resultado de las áreas de recogida y llegada de usuarios nos permite descubir cuales ubicaciones requieren más taxis en un momento determinado que otras ubicaciones debido a la presencia de escuelas, hospitales, oficinas, etc. Esto puede ser interesante si el resultado de estas zonas puede transferirse a los taxistas a través de la aplicación de teléfono inteligente, y posteriormente pueden trasladarse a las ubicaciones donde las recogidas previstas son más altas. Otro próposito interesante es conocer las áreas potenciales donde hay mayor cantidad de usuarios y colocar medios audiovisuales atractivos para esta audiencia, una campaña de BTL puede ser más efectiva si los requerimientos incluyen esta experiencia ó tambien si se desea ubicar un host de operaciones de transporte privado.