-
Notifications
You must be signed in to change notification settings - Fork 2
/
04-redes_sociales.Rmd
559 lines (361 loc) · 27 KB
/
04-redes_sociales.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
# Obteniendo y analizando datos de redes sociales
## Investigando con social media
Los contenidos generados en las redes sociales son producidos y recopilados por usuarios individuales (o representeantes de organizaciones) que participan en plataformas de acceso público tales como Twitter, Facebook, o Instagram. Si bien esas tres son las más populares, existen muchísimas otras plataformas que funcionan como repositorios de información online, como Yelp (reseñas de restoranes) o Properati (listados de propiedades en venta y alquiler), entre tantos otros.
La información producida en redes sociales llama la atención de investigadores en temas sociales por el nivel de detalle que encierra. Los usuarios registran y transmiten en forma pública un amplio abanico de datos personales: su paradero, estado de ánimo, intenciones futuras, etc. Es por eso que la "minería" de datos capturados _online_ se utiliza para estudiar procesos sociales, políticos, y hasta meteorológicos (monitoreando menciones a eventos climáticos).
### Los desafíos de trabajar con información de repositorios sociales
Por supuesto, no todo son ventajas. El análisis de datos extraidos de redes sociales se enfrenta a varios obstáculos, entre ellos:
* __"Suciedad" de los datos__. Los contenidos publicados en redes sociales suelen combinar texto, imágenes y video, lo cual requiere un esfuerzo considerable para identificar y clasificar los tipos de contenido disponibles. Incluso el contenido más fácil de tratar, el texto, requiere de limpieza previa: hay que lidiar con abreviaciones, emojis, puntuación inusual, etc.
* __Inconsistencia__. Los regisros capturados desde repositorios online suelen ser inconsistentes: Muchas veces, uno o más de los valores de sus atributos (tales como "usario", "mensaje", "idioma", etc) faltan en muchos de los registros. Por ejemplo, algunos contienen coordenadas espaciales que permiten ubicarlos en el espacio, pero en muchos casos no están georreferenciados. Eso dificulta saber dónde está siendo producida la información, desde donde se emite.
* __Sesgo y veracidad dudosa__. Al analizar los datos, es tentador realizar inferencias acerca de lo que la población en general hace o quiere. Pero hay que tener en cuenta que las personas que producen contenidos online son un grupo particular, que tiende a ser más joven y de nivel socioeconómico mayor a la media. Por otra parte, que algo se haya dicho online dista mucho de ser cierto o sincero. Ni siquiera podemos asumir que los usuarios son individuos humanos; las redes sociales son utilizadas en creciente medida por "bots", software automático que publica contenidos en gran volumen simulando ser una persona, o un grupo de personas, con el fin de manipular la opinión pública.
* __Volumen__. Cuando uno decide acumular los datos que obtiene de redes sociales, durante meses o años, el volumen alcanzado no es trivial. Resguardar, ordenar, clasificar y extraer sentido de decenas o centenas de millones de registros es un desafío de _big data_.
* __Limitaciones de acceso__: Las empresas que controlan los repositorios de datos producidos en redes sociales vigilan con cuidado a quienes acceden, y limitan la cantidad de información que puede extraerse. En el caso de Twitter, las consultas permitidas a su base de datos se limitan al contenido producido en la última semana, y no entrega más de 18,000 tweets por consulta.
## Conectando R a Twitter
Para acceder a los sistemas de Twitter necesitamos obtener una autorización, identificándonos con nuestro usuario en la red. Este paso es inevitable, ya que sin una autorización Twitter no responderá nuestras consultas. Por suerte, el trámite para obtener acceso es inmediato, y como resultado obtendremos una serie de códigos de identificación, conocidos en su conjunto como _API keys_.
### Obteniendo autorización
El primer paso es, si no lo hemos hecho aún, crear un usuario de Twitter en https://twitter.com/signup. Luego seguimos los pasos de éste instructivo https://towardsdatascience.com/access-data-from-twitter-api-using-r-and-or-python-b8ac342d3efe. Nota: Twitter nos preguntará cómo se llama la "app" para la cual estamos solicitand acceso. No vamos a crear ninguna app, pero aún así tenemos que elegir un nombre; usemos "RTWEET" (aunque podría ser cualquier otro). Al completar los pasos estaremos en poder de cuatro códigos: _Consumer Key_, _Consumer Secret_, _Access Token_ y _Access Token Secret_. Tomemos nota de ellos.
### Acceso a Twitter via R: el paquete _rtweet_
`rtweet` provee un conjunto de funciones que nos facilitan interactuar con Twitter. Si no lo tenemos instalado, lo conseguimos vía:
```{r eval=FALSE}
install.packages("rtweet")
```
Y lo activamos junto al resto de los paquetes que vamos a usar.
```{r}
library(rtweet)
library(tidyverse)
```
A continuación, le pasamos a `rtweet` los datos de autorización que conseguimos antes para crear un "token" (en la jerga de Twitter, es una especie de comprobante de que estamos autorizados a acceder a los datos)
```{r eval=FALSE}
# El nombre que le asgnamos a la app en el formulario de autorización
appname <- "RTWEET"
## consumer key (en el ejemplo no es una clave real, usar la verdadera)
consumer_key <- "la_secuencia_de_caracteres_de_nuestra_consumer_key"
## consumer secret (en el ejemplo no es un clave real, usar la verdadera)
consumer_secret <- "la_secuencia_de_caracteres_de_nuestra_consumer_secret"
## consumer key (en el ejemplo no es una clave real, usar la verdadera)
access_token <- "la_secuencia_de_caracteres_de_nuestro_access_token"
## consumer secret (en el ejemplo no es un clave real, usar la verdadera)
access_secret <- "la_secuencia_de_caracteres_de_nuestro_access_secret"
twitter_token <- create_token(
app = appname,
consumer_key = consumer_key,
consumer_secret = consumer_secret,
access_token = access_token,
access_secret = access_secret)
```
Al ejecutar esas líneas se abrirá una ventana en nuestro navegador solicitando autorizar el acceso vía R -lo aceptamos, por supuesto.
Ahora si, estamos listos para realizar consultas en el archivo de Twitter. La función `search_tweets()` permite obtener tweets que cumplan los requisitos que fijemos. Por ejemplo, para buscar tweets que contienen el término "inflacion", usamos:
```{r eval=FALSE}
tweets <- search_tweets(q = "inflacion", n = 3000)
```
```{r echo=FALSE}
tweets <- readRDS("data/tweets_inflacion.RDS")
```
El parámetro n = 3000 es para limitar la búsqueda a los primeros 3000 tweets hallados.
También puede hacerse una búsqueda por múltiples términos. Por ejemplo, buscando "ciudad+universitaria" hace que Twitter devuelva resultados donde las palabras aparecen juntas y en ese orden; como alternativa, al optar por "ciudad universitaria" se obtienen tweets donde aparezcan esas palabras en cualquier parte del texto, sin importar su orden o si aparecen contiguas.
El resultado es un dataframe de 3000 observaciones -el número máximo que habíamos solicitado- y 88 columnas. `rtweet` incluye `users_data()`, una función que muestra detalles de los usuarios que han producido los tweets que capturamos:
```{r}
users_data(tweets) %>% head()
```
También podemos explorar los resultados en base a las 88 variables disponibles. Revisemos los nombres:
```{r}
names(tweets)
```
Allí hay de todo para explorar.
### Usuarios más populares
Según la cantidad de seguidores:
```{r}
options(scipen = 20)
ggplot(tweets) +
geom_histogram(aes(x = followers_count))
```
El gráfico muestra una distribución de ["power law"](https://es.wikipedia.org/wiki/Ley_potencial), típica en los rankings de popularidad. Hay una enorme masa de usuarios con popularidad mínima (apenas un puñado de seguidores) y un número muy pequeño de usuarios que alcanza una cantidad deseguidores cientos o miles de veces superior a la de la mayoría.
Obtenemos un top 5 de los usuarios más populares (con más seguidores), su procedencia, y el contenido del tweet:
```{r}
tweets %>%
top_n(5, followers_count) %>%
arrange(desc(followers_count)) %>%
select(screen_name, followers_count, location, text)
```
### Tweets más populares
En base a la cantidad de retweets que recibieron. Nos quedamos sólo con los tweets originales, descartando los que son retweets en si mismos ("is_retweet == TRUE"), y revisamos la distribución de sus retweets:
```{r}
ggplot(filter(tweets, !is_retweet))+
geom_histogram(aes(x = retweet_count))
```
Otra ditribución _power law_. Identifiquemos el tweet original más que sumó más retweets:
```{r}
tweets %>%
filter(!is_retweet) %>%
filter(retweet_count == max(retweet_count)) %>%
select(screen_name, retweet_count, followers_count, location, text)
```
Nota: Si no estamos interesados en capturar retweets, podemos evitarlos al momento de consultar la base de Twitter, as'i `tweets <- search_tweets(q = "inflacion", n = 500, include_rts = FALSE)`
### La hora del día a la que se producen los tweets
`rtweet()` provee una funció que hace facil mostrar la evolución temporal de nuestros tweets: `ts_plot()`. Podemos ver la frecuencia de tweets por segundo, hora, día, semana, mes o año eligiendo el parámetro correspondiente ("seconds", "minutes", "hours", "days", "weeks", "months", o "years")
```{r}
ts_plot(tweets, "minutes")
```
### Procedencia de los usuarios
```{r}
tweets %>%
ggplot() +
geom_bar(aes(location)) +
coord_flip() +
labs(title = "Procedencia de los usuarios",
x = "cantidad",
y = "ubicación")
```
Dado que el campo "location" refleja el texto que cada usuario eligió para describir su ubicación (no se trata de las coordenadas de origen del tweet) las variabilidad es grande. Algunas escriben su país, otros su ciudad, otras su barrio... y hay quienes eligen opciones poéticas cómo "algún lugar del mundo". En todo caso, la abundancia de opciones resulta en un gráfico muy difícil de leer.
Probamos extraer el top 10 de lugares más frecuentes, eliminando los tweets de usuarios sin datos en su atributo "location".
```{r}
tweets %>%
filter(location != "", !is.na(location)) %>%
count(location) %>%
top_n(10, n) %>%
ggplot() +
geom_col(aes(x = reorder(location, n), y = n)) +
coord_flip() +
labs(title = "Procedencia de los usuarios",
x = "ubicación",
y = "cantidad")
```
## Escuchando tweets en tiempo real
Como alternativa a consultar el archivo "histórico" de Twitter, es posible conectar a su API de streaming, que entrega tweets en tiempo real al instante en que se producen. La función `stream_tweets()` permite iniciar una conexión y capturar tweets hasta que concluya el tiempo dispuesto por el parámetro "timeout", expresado en segundos.
Por ejemplo, para "escuchar" el stream de Twitter por un minuto (60 segundos), y capturar mensajes que incluyan los términos _accidente_ y _tránsito_:
```{r eval=FALSE}
captura_streaming <- stream_tweets(q = "accidente+tránsito", timeout = 60)
```
```{r echo=FALSE}
captura_streaming <- readRDS("data/tweets_streaming.RDS")
```
Verificamos el resultado (sólo los campos de usuario y texto del tweet):
```{r}
captura_streaming[4:5]
```
## Capturando tweets por períodos prolongados
Cuando queremos monitorear un evento de actualidad, por ejemplo capturando tweets que mencionen una palabra o hashtag de interés, resulta necesario mantener las escucha activa durante varias horas o días. La solución para este caso es usar la función `stream_tweets()`, que permite iniciar un proceso de escucha de tiempo arbitrario. Dado que no se sabe que puede fallar en un proceso que dura varios días, la función se encarga de guardar los resultados en un archivo local a medida que se obtienen, y reiniciar la conexión a Twitter en forma automática si se interrumpe por algún motivo (como un corte momentáneo de acceso a internet).
La usamos así:
```{r eval=FALSE}
terminos_de_busqueda <- "accidente + tránsito"
# una semana: 60 segundos * 60 * 24 * 7
tiempo <- 60 * 60 * 24 * 7
# El archivo donde guardar los resultados en disco (tendrá formato json, así que lo usamos en el nombre de archivo)
archivo <- "busqueda_tweets.json"
stream_tweets(q = terminos_de_busqueda,
timeout = tiempo,
file_name = archivo,
parse = FALSE)
```
Una vez que el período de captura termina, podemos leer el archivo generado.
```{r eval=FALSE}
# en el paso anterior definimos que el nombre de archivo es "busqueda_tweets_DT_VP.json"
tweets <- parse_stream("busqueda_tweets.json")
```
Y con eso concluye el proceso. Ya estamos listos para analizar el contenido.
## Capturando tweets en zonas específicas
Imaginemos ahora que queremos obtener tweets originados en un lugar en particular. En un barrio, una ciudad, o un país. Para ello podemos aprovechar que Twitter permite realizar búsquedas por área geográfica.
Por ejemeplo, iniciemos la descarga de tweets que mencionen el nombre que se le da en Buenos Aires al metro: "subte". La clave está en que además de los términos de búsqueda vamos a especificar un radio de 20 millas (~32 km) en torno al área céntrica (el _downtown_) de la Ciudad:
```{r eval=FALSE}
tweets_transporte <- search_tweets(q = "subte",
geocode = "-34.603722,-58.381592,20mi",
include_rts = FALSE,
n = 100000,
retryonratelimit = TRUE)
```
```{r echo=FALSE}
tweets_transporte <- readRDS("data/tweets_transporte.RDS")
```
El proceso puede tomar un rato. Quien no pueda esperar, puede descargar unos resultados obtenidos previamente:
```{r eval=FALSE}
tweets_transporte <- readRDS(url("https://bitsandbricks.github.io/data/tweets_transporte.RDS"))
```
### Extraer las coordenadas
Algunos de los tweets, aquellos que fueron publicados desde un teléfono móvil u otro dispositivo con GPS, tienen coordenadas de posición precisas (latitud y longitud). El dataframe creado por `rtweet` guarda la pareja de coordenadas em el campo "coords_coords", dentro de una lista. Es decir que en lugar de un valor simple, cada elemento de la columna contiene una lista de varios valores. De manera similar, también crea otras dos columnas, "geo_coords" y "bbox_coords" que contienen datos sobre la ubicación del tweet en forma de lista.
Esto trae dos problemas:
* No podemos usar los verbos de manipulación de datos con esas columnas (filter, mutate, arrange, etc) porque están diseñados para trabajar con valores atómicos, como "hola" y no listas, como ("hola", "chau", "sin datos").
* No podemos guardar el dataframe en formato .csv, el favorito de los que comparten datos, porque no hay forma estandarizada de indicar que algunos campos contienen una lista de datos en lugar de un valor único. `write.csv` y `write_csv` intentan guardar el dataframe en un archivo .csv, pero fallan al encontrar la primera columna que contiene listas.
La solución es simple: usamos la función `lat_lng()`, que agrega al dataframe dos columnas adicionales llamadas "lat" y "lng", conteniendo latitud y longitud para los tweets que traen posición exacta.
```{r}
tweets_transporte <- lat_lng(tweets_transporte)
```
Además, si quisiéramos guardar luego los datos en formato _.csv_, podemos descartar los campos problemáticos -los que contienen información geográfica en forma de listas-. La función `select()` nos permite retirarlos:
```{r}
tweets_transporte <- tweets_transporte %>%
select(-geo_coords, -coords_coords, -bbox_coords)
```
Para trabajar con los tweets georefernciados como un conjunto aparte, filtramos nuestra base para conservar sólo los mensajes que contienen coordenadas exactas de posición.
```{r}
tweets_transporte_geo <- tweets_transporte %>%
filter(!is.na(lat), !is.na(lng))
```
El resultado evidencia que los tweets georeferenciados son sólo una fracción del total que se produce:
```{r}
nrow(tweets_transporte_geo)
```
A continuación: ¡veamos los tweets en el mapa!
## Visualizando los datos georeferenciados
### Mapas estáticos con ggmap
`ggmap` es un paquete de R que complementa a ggplot, agregando funciones que permiten adquirir y visualizar mapas en forma fácil.
Si no lo tenemos instalado, ya sabemos que hacer:
```{r eval=FALSE}
install.packages("ggmap")
```
Lo activamos:
```{r}
library(ggmap)
```
Ahora, para obtener un mapa base del área donde se encuentran los puntos que queremos mostrar, necesitamos determinar la "bounding box": el rango de latitud y longitud que forma un rectángulo conteniendo todas las posiciones. En resumidas cuentas, se trata de los valores de latitud máxima y mínima, y de longitud máxima y mínima.
Los proveedores de mapas online suelen solicitar los valores en este orden: izquierda, abajo, derecha, arriba. Es decir, posición mas al oeste, posición mas al sur, posición mas al este, posición mas al norte.
Cuando disponemos de un dataframe con columnas de latitud y longitud, obtener la _bounding box_ es bastante fácil:
```{r}
bbox <- make_bbox(lon = tweets_transporte_geo$lng, lat = tweets_transporte_geo$lat)
bbox
```
Con eso podemos descargar un mapa del área. Como opción por defecto, `ggmap` solicita los mapas a Google Maps, pero esta ha dejado de ser la alternativa ideal: desde octubre de 2018, Google exige a los usarios registrarse y proveer una tarjeta de crédito para descargar información mediante porgramas propios. Por eso vamos a usar otra de las fuentes habilitadas por `ggmap`, el servicio de mapas de [Stamen Design](http://maps.stamen.com).
Lo descargamos entregando la bounding box del área que nos interesa y un nivel de zoom. El nivel de zoom -un número de 1 a 20- indica el detalle que tendrá el mapa descargado. Para un área metropolitana un zoom de entre 10 y 12 es adecuado.
```{r cache=TRUE}
mimapa <- get_stamenmap(bbox, zoom = 11)
```
Para ver el resultado usamos `ggmap()`:
```{r}
ggmap(mimapa)
```
Stamen ofrece varios estilos de mapa: "terrain" (usado por defecto), "terrain-background", "terrain-labels", "terrain-lines", "toner", "toner-2010", "toner-2011", "toner-background", "toner-hybrid", "toner-labels", "toner-lines",
"toner-lite", "watercolor".
Probemos algunos:
```{r cache=TRUE}
mimapa_terrain_lines <- get_stamenmap(bbox, maptype = "terrain-lines", zoom = 11)
mimapa_toner_lite <- get_stamenmap(bbox, maptype = "toner-lite", zoom = 11)
mimapa_watercolor <- get_stamenmap(bbox, maptype = "watercolor", zoom = 11)
ggmap(mimapa_terrain_lines)
ggmap(mimapa_toner_lite)
ggmap(mimapa_watercolor)
```
Cuando descargamos un mapa que vamos a usar de base para visualizar datos, siempre es una buena idea elegir una opción en escala de grises, sin colores que compitan contra los datos que proyectaremos. Probamos entonces con "toner-lite" para el mapa que usaremos de aqui en adelante.
```{r cache=TRUE}
mapa_BA <- get_stamenmap(bbox, maptype = "toner-lite", zoom = 11)
ggmap(mapa_BA)
```
Ahora agregamos capas de puntos mostrando la posición de los tweets. La sintaxis es la misma que aprendimos para `ggplot`; de hecho, `ggmap` es una llamada a `ggplot` que tras bambalinas se encarga de los ajustes necesarios para mostrar el mapa como fondo. Habiendo revisado la data de Moreno, sabemos que las columnas de longitud y latitud de los puntos georeferenciados se llaman "lon" y "lat". Al graficar los puntos, las usaremos como posición x e y respectivamente.
```{r}
ggmap(mapa_BA) +
geom_point(data = tweets_transporte_geo, aes(x = lng, y = lat))
```
También podemos asignar a cada punto un color de acuerdo a la popularidad del usuario:
```{r}
ggmap(mapa_BA) +
geom_point(data = tweets_transporte_geo,
aes(x = lng, y = lat, color = followers_count)) +
scale_color_distiller(palette = "Spectral")
```
¿Qué pasó aquí? Tenemos un escala de colores que llega hasta 600.000, en el tono rojo, pero en el mapa solo vemos puntos azules, los que indican una cantidad baja de seguidores. La explicación está en la relativa rareza de usuarios de Twitter con cientos de miles de seguidores. Dado que la inmensa mayoría de usuarios de la red sólo tienen un puñado de seguidores, ocurre que puntitos que los representan suelen tapar a los esporádicos usuarios ultra populares. Si lo que queremos es mostrar los tweets de éstos últimos, podemos recurrir a un pequeño truco. Dado que las filas de un data frame se grafican en orden, si ordenamos las observaciones en orden creciente de "followers_count" los usuarios populares serán graficados al final, garantizando que su color aparezca por encima de otros.
```{r}
tweets_transporte_geo <- arrange(tweets_transporte_geo, followers_count)
ggmap(mapa_BA) +
geom_point(data = tweets_transporte_geo,
aes(x = lng, y = lat, color = followers_count)) +
scale_color_distiller(palette = "Spectral")
```
Tambien podemos usar el tamaño de cada punto para representar la repercusión de los tweets, en base a la cantidad de "retweets" que han obtenido:
```{r}
ggmap(mapa_BA) +
geom_point(data = tweets_transporte_geo,
aes(x = lng, y = lat, color = followers_count, size = retweet_count),
alpha = .5) +
scale_color_distiller(palette = "Spectral")
```
### Mapas interactivos con leaflet
Con la explosión de de popularidad de los mapas online, con Google Maps al frente, se ha vuelto habitual explorar información geográfica en entornos interactivos, que permiten al usuario desplazarse libremente por la superficie terrestre y cambiar el nivel de zoom con el que se muestran los datos. Un mapa con información tan precisa como la posición de los tweets, que incluso permite ver a parcela desde donde se han emitido, se beneficia en extremo de la posibilidad de variar la escala de visualización a voluntad.
Desde R es fácil proyectar nuestros datos sobre mapas interactivos, usando el paquete `leaflet`. Si aún no lo tenemos en nuestro sistema, lo obtenemos mediante:
```{r eval=FALSE}
install.packages("leaflet")
```
Una vez que está instalado, lo activamos
```{r}
library(leaflet)
```
EL uso de leaflet es similar al de `ggplot`; uno toma un dataframe y lo muestra mediante capas que exponen distintos aspectos de la información. Para empezar, hacemos
```{r}
leaflet(tweets_transporte_geo)
```
... y no obtuvimos mucho. Tal como pasa con `ggplot()`, si uno no define ninguna capa de visualización, el resultado es una especie de lienzo vacío.
Siguiente paso: agregar un mapa base. Para sumar capas a un mapa de `leaflet` usamos " %>% " en ugar del " + " que requiere `ggplot()`, pero el concepto es el mismo.
```{r eval=FALSE}
leaflet(tweets_transporte_geo) %>%
addTiles()
```
```{r echo=FALSE}
leaflet(tweets_transporte_geo) %>%
addProviderTiles(providers$OpenStreetMap)
```
Ahora está un poco mejor, nos encontramos con un mapa, pero falta que aparezcan nustros datos. Es fácil: con `addMarkers()` leaflet se encarga de buscar las coordenadas de cada observación, y si aparecen con algún nombre esperable, las identifica y sitúa en el mapa un pin por cada una.
Nombres esperables serían "latitude" y "longitude" o también, como en nuestro caso, "lat" y "lng". Si las coordenadas aparecieran bajo columnas con nombres menos interpretables, se le puede aclarar a `leaflet` cuáles son vía paramétros.
```{r eval=FALSE}
leaflet(tweets_transporte_geo) %>%
addTiles() %>%
addMarkers()
```
```{r echo=FALSE}
leaflet(tweets_transporte_geo) %>%
addProviderTiles(providers$OpenStreetMap) %>%
addMarkers()
```
Ya tenemos un mapa útil! Para mejorarlo, agregamos la opción de "popup", que permite extraer información adicional cliqueando sobre un pin. Por ejemplo, el contenido del campo con el texto de cada tweet (nótese el uso de "~", que leaflet requiere para entender que nos referimos a un campo presente en el dataframe que le pasamos).
```{r eval=FALSE}
leaflet(tweets_transporte_geo) %>%
addTiles() %>%
addMarkers(popup = ~text)
```
```{r echo=FALSE}
leaflet(tweets_transporte_geo) %>%
addProviderTiles(providers$OpenStreetMap) %>%
addMarkers(popup = ~text)
```
Para sumar una dimensión más a la visualización, podemos usar el color para indicar la cantidad de seguidores del autor de cada tweet. Para codificar por color, `leaflet` requiere definir una paleta de colores para aplicar a nuestros datos. Al crear una paleta debemos elegir la función correspondiente al tipo de datos que vamos a mostrar: `colorFactor()` para variables categóricas, `colorNumeric()` para variabes numéricas, o `colorQuantile()` también para variables numéricas, pero agrupadas en cuantiles. La función requiere al menos dos parámetros. Uno es "palette", para definir los tonos a usar. Aquí funcionan nuestros amigos _viridis_, _magma_, _plasma_ e _inferno_, y también las [paletas Brewer](https://data.library.virginia.edu/files/pal_fig_3.png), como _"Spectral_ o _Accent_). El parametro restante es "domain", que simplemente toma un vector con los datos que vamos a representar con la paleta.
Como la cantidad de seguidores es una variable numérica, podemos usar:
```{r}
paleta <- colorNumeric(
palette = "viridis",
domain = tweets_transporte_geo$followers_count)
```
Y luego la usamos en nuestro mapa:
```{r eval=FALSE}
leaflet(tweets_transporte_geo) %>%
addTiles() %>%
addCircleMarkers(popup = ~text,
color = ~paleta(followers_count))
```
```{r echo=FALSE}
leaflet(tweets_transporte_geo) %>%
addProviderTiles(providers$OpenStreetMap) %>%
addCircleMarkers(radius = ~retweet_count,
popup = ~text,
color = ~paleta(followers_count))
```
Como siempre es muy util agregar una leyenda que explique la codificación de los datos. `leaflet` sólo permite mostrar leyendas basadas en color (no en el diamétro de los círculos), pero algo es algo. Agregamos la leyenda así:
```{r eval=FALSE}
leaflet(tweets_transporte_geo) %>%
addTiles() %>%
addCircleMarkers(radius = ~retweet_count,
popup = ~text,
color = ~paleta(followers_count)) %>%
addLegend(title = "seguidores", pal = paleta, values = ~followers_count)
```
```{r ultimo_chunk_redes_sociales, echo=FALSE}
leaflet(tweets_transporte_geo) %>%
addProviderTiles(providers$OpenStreetMap) %>%
addCircleMarkers(radius = ~retweet_count,
popup = ~text,
color = ~paleta(followers_count)) %>%
addLegend(title = "seguidores", pal = paleta, values = ~followers_count)
```
Esto es sólo una introducción a la producción de mapas interactivos.
Para acceder a un recorrido por muchas otras opciones disponibles con `leaflet`, podemos visitar https://rstudio.github.io/leaflet/
## Ejercicios
**Capturando y explorando datos de Twitter**
I. Descargar tweets que se originen en los alrededores de la Ciudad con la que trabajaron en los capítulos anteriores, y explorar las columnas/variables que contiene.
II. Analizar:
a. ¿Cuáles son los mensajes con más repercusión? ¿Qué dicen?
b. ¿En qué momento del día se realiza la mayor cantidad de tweets? Graficar.
c. ¿Cómo se distribuye la popularidad de los usuarios? ¿Quiénes son los 5 que más seguidores tienen? Graficar.
d. Aislando 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.