library(datos) library(tidyverse) vuelos ?vuelos # filter filter(vuelos, mes == 1, dia == 1, salida_programada < 600) # uso básico ene1 <- filter(vuelos, mes == 1, dia == 1) # guardamos el resultado en ene1 # 'filter' no edita la base de datos original (vuelos) (dic25 <- filter(vuelos, mes == 12, dia == 25)) # guardamos el resutlado en dic25 # y se muestra en la consola # ojo con comparar igualdad entre reales sqrt(2)^2 == 2 near(sqrt(2)^2, 2) # combinando comparaciones con operadores lógicos filter(vuelos, mes == 11 | mes == 12) nov_dic <- filter(vuelos, mes %in% c(11, 12)) # hay más de una manera de escribir una condición lógica filter(vuelos, !(atraso_llegada > 120 | atraso_salida > 120)) filter(vuelos , atraso_llegada <= 120, atraso_salida <= 120) # Datos faltantes # Comportamiento del objeto NA > 5 10 == NA NA + 10 NA / 2 NA == NA is.na(NA) # esta es la manera correcta de preguntar si un objeto es NA # Como hacer preguntas (querys) relativas a datos faltantes usando filter df <- tibble(x = c(1, NA, 3)) filter(df, x > 1) filter(df, is.na(x) | x > 1) # arrange arrange(vuelos, anio, mes, dia) # Pasamos las variables en orden de prioridad arrange(vuelos, desc(atraso_salida)) # En caso que queramos orden descendiente # los datos faltantes se ponen al final df <- tibble(x = c(5, 2, NA)) arrange(df, x) arrange(df, desc(x)) # select select(vuelos, anio, mes, dia) # seleccionamos columnas por nombre select(vuelos, anio:dia) # seleccionamos un rango de columnas select(vuelos, -(anio:dia)) # eliminamos un rango de columnas # Hay argumentos de select que nos ayudan a imponer condiciones complejas ?select # Podríamos cambiar nombres de variables ussando select, # pero lo metodológicamente correcto y prolijo es usar la función 'rename' rename(vuelos, cola_num = codigo_cola) # Podemos usar select para reordenar las columnas select(vuelos, fecha_hora, tiempo_vuelo, everything()) # También disponemos de la función 'last_col', referencia a la última columna select(vuelos, last_col(5):last_col()) # mutate vuelos_sml <- select(vuelos, anio:dia, starts_with("atraso"), distancia, tiempo_vuelo ) mutate(vuelos_sml, ganancia = atraso_salida - atraso_llegada, velocidad = (distancia / tiempo_vuelo) * 60 ) # creamos nuevas variables a partir de las que tenemos # descartamos las variables anteriores mutate(vuelos_sml, ganancia = atraso_salida - atraso_llegada, horas = tiempo_vuelo / 60, ganacia_por_hora = ganancia / horas ) # las variables se crean en el momento, las podemos referenciar # siempre y cuando las creemos en el orden correcto transmute(vuelos, ganancia = atraso_salida - atraso_llegada, horas = tiempo_vuelo / 60, ganancia_por_hora = ganancia / horas ) # similar a mutate, pero conservamos las variables anteriores # summarise summarise(vuelos, atraso = mean(atraso_salida, na.rm = TRUE)) # creamos un estadístico a partir de una variable # group_by por_dia <- group_by(vuelos, anio, mes, dia) summarise(por_dia, atraso = mean(atraso_salida, na.rm = TRUE)) # pipe por_destino <- group_by(vuelos, destino) atraso <- summarise(por_destino, conteo = n(), distancia = mean(distancia, na.rm = TRUE), atraso = mean(atraso_llegada, na.rm = TRUE) ) atraso <- filter(atraso, conteo > 20, destino != "HNL") ggplot(data = atraso, mapping = aes(x = distancia, y = atraso)) + geom_point(aes(size = conteo), alpha = 1/3) + geom_smooth(se = FALSE) atrasos <- vuelos %>% group_by(destino) %>% summarise( conteo = n(), distancia = mean(distancia, na.rm = TRUE), atraso = mean(atraso_llegada, na.rm = TRUE) ) %>% filter(conteo > 20, destino != "HNL") # se viene ggvis, que es como ggplot2 pero mejor integrado a tidyverse! # Vimos que tenemos que sacar los valores faltantes, si no tenemos problema vuelos %>% group_by(anio, mes, dia) %>% summarise(mean = mean(atraso_salida)) # Si no tenemos un argumento que ignore los NA, podemos filtrarlos no_cancelados <- vuelos %>% filter(!is.na(atraso_salida), !is.na(atraso_llegada)) %>% group_by(anio, mes, dia) %>% summarise(mean = mean(atraso_salida)) # Es importante llevar rastro de la cantidad de elementos en cada grupo, # ya que puede que no todos estén correctamente representados # Opción 1 no_cancelados <- vuelos %>% filter(!is.na(atraso_salida), !is.na(atraso_llegada)) atrasos <- no_cancelados %>% group_by(codigo_cola) %>% summarise( atraso = mean(atraso_llegada) ) ggplot(data = atrasos, mapping = aes(x = atraso)) + geom_freqpoly(binwidth = 10) # Opción 2 atrasos <- no_cancelados %>% group_by(codigo_cola) %>% summarise( atraso = mean(atraso_llegada), conteo = n() ) ggplot(data = atrasos, mapping = aes(x = n, y = atraso)) + geom_point(alpha = 1/10) # Si eliminamos grupos subrepresentados, puede ayudarnos a visualizar patrones generales atrasos %>% filter(conteo > 25) %>% ggplot(mapping = aes(x = n, y = atraso)) + geom_point(alpha = 1/10) # Pasemos ahora a la base de datos 'bateadores' ?bateadores # Queremos ver la relación entre la eficiencia de bateo, y el tiempo de bateo bateo <- as_tibble(datos::bateadores) rendimiento_bateadores <- bateo %>% group_by(id_jugador) %>% summarise( pb = sum(golpes, na.rm = TRUE) / sum(al_bate, na.rm = TRUE), ab = sum(al_bate, na.rm = TRUE) ) ggplot(rendimiento_bateadores) + geom_point(aes(x = ab, y = pb), alpha = 0.2) rendimiento_bateadores %>% filter(ab > 100) %>% ggplot(mapping = aes(x = ab, y = pb)) + geom_point() + geom_smooth(se = FALSE) rendimiento_bateadores %>% arrange(desc(pb)) # Estadísticos importantes # La media y la mediana son siempre cantidades importantes a tener en cuenta # como medidas de centralidad no_cancelados %>% group_by(anio, mes, dia) %>% summarise( prom_atraso1 = mean(atraso_llegada), prom_atraso2 = mean(atraso_llegada[atraso_llegada > 0]), # el promedio de atrasos positivos median_atraso1 = median(atraso_llegada), median_atraso2 = median(atraso_llegada[atraso_llegada > 0]) ) # Para medir dispersión, podemos considerar la desviación estándar y el rango intercuartil no_cancelados <- vuelos %>% filter(!is.na(atraso_salida), !is.na(atraso_llegada)) no_cancelados %>% group_by(destino) %>% summarise(distancia_sd = sd(distancia), distancia_iqr = IQR(distancia), count = n()) %>% arrange(desc(distancia_sd)) # Para medir rangos, se suelen usar cuantiles de interés no_cancelados %>% group_by(anio, mes, dia) %>% summarise( primero = min(atraso_salida), ultimo = max(atraso_salida), q05 = quantile(atraso_salida, 0.05), q95 = quantile(atraso_salida, 0.95) ) # Para acceder a posiciones, tenemos algunas opciones, pero no suelen ser muy usadas # Pero si realmente las necesitamos, es importante usarlas, porque es difícil controlar # el tamaño de las agrupaciones no_cancelados %>% group_by(anio, mes, dia) %>% summarise( primera_salida = first(horario_salida), ultima_salida = last(horario_salida), tercer_salida = nth(horario_salida, 3) ) # Podemos presentar los datos de otras maneras usando filter # Qué hace el siguiente código? no_cancelados %>% group_by(anio, mes, dia) %>% mutate(r = min_rank(desc(horario_salida))) %>% filter(r %in% range(r)) # Para conteo, aparte de n(), podemos eliminar los NA primero, y además podemos # contar los datos sin repeticiones # También disponemos de la función count(), que abrevia el proceso no_cancelados %>% group_by(destino) %>% summarise(aerolineas = n_distinct(aerolinea)) %>% arrange(desc(aerolineas)) no_cancelados %>% group_by(destino) %>% summarise(aerolineas = sum(!is.na(aerolinea))) %>% arrange(desc(aerolineas)) no_cancelados %>% count(destino) no_cancelados %>% count(codigo_cola, wt = distancia) # para conteos ponderados # A veces queremos filtarar, agrupar u ordenar según condiciones lógicas no_cancelados %>% group_by(anio, mes, dia) %>% summarise(n_temprano = sum(horario_salida < 500)) no_cancelados %>% group_by(anio, mes, dia) %>% summarise(hora_prop = mean(atraso_llegada > 60)) # Si queremos deshacer una agrupación, tenemos la función ungroup() # Combinando las herramientas que estuvimos viendo, podemos hacer # tareas complejas con código sencillo # Pedimos los 10 vuelos que más se retrasaron por día del año vuelos_sml %>% group_by(anio, mes, dia) %>% filter(rank(desc(atraso_llegada)) < 10) # Destinos más populares que un umbral vuelos_sml <- select(vuelos, anio:dia, starts_with("atraso"), distancia, tiempo_vuelo ) destinos_populares <- vuelos %>% group_by(destino) %>% filter(n() > 365) destinos_populares # Estandarizaciones por grupo destinos_populares %>% filter(atraso_llegada > 0) %>% mutate(prop_atraso = atraso_llegada / sum(atraso_llegada)) %>% select(anio:dia, destino, atraso_llegada, prop_atraso) # De todas formas, es difícil verificar que un código que combina # filtros y grupos está libre de errores. Hay que tener cuidado