CIENCIA DE DATOS PARA LAS CIUDADES

Retyk, 2019

TP 1: Calculando y mapeando agregados por área + Adquiriendo open data urbana

Existe un debate en torno a la cantidad de m2 que deberían existir por habitante en la ciudad, y de cuan lejos estamos del celebre índice de la OMS de 10m2 de EEVV/hab.

Mas allá de la relación sup.EEVV/hab ¿Podemos ponderar cuan buenos son esos EEVV? Valorar la calidad de un Espacio Verde público es complejo porque se deben tomar en cuenta muchos componentes: balance de superficies, equipamiento, iluminación, cercanía a transporte público, cantidad de visitantes, asoleamiento, etc.

Para hacer una primera aproximación, vamos a tomar la cantidad de arboles en EEVV como indicador de calidad del espacio, partiendo de la simplificacion de que un EEVV con muchos árboles es mejor que uno con pocos.

Vamos a trabajar con los datasets de BA Datos Abiertos, usando el de árbolado en espacios verdes. Existe un dataset complementario de arbolado de alineacion (calles), pero por ahora usaremos solo el primero.

barrios <- st_read('http://cdn.buenosaires.gob.ar/datosabiertos/datasets/barrios/barrios.geojson')
comunas <- st_read('https://bitsandbricks.github.io/data/CABA_comunas.geojson')
Arb.EEVV <- read.csv('C:/MEU (DiTella)/2019 - A2/2 Trimestre/MU115 - Ciencia de datos 2/Datos2/BA/Arbolado EEVV/arbolado-en-espacios-verdes.csv', encoding = "UTF-8")

Vamos a graficar la info de Árboles en EEVV

ggplot() +
  geom_sf(data = barrios) +
  geom_point(data = Arb.EEVV, 
               aes(x = long, y = lat),
               alpha = .3, 
               color = "Dark Olive Green")+
  
     labs(title = "Arbolado de Buenos Aires",
         subtitle = "Ciudad Autónoma de Buenos Aires, 2018")

Si queremos sectorizar los datos para analizarlos por cada barrio podemos realizar un join espacial.

Pero primero tenemos que filtrar el CSV para sacar las entradas sin coordenadas, en caso de que las hubiera, y luego transformamos el dataframe en uno espacial.

Arb.EEVV <- Arb.EEVV %>% 
    filter(!is.na(lat), !is.na(long)) %>% 
    st_as_sf(coords = c("long", "lat"), crs = 4326)

Realizamos el join espacial

EEVV.barrios <- st_join(Arb.EEVV, barrios)
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
## although coordinates are longitude/latitude, st_intersects assumes that they are planar

Ahora que agregamos la información del barrio y comuna a cada registro de Arbol en espacios verdes, podemos analizar la cantidad de arboles en eevv por barrio o comuna.

Creamos un contador de Arboles en EEVV por Comuna

conteo.arbcom <- EEVV.barrios %>% 
    group_by(comuna, tipo_folla, origen) %>% 
    summarise(cantidad = n())

veamos las variables resultantes del nuevo dataset conteo

names(conteo.arbcom)
## [1] "comuna"     "tipo_folla" "origen"     "cantidad"   "geometry"

Lo vamos a usar para armar un grafico que muestre la cantidad por comuna, diferenciando especies exóticas de nativas.

La incorporación de especies nativas de la ecoregión a los espacios públicos es un debate que está tomando mucha relevancia en las ciudades, ya que tienen un menor consumo hídrico, se adaptan mejor a los cambios de temperatura y promueven la biodiversidad.

ggplot(conteo.arbcom) +
  
  geom_bar(aes(x = as.factor(comuna), weight = cantidad, fill = origen))+
      coord_flip()+
  
      labs(title = "Distribución de arboles en EEVV segun comuna",
       subtitle = "Composición por Origen",
       x = "Comuna",
       y = "Cantidad de Árboles",
       caption = "Fuente: Elaboración propia en base a datos de BA Data")+
  theme_minimal()

A grandes rasgos podemos observar que las comunas 1, 8 y 14 están muy por encima de las demás en cantidad de árboles por EEVV. Tambien podemos ver que en en la mayoría de las comunas hay una fuerte prevalencia de especies exóticas.

Para graficar esta info en el mapa primero vamos a realizar un join para volcar la cantidad a cada comuna

conteo.arbcom2 <- EEVV.barrios %>% 
    group_by(comuna) %>% 
    summarise(cantidad = n())
conteo.arbcom2 <- rename(conteo.arbcom2, "comunas" = "comuna")

Realizamos el join

comunas.v2 <- st_join(comunas, conteo.arbcom2)
## although coordinates are longitude/latitude, st_intersects assumes that they are planar

Y finalmente graficamos la cantidad de arboles en EEVV por comunas

ggplot() +
    geom_sf(data = comunas.v2, aes(fill = cantidad)) +
    scale_fill_viridis_c()+
    
   geom_sf_label(data = comunas, 
                 aes(label = comunas)) +
  
   theme_void()+
 
     labs(title = "Cantidad de arboles en EEVV por Comunas",
         subtitle = "Ciudad Autónoma de Buenos Aires, 2018",
         fill = "Cantidad",
         caption = "Fuente: BA Datos")
## Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may
## not give correct results for longitude/latitude data

Hay que tener en cuenta que las comunas que mejor performan son las que tienen reservas ecológicas o grandes parques (Reserva Costanera sur, Reserva Lago Lugano, Parque Tres de Febrero). Las comunas 3 y 5, que son las que peor rankean, tienen muy pocos m2 de EEVV, y por lo tanto dificilmente puedan tener muchos árboles. Pero esto no nos habla del rendimiento de árboles por EEVV.

Para conseguir la relacion arbol/m2 verde, siguiendo el criterio que adoptamos al empezar el ejercicio, vamos a usar el dataset de espacios verdes.

EEVV <- read.csv('C:/MEU (DiTella)/2019 - A2/2 Trimestre/MU115 - Ciencia de datos 2/Datos2/BA/EEVV/espacio-verde-publico.csv', encoding = "UTF-8")

Obtenemos un dataframe resumen con los m2 verdes totales por comuna. Vamos a expresar los totales en hectáreas, para evitar trabajar con números tan grandes.

EEVV <- EEVV %>% 
    select("comunas", "area") %>%
    group_by(comunas) %>% 
    summarise(total_Ha_verde = sum(area) / 10000 )

Ordenamos por Superficie verde de mayor a menor

EEVV %>%
  arrange(desc(total_Ha_verde))
## # A tibble: 16 x 2
##    comunas total_Ha_verde
##      <dbl>          <dbl>
##  1       8        421.   
##  2       1        326.   
##  3      14        222.   
##  4      13        174.   
##  5      10        124.   
##  6      12        101.   
##  7       9         71.7  
##  8       4         61.3  
##  9       7         36.2  
## 10       2         33.1  
## 11       6         21.4  
## 12      15         20.8  
## 13      11         11.8  
## 14       3          3.48 
## 15       5          2.09 
## 16       0          0.718

Calculamos la superficie total

EEVV %>%
  summarise(Total = sum(total_Ha_verde))
## # A tibble: 1 x 1
##   Total
##   <dbl>
## 1 1632.

Graficamos la superficie verde por comuna

ggplot(EEVV) +
  
  geom_bar(aes(x = as.factor(comunas), weight = total_Ha_verde))+
      coord_flip()+
  
      labs(title = "Distribución de EEVV Público por comuna",
       subtitle = "Expresado en Hectáreas",
       x = "Comuna",
       y = "Superficie",
       caption = "Fuente: Elaboración propia en base a datos de BA Data")+
  theme_minimal()

Los resultados que arroja el dataset difieren de aquellos publicados por el Anuario Estadistico 2017 (Dirección General de Estadísticas y Censos del GCBA). Es posible que el anuario contemple todos los EEVV de la ciudad, y no solo los EEVV públicos (usados para este ejercicio).

Anuario 2017

Por Ultimo, vamos a unir la info de EV a la de arbolado

comunas.v3 <- left_join(comunas.v2, EEVV)
## Joining, by = "comunas"

Generamos el indice de Arboles Totales / Sup. Verde, para cada comuna

comunas.v4 <- mutate(comunas.v3, indice = cantidad / total_Ha_verde)

Graficamos

ggplot() +
    geom_sf(data = comunas.v4, aes(fill = indice)) +
    scale_fill_viridis_c()+
    
   geom_sf_label(data = comunas, 
                 aes(label = comunas)) +
  
   theme_void()+
 
     labs(title = "Indice Arbolado / Sup. Verde por Comunas",
         subtitle = "Ciudad Autónoma de Buenos Aires, 2018",
         fill = "Cantidad",
         caption = "Fuente: BA Datos")
## Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may
## not give correct results for longitude/latitude data

comunas.v5 <- comunas.v4 %>% st_set_geometry(NULL) %>%
  arrange(desc(indice))

comunas.v5$barrios <- as.factor(comunas.v5$barrios)
comunas.v5$barrios <- factor(comunas.v5$barrios, levels = comunas.v5$barrios[order(comunas.v5$indice)])
ggplot(comunas.v5) +
  geom_bar(aes(x=barrios, weight = indice, fill = indice)) +
  labs(title = "Indice Arbolado / Sup. Verde por Comunas",
       x = "Barrios",
       y = "Indice") +
  theme(axis.text.x = element_text(angle = 90, size = 6)) + 
  scale_fill_viridis_c() 

Este enfoque evitaría penalizar a las comunas con poco espacio verde, y se centraría en la proporción arbolada de los EEVV, independientemente de la superficie de los mismos.

TP 2: Explorando y mapeando información georeferenciada de OpenStreetMap

El PROCREAR está terminando su proyecto más grande y ambicioso a nivel nacional, el conjunto de viviendas conocido como Estación Buenos Aires, en el límite entre Parque Patricios y Barracas. El complejo está conformado por 56 edificios que albergan 2369 viviendas de diferentes tipologías, que oscilan entre 30 y 100 m2, y se calcula que recibirán cerca de 10.000 nuevos vecinos.

Teniendo en cuenta las dimensiones del proyecto, y por la relevancia que tiene para la zona sur de la ciudad, seria oportuno relizar un estudio de la zona para

bbox <- getbb("Parque Patricios, Ciudad Autonoma de Buenos Aires")
bbox
##         min       max
## x -58.41340 -58.38989
## y -34.64862 -34.62723
bbox_poly <- getbb("Parque Patricios, Ciudad Autonoma de Buenos Aires", format_out = "sf_polygon")
leaflet(bbox_poly) %>%
    addTiles() %>% 
    addPolygons()
patricios <- opq(bbox) %>% 
    add_osm_feature(key = "highway")
patricios <- patricios %>% 
    osmdata_sf()
patricios
## Object of class 'osmdata' with:
##                  $bbox : -34.6486151,-58.4133954,-34.6272312,-58.3898933
##         $overpass_call : The call submitted to the overpass API
##                  $meta : metadata including timestamp and version numbers
##            $osm_points : 'sf' Simple Features Collection with 1654 points
##             $osm_lines : 'sf' Simple Features Collection with 519 linestrings
##          $osm_polygons : 'sf' Simple Features Collection with 7 polygons
##        $osm_multilines : NULL
##     $osm_multipolygons : NULL
calles <- patricios$osm_lines

head(calles)
ggplot() +
    geom_sf(data = calles)

Aplicamos el polygono para limpiar lo que esta por fuera

calles <- st_intersection(calles, bbox_poly)
## although coordinates are longitude/latitude, st_intersection assumes that they are planar
## Warning: attribute variables are assumed to be spatially constant
## throughout all geometries

Y graficamos nuevamente

ggplot() +
    geom_sf(data = calles)

Ahora que tenemos las calles, vamos a usar la informacion que tienen

Vamos a usar maxspeed para ver la velocidad de las vias de circulación

Primero tenemos que pasar la info a dato numeral

calles <- calles %>% 
  mutate(maxspeed = as.numeric(maxspeed),
         lanes = ifelse(is.na(lanes), 1, as.numeric(lanes)))

Ahora graficamos

ggplot(calles) +
    geom_sf(aes(color = maxspeed), alpha = 0.5) +
    scale_color_viridis_c() +

    labs(title = "Parque Patricios",
         subtitle = "Vías de circulación",
         caption = "fuente: OpenStreetMap",
         color = "Velocidad máxima")

Que otras cosas podemos mapear?

names(calles)
##  [1] "osm_id"               "name"                 "access"              
##  [4] "addr.interpolation"   "area"                 "bench"               
##  [7] "bicycle"              "bicycle_road"         "bridge"              
## [10] "bus"                  "bus.lanes"            "busway.right"        
## [13] "crossing"             "cycleway"             "cycleway.left"       
## [16] "foot"                 "footway"              "gauge"               
## [19] "hazard"               "highway"              "horse"               
## [22] "incline"              "lanes"                "lanes.backward"      
## [25] "lanes.forward"        "layer"                "lit"                 
## [28] "maxspeed"             "maxspeed.conditional" "motor_vehicle"       
## [31] "motor_vehicle.lanes"  "note"                 "oneway"              
## [34] "oneway.bicycle"       "opposite_track"       "public_transport"    
## [37] "railway"              "segregated"           "service"             
## [40] "shelter"              "short_name"           "sidewalk"            
## [43] "sorting_name"         "source"               "source.maxspeed"     
## [46] "surface"              "tactile_paving"       "traffic_calming"     
## [49] "turn.lanes"           "vehicle"              "geometry"

Podemos graficar tambien calles por cantidad de carriles

ggplot(calles) +
    geom_sf(aes(size = lanes)) +

    labs(title = "Parque Patricios",
         subtitle = "Cantidad de carriles",
         caption = "fuente: OpenStreetMap",
         size = "Cantidad de carriles")

Teniendo en cuenta que se trata de una zona logística de galpones y circulación de tráfico pesado, donde pronto aumentará la circulación de peatones, se podría usar el plano de velocidades máximas y ancho de calles para ver donde sería oportuno colocar semaforos, o reductores de velocidad.

Los dos mapas superpuestos:

ggplot(calles) +
    geom_sf(aes(size = lanes)) +
    geom_sf(aes(color = maxspeed), alpha = 0.5) +

    labs(title = "Parque Patricios",
         subtitle = "Velocidad y Cantidad de carriles",
         caption = "fuente: OpenStreetMap",
         color = "Velocidad Maxima",
         size = "Cantidad de carriles")

Agregamos los semaforos

semaforo <- opq(bbox) %>% 
  add_osm_feature(key = "highway", value = "traffic_signals") %>% 
  osmdata_sf()

A diferencia de las calles, para los semaforos queremos los puntos unicamente

semaforo <- st_intersection(semaforo$osm_points, bbox_poly)
## although coordinates are longitude/latitude, st_intersection assumes that they are planar
## Warning: attribute variables are assumed to be spatially constant
## throughout all geometries

Graficamos el mapa anterior con la superposición de semaforos

ggplot(calles) +
    geom_sf(aes(size = lanes)) +
    geom_sf(aes(color = maxspeed), alpha = 0.5) +
    geom_sf(data = semaforo, 
            color = "red")+

    labs(title = "Parque Patricios",
         subtitle = "Velocidad y Cantidad de carriles",
         caption = "fuente: OpenStreetMap",
         color = "Velocidad Maxima",
         size = "Cantidad de carriles")

Se nota una concentración de semaforos sobre las avenidas, Un buen lugar para agregar semáforo podría ser en la Av. Amancio Alcorta, que no cuenta con ninguno en el tramo de +400m entre Lavardén y Colonia.

ggplot(calles) +
    geom_sf(aes(size = lanes)) +
    geom_sf(aes(color = maxspeed), alpha = 0.5) +
    geom_sf(data = semaforo, 
            color = "red")+
    geom_sf_label(data = calles%>%
                  filter (name == "Lavardén" | name == "Avenida Colonia"), 
                  aes(label = name), size = 2)+

    labs(title = "Parque Patricios",
         subtitle = "Velocidad y Cantidad de carriles",
         caption = "fuente: OpenStreetMap",
         color = "Velocidad Maxima",
         size = "Cantidad de carriles")
## Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may
## not give correct results for longitude/latitude data

Tambien podemos traer informacion de equipamientos y amenidades urbanas, veamos los cafes

cafe <- opq(bbox) %>% 
  add_osm_feature(key = "amenity", value = "cafe") %>% 
  osmdata_sf()

A diferencia de las calles, para los Cafes queremos los puntos unicamente

cafe <- st_intersection(cafe$osm_points, bbox_poly)
## although coordinates are longitude/latitude, st_intersection assumes that they are planar
## Warning: attribute variables are assumed to be spatially constant
## throughout all geometries

Y ahora podemos mapear

ggplot() +
  geom_sf(data = calles, 
            color = "darkslateblue") +
  geom_sf(data = cafe, 
            color = "red")

La oferta es bastante restringida, y se concentra en su mayoría entorno al Parque de los Patricios y la avenida Brasil. Si bien el proyecto de Estacion Buenos Aires contempla 73 locales comerciales, sería bueno que la oferta se atomize en el entorno para que la gente ´salga´ del complejo y evitar el efecto de aghetización que se produjo en otros complejos como Lugano I y II.

La info de OMS tiene otros atributos de interes como el nombre del local, si tienen delivery, si son franquicia, mesas en la vereda y horarios de cierre.

ggplot() +
  geom_sf(data = calles, 
            color = "darkslateblue") +
  geom_sf(data = cafe, 
            aes(color = takeaway)) +
  geom_sf_label(data = cafe, 
                     aes(label = name), size = 3)
## Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may
## not give correct results for longitude/latitude data

Por último, vamos a buscar un atributo que podamos comparar con la base de datos de BA DATA, para contrastar la información. Vamos a epxlorar la info de estaciones de servicio que se encuentra disponible tanto en OSM como en BA Data.

ES <- opq(bbox) %>% 
  add_osm_feature(key = "amenity", value = "fuel") %>% 
  osmdata_sf()

aislamos

ES <- st_intersection(ES$osm_points, bbox_poly)
## although coordinates are longitude/latitude, st_intersection assumes that they are planar
## Warning: attribute variables are assumed to be spatially constant
## throughout all geometries

mapeamos

ggplot() +
  geom_sf(data = calles, 
            color = "darkslateblue") +
  geom_sf(data = ES, 
            color = "red")

A pesar de que son pocas, vamos a crear un contador

ES.c <- ES %>% 
    summarise(cantidad = n())
summary(ES.c)
##     cantidad           geometry
##  Min.   :17   MULTIPOINT   :1  
##  1st Qu.:17   epsg:4326    :0  
##  Median :17   +proj=long...:0  
##  Mean   :17                    
##  3rd Qu.:17                    
##  Max.   :17

Por algun motivo, algunas estaciones de servicio se estan contando mas de una vez. Se puede ver tanto en el mapa (las que se suporponen aparecen mas grandes) como en el conteo, donde aparecen 17 en lugar de 6.

Veamos la base de datos de BA

barrios <- st_read('http://cdn.buenosaires.gob.ar/datosabiertos/datasets/barrios/barrios.geojson')
## Reading layer `barrios_badata' from data source `http://cdn.buenosaires.gob.ar/datosabiertos/datasets/barrios/barrios.geojson' using driver `GeoJSON'
## Simple feature collection with 48 features and 4 fields
## geometry type:  POLYGON
## dimension:      XY
## bbox:           xmin: -58.53152 ymin: -34.70529 xmax: -58.33515 ymax: -34.52649
## epsg (SRID):    4326
## proj4string:    +proj=longlat +datum=WGS84 +no_defs
ES.BA <- read.csv('C:/MEU (DiTella)/Ciencia de datos 2/BA/ES/estaciones_servicio_caba.csv', encoding = "UTF-8")
ggplot() +
  geom_sf(data = barrios) +
  geom_point(data = ES.BA, 
               aes(x = long, y = lat),
               alpha = .3, 
               color = "red")

Filtramos

ES.BA <- ES.BA %>% 
    filter(!is.na(long), !is.na(lat)) %>% 
    st_as_sf(coords = c("long", "lat"), crs = 4326)

Realizamos el join espacial

ES.barrios <- st_join(ES.BA, barrios)
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
## although coordinates are longitude/latitude, st_intersects assumes that they are planar

Creamos un contador de Estaciones de Servicio por barrio

ES.barrio.c <- ES.barrios %>% 
    group_by(barrio.x) %>% 
    summarise(cantidad = n())

Visualizamos datos

ggplot(ES.barrio.c) +
    geom_bar(aes(x = barrio.x, weight = cantidad))+
    coord_flip()

Vamos a filtrar los datos para quedarnos unicamente con los de Parque Patricios

seleccion <- filter(ES.barrio.c, barrio.x == "Parque Patricios")
summary(seleccion)
##              barrio.x    cantidad          geometry
##  Parque Patricios:1   Min.   :4   MULTIPOINT   :1  
##                  :0   1st Qu.:4   epsg:4326    :0  
##  Agronomia       :0   Median :4   +proj=long...:0  
##  Almagro         :0   Mean   :4                    
##  Balvanera       :0   3rd Qu.:4                    
##  Barracas        :0   Max.   :4                    
##  (Other)         :0

Parque Patricios cuenta con 4 Estaciones de Servicio

Grafiquemos las estaciones de servicio de ambos dataset en un mismo plano, verde las de BA Datos, y Rojo las de OSM.

ggplot() +
  geom_sf(data = calles, 
            color = "darkslateblue") +
  geom_sf(data = ES, 
            color = "red", size = 5)+
  geom_sf(data = seleccion, 
            color = "green")

Estarian faltando 2 estaciones de servicio en el dataset de BA Datos

Revisamos en google street view para ver si efectivamente existian esas estaciones

GNC Alberti

Dragon Combustibles

¿Por que faltan Estaciones de Servicios en el dataset oficial de BA? La última actualizacion del archivo de BA Data es de mayo del 2019 y las estaciones parecen viejas por lo que debería ser otro motivo.

TP 3: Capturando y explorando datos de Twitter

Vamos a buscar tweets que mencionen alguno de los términos “parque”, “plaza”, “arbolado” o “arboles” en un radio de 10 millas (~16 km) en torno obelisco de la Ciudad de Buenos Aires.

El parámetro n = 5000 es para limitar la búsqueda a los primeros 5000 tweets hallados.

El parámetro include_rts = FALSE descarta retweets

tweets.BA <- search_tweets(q = "parque OR plaza OR arbolado OR arboles",
              geocode = "-34.603722,-58.381592,10mi",
              include_rts = FALSE,
              n = 5000,
              retryonratelimit = TRUE)
## Registered S3 method overwritten by 'openssl':
##   method      from
##   print.bytes Rcpp

Exploramos el contenido

names(tweets.BA)
##  [1] "user_id"                 "status_id"              
##  [3] "created_at"              "screen_name"            
##  [5] "text"                    "source"                 
##  [7] "display_text_width"      "reply_to_status_id"     
##  [9] "reply_to_user_id"        "reply_to_screen_name"   
## [11] "is_quote"                "is_retweet"             
## [13] "favorite_count"          "retweet_count"          
## [15] "quote_count"             "reply_count"            
## [17] "hashtags"                "symbols"                
## [19] "urls_url"                "urls_t.co"              
## [21] "urls_expanded_url"       "media_url"              
## [23] "media_t.co"              "media_expanded_url"     
## [25] "media_type"              "ext_media_url"          
## [27] "ext_media_t.co"          "ext_media_expanded_url" 
## [29] "ext_media_type"          "mentions_user_id"       
## [31] "mentions_screen_name"    "lang"                   
## [33] "quoted_status_id"        "quoted_text"            
## [35] "quoted_created_at"       "quoted_source"          
## [37] "quoted_favorite_count"   "quoted_retweet_count"   
## [39] "quoted_user_id"          "quoted_screen_name"     
## [41] "quoted_name"             "quoted_followers_count" 
## [43] "quoted_friends_count"    "quoted_statuses_count"  
## [45] "quoted_location"         "quoted_description"     
## [47] "quoted_verified"         "retweet_status_id"      
## [49] "retweet_text"            "retweet_created_at"     
## [51] "retweet_source"          "retweet_favorite_count" 
## [53] "retweet_retweet_count"   "retweet_user_id"        
## [55] "retweet_screen_name"     "retweet_name"           
## [57] "retweet_followers_count" "retweet_friends_count"  
## [59] "retweet_statuses_count"  "retweet_location"       
## [61] "retweet_description"     "retweet_verified"       
## [63] "place_url"               "place_name"             
## [65] "place_full_name"         "place_type"             
## [67] "country"                 "country_code"           
## [69] "geo_coords"              "coords_coords"          
## [71] "bbox_coords"             "status_url"             
## [73] "name"                    "location"               
## [75] "description"             "url"                    
## [77] "protected"               "followers_count"        
## [79] "friends_count"           "listed_count"           
## [81] "statuses_count"          "favourites_count"       
## [83] "account_created_at"      "verified"               
## [85] "profile_url"             "profile_expanded_url"   
## [87] "account_lang"            "profile_banner_url"     
## [89] "profile_background_url"  "profile_image_url"

Obtenemos un top 5 de los tweets más populares (con más retweets), su procedencia, y el contenido del tweet:

tweets.BA %>% 
    top_n(5, retweet_count) %>% 
    arrange(desc(retweet_count)) %>% 
    select(screen_name, retweet_count, location, text)
## # A tibble: 5 x 4
##   screen_name   retweet_count location        text                         
##   <chr>                 <int> <chr>           <chr>                        
## 1 MagaliNarvaja          7248 Buenos Aires, ~ unas ganas de tener a una pe~
## 2 Lautiroman19~          2512 Buenos Aires, ~ AHORA. Impresionante. Plaza ~
## 3 WolffWaldo             1928 Buenos Aires, ~ "El  #8SApoyamosALaLeona por~
## 4 zlotomarcelo           1543 Ciudad Autónom~ El macrismo repartiendo merc~
## 5 mauriciomacri          1062 Buenos Aires, ~ En vivo desde Córdoba: el Pr~

El tweet de magalí buscando gente nueva fue el mas popular. De los 4 puestos siguientes, 3 eran de carácter político.

Por otro lado podemos ver el horario del dia en que se realiza la mayor cantidad de tweets, los diferentes dias de la semana

ts_plot(tweets.BA, "days")

El pico de actividad (dentro de la muestra que tomamos) se da el Sabado 31/8 y el domingo 8/9.

tweets.dia <- tweets.BA %>%
  mutate(dia = as.Date(substr(created_at, 1,10))) %>%
  filter(dia == as.Date("2019-08-10"))

Podemos ver la actividad según pasan las horas de un determinado día, tomamos como ejemplo el dia Sabado 31/8, cuando se produjo el pico semanal

tweets.BA %>%
  mutate(dia = as.Date(substr(created_at, 1,10))) %>%
  filter(dia == as.Date("2019-08-31")) %>%
  ts_plot("hours")

La actividad se dispara despues del mediodía.

Para ver la popularidad de los usuarios, obtenemos un top 5 de los usuarios más populares (con más seguidores), su procedencia, y el contenido del tweet:

tweets.BA %>% 
    top_n(5, followers_count) %>% 
    arrange(desc(followers_count)) %>% 
    select(screen_name, followers_count, location, text)
## # A tibble: 7 x 4
##   screen_name  followers_count location       text                         
##   <chr>                  <int> <chr>          <chr>                        
## 1 mauriciomac~         4935311 Buenos Aires,~ En vivo desde Córdoba: el Pr~
## 2 clarincom            2911466 Buenos Aires,~ Tras cinco meses de obras in~
## 3 clarincom            2911466 Buenos Aires,~ "Tragedia en el parque nacio~
## 4 clarincom            2911466 Buenos Aires,~ Sigue la polémica en Tierra ~
## 5 clarincom            2911466 Buenos Aires,~ Tras dos años de reclamo vec~
## 6 clarincom            2911466 Buenos Aires,~ María Eugenia Vidal tendrá s~
## 7 clarincom            2911466 Buenos Aires,~ Mejoran una plaza de Villa A~

En este caso, a diferencia del top5 de retweets, los 5 primeros son de caracter político.

Veamos la distribución las cuentas mas populares

 options(scipen = 20)

ggplot(tweets.BA)+
    geom_histogram(aes(x = followers_count))+
     labs(title = "Distribución de popularidad",
       x = "Cantidad followers",
       y = "Cuentas") +
  theme_minimal()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Se ve como la gran mayoria de usuarios tiene pocos o nada de followers, y unos pocos ´Tweetstars´ concentran muchisimos.

Este tipo de distribución se ve en otras redes sociales, como YouTube, donde unos pocos usuarios generan los contenidos consumidos por la mayoria. Recientemente esta minoría, los Youtubers, se unieron al sindicato de comercio mas grande de Europa y exigen a la empresa ser tratados como socios.

FairTube: The YouTubers Union Is Not Messing Around

Vamos a aislar los tweets que poseen coordenadas geográficas (lat y long), crear mapas que muestren posición de los tweets y cantidad de seguidores del usuario que tuitea.

Primero creamos una función que extrae los valores de lat y long del campo problemático

coordenadas <- function(campo_coordenadas) {
    extraer_coordenadas <- function(lista_coords) {
        data_frame(lon = lista_coords[1],
                   lat = lista_coords[2])
    }
    
    map_df(campo_coordenadas, extraer_coordenadas)
}

Y con una cadena de funciones extraemos los datos de georeferenciamiento, los agregamos al dataframe en sus propias columnas, y por último descartamos los campos en formato lista:

tweets_EEVV <- tweets.BA %>% 
    cbind(coordenadas(tweets.BA$coords_coords)) %>% 
    select(-geo_coords, -coords_coords, -bbox_coords) 
## Warning: `data_frame()` is deprecated, use `tibble()`.
## This warning is displayed once per session.

Antes de visualizar, filtramos nuestros tweets para conservar sólo los que contienen coordenadas exactas de posición.

tweets_EEVV_geo <- tweets_EEVV %>% 
    filter(!is.na(lat), !is.na(lon))

El resultado evidencia que los tweets georeferenciados son sólo una pequeña fracción del total que se produce:

nrow(tweets_EEVV_geo)
## [1] 351

Delimitamos los bordes externos del boundinbox

bbox <- c(min(tweets_EEVV_geo$lon),
          min(tweets_EEVV_geo$lat),
          max(tweets_EEVV_geo$lon),
          max(tweets_EEVV_geo$lat))
require(leaflet)
gama <- colorNumeric(palette = "plasma",
                        domain = tweets_EEVV_geo$followers_count)
leaflet(tweets_EEVV_geo) %>% 
    addTiles() %>% 
    addCircleMarkers(popup = ~text,
                     color = ~gama(followers_count)) %>% 
    addLegend(title = "Popularidad", pal = gama, values = ~followers_count)
## Assuming "lon" and "lat" are longitude and latitude, respectively

El tweet del usuario mas popular, un runner que nos regala la siguiente postal desde el Parque 3 de Febrero: "Pasadas en la mañana de Palermo. Los días no pueden ser más lindos, espectacular el cielo del Parque. Mi gente a pleno. Tarea cumplida. #skechersargentina #correrayuda #correrparavivir… https://t.co/ps4Bn7VysJ"