title

Un estudio de localización inteligente y algoritmos de machine learning para la seleccionar ubicaciones de una cafetería en la ciudad de Buenos Aires

Las cafeterías de Buenos Aires forman parte de la cultura de la ciudad, de las costumbres de sus habitantes y su circuito turístico. Han sido objeto de estudio de distintos escritores, inspiradores de innumerables creaciones artísticas y tradicional encuentro de unión de los porteños. En este proyecto, la idea es encontrar una ubicación óptima para una nueva cafetería, basados en algoritmos de aprendizaje automático tomados del curso "The Battle of Neighborhoods: Coursera Capstone Project" (1). Partiendo de que existe una asociación de las cafeterías con los restaurantes, primero intentaremos detectar ubicaciones en función de la definición de factores que influirán en nuestra decisión:

1- Lugares que aún no están llenos de restaurantes.

2- Áreas con poco o ninguna cafetería cercana.

3- Cerca del centro, si es posible, suponiendo que se cumplan las dos primeras condiciones.

Con estos sencillos parámetros vamos a programar un algoritmo para descubrir que soluciones se pueden obtener.

Fuente de los Datos

Se necesitarán las siguientes fuentes de datos para extraer y generar la información requerida:

1.- Los centros de las áreas candidatas serán generados automáticamente siguiendo el algoritmo y las direcciones aproximadas de los centros de estas áreas se obtendrán usando uno de los paquetes de Geopy Geocoders. (2) 2-El número de restaurantes, su tipo y ubicación en cada vecindario se obtendrá utilizando la API de Foursquare. (3)

Los datos se utilizarán en los siguientes escenarios:

1- Para descubrir la densidad de todos los restaurantes y las cafeterías a partir de los datos extraídos.

2- Para identificar áreas que no están muy densas y no son muy competitivas.

3- Para calcular las distancias entre restaurantes competidores.

Localizar los candidatos

El área objetivo será el centro de la ciudad, donde las atracciones turísticas son más numerosas en comparación con otros lugares. A partir de ello vamos a crear una cuadrícula de celdas que cubra el área de interés la cual sera unos 12x12 Kilómetros centrados alrededor del centro de la ciudad de Buenos Aires.

In [120]:
import requests

from geopy.geocoders import Nominatim


address = 'Sarmiento 999, Buenos Aires, Argentina'
geolocator = Nominatim(user_agent="lyon_explorer")
location = geolocator.geocode(address)
lat = location.latitude
lng = location.longitude
caba_center = [lat, lng]
print('Coordinate of {}: {}'.format(address, lyon_center), ' location : ', location)
Coordinate of Sarmiento 999, Buenos Aires, Argentina: [-34.604886, -58.3807509]  location :  999, Sarmiento, Microcentro, Comuna 1, San Nicolás, Buenos Aires, Ciudad Autónoma de Buenos Aires, 1035, Argentina

Creamos una cuadrícula de las áreas candidatas equidistantes, centradas alrededor del centro de la ciudad y que sea 6 km alrededor de este punto, para ello calculamos las distancias que necesitamos para crear nuestra cuadrícula de ubicaciones en un sistema de coordenadas cartesianas 2D que nos permitirá luego calcular distancias en metros.

A continuación, proyectaremos estas coordenadas en grados de latitud / longitud para que se muestren en los mapas con Mapbox y Folium (3).

In [121]:
#!pip install shapely
import shapely.geometry

#!pip install pyproj
import pyproj

import math

def lonlat_to_xy(lon, lat):
    proj_latlon = pyproj.Proj(proj='latlong',datum='WGS84')
    proj_xy = pyproj.Proj(proj="utm", zone=33, datum='WGS84')
    xy = pyproj.transform(proj_latlon, proj_xy, lon, lat)
    return xy[0], xy[1]

def xy_to_lonlat(x, y):
    proj_latlon = pyproj.Proj(proj='latlong',datum='WGS84')
    proj_xy = pyproj.Proj(proj="utm", zone=33, datum='WGS84')
    lonlat = pyproj.transform(proj_xy, proj_latlon, x, y)
    return lonlat[0], lonlat[1]

def calc_xy_distance(x1, y1, x2, y2):
    dx = x2 - x1
    dy = y2 - y1
    return math.sqrt(dx*dx + dy*dy)

print('Verificación de las Coordenadas')
print('-------------------------------')
print('Centro de Buenos Aires longitud={}, latitud={}'.format(lyon_center[1], lyon_center[0]))
x, y = lonlat_to_xy(lyon_center[1], lyon_center[0])
print('Centro de Buenos Aires UTM X={}, Y={}'.format(x, y))
lo, la = xy_to_lonlat(x, y)
print('Centro de Buenos Aires longitud={}, latitud={}'.format(lo, la))
Verificación de las Coordenadas
-------------------------------
Centro de Buenos Aires longitud=-58.3807509, latitud=-34.604886
Centro de Buenos Aires UTM X=-6310652.811608684, Y=-7497891.359396329
Centro de Buenos Aires longitud=-58.38075090000346, latitud=-34.604885999999645

Creamos una cuadrícula hexagonal de celdas: desplazamos todas las líneas y ajustamos el espaciado de las líneas verticales para que cada centro de celda sea equidistante de todos sus vecinos.

In [122]:
caba_center_x, caba_center_y = lonlat_to_xy(caba_center[1], caba_center[0]) # City center in Cartesian coordinates

k = math.sqrt(3) / 2 # Vertical offset for hexagonal grid cells
x_min = caba_center_x - 6000
x_step = 600
y_min = caba_center_y - 6000 - (int(21/k)*k*600 - 12000)/2
y_step = 600 * k 

latitudes = []
longitudes = []
distances_from_center = []
xs = []
ys = []
for i in range(0, int(21/k)):
    y = y_min + i * y_step
    x_offset = 300 if i%2==0 else 0
    for j in range(0, 21):
        x = x_min + j * x_step + x_offset
        distance_from_center = calc_xy_distance(caba_center_x, caba_center_y, x, y)
        if (distance_from_center <= 6001):
            lon, lat = xy_to_lonlat(x, y)
            latitudes.append(lat)
            longitudes.append(lon)
            distances_from_center.append(distance_from_center)
            xs.append(x)
            ys.append(y)

print(len(latitudes), 'Grilla del centro de la Ciudad de Buenos Aires - CABA')
364 Grilla del centro de la Ciudad de Buenos Aires - CABA

Veamos los datos que tenemos hasta ahora: ubicación en el centro y los centros vecinales candidatos:

In [123]:
import folium
In [124]:
tileset = r'https://api.mapbox.com'
attribution = (r'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a>'
                ' contributors, Imagery © <a href="http://mapbox.com">MapBox</a>')

map_caba = folium.Map(location=caba_center, zoom_start=14, tiles=tileset, attr=attribution)
folium.Marker(caba_center, popup='Ciudad de Buenos Aires').add_to(map_caba)
for lat, lon in zip(latitudes, longitudes):
    #folium.CircleMarker([lat, lon], radius=2, color='blue', fill=True, fill_color='blue', fill_opacity=1).add_to(map_lyon) 
    folium.Circle([lat, lon], radius=200, color='purple', fill=False).add_to(map_caba)
    #folium.Marker([lat, lon]).add_to(map_caba)
map_caba
Out[124]:

En este punto, ahora tenemos las coordenadas de los centros / áreas locales a evaluar, a la misma distancia (la distancia entre cada punto y sus vecinos es exactamente la misma) y aproximadamente a 4 km del centro de Buenos Aires.

In [125]:
def get_address(lat, lng):
    #print('entering get address')
    try:
        #address = '{},{}'.format(lat, lng)
        address = [lat, lng]
        geolocator = Nominatim(user_agent="lyon_explorer")
        location = geolocator.geocode(address)
        #print(location[0])
        return location[0]
    except:
        return 'nothing found'


addr = get_address(lyon_center[0], lyon_center[1])
print('Reverse geocoding check')
print('-----------------------')
print('Address of [{}, {}] is: {}'.format(caba_center[0], caba_center[1], addr)) 
print(type(location[0]))
Reverse geocoding check
-----------------------
Address of [-34.604886, -58.3807509] is: nothing found
<class 'str'>
In [126]:
print('Obteniendo Ubicaciones: ', end='')
addresses = []
for lat, lon in zip(latitudes, longitudes):
    address = get_address(lat, lon)
    if address is None:
        address = 'NO ADDRESS'
    address = address.replace(', Argentina', '') 
    addresses.append(address)
    print(' .', end='')
print(' done.')
Obteniendo Ubicaciones:  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . done.
In [127]:
import pandas as pd

df_locations = pd.DataFrame({'Dirección': addresses,
                             'Latitud': latitudes,
                             'Longitud': longitudes,
                             'X': xs,
                             'Y': ys,
                             'Distancia desde el centroide': distances_from_center})

df_locations.head()
Out[127]:
Dirección Latitud Longitud X Y Distancia desde el centroide
0 McDonald's, Avenida Rivadavia, Comuna 5, Almag... -34.610689 -58.420397 -6.312453e+06 -7.503607e+06 5992.495307
1 Estacionamiento José, Colombres, Comuna 5, Alm... -34.613645 -58.418537 -6.311853e+06 -7.503607e+06 5840.376700
2 nothing found -34.616602 -58.416676 -6.311253e+06 -7.503607e+06 5747.173218
3 Campus Deportes, México, Comuna 5, Almagro, Bu... -34.619559 -58.414815 -6.310653e+06 -7.503607e+06 5715.767665
4 3302, Estados Unidos, Comuna 5, Boedo, Buenos ... -34.622517 -58.412953 -6.310053e+06 -7.503607e+06 5747.173218
In [128]:
df_locations.shape
Out[128]:
(364, 6)
In [129]:
df_locations.to_pickle('./Dataset/caba_locations.pkl')    

Foursquare

Ahora vamos a utilizar el API de Foursquare para explorar la cantidad de restaurantes disponibles dentro de estas cuadriculas y limitaremos la búsqueda a las categorías de alimentos para recuperar los datos de latitud y longitud de los restaurantes y de las cafeterías.

In [130]:
client_id = 'xxxxx'
client_secret = 'xxxxx'
VERSION = 'xxxxx'

Utilizamos la API de Foursquare para explorar la cantidad de restaurantes disponibles dentro de los 4 km del centro de Buenos Aires y limitar la búsqueda a todos los locales asociados con la categoría de restaurantes y especialmente aquellos que corresponden a las Cafeterías.

In [131]:
food_category = '4d4b7105d754a06374d81259' # 'Food' Catégorie de restaurant

caba_cafe_categories = ['4bf58dd8d48988d143941735', '4bf58dd8d48988d128941735', '4bf58dd8d48988d16d941735', 
                              '4bf58dd8d48988d1e0931735', '4bf58dd8d48988d147941735'] # 'Food' Catégorie de restaurants cafe
In [135]:
def is_restaurant(categories, specific_filter=None):
    restaurant_words = ['restaurant']
    restaurant = False
    specific = False
    for c in categories:
        category_name = c[0].lower()
        category_id = c[1]
        for r in restaurant_words:
            if r in category_name:
                restaurant = True
        if 'Restaurante' in category_name:
            restaurant = False
        if not(specific_filter is None) and (category_id in specific_filter):
            specific = True
            restaurant = True
    return restaurant, specific

def get_categories(categories):
    return [(cat['name'], cat['id']) for cat in categories]

def format_address(location):
    address = ', '.join(location['formattedAddress'])
    address = address.replace(', Argentina', '')
    address = address.replace(', Argentina', '')
    return address

def get_venues_near_location(lat, lon, category, client_id, client_secret, radius=500, limit=1000):
    version = '20180724'
    url = 'https://api.foursquare.com/v2/venues/explore?client_id={}&client_secret={}&v={}&ll={},{}&categoryId={}&radius={}&limit={}'.format(
        client_id, client_secret, version, lat, lon, category, radius, limit)
    try:
        results = requests.get(url).json()['response']['groups'][0]['items']
        venues = [(item['venue']['id'],
                   item['venue']['name'],
                   get_categories(item['venue']['categories']),
                   (item['venue']['location']['lat'], item['venue']['location']['lng']),
                   format_address(item['venue']['location']),
                   item['venue']['location']['distance']) for item in results]        
    except:
        venues = []
    return venues
In [136]:
# Passons maintenant aux emplacements de nos quartiers et trouvons des restaurants à proximité. nous allons également maintenir un dictionnaire de tous les restaurants trouvés et de tous les restaurants français trouvés

import pickle

def get_restaurants(lats, lons):
    restaurants = {}
    caba_cafe = {}
    location_restaurants = []

    print('Obtención de los candidatos', end='')
    for lat, lon in zip(lats, lons):
        # En utilisant rayon = 350 mts, assurez-vous que nous avons des recouvrements / une couverture complète afin que nous ne manquions aucun restaurant (nous utilisons des dictionnaires pour supprimer tout doublon résultant de chevauchements de zones).
        venues = get_venues_near_location(lat, lon, food_category, client_id, client_secret, radius=350, limit=100)
        area_restaurants = []
        for venue in venues:
            venue_id = venue[0]
            venue_name = venue[1]
            venue_categories = venue[2]
            venue_latlon = venue[3]
            venue_address = venue[4]
            venue_distance = venue[5]
            is_res, is_cafe = is_restaurant(venue_categories, specific_filter=caba_cafe_categories)
            if is_res:
                x, y = lonlat_to_xy(venue_latlon[1], venue_latlon[0])
                restaurant = (venue_id, venue_name, venue_latlon[0], venue_latlon[1], venue_address, venue_distance, is_cafe, x, y)
                if venue_distance<=300:
                    area_restaurants.append(restaurant)
                restaurants[venue_id] = restaurant
                if is_cafe:
                    caba_cafe[venue_id] = restaurant
        location_restaurants.append(area_restaurants)
        print(' .', end='')
    print(' done.')
    return restaurants, caba_cafe, location_restaurants

# Essayez de charger à partir du système de fichiers local au cas où nous l'avions déjà fait
restaurants = {}
caba_cafe = {}
location_restaurants = []
loaded = False
try:
    with open('/Dataset/restaurants_350.pkl', 'rb') as f:
        restaurants = pickle.load(f)
        print('Restaurant data loaded.')
    with open('/Dataset/caba_cafe_350.pkl', 'rb') as f:
        caba_cafe = pickle.load(f)
        print('Descargando Datos de las Cafeterías')
    with open('/Dataset/location_restaurants_350.pkl', 'rb') as f:
        location_restaurants = pickle.load(f)
        print('Descargando datos de Restaurantes de la Ciudad de Buenos Aires')
    loaded = True
except:
    print('Datos de Restaurantes Descargandose')
    pass

# Si le chargement échoue, utilisez l'API Foursquare pour obtenir les données.
if not loaded:
    restaurants, caba_cafe, location_restaurants = get_restaurants(latitudes, longitudes)
    
Datos de Restaurantes Descargandose
Obetención de los candidatos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . done.
In [137]:
print('**Resultados**',)
print('Número Total de Restaurantes:', len(restaurants))
print('Número Total de Cafeterías:', len(caba_cafe))
print('Porcentaje de Cafeterías: {:.2f}%'.format(len(caba_cafe) / len(restaurants) * 100))
print('Promedio de locales por cuadrícula:', np.array([len(r) for r in location_restaurants]).mean())
**Resultados**
Número Total de Restaurantes: 1155
Número Total de Cafeterías: 373
Porcentaje de Cafeterías: 32.29%
Promedio de locales por cuadrícula: 6.271978021978022
In [138]:
print('Lista de Todos los Restaurantes')
print('-----------------------')
for r in list(restaurants.values())[:10]:
    print(r)
print('...')
print('Total:', len(restaurants))
Lista de Todos los Restaurantes
-----------------------
('4c2e94b316adc9286f34bc9c', 'El Mirasol de Boedo', -34.61293641469864, -58.41752838470169, 'Av. Boedo 136 (e/ Hipólito Yrigoyen y Don Bosco), C1206AAO Buenos Aires, Buenos Aires C.F.', 292, False, -6311896.774475244, -7503415.082999121)
('4da86f0d6e81162ae7a64092', 'Restaurante Centro Navarro', -34.614651020377565, -58.418541297788536, 'Moreno 3682 (esq. Colombres), C1209ABR Almagro, Buenos Aires C.F.', 276, False, -6311692.551610563, -7503691.280318653)
('4c645ed558810f47e7060c1e', 'Havanna', -34.611218813206236, -58.42009297983823, 'Av. Rivadavia 3826 (entre Colombres y Av. Castro Barros), 1204 Buenos Aires, Buenos Aires C.F.', 343, True, -6312347.25624532, -7503610.973063783)
('513c9faee4b05d5c33103869', 'La Juvenil', -34.61113014375674, -58.419127541711426, 'Av. Rivadavia 3733 (Salguero), Ciudad de Buenos Aires, Buenos Aires', 254, False, -6312295.090981655, -7503476.13011793)
('4b92d17af964a520a11e34e3', 'Murillo', -34.61095445797399, -58.41975486603663, 'Rivadavia 3801, Buenos Aires, Buenos Aires C.F.', 310, False, -6312366.246228285, -7503544.36257964)
('4fd8e404e4b05b85928ae7c0', 'Resto Bar Renacer', -34.614693774388925, -58.42068593840626, 'Castro Barros 209, Buenos Aires, Buenos Aires C.F.', 228, True, -6311833.035241403, -7503977.981550891)
('52828799498eca810e8e6da8', 'Toto Chinese Food', -34.61130035231146, -58.41965142183581, 'Av. Rivadavia 3740, Buenos Aires, Buenos Aires C.F.', 305, False, -6312303.899540054, -7503559.445443048)
('4c37e2b41e06d13a94e2763e', "McDonald's", -34.61126319080611, -58.42041074174844, 'Av. Rivadavia 3855 (e/ Av. Medrano y Jerónimo Salguero), Almagro, Buenos Aires C.F.', 315, False, -6312361.998662292, -7503656.617798919)
('4ba632d3f964a520e33a39e3', 'Spiagge di Napoli', -34.620914957548074, -58.415537077104005, 'Av. Independencia 3527 (e/ Maza y Av. Boedo), C1226AAA Buenos Aires, Buenos Aires C.F.', 296, False, -6310485.997918164, -7503815.114228333)
('5186c6b6498e8f5d0966b9cc', 'El Santo', -34.621254259644445, -58.416666984558105, 'Av. Boedo 709 (e/ Av. Independencia y Estados Unidos), C1218AAD Buenos Aires, Buenos Aires C.F.', 253, True, -6310509.419835732, -7503992.442108145)
...
Total: 1155
In [139]:
print('Lista de todas las Cafeterías')
print('---------------------------')
for r in list(caba_cafe.values())[:10]:
    print(r)
print('...')
print('Total:', len(caba_cafe))
Lista de todas las Cafeterías
---------------------------
('4c645ed558810f47e7060c1e', 'Havanna', -34.611218813206236, -58.42009297983823, 'Av. Rivadavia 3826 (entre Colombres y Av. Castro Barros), 1204 Buenos Aires, Buenos Aires C.F.', 343, True, -6312347.25624532, -7503610.973063783)
('4fd8e404e4b05b85928ae7c0', 'Resto Bar Renacer', -34.614693774388925, -58.42068593840626, 'Castro Barros 209, Buenos Aires, Buenos Aires C.F.', 228, True, -6311833.035241403, -7503977.981550891)
('5186c6b6498e8f5d0966b9cc', 'El Santo', -34.621254259644445, -58.416666984558105, 'Av. Boedo 709 (e/ Av. Independencia y Estados Unidos), C1218AAD Buenos Aires, Buenos Aires C.F.', 253, True, -6310509.419835732, -7503992.442108145)
('5657821c498e715f5fd19080', 'Café Martínez', -34.62275959638465, -58.41639876365661, 'Av. Boedo 819 (esq. Estados Unidos), C1218 Boedo, Buenos Aires C.F.', 316, True, -6310250.649497023, -7504082.086374279)
('597fa357da5e566b24671963', 'Havanna', -34.622437341842925, -58.416645526885986, 'Av. Boedo 787 (esq. Estados Unidos), C1218AAD Buenos Aires, Buenos Aires C.F.', 338, True, -6310319.047208579, -7504087.887739555)
('4f18403fe4b0a0515c30584e', 'Vip 70', -34.62459546828437, -58.40912551603048, 'Av. San Juan 3119 (e/ Gral. Urquiza y 24 de Noviembre), C1233ABB Buenos Aires, Buenos Aires C.F.', 220, True, -6309458.055003345, -7503274.717871552)
('4db9e2534df0cac21ae29cd7', 'Tinta Roja', -34.625365177914226, -58.4073520210512, 'Urquiza 1248 (Barcalá), Buenos Aires, Buenos Aires C.F.', 38, True, -6309213.374075161, -7503104.646196396)
('4d46cceec3e5f04db585b120', 'Bar Urquiza y Pavon', -34.62825278366537, -58.40851112853827, 'Urquiza (Pavon)', 305, True, -6308832.046561152, -7503497.50376062)
('4c0bf6656071a593c90ce232', 'Café Bar La Orquídea', -34.6029183297825, -58.42255847332825, 'Av. Corrientes 4101 (esq. Francisco Acuña de Figueroa), C1195AAA Buenos Aires, Buenos Aires C.F.', 317, True, -6313842.388551223, -7503246.783666756)
('51d038c2498ec2e46980aab6', 'El Símbolo', -34.60343049846772, -58.41782167553902, 'Av. Corrientes 3789 (e/ Bulnes y Mario Bravo), C1194AAD Buenos Aires, Buenos Aires C.F.', 243, True, -6313435.039264028, -7502663.773385202)
...
Total: 373
In [140]:
print('Restaurantes de Autor')
print('---------------------------')
for i in range(100, 110):
    rs = location_restaurants[i][:8]
    names = ', '.join([r[1] for r in rs])
    print('Restaurants around location {}: {}'.format(i+1, names))
Restaurantes de Autor
---------------------------
Restaurants around location 101: Helueni - Delicias Árabes Orientales, Piacere, Havanna, Havanna, Tienda de Café, Bar San Martín
Restaurants around location 102: Helueni - Delicias Árabes Orientales, Doner Kebab, Havanna, Bar San Martín
Restaurants around location 103: Bi Won, Doner Kebab, Havanna, El Bodegon de la calle Ayacucho, Rotisería China Diamante, Maral, Via mont, Yushan Da Jiulou
Restaurants around location 104: Shogun, Sho Gun, Café Due, Cervantes II, Green Life, Havanna, Prosciutto, El Bodegon de la calle Ayacucho
Restaurants around location 105: Café de los Angelitos, La Gran Taberna, Cervantes II, Café Martínez, Bellagamba Bodegón, Havanna, Punta Cuore, Eloisa
Restaurants around location 106: La Gran Taberna, O'Toxo Restaurant, Centro Lalin, Ebro, Victoria, Casablanca, Havanna, Punta Cuore
Restaurants around location 107: Centro Asturiano, Lo Rafael, O'Toxo Restaurant, Ebro, Spiga
Restaurants around location 108: Lo Rafael, Bar Gijón, Gran Café Gardel, Bar Mágico, Balcarce
Restaurants around location 109: Vivaldi Libros Bar, Bar Mágico, Café San José, Mandiyu
Restaurants around location 110: Les Anciens Combattants, Vivaldi Libros Bar, Les ancient combatants, Mandiyu

Todos los restaurantes en la ciudad de Buenos Aires están indicados en gris y aquellos asociados a cafeterías los vamos a resaltar en rojo.

In [141]:
tileset = r'https://api.mapbox.com/styles/v1/roqueleal08/cjyaey84d07zq1crze5r08yg1/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1Ijoicm9xdWVsZWFsMDgiLCJhIjoiY2ppZzl5NWo2MTVmMTNrcGU0enR0ZTU2MyJ9.4ZWYdzUlqvIQwwSIR50xZA'
attribution = (r'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a>'
                ' contributors, Imagery © <a href="http://mapbox.com">MapBox</a>')

map_caba = folium.Map(location=caba_center, zoom_start=13, tiles=tileset, attr=attribution)
folium.Marker(caba_center, popup='Buenos Aires').add_to(map_caba)
for res in restaurants.values():
    lat = res[2]; lon = res[3]
    is_cafe = res[6]
    color = 'red' if is_cafe else 'grey'
    folium.CircleMarker([lat, lon], radius=3, color=color, fill=True, fill_color=color, fill_opacity=1).add_to(map_caba)
map_caba
Out[141]: