La visualización y uso de análisis exploratorios en R es una herramienta importante para la generación de información, pero es raro que obtenga los datos exactamente en la forma correcta que necesita. A menudo deberá crear algunas variables o resúmenes nuevos, o tal vez solo desea cambiar el nombre de las variables o reordenar las observaciones en para que sea un poco más fácil trabajar con los datos. Aprenderás cómo hacer todo eso (¡y más!) en este capítulo, que le enseñará cómo para transformar sus datos usando el paquete dplyr
. Pero antes deberemos aprender a unir las bases de datos con la función merge()
.
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
En la sesión anterior estuvimos trabajando con una base de datos de fútbol. El día de hoy trabajaremos con dos bases de datos, todas ellas con información de la empresa AirBnB. Airbnb es una compañía que ofrece una plataforma digital dedicada a la oferta de alojamientos a particulares y turísticos (alquiler vacacional) mediante la cual los anfitriones pueden publicitar y contratar el arriendo de sus propiedades con sus huéspedes; anfitriones y huéspedes pueden valorarse mutuamente, como referencia para futuros usuarios.En esta ocasión tenemos los datos de los alojamientos de la ciudad de Barcelona (España) durante el año 2019. Estos datos se encuentran fragmentados en dos bases diferentes, la primera sobre la ubicación del sitio (Clase 3-1) y la siguiente con la información del alojamiento y sus valoraciones (Clase 3-2)
setwd("C:/Users/Andres Acero/Dropbox/Politécnico/Curso R")
data1 <- read.csv("Clase 3-1.csv")
data2 <- read.csv("Clase 3-2.csv")
Clase 3-1: https://www.dropbox.com/s/k3ilhjyia0lvd55/Clase%203-1.csv?dl=0
Clase 3-2: https://www.dropbox.com/s/fi39f6jpv62z5jm/Clase%203-2.csv?dl=0
Una vez hemos cargado las bases de datos nos damos cuenta que tienen una cantidad desigual de datos:
dim(data1)
## [1] 10367 6
dim(data2)
## [1] 11279 10
Por tanto, no podemos hacer operaciones directamente sobre los datos. Por tanto, lo primero es crear una base de datos conjunta usando la función merge()
Para muchos de ustedes debe ser muy común hacer cruces de bases de datos que se hace con lenguajes como SQL. El comando JOIN
es una herramienta muy poderosa que presenta diferentes opciones con las cuales cruzar dos o más tablas. R ha definido una serie de comandos que tratan de “emular” el comportamiento. La función merge()
permite fusionar o unir dos data frames por columnas comunes o por nombres de fila. Esta función permite realizar diferentes combinaciones de bases de datos (SQL), como unión izquierda (left join), unión interna (inner join), unión derecha (right join) o unión completa (full join), entre otras. Iremos probando estas operaciones con nuestras bases de datos de AirBnB.
Un inner join (en realidad un natural join), es la unión de conjuntos de datos más habitual que se puede realizar. Consiste en fusionar dos data frames en uno que contenga los elementos comunes de ambos, como se describe en la siguiente ilustración:
Figura 1: Inner Join
Para fusionar o unir los dos conjuntos de datos de muestra, solo tienes que pasarlos a la función merge, sin la necesidad de cambiar otros argumentos, debido a que, de manera predeterminada, la función combina los conjuntos de datos por los nombres de las columnas comunes. En consecuencia, en este caso, la función fusiona los datos por las primera columnas, id
y host_id
:
data3 <-merge(x=data1, y=data2)
Como podrán notar, en la intersección de las dos bases de datos, que tenemos 8459 lugares. Si queremos la información completa de los lugares, esta es la mejor opción. Por otro lado, si queremos asegurarnos que sea por estas variables podemos modificar la función merge()
:
data3 <- merge(x=data1, y=data2, by=c("id","host_id"))
¿En qué casos de ustedes se les ocurre que les podría servir esta función?
Pero ¿qué pasa si queremos tener las bases de datos completos? En muchas ocasiones tener una gran cantidad de datos ayudan aunque estén incompleto, por lo que un full (outer) join es muy útil. El outer join, o unión completa, combina todas las columnas de ambos conjuntos de datos en uno para todos los elementos
Figura 2: Full Join
Para realizar esta actividad usaremos el parámetro all
hacia TRUE, como lo ven a continuación:
data3 <- merge(x=data1, y=data2, all = TRUE)
Como podrán notar, en la unión de las dos bases de datos tenemos 13187 lugares.Ahora, si revisamos los datos veremos que tenemos ahora datos en NA
, por lo que esto podría ser problemático para analizar los datos:
unique(data3$room_type)
## [1] "Entire home/apt" "Private room" "Shared room" NA
## [5] ""
¿En qué casos de ustedes se les ocurre que les podría servir esta función?
Ahora, pensemos que necesitamos preservar la información de las ubicaciones de los alojamientos pero la otra información no es tan importante. Para eso podremos conservar toda la información de la base de datos en el lado izquierdo y solamente la información que coincida en la base de datos en el lado derecho. Por tanto, El left join en R consiste en unir todas las filas del primer data frame con los valores correspodientes del segundo.
Figura 3: Left Join
Para realizar esta actividad usaremos el parámetro all.x
hacia TRUE, como lo ven a continuación:
data3 <- merge(x=data1, y=data2, all.x = TRUE)
Como podrán notar, esta función genera la misma cantidad de posiciones que data1 (izquierdo). Al igual que el método anterior, este método llena los espacios vacíos con N/A, los cuales son problemáticos:
unique(data3$room_type)
## [1] "Entire home/apt" "Private room" "Shared room" NA
## [5] ""
¿En qué casos de ustedes se les ocurre que les podría servir esta función?
¿Y si necesitamos lo contrario?, es decir, que queremos conservar la información completa del lado derecho. El right join en R es lo opuesto al left join. En este caso, la combinación consiste en unir todas las filas del segundo data frame con las correspondientes en el primero.
Figura 4: Right Join
Para realizar esta actividad usaremos el parámetro all.y
hacia TRUE, como lo ven a continuación:
data3 <- merge(x=data1, y=data2, all.y = TRUE)
Como podrán notar, esta función genera la misma cantidad de posiciones que data2 (derecho). Al igual que el método anterior, este método llena los espacios vacíos con N/A, los cuales son problemáticos:
unique(data3$neighbourhood_group)
## [1] "Sant Martí" "Eixample" "Gràcia"
## [4] "Horta-Guinardó" "Les Corts" "Ciutat Vella"
## [7] "Sants-Montjuïc" "Sarrià-Sant Gervasi" NA
## [10] "Sant Andreu" "Nou Barris"
¿En qué casos de ustedes se les ocurre que les podría servir esta función?
La última opción para hacer el cruce de la base de datos es poner cada posible combinación de datos. El cross join o unión cruzada, realiza el producto cartesiano de los conjuntos de datos. En matemáticas, el producto cartesiano de dos conjuntos es una operación, que resulta en otro conjunto, cuyos elementos son todos los pares ordenados que pueden formarse de forma que el primer elemento del par ordenado pertenezca al primer conjunto y el segundo elemento pertenezca al segundo conjunto.
Figura 5: Cross Join
Para realizar esta actividad usaremos el parámetro By
hacia NULL, como lo ven a continuación:
data3 <- merge(x=data1[1:10,], y=data2, by= NULL[1:10,])
Este proceso, dada la cantidad de operaciones, se demora una cantidad considerable de tiempo y crea un archivo con demasiadas filas (por lo que se limita el tamaño del ejemplo).
¿En qué casos de ustedes se les ocurre que les podría servir esta función?
En el caso de requerir unir más de una base de datos, podemos usar un proceso iterativo o anidado como podrán ver acá:
data3 <- merge(x=data1[1:100,], merge(x=data1[100:500,],y=data2, all=TRUE), all.x = TRUE)
Una vez hemos aprendido cómo unir las bases de datos, los reto a que me den la respuesta a las siguientes preguntas:
Realice las siguientes operaciones con el archivo “Clase 3-2.csv”
Indique el valor promedio de las habitaciones de Barcelona
¿El número de noches se comporta como una distribución normal? (Solamente utilice la gráfica)
¿Existe una relación entre las revisiones por mes y la disponibilidad por año?
Realice las mismas operaciones con una nueva base de datos que incluya ambos archivos usando Inner Join
En muchas ocasiones la información que obtenemos puede tener vacíos en algunas posiciones, estar ordenada de forma poco práctica o contener más información de la que necesitamos. Con el fin de depurar la información disponible, ordenarla de forma adecuada para su procesamiento o agregar información adicional, podemos realizar una serie de operaciones.
Dplyr es una librería ampliamente usada en la transformación de datos dentro de R. Sus funciones destacadas incluyen:
Filtrar información de acuerdo a diferentes parámetros.
Reordenar, adicionar o eliminar las columnas de un arreglo.
Seleccionar información relevante y crear un arreglo secundario con dicha información.
Agrupar bases de datos
Las funciones que se verá a continuación trabajan de forma similar:
El primer argumento siempre será la lista que contiene la información.
Los siguientes argumentos describen que hacer con los datos.
El resultado de su uso es una nueva lista o data frame.
Imaginemos que tenemos la base de datos de la clase anterior. Muchas de las preguntas que se formularon necesitaban que se obtuvieran una serie de filtros sobre características específicas de la base de datos. Para ello utilizaremos la función Filter, una función que nos permite acortar la información que se muestra de una lista basándose en los valores que contiene. En los input correspondientes se debe nombrar la variable a filtrar y el valor que se desea. Sobre la base de datos conjunta (Inner Join) vamos a estar trabajando. Quisiera filtrar los datos para habitaciones privadas:
data3 <- merge(x=data1, y=data2)
data4 <- filter(data3, room_type == "Private room")
En casos especiales se desea filtrar pensando un grupo de parámetros para una misma variable. En dichos casos podemos usar operadores lógicos para agrupar dichas condiciones. Ahora quiero saber, adicionalmente, los que tengan más de 32 días de uso:
data4 <- filter(data3, room_type == "Private room" & minimum_nights > 32)
Las condiciones que podremos dar son las siguientes:
Figura 6: Operaciones relacionales
En algunas ocasiones la recolección de datos incluye campos que no fueron llenados. Al importar una base de datos con estos campos vacíos R los considera como “NA”. Cualquier operación que involucre un campo NA producirá un error y si operamos una base de datos sin depurar puede ser problemático.
is.na() nos provee una herramienta simple con la cual podemos localizar dichos campos durante el preprocesamiento de la información, permitiéndonos elegir que operación será la más adecuada.
Además, los operadores lógicos son:
Figura 7: Operaciones lógicos
¿Qué ejemplos se les ocurren a ustedes?
Al manejar grandes volúmenes de datos se hace poco práctico ordenar valores uno a uno, arrange()
nos permite crear una lista en la que los valores de las filas se ordenarán de acuerdo a los parámetros que suministremos. Si suministramos más de un parámetro a arrange()
, el orden se tomara como prioritario para los primeros parámetros que se suministren. Si yo quisiera organizar los datos por noches disponibles al año, el comando es el siguiente:
head(data3)
## id host_id neighbourhood_group neighbourhood
## 1 10003263 34111537 Sants-Montjuïc el Poble Sec
## 2 10005342 51395102 Ciutat Vella Sant Pere, Santa Caterina i la Ribera
## 3 10007287 383697 Sants-Montjuïc el Poble Sec
## 4 10008491 40676061 Eixample el Fort Pienc
## 5 10009651 51412210 Eixample la Nova Esquerra de l'Eixample
## 6 10009907 8876390 Ciutat Vella Sant Pere, Santa Caterina i la Ribera
## latitude longitude room_type price minimum_nights number_of_reviews
## 1 41.37116 2.16541 Entire home/apt 45 2 8
## 2 41.38608 2.17976 Entire home/apt 30 31 66
## 3 41.37433 2.16672 Private room 88 1 37
## 4 41.39707 2.18052 Private room 150 32 3
## 5 41.38325 2.14671 Entire home/apt 90 3 77
## 6 41.38958 2.17895 Entire home/apt 48 60 2
## last_review reviews_per_month calculated_host_listings_count availability_365
## 1 01/07/2016 0.22 1 0
## 2 10/03/2019 1.68 1 248
## 3 10/03/2019 0.98 16 227
## 4 31/01/2019 0.19 18 112
## 5 09/04/2019 1.93 1 95
## 6 30/06/2017 0.08 6 43
data4 <-arrange(data3, availability_365)
head(data4)
## id host_id neighbourhood_group neighbourhood
## 1 10003263 34111537 Sants-Montjuïc el Poble Sec
## 2 10018775 51446397 Gràcia la Vila de Gràcia
## 3 10085581 19060475 Eixample la Sagrada Família
## 4 10111416 19060475 Eixample la Sagrada Família
## 5 10120072 8251905 Ciutat Vella Sant Pere, Santa Caterina i la Ribera
## 6 10150711 52096900 Sant Martí el Camp de l'Arpa del Clot
## latitude longitude room_type price minimum_nights number_of_reviews
## 1 41.37116 2.16541 Entire home/apt 45 2 8
## 2 41.40058 2.15427 Private room 22 1 4
## 3 41.40954 2.17467 Private room 45 2 33
## 4 41.41079 2.17552 Entire home/apt 25 3 27
## 5 41.38482 2.17982 Private room 40 7 85
## 6 41.41076 2.18219 Private room 11 4 2
## last_review reviews_per_month calculated_host_listings_count availability_365
## 1 01/07/2016 0.22 1 0
## 2 20/05/2018 0.27 1 0
## 3 23/09/2017 0.83 2 0
## 4 23/09/2017 0.68 2 0
## 5 15/08/2018 2.13 1 0
## 6 27/03/2016 0.05 1 0
La función auxiliar para los parámetros que recibe arrange es desc()
para generar valores descendientes ya que lo ordena para valores ascendentes.
data4 <-arrange(data3, desc(availability_365))
head(data4)
## id host_id neighbourhood_group neighbourhood latitude
## 1 10034834 8848709 Sant Martí la Vila Olímpica del Poblenou 41.38795
## 2 10237654 8848709 Sant Martí la Vila Olímpica del Poblenou 41.38739
## 3 11975045 7414663 Sant Martí el Camp de l'Arpa del Clot 41.41122
## 4 12219001 45515449 Eixample la Dreta de l'Eixample 41.39520
## 5 12337767 14304404 Sant Andreu el Congrés i els Indians 41.42653
## 6 13345852 75620994 Les Corts les Corts 41.38788
## longitude room_type price minimum_nights number_of_reviews last_review
## 1 2.19836 Entire home/apt 450 2 7 27/07/2018
## 2 2.19864 Entire home/apt 295 1 1 29/05/2016
## 3 2.18108 Entire home/apt 189 15 5 31/10/2016
## 4 2.17354 Entire home/apt 60 30 1 31/08/2018
## 5 2.18026 Private room 39 1 1 27/06/2016
## 6 2.13748 Entire home/apt 85 32 2 02/11/2016
## reviews_per_month calculated_host_listings_count availability_365
## 1 0.18 8 365
## 2 0.03 8 365
## 3 0.14 38 365
## 4 0.13 2 365
## 5 0.03 2 365
## 6 0.06 13 365
¿Qué ejemplos se les ocurren a ustedes?
Algunas veces tenemos a nuestra disposición más información de la que es necesaria, en bases de datos donde contamos con muchas columnas puede ser un factor distractor si no contamos con la práctica suficiente. La función select()
nos permite extraer de las bases de datos la información necesaria, dicha información podrá ser almacenada en un nuevo arreglo. La primera versión es seleccionar algunas columnas
data4 <- select(data3, id, price, last_review)
head(data4)
## id price last_review
## 1 10003263 45 01/07/2016
## 2 10005342 30 10/03/2019
## 3 10007287 88 10/03/2019
## 4 10008491 150 31/01/2019
## 5 10009651 90 09/04/2019
## 6 10009907 48 30/06/2017
Si nuestra intención, por el contrario, es quitar alguna columna, lo que debemos hacer es poner un guión -
:
data4 <- select(data3, -host_id)
head(data4)
## id neighbourhood_group neighbourhood latitude
## 1 10003263 Sants-Montjuïc el Poble Sec 41.37116
## 2 10005342 Ciutat Vella Sant Pere, Santa Caterina i la Ribera 41.38608
## 3 10007287 Sants-Montjuïc el Poble Sec 41.37433
## 4 10008491 Eixample el Fort Pienc 41.39707
## 5 10009651 Eixample la Nova Esquerra de l'Eixample 41.38325
## 6 10009907 Ciutat Vella Sant Pere, Santa Caterina i la Ribera 41.38958
## longitude room_type price minimum_nights number_of_reviews last_review
## 1 2.16541 Entire home/apt 45 2 8 01/07/2016
## 2 2.17976 Entire home/apt 30 31 66 10/03/2019
## 3 2.16672 Private room 88 1 37 10/03/2019
## 4 2.18052 Private room 150 32 3 31/01/2019
## 5 2.14671 Entire home/apt 90 3 77 09/04/2019
## 6 2.17895 Entire home/apt 48 60 2 30/06/2017
## reviews_per_month calculated_host_listings_count availability_365
## 1 0.22 1 0
## 2 1.68 1 248
## 3 0.98 16 227
## 4 0.19 18 112
## 5 1.93 1 95
## 6 0.08 6 43
Y si queremos hacer de un punto al otro del arreglo, las podemos escoger usando el símbolo :
:
data4 <- select(data3, host_id:price)
head(data4)
## host_id neighbourhood_group neighbourhood latitude
## 1 34111537 Sants-Montjuïc el Poble Sec 41.37116
## 2 51395102 Ciutat Vella Sant Pere, Santa Caterina i la Ribera 41.38608
## 3 383697 Sants-Montjuïc el Poble Sec 41.37433
## 4 40676061 Eixample el Fort Pienc 41.39707
## 5 51412210 Eixample la Nova Esquerra de l'Eixample 41.38325
## 6 8876390 Ciutat Vella Sant Pere, Santa Caterina i la Ribera 41.38958
## longitude room_type price
## 1 2.16541 Entire home/apt 45
## 2 2.17976 Entire home/apt 30
## 3 2.16672 Private room 88
## 4 2.18052 Private room 150
## 5 2.14671 Entire home/apt 90
## 6 2.17895 Entire home/apt 48
Finalmente, también lo podemos hacer para eliminar un rango de columnas:
data4 <- select(data3, -(host_id:price))
head(data4)
## id minimum_nights number_of_reviews last_review reviews_per_month
## 1 10003263 2 8 01/07/2016 0.22
## 2 10005342 31 66 10/03/2019 1.68
## 3 10007287 1 37 10/03/2019 0.98
## 4 10008491 32 3 31/01/2019 0.19
## 5 10009651 3 77 09/04/2019 1.93
## 6 10009907 60 2 30/06/2017 0.08
## calculated_host_listings_count availability_365
## 1 1 0
## 2 1 248
## 3 16 227
## 4 18 112
## 5 1 95
## 6 6 43
¿Qué ejemplos se les ocurren a ustedes?
En algunas ocasiones debemos añadir valores nuevos a nuestras bases de datos, bien sea más información o el resultado de alguna operación. Con la función mutate()
podemos computar tranformaciones de variables en un data frame. A menudo, tendremos la necesidad de crear nuevas variables que se calculan a partir de variables existentes,mutate()
nos proporciona una interface clara para realizar este tipo de operaciones. Vamos a crear una variable del precio mínimo del lugar al multiplicar el precio por noche por la mínima cantidad de noches:
data4 <- mutate(data3, minPrice = price*minimum_nights)
summary(data4$minPrice)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.0 66.0 140.0 482.1 380.0 30000.0
Y ahora, ¿qué hago si yo quiero crear un nuevo dataframe que tenga el resumen de las variables? Sencillo, para eso existe el método summarise()
. Este método funciona de manera análoga que la función mutate()
, pero en lugar de crear una nueva columna con el cálculo que se realice lo que obtienes es el resultado de cada una de las operaciones en un nuevo dataframe. Así por ejemplo, ara calcular la media, mediana y la desviación estandar de la variable price
en el conjunto de datos:
data4 <- summarise(data3, media= mean(price), mediana=median(price), desviacion= sd(price))
data4
## media mediana desviacion
## 1 96.74914 60 187.2671
Todas las operaciones que vimos las clases anteriores y las que aprendieron en el curso anterior de R las podrán utilizar acá. Sin embargo, tener la información de toda la columna no parece tan interesante. Por tanto, existe otro método que nos ayudará con esta labor, group_by()
. Esta función agrupa un conjunto de filas seleccionado en un conjunto de filas de resumen de acuerdo con los valores de una o más columnas o expresiones. Si quisieramos agrupar, por ejemplo, a las variables de nuestro dataframe de acuerdo con el área en el que está debemos hacer las siguientes operaciones:
data4 <- group_by(data3, neighbourhood_group)
head(data4)
## # A tibble: 6 x 14
## # Groups: neighbourhood_group [3]
## id host_id neighbourhood_gr~ neighbourhood latitude longitude room_type
## <int> <int> <chr> <chr> <dbl> <dbl> <chr>
## 1 10003263 34111537 Sants-Montjuïc el Poble Sec 41.4 2.17 Entire h~
## 2 10005342 51395102 Ciutat Vella Sant Pere, S~ 41.4 2.18 Entire h~
## 3 10007287 383697 Sants-Montjuïc el Poble Sec 41.4 2.17 Private ~
## 4 10008491 40676061 Eixample el Fort Pienc 41.4 2.18 Private ~
## 5 10009651 51412210 Eixample la Nova Esqu~ 41.4 2.15 Entire h~
## 6 10009907 8876390 Ciutat Vella Sant Pere, S~ 41.4 2.18 Entire h~
## # ... with 7 more variables: price <int>, minimum_nights <int>,
## # number_of_reviews <int>, last_review <chr>, reviews_per_month <dbl>,
## # calculated_host_listings_count <int>, availability_365 <int>
Si miramos el resultado no veremos un cambio, ¿cierto? Lo que realizó fue un dataframe que tiene particiones internas que podremos utilizar. La función group_by()
es extremadamente útil trabajando en conjunción con la función summarise()
ya que permite realizar las operaciones sobre cada una de las divisiones que se crean. Ahora cruzaremos las dos operaciones, buscaremos la media, la moda y la desviación estándar de cada una de las áreas de Barcelona:
data4 <- summarise(group_by(data3, neighbourhood_group), media= mean(price), mediana=median(price), desviacion= sd(price))
data4
## # A tibble: 10 x 4
## neighbourhood_group media mediana desviacion
## <chr> <dbl> <dbl> <dbl>
## 1 Ciutat Vella 73.0 50 70.3
## 2 Eixample 125. 80 199.
## 3 Gràcia 87.8 65 196.
## 4 Horta-Guinardó 55.2 38 66.3
## 5 Les Corts 102. 50 318.
## 6 Nou Barris 42.1 29 55.5
## 7 Sant Andreu 50.0 30 134.
## 8 Sant Martí 94.5 52 158.
## 9 Sants-Montjuïc 90.7 55 300.
## 10 Sarrià-Sant Gervasi 90.9 60 80.4
¿Qué ejemplos se les ocurren a ustedes?
El operador pipeline %>%
es útil para concatenar múltiples dplyr operaciones. Obsérvese en el siguiente ejemplo, que cada vez que queremos aplicar mas de una función, la instrucción es una secuencia de llamadas a funciones de forma anidada y que resulta ilegible:
data4 <- summarise(group_by(data3, neighbourhood_group), media= mean(price), mediana=median(price), desviacion= sd(price))
summary(data4)
## neighbourhood_group media mediana desviacion
## Length:10 Min. : 42.06 Min. :29.00 Min. : 55.47
## Class :character 1st Qu.: 59.66 1st Qu.:41.00 1st Qu.: 72.80
## Mode :character Median : 89.25 Median :51.00 Median :146.29
## Mean : 81.14 Mean :50.90 Mean :157.79
## 3rd Qu.: 93.60 3rd Qu.:58.75 3rd Qu.:198.26
## Max. :125.10 Max. :80.00 Max. :317.53
Este anidamiento no es una forma natural de expresar un secuencia de operaciones. El operador %>%
nos permite escribir una secuencia de operaciones de izquierda a derecha:
data4 <- data3 %>% group_by(neighbourhood_group) %>% summarise(media= mean(price), mediana=median(price), desviacion= sd(price))
summary(data4)
## neighbourhood_group media mediana desviacion
## Length:10 Min. : 42.06 Min. :29.00 Min. : 55.47
## Class :character 1st Qu.: 59.66 1st Qu.:41.00 1st Qu.: 72.80
## Mode :character Median : 89.25 Median :51.00 Median :146.29
## Mean : 81.14 Mean :50.90 Mean :157.79
## 3rd Qu.: 93.60 3rd Qu.:58.75 3rd Qu.:198.26
## Max. :125.10 Max. :80.00 Max. :317.53
El atajo para sacar el pipe es Ctrl + Shift + M (Windows) o Cmd + Shift + M