# EDA for SP500 data # datos: https://www.kaggle.com/datasets/andrewmvd/sp-500-stocks?resource=download # 0 ) operaciones, objetos, funciones, bibliotecas, operador pipe ... # R como calculadora 3+4 x <- 5^3 # tipos de vectores z <- 1:10 class(z) x <- runif(10) class(x) y <- letters[1:10] hoja.datos <- data.frame( var1=z, var2=x, var3=y ) # funciones en R exp(3) log( 1 ) median(z) mean(z) median( exp(z) ) quantile(z, prob=.5, type = 3) # pedir ayuda help(quantile) ? median # operador pipe |> o %>% median( exp(z) ) z |> exp() |> median() # bibliotecas de R # install.packages("ggplot2") # una vez library(lubridate) # para operar con fechas library(dplyr) # para manipular datos library(ggplot2) # para graficar ############################################# #1) SP500: grafico de la serie y retornos ------------------ sp.idx <- read.csv('datos/sp500_index.csv') |> mutate( Date = as_date(Date) ) # gráfico de lineas con ggplot ggplot(sp.idx) + geom_line( aes(x=Date, y=S.P500) ) # Obtener retornos mensuales de sp500 # return: r = log(sp_t+1) - log(sp_t) # Nos quedamos con el valor en el ultimo dia de cada mes sp.idx.mes <- sp.idx |> mutate( mm = month(Date), yy = year(Date) ) |> group_by(yy, mm) |> filter( Date == last(Date) ) |> ungroup() xret <- sp.idx.mes$S.P500 |> log() |> diff() # calcula retorno sp.idx.mes$rr.sp500 <- c(NA, xret) # el primero se pierde rm(xret) # gráfico de lineas para los retornos ggplot(sp.idx.mes) + geom_line(aes(x=Date, y=rr.sp500)) ############################################# # 2) datos de acciones que componen SP500 sp.stk <- read.csv('datos/sp500_stocks.csv') sp_names <- read.csv('datos/sp500_companies.csv') # Para una accion: ver relación con SP500 # filtrar para AAPL # seleccionar columnas: fecha, precio cierre # arreglar formato de fecha # quedarse con el ultimo dia del mes sp.apl <- sp.stk |> filter(Symbol == 'AAPL') |> select(Date, Symbol, Close, Volume) |> mutate(Date = as_date(Date) ) |> mutate( mm = month(Date), yy = year(Date) ) |> group_by(yy, mm) |> filter( Date == last(Date) ) |> ungroup() # Exceso de retornos: nesecitamos activo libre de riesgo # DBT3: interes a 3 meses tesoro de usa tbill <- read.csv('datos/DTB3.csv') |> mutate(DATE = as_date(DATE), DTB3=as.numeric(DTB3) ) |> mutate( mm = month(DATE), yy = year(DATE) ) tbill.mes <- tbill |> group_by(yy, mm) |> summarise(tbill = mean(DTB3, na.rm = TRUE)) # Calcula exceso de retorno para AAPL # ordenar datos aapl por fecha # obtener retornos y remover NA # merge con SP500 # merge con tbill.mes # corregir retornos con tbill sp.apl <- sp.apl |> arrange(Date) |> mutate(rr = c(NA, diff(log(Close)) ) ) |> filter( !is.na(rr) ) |> inner_join(sp.idx.mes) |> inner_join(tbill.mes) |> mutate( rr = rr - tbill/100) # Estudiamos la relación con un modelo lineal # pendiente de la recto: sensibilidad de Apple respecto del mercado # Intercepto: retorno de apple si el retorno de mercado es 0 lm(rr ~ rr.sp500, data=sp.apl) # gráfico de puntos con linea: 2 capas gráficas ggplot(sp.apl) + geom_point(aes(rr.sp500, rr)) + geom_smooth(aes(rr.sp500, rr), method = 'lm') ############################################# # 3) Retorno y modelo para todas las acciones juntas -------- # Repetir el procesamiento para AAPL pero para cada una # de las 500. # Similar pero ahora tenemos que agrupar por Symbol # ademas de mes y año sp.stk.mes <- sp.stk |> select(Date, Symbol, Close, Volume) |> mutate(Date = as_date(Date) ) |> mutate( mm = month(Date), yy = year(Date) ) |> group_by(yy, mm, Symbol) |> # agrupo por mes, año y acion filter( Date == last(Date) ) |> # precio ultimo dia de mes por Symbol group_by(Symbol) |> # agrupo por Symbol para calcular retornos de cada accion mutate(rr = c(NA, diff(log(Close)) ) ) |> filter(!is.na(rr)) |> inner_join(sp.idx.mes) |> inner_join(tbill.mes) |> mutate(rr = rr - tbill/100) |> group_by(Symbol) |> mutate(rr.mn = mean(rr) ) # El procesamiento anterior puedo guardarlo en un archivo con write.csv: write.csv(sp.stk.mes, file='datos/sp_stk_mes.csv', row.names = FALSE) # y cuando quiera usarlo, lleerlo como los datos originales: sp.stk.mes <- read.csv('datos/sp_stk_mes.csv') |> mutate(Date = as_date(Date)) # Grafico de la Figura 1: sp.stk.mes |> ggplot() + geom_line(aes(x=Date, y=rr, group=Symbol, color=100*rr.mn)) + geom_line(aes(x=Date, y=rr.sp500), linewidth=I(1)) + scale_color_distiller(palette = 'Spectral', name='') # 3) Modelo CAPM # rr_jt = a_j + b_j m_t # Paso intermedio: modelo con 4 empresas ----------- algunas <- sample(sp_names$Symbol, size = 4) # que empresas salen seleccionadas: sp_names |> filter(Symbol %in% algunas) |> select(Symbol, Shortname, Sector, Marketcap, Weight) # Obtenemos alpha y beta para cada empresa md0 <- lm( rr ~ 0 + Symbol + Symbol:rr.sp500, data = filter(sp.stk.mes, Symbol %in% algunas) ) # resumen de resultados del modelo: 4 valoes para alpha, y cuatro para beta summary(md0) coef(m0)[1:4] # los 4 valores de alpha coef(m0)[5:8] # los 4 valores de beta #------------ # Ahora con todos los datos md1 <- lm( rr ~ 0 + Symbol + Symbol:rr.sp500, data = sp.stk.mes) # cuantos coefficientes hay? coef(md1) |> length() # 1002, 501 alphas y 501 betas # miramos que el 'name' de los alphas es # la palabra 'Symbol' y pegado el nombre de la acción # mira los primeros 3 coef(md1)[1:3] |> names() # usamos funcion gsub() para remover la palabra 'Symbol' res <- data.frame( a = md1$coefficients[1:501 ], b = md1$coefficients[502:1002], Symbol = gsub('Symbol', '', names(md1$coefficients[1:501]))) |> inner_join( select(sp_names, Symbol, Shortname, Marketcap, Weight ) ) # Todos los coeficientes en un gráfico de puntos, # tamaño del punto es la capitalizacion de la empresa res |> ggplot() + geom_point( aes(x=b,y=a, size=Weight ) ) # Figura 2: en lugar de puntos graficamos texto, # para las empresas que representan mas de .5% del mercado res |> filter(Weight > 0.005) |> ggplot() + geom_text( aes(x=b,y=a, size=Weight, label=Symbol ) ) + theme(legend.position = 'none') ----------- ################ # Clase 2 26/4 ################ # R como calculadora 3+4 x <- 5*9 x ################ #Tipos de vectores class (x) z <- runif (1:10) #generacion de numeros aleatorios, aca entre 1 y 10 z class(z) y <-letters[1:10] y hoja.datos<- data.frame (var1 = x, var2 = y, var3 = z) hoja.datos ################ # funciones en R exp(3) #exponente log(1) #logaritmo median (z) #mediana mean (z) #media median (exp(z)) quantile(z, prob = .5, type = 3) ################ #pedir ayuda help (quantile) ? median ################ #operador pipe |> o %>% median (exp (z)) #es lo mismo que z |> exp() |> median() #el exponente de z, le hacemos la mediana #bibliotecas R install.packages('ggplot2') #lo podes correr solo una vez, queda agregada a Rstudio install.packages('lubridate') install.packages('dplyr') library (lubridate) #para operar con fechas library (dplyr) #para manipular datos library (ggplot2) #para graficar ################ #OBJ 1: describir la evolucion de SP500 #leer sp500index.csv #transformar la columna date sp.idx <- read.csv( file = 'sp500_index.csv') #importar el dato de la carpeta contenedora View (sp.idx) # ver los datos str (sp.idx) #estructura de los datos # no quiero que me de los datos de fecha en .... sp.idx <- read.csv( file = 'sp500_index.csv') |> mutate (Date = as_date (Date)) #mutate es una funcion del paquete dyplr #graficar con ggplot #ggplot(DATOS) + geom_TIPO( MAPEO ) # geom tiene varias ggplot(sp.idx) + geom_line (aes (x = Date, y = S.P500)) + geom_hline( yintercept = 5000, color='tan2') ################ #OBJ 2: estudiar retornos mensuales de sp500 #agrupar por mes y anio #filtrar ultimo dia del mes #calular retorno y agregarlo como columna sp.idx.mes <- sp.idx |> mutate (mm = month (Date), yy = year (Date)) |> group_by(yy, mm) |> filter(Date == last (Date)) View(sp.idx.mes) #se pasa de 2500 observaciones a 120, divididas x mes xret <- sp.idx.mes$S.P500 |> #el operador $ es para ir a una columna en especial log() |> diff() #calculamos la diferencia de los logaritmos sp.idx.mes$rrSP <- c(NA, xret) #se agrega la columna rrSP de una, donde la primera no tenga datos, ya que no es la resta de uno con otro, y el resto es xret ################## #OBJ 3: Estudiar la relacion de una empresa con SP500 sp.stk <- read.csv( file = 'sp500_stocks.csv') sp_names <- read.csv( file = 'sp500_companies.csv') # para ver una accion: ver la relacion con SP500 #filtrar las de AAPL #seleccionar las columnas: fecha, precio cierre #arreglar formato de fecha #quedarse con el ultimo dia del mes sp.apl <- sp.stk |> filter(Symbol == 'AAPL')|> #se filtra por apple select( Date, Close) |> # se selecciona la fecha de cierre y el nivel de cierre mutate (Date = as_date(Date))|> mutate(mm = month(Date), yy = (Date)) |> group_by(mm, yy) filter (Date == last (Date)) View (sp.apl) # Exceso de retornos: nesecitamos activo libre de riesgo # DBT3: interes a 3 meses tesoro de usa tbill <- read.csv('datos/DTB3.csv') |> mutate(DATE = as_date(DATE), DTB3=as.numeric(DTB3) ) |> mutate( mm = month(DATE), yy = year(DATE) ) tbill.mes <- tbill |> group_by(yy, mm) |> summarise(tbill = mean(DTB3, na.rm = TRUE)) # Calcula exceso de retorno para AAPL # ordenar datos aapl por fecha # obtener retornos y remover NA # merge con SP500 # merge con tbill.mes # corregir retornos con tbill sp.apl <- sp.apl |> arrange(Date) |> mutate(rr = c(NA, diff(log(Close)) ) ) |> filter( !is.na(rr) ) |> inner_join(sp.idx.mes) |> inner_join(tbill.mes) |> mutate( rr = rr - tbill/100) #graficar retornos de AAPL contra retornos SP500 #alinear linea al grafico, estimar modelo lineal ggplot(sp.apl) + geom_point(aes(x= rrSP, y=rr)) + #puntitos geom_smooth(aes(x=rrSP, y rr), #la regresion de los puntos lm (rr ) #lineal model, regresion # Repetir el procesamiento para AAPL pero para cada una # de las 500. # Similar pero ahora tenemos que agrupar por Symbol # ademas de mes y año sp.stk.mes <- sp.stk |> select(Date, Symbol, Close, Volume) |> mutate(Date = as_date(Date) ) |> mutate( mm = month(Date), yy = year(Date) ) |> group_by(yy, mm, Symbol) |> # agrupo por mes, año y acion filter( Date == last(Date) ) |> # precio ultimo dia de mes por Symbol group_by(Symbol) |> # agrupo por Symbol para calcular retornos de cada accion mutate(rr = c(NA, diff(log(Close)) ) ) |> filter(!is.na(rr)) |> inner_join(sp.idx.mes) |> inner_join(tbill.mes) |> mutate(rr = rr - tbill/100) |> group_by(Symbol) |> mutate(rr.mn = mean(rr) ) # El procesamiento anterior puedo guardarlo en un archivo con write.csv: write.csv(sp.stk.mes, file='datos/sp_stk_mes.csv', row.names = FALSE) # y cuando quiera usarlo, lleerlo como los datos originales: sp.stk.mes <- read.csv('datos/sp_stk_mes.csv') |> mutate(Date = as_date(Date)) # Grafico de la Figura 1: sp.stk.mes |> ggplot() + geom_line(aes(x=Date, y=rr, group=Symbol, color=100*rr.mn)) + geom_line(aes(x=Date, y=rr.sp500), linewidth=I(1)) + scale_color_distiller(palette = 'Spectral', name='') ----------- library(ggplot2) ############################################## #1) Datos de Jugo de Naranja ------------- # precio y ventas de 3 marcas de jugo de naranja en tiendas de USA en 90s # feat indica si hubo publicidad en esa semana oj <- read.csv('datos/oj.csv') head(oj) class(oj) # tipos de variables: # numéricas: cuantifican algo, subdividimos en continuas y discretas # categóricas: indican una categoría o cualidad, subdividimos en nominales y ordinales # en los datos: sales y price son numéricas continuas, brand y feat son categóricas str(oj) # crear factores oj$brandF <- factor(oj$brand) oj$featF <- factor(oj$feat, labels=c('NOadv', 'adv') ) ############################################## # 2) Graficos Univariados ----------------------- ## variables categóricas: barras # geom_bar() calcula y grafica los totales de una variable categórica # ggplot: semanas con publicidad o no # color de las barras? ## variables numéricas, histograma # geom_histogram() calcula y gráfica histogramas de una variable numérica # ggplot: histogramas de precio promedio por semana ### que mirar en histograma?: ### efecto de los bins ############################################## # 3) Gráficos bivariados ------------------- # Primer paso en el mundo multivariado: # Queremos estudiar la relación entre dos vairables. # Dependiendo la naturaleza de las variables tenemos distintas alternativas ### Dos continuas: diagrama de dispersión ### ggplot: ver relación entre precio y ventas # ( es necesario transformar variables? son demasiados puntos? ) ### Dos categóricas: gráficos de barras con color ### ggplot: Semanas con marcas y publicidad # apiladas al 100%? agrupadas? ### 1 continua y 1 categórica: gráfico de caja # diagrama de cajas es sencillo, bueno para comparar # ggplot: ver el precio por marcas ############################################## # 3) Colores, paneles ------------------- ### Escala de color: muy importante, millones de detalles # algunas paletas de colores library(RColorBrewer) # solo para ver los tipos de paletas display.brewer.all() # ggplot: Semanas con marcas y publicidad # modificando escala de color # ggplot: ver relación entre precio y ventas # coloreando por marca, o por publicidad ### Paneles: repetir un gráfico en varios subconjuntos de los datos # facet_grid() los paneles se disponen en una grilla # facet_wrap() los paneles se disponen de forma flexible # ggplot: histograma de precio por marca # ggplot: relación ventas-precio por marca ############################################## # 4) Efecto de publicidad y otras capas ------------------- # Combinar geometria, paneles y color para ver efecto de publicidad # ggplot: cajas de precio coloreada por publicidad, separada por marca # agregar capas con nombre de etiquetas # ggplot: puntos de ventas-precio, coloreados por publicidad, separados por marca # agregar capa de modelo lineal ---------- #En este Script comenzaremos a dar nuestros primeros pasos en el lenguaje R. #Este Script tiene como cometido facilitar el aprendizaje de los conceptos de: DataFrames. ######### ######### ######### ######### Data Frames ######### ######### ######### ######### #Es la forma más común de almacenar los datos en R, realizar análisis estadístico y manipular datos. #Es una estructura de dos dimensiones, que comparte propiedades de matrices y listas. #La diferencia con las matrices es que los elementos de un data.frame pueden ser de diferente clase, numeric, character, logical, factors, etc #Son un caso especial de listas, en donde cada elemento de ella debe tener el mismo largo. #Se busca que tengan una estructura rectangular donde: #Cada columna sea una variable #Cada fila una observación #cada celda un valor colaboradores <- c("Bruno", "Santiago", "Juan", "Carlos") horas_por_proyecto <- matrix(1:20, nrow=4, ncol=5) #Unimos el vector a la matriz colaboradores_por_proyecto <- cbind(colaboradores, horas_por_proyecto) #unimos por la columna datos <- data.frame(colaboradores_por_proyecto) View(datos) ######### ######### ######### ######### Directorios ######### ######### ######### ######### # En el día a día, lo más común es que debamos importar archivos de datos a R en un formato data.frame. # Antes de importar cualquier tipo de archivo que contenga nuestros datos, debemos conocer el directorio de trabajo en donde estamos trabajando y el directorio de trabajo en donde se encuentran nuestros datos. #El directorio de trabajo en R es la carpeta en la que estás trabajando. En consecuencia, es la ruta donde se guardaran tus objetos de R. # Con la función "obtener directorio de trabajo" getwd() obtendrás cual es tu directorio de trabajo getwd() # ¿Como puedo cambiar la ruta de mi directorio de trabajo? setwd("C:\Users\miusuario\MiRuta") #Cuando copias la ruta de un directorio, es habitual que las carpetas del directorio se separen mediante una barra invertida (\) . #Si pegas directamente esta ruta el directorio no se cambiar? y la función anterior dar? un error. #Si no consigues cambiar el directorio de trabajo recuerda usar '\\' o '/' en lugar de '\' al escribir la ruta. #setwd("C:/Users/miusuario/Miruta") #Alternativamente, desde R 4.0.0 setwd ("C:/Users/usuario/Desktop/Certificación") #Si no quieres utilizar codigo para hacer esto, puedes usar la interfaz de R. #Session >> Set Working Directory #Para saber que archivos hay dentro de mi directorio de trabajo uso dir() list.files() ######### ######### ######### ######### Importación ######### ######### ######### ######### # El caso más sencillo es cuando los datos se encuentran almacenados en un archivo de texto plano (.txt o .csv) # La función para importar texto plano es read.table() #Investiga la función read.table() getwd() datos.csv <- read.table("C:/Users/usuario/Desktop/Certificación/fortune1000.csv", header = TRUE, sep = ",") View(datos.csv) # Si solo especifico el nombre y extensión de mi archivo, R asume que estamos tratando de importar algo del directorio de trabajo. # Para importar un archivo ubicado fuera del directorio, debes proveer a R la ruta completa del archivo. # read.table solo nos va a servir para archivos .csv o .txt # La manera más habitual de importar Excels es con read_excel install.packages("readxl") library(readxl) # Antes de cargar datos en Excel, veamos los parámetros de la función read_excel desde la documentación datos.excel <- read_excel(path = "data_ventas.xlsx", sheet = "data") View(datos.excel) ######### ######### ######### ######### Exploración de Data Frames ######### ######### ######### ######### # Para realizar una visualización rápida de como son las variables y sus valores # Existen dos funciones muy útiles: head() y tail() head(datos.csv, 10) tail(datos.csv) # Mirar toda la base: View(datos.csv) #Cantidad de filas y columnas nrow(datos.csv) ncol(datos.csv) dim(datos.csv) # Nos puede interesar saber qué variables tenemos en la base # Para ello, miramos los nombres de cada columna con la función colnames() names(datos.csv) colnames(datos.csv) # Es muy importante revisar siempre que las columnas de mi data.Frame tomen el tipo de dato esperado str(datos.csv) #Estadísticas descriptivas simples summary(datos.csv) # Podemos cambiar el nombre de la columna colnames(datos.csv) [2] <- "Empresa" ##Tu turno: Traducir los nombre de las columnas 4 a 8 por Industria, Ubicacion, Ingresos, Ganancias Y Empleados colnames(datos.csv) [4:8] <- c("Industria", "Ubicacion", "Ingresos", "Ganancias", "Empleados") ######### ######### ######### ######### Manipulación de Data Frames ######### ######### ######### ######### #Acceso por indice #data.frame[fila, columna] datos.csv[1,] #Fila 1, todas las columnas datos.csv[,1] #Columna 1, todas las filas datos.csv[1] #Columna 1, todas las filas datos.csv[seq(1,6,2), c(1:4)] #Contar para las filas 1 a 6 de 2 en 2 #Acceso por etiqueta datos.csv[c(1:10), "Empresa"] datos.csv[c(1:10), c("Empresa", "Ganancias")] #las ganancias de las 10 primeras empresas #Cuando trabajemos con data.frames, tambien podemos utilizar el operador $ para seleccionar columnas datos.csv$Empresa #Acceso mediante mascaras booleanas. usar condiciones para filtrar las filas que necesito. Te tira verdaderos o falsos datos.csv$Ingresos > 100000 #agarra las filas que sean mayores a 100000 mascara <- datos.csv$Ingresos > 100000 mascara datos.csv [mascara, ] ingresos.100000 <- datos.csv[datos.csv$Ingresos > 100000, ] datos.csv[datos.csv$Sector == "Financials", ] datos.csv[datos.csv$Sector != "Financials", ] # Tambien puedes combinar condiciones mediante los operadores or (|) y and (&) datos.csv[datos.csv$Sector == "Financials" & datos.csv$Industria == "Diversified Financials", "Empresa" ] #datos donde el sector es Financials y la industria es diversified financials, solo con los datos de esa empresa datos.csv[datos.csv$Ingresos > 100000 |datos.csv$Empleados < 500, ] # Otra forma: which. En lugar de devolver una mascara booleana, devuelve los indices donde se cumple la condición which(datos.csv$Ingresos > 100000) #nos dice solo en que fila se cumple la condicion de which datos.csv [which(datos.csv$Ingresos > 100000),] # Otra forma: Subset subset(datos.csv, subset = "Ingresos" > 100000) # Ordenar order(datos.csv$Ganancias, decreasing = TRUE) #indice de las filas ordenadas en terminos de mayor a menor Ganancia datos.csv[order(datos.csv$Ganancias, decreasing = TRUE), ] #nos ordena toda la tabla con los datos de ganancias de mayor a menor ##Ejercicios: utilizando datos_excel # Muestra únicamente el Id de las ventas que: # Fueron en Montevideo o Canelones, de los productos puerta y pico en donde se vendieron más de 10 unidades. # Busca 2 formas de hacerlo datos.csv[datos.excel$Departamento == c('Montevideo', 'Canelones') & datos.excel$Producto == c('Puerta', 'Pico') & datos.excel$Cantidad >= 10, 1] subset(datos.excel, (Departamento == 'Montevideo' | Departamento == 'Canelones') & (Producto == 'Puerta' | Producto == 'Pico') & Cantidad >= 10) ######### ######### ######### ######### Exportar ######### ######### ######### ######### #install.packages("writexl") library("writexl") write_xlsx(ingresos.100000, "export_r.xlsx") #exportar el archivo a uno .xlsx ######### ######### ######### ######### Duplicados y faltantes######### ######### ######### ######### #Tu turno: importa el archivo encuesta_sueldos_sysarmy_1s2020.csv y guardalo en un objeto llamado "Encuesta". # Verifica que "Encuesta" es un dataframe, tiene 5988 observaciones y 53 variables. # Tambien verifica que las palabras con tildes se muestren correctamente. Investiga el parámetro encoding. Encuesta <- read.csv('Encuesta_sueldos_sysarmy_1s2020.csv', encoding = 'UTF-8') #para poner los tildes View(Encuesta) #Rápida mirada a la base names(Encuesta) head(Encuesta) tail(Encuesta) summary(Encuesta) # Puedo obtener rápidamente una tabla de frecuencias de mis datos con la funcion table(): table(Encuesta$me_identifico) # También me puede interesar obtener una tabla de frecuencias prop.table(table(Encuesta$me_identifico)) # La misma no suele ser útil para campos de tipo "texto libre" table(Encuesta$bases_de_datos) #¿Tengo filas duplicadas en mi data.frame? duplicated(Encuesta) #¿Cuantas son? sum(duplicated(Encuesta)) #Eliminemos los duplicados #Forma 1: Conociendo las filas duplicadas, podemos hacer un subset de nuestros datos. Elondion <- Encuesta [!duplicated(Encuesta),] #Forma 2: Utilizando unique() install.packages("tidyverse") library(tidyverse) Elondion_2 <- unique(Encuesta) # Datos faltantes # La falta de datos es un problema cotidiano con el que un profesional de los datos tiene que lidiar. # Los datos faltantes se definen como valores que no están disponibles y que serán significativos si se observan. # La mayoría de los conjuntos de datos en el mundo real contienen datos faltantes. # Antes de poder utilizar la información, es necesario transformar esos campos para que puedan ser utilizados para el análisis y el modelado. is.na(Encuesta) # Esta función devuelve una matriz con dimensiones iguales al Encuesta # TRUE indica que se trata de un dato faltante y FALSE que no. # Para R TRUE tiene como valor 1 y FALSE el 0, por lo que con sum() puedo conocer cuantos NA tengo en mi dataset. sum(is.na(Encuesta)) # Cuando tenemos data.frames muy grandes, quizás es dificil visualizar si tenemos algún dato faltaste con is.na() # Con anyNA() tenemos de forma rápida si hay o no datos faltantes. anyNA(Encuesta) # Tambien podríamos estar interesados en saber que filas no tienen datos faltantes. complete.cases(Encuesta) #Que ocurre si tengo datos faltantes? #Media de una columna numérica mean(Encuesta$salario_mensual_bruto_en_tu_moneda_local) #Otras estadísticas frecuentes median(Encuesta$salario_mensual_bruto_en_tu_moneda_local) sd(Encuesta$salario_mensual_bruto_en_tu_moneda_local) min(Encuesta$salario_mensual_bruto_en_tu_moneda_local) max(Encuesta$salario_mensual_bruto_en_tu_moneda_local) summary(Encuesta$salario_mensual_bruto_en_tu_moneda_local) # Existen distintos enfoques para lidiar con datos faltantes: #1: Retener los datos faltantes (en los casos en que no interfieren con el análisis). # Como vimos en el punto anterior, para realizar ciertos cálculos puedo pedirle a R que "ignore" los NA. #2: Eliminar la observación completa (toda la fila). Se analizan únicamente los casos sin datos faltantes. # Con drop_na() podemos eliminar las filas completas #3: Imputar el dato faltante (reemplazarlo por otro valor). # Por ejemplo, podríamos hacer la ficción de que cada dato faltaste tiene como valor la media muestral. ######### ######### ######### ######### Anexar y combinar data.frames ######### ######### ######### ######### # Te han encargado la tarea de conocer cuales han sido los platos más y menos exitosos de las últimas dos semanas en una app de comidas. # Tambien debes conocer características de tu clientela de forma de poder hacer publicidad segmentada. # Sin embargo, la información esta dispersa en varios archivos. # Deberás consolidarla para poder sacar conclusiones al respecto. #Antes de comenzar, importemos los datos con los cuales vamos a trabajar. Ventas_semana_1 <- read.csv("Restaurant_Ventas1.csv") Ventas_semana_2 <- read.csv("Restaurant_Ventas2.csv") Clientes <- read.csv("Restaurant_Clientes.csv", sep=";") Comidas <- read.csv("Restaurant_Comidas.csv") Rating <- read.csv("Restaurant_Ventas1_Rating.csv", sep=";") # Exploración inicial. class() head() str() summary() # Consolidemos toda la información de ventas en un único data.frame llamado "Ventas" # Para ello, podemos utilizar una función que ya hemos visto rbind() rbind(Ventas_semana_1, Ventas_semana_2) # Cuidado! Para utilizar rbind() con dataframes, los nombres de las variables deben ser iguales. Ventas <- rbind(Ventas_semana_1, setNames(Ventas_semana_2, names(Ventas_semana_1)) ) # Ten en cuenta, que para obtener información sobre las ventas, debes buscar la información en las filas del resto de las tablas. # Si esta tarea se hace de forma incorrecta, puede provocar problemas serios en análisis posteriores. # Existen cuatro formas distintas por las cuales podemos combinar nuestros conjuntos de datos: # Unión interna (Inner Join) # Unión completa (Full Join) # Unión a la izquierda (Left Join) # Unión a la derecha (Right Join) # Para combinar data.frames existe una función para llevar a cabo todos los tipos de fusiones que existen. # Esa función es merge(), investígala. #Por defecto, merge() efectúa una unión interna, por lo que solo traerá los registros en común entre los data.frames. # ¿Cual fue la comida ordenada por cada uno de los clientes? # Debo relacionar el data.frame de Ventas con el de comidas # ¿Qué campo tienen en común? df <- merge(x=Ventas, y=Comidas, by="Food.ID" ) # ¿Puedo tener información sobre los clientes que hicieron esas compras? # La tabla Clientes cuenta con información de cada persona que tiene una cuenta en la app # Debo relacionar mi df con el de Clientes # ¿Qué campo tienen en común? df2 <- merge(df, Clientes, by.x=c("Customer.ID"), by.y=c("ID") ) # Algunos de tus clientes puntúan el servicio. # Obten el puntaje brindado por cada cliente sin perder información de los clientes que no han brindado puntaje. df3 <- merge(df2, Rating, by.x=c("Customer.ID"), by.y=c("Customer"), all.x=TRUE ) ## Tu turno: Responde los siguientes puntos ## Obten a partir de tu base de clientes, un listado de aquellos que no han realizado pedidos en las últimas 2 semanas. ## ¿Qué comidas han obtenido una puntuación mayor a 8? ¿Y menor a 2? ## ¿Cuantas ventas han sido a mujeres? ¿Y a hombres? ------------ #En este Script continuaremos con algunos conceptos esenciales que tenemos que conocer para manejar R. #Este Script tiene como cometido facilitar el aprendizaje de los conceptos de: estructuras de control y funciones. #Cuando no sabes que hace una función o como utilizarla, te recomendamos usar la ayuda de R. Esta se obtiene con ? o ?? delante del nombre de la función. Otra forma de obtener ayuda en R es utilizando help() ######### ######### ######### ######### Estructuras de control ######### ######### ######### ######### #Las estructuras de control permiten tomar decisiones y repetir acciones en función de condiciones específicas. #En R, las principales estructuras de control son los condicionales (if-else) y los bucles (for, while) # IF - ELSE #Las estructuras if - else en R permiten ejecutar un bloque de código si una condición es verdadera. x <- 6 if( x > 5 ){ print ('x es mayor que 5') } else { print ('x es menor o igual que 5') } edad <- as.numeric(readline("Ingresa tu edad: ")) #El usuario debe interactuar con la consola para poder continuar if( edad >= 18) { print ('Eres mayor de edad') } else { print ('Eres menor de edad') } # Puedo usar tantos if-else como quiera. # Evaluemos si un numero es positivo (menor o mayor que 5) o negativo. x <- 2 if (x > 0) { if (x < 5) { print('x es positivo y menor que 5') } else { print ('x es positivo y mayor o igual que 5') } } else { print('x es negativo') } # Puedo usarlo para crear o editar variables a <- 7 b <- 5 if (a < 3) { result <- 10 } else if (a < 5 & b > 3) { result <- 20 } else if (a > 10 & b < 7) { result <- 30 } else { result <- 40 } # Una alternativa es la utilización de la función ifelse() # Es una función vectorizadas, las cuales nos permiten trabajar de forma más eficiente sin la necesidad de iterar explícitamente sobre cada elemento del vector. #Cuando se utiliza una función vectorizada como ifelse, #las operaciones se aplican de forma automática a cada elemento de los vectores de entrada, #lo que permite un procesamiento rápido y eficiente de grandes conjuntos de datos. # Nos pueden servir para crear nuevas columnas facilmente en nuestro Data.Frame # Volvamos a importar encuesta_sueldos_sysarmy_1s2020.csv Encuesta <- read.csv("encuesta_sueldos_sysarmy_1s2020.csv", encoding = "UTF-8") # Creemos una columna que nos diga si el salario del encuestado está por encima o por debajo de la media # Calcular la media del salario mensual neto media_salario <- mean(Encuesta$salario_mensual_bruto_en_tu_moneda_local) Encuesta$mejor_que_media <- ifelse(Encuesta$salario_mensual_bruto_en_tu_moneda_local > media_salario, 'Salario encima de la media', 'Salario por debajo de la media') table(Encuesta$mejor_que_media) #se nota que hay solo un salario por encima de la media # Calcular en que quintil está el encuestado # Calcular percentiles del salario mensual neto quintiles_de_salario <- quantile(Encuesta$salario_mensual_bruto_en_tu_moneda_local, probs = c(0.25, 0.5, 0.75), na.rm = TRUE) Encuesta$quintil_salario <- ifelse(Encuesta$salario_mensual_bruto_en_tu_moneda_local <= quintiles_de_salario [1], 'Percentil 25', ifelse(Encuesta$salario_mensual_bruto_en_tu_moneda_local <= quintiles_de_salario [2], 'Percentil 50', ifelse(Encuesta$salario_mensual_bruto_en_tu_moneda_local <= quintiles_de_salario [3], 'Percentil 75', 'Percentil 100'))) #haciendo una columna que diga en que percentil esta cada caso en relacion a su salario mensual... quintiles_salario <- table(Encuesta$quintil_salario) quintiles_salario [order(quintiles_salario)] #ordenar los percentiles por orden alfabetico # Crear nueva columna con el percentil del salario usando ifelse # Crear una categoria sobre la experiencia laboral del encuestado # La función cut() también nos puede ser útil # For # Permiten repetir una serie de instrucciones un número específico de veces o para cada elemento de una secuencia. # Son útiles cuando necesitas realizar una operación iterativa sobre un conjunto de datos o realizar una tarea repetitiva. 1:5 for (i in 1:5) { cat ('Iteracion: ', i, '\n') #cat = Concatenar } #hace un bucle durante 5 etapas iterable <- c(1:5) for (j in iterable) { print('cabeza') } # Tratemos de imprimir cuantos valores distintos tiene cada columna # Para ello, obtener el número de columnas en el dataframe Encuesta # Iterar sobre cada columna del dataframe Encuesta for (i in 1:ncol(Encuesta)) { #obtener los valores unicos de cada columna valores_unicos <- unique(Encuesta[[i]]) # print (names(Encuesta[i])) print(length(valores_unicos)) } # Con break puedo escapar del loop antes de completar la itereación for (i in 1:10){ if (i == 5) { break } #corta en 5 cat ('Iteracion: ', i, '\n') } for (i in 1:10) { if (i == 5) { next # saltear el 5 } cat('Iteracion:', i, '\n') } # While #se utiliza para ejecutar un bloque de código repetidamente mientras una condición especificada sea verdadera. # Es útil cuando no conoces de antemano cuántas veces necesitarás iterar, pero sabes que deseas continuar mientras se cumpla una cierta condición. # Sumar números hasta que la suma exceda 100 suma <- 0 contador <- 1 while (suma <= 100) { suma <- suma + contador cat('Iteracion', contador) cat('Suma parcial:', suma, '\n') } #sumame de a 1 hasta que pase 100 while (suma <= 100) { suma <- suma + contador cat('Iteracion', contador) cat('Suma parcial:', suma, '\n') contador <- contador + 1 } #sumame de a 'contador', pero cada vez que sumes sumale uno al contador ######### ######### ######### ######### Funciones ######### ######### ######### ######### # Una función en R es un bloque de código que realiza una tarea específica. # Puedes definir funciones para reutilizar código, mejorar la legibilidad y modularidad de tu programa. # Definir una función # Crea un programa que reciba un número y devuelva su cuadra # Crear una función que reciba 2 números y devuelva máximo # Puedo hacer que los parámetros sean opcionales #¿Que ocurre si quiero calcular el máximo de más de dos numeros? # Desafios # Crea una función 'valor_absoluto' que reciba como parámetro un número y devuelva su valor absoluto. #Nota: en R existe una versión más general de esta función llamada abs. print(valor_absoluto(-5)) # Debería imprimir 5 print(valor_absoluto(10)) # Debería imprimir 10 print(valor_absoluto(0)) # Debería imprimir 0 #Genera una función que, dada una tasa de interés mensual, un plazo (en meses) y un monto capital, devuelva el capital+interés luego del plazo. #Si no se especifica el parámetro capital, la función debe utilizar el valor 1000. #Si no se especifica el plazo, debe ser 12 #Nota: El monto final es el capital * (1 + tasa_interes_mensual) elevado al plazo calcular_monto_final(100, 0.05, 6) # Crea una función analizar_datafram eque tome un DataFrame e imprima la cantidad de valores unicos y valores NA por columna # Definir la función para analizar un DataFrame analizar_dataframe(Encuesta) ----------- #En este Script continuaremos con algunos conceptos esenciales que tenemos que conocer para manejar R. #Este Script tiene como cometido facilitar el aprendizaje de los conceptos de: manipulación de Dataframes con dplyr #Cuando no sabes que hace una función o como utilizarla, te recomendamos usar la ayuda de R. Esta se obtiene con ? o ?? delante del nombre de la función. Otra forma de obtener ayuda en R es utilizando help() ######### ######### ######### ######### El paquete Dplyr ######### ######### ######### ######### #Este paquete nos proporciona ninguna nueva funcionalidad a R per se. #Todo aquello que podemos hacer con dplyr lo podríamos hacer con la sintaxis básica de R. # Sin embargo, dplyr # - proporciona una "gramática" (verbos) para la manipulación y operaciones datos en data.frames # - facilita la lectura del código (importante para compartir codigo y reproducibilidad) # - implementada en lenguaje C++, mejora performance #Los principles verbos de dplyr son: select(), filter(), arrange(), rename(), mutate() y summarize(). # Hoja de ruta: # 1- cargar datos de vuelos # 2- presentar los 'verbos' básicos # 3- operador pipe para encadenar operaciones # 4- dplyr + ggplot2 #install.packages("dplyr") library(dplyr) # Importemos nuestros datos con fread(). Está ultima es útil para importar data.frames grandes de una forma más rápida #install.packages("data.table") library(data.table) setwd('C:/Users/usuario/Desktop/Certificación') vuelos <- fread('flights.csv') # que hay en los datos? View(vuelos) head(vuelos) str(vuelos) #####Select() #Con la función select podemos seleccionar columnas de un data frame # util cuando hay muchas columnas pero solo estamos interesados en trabajar # con algunas #En su uso más básico, simplemente pasamos a la función las columnas que queremos vuelos_columnas_select <- select(vuelos, tailnum, origin, dest, distance) #select selecciona las columnas de la base class(vuelos_columnas_select) #es un dataframe select(vuelos, 1, 2 ) #selecciono las columnas 1 y 2 #Puedo seleccionar un rango de columnas con : select(vuelos, year, flight:distance) #Tambien podemos excluir de la selección con - select(vuelos, -year, -month, - carrier) # Existen otros metodos de selección utiles # Seleccionar todo: everything() select(vuelos, everything()) # Columnas que comiencen por o terminen por: start_with(), ends_with() select(vuelos, starts_with("arr")) select(vuelos, starts_with("dep")) select(vuelos, ends_with("time")) # Columnas que contienen un string select(vuelos, contains("_")) #####Filter(): nos permite filtrar filas según una o más condiciones # Vuelos de menos de una hora de tiempo de vuelo filter(vuelos, air_time < 60) # Vuelos de larga distancia filter (vuelos, distance > 2000) # Otros ejemplos # Vuelos desde PDX filter(vuelos, origin == "PDX") # Vuelos con origen distinto de ABQ filter(vuelos, origin != "ABQ") # Podemos usar los operadores & y | filter(vuelos, dep_delay > 30 & arr_delay > 30) #se atrasaron media hora en la salida y media hora en la llegada filter(vuelos, dep_delay > 30 | arr_delay > 30) #se atrasaron media hora en la salida o media hora en la llegada #xor(OR Exclusivo): # Vuelos que salieron con retraso mayor a 30 minutos o llegaron con retraso mayor a 30 minutos, pero no ambos filter(vuelos, xor(dep_delay > 30, arr_delay > 30)) # Filtrar por NA filter(vuelos, is.na(arr_delay)) # Me quedo con las filas NA filter(vuelos, !is.na(arr_delay)) #Quito las filas NA #####Arrange(): se utiliza para ordenar las filas de un data frame de acuerdo a una o varias columnas. # Ordenemos los vuelos por hora de salida. Si no especifico nada, lo hará de forma ascendente arrange (vuelos, dep_time) arrange (vuelos, desc(dep_time)) # Ordenar vuelos por el retraso en la salida en orden descendente arrange(vuelos, desc(dep_delay)) # Ordenar por más de una columna arrange (vuelos, origin, dest, carrier) #####Rename(): se utiliza para cambiar facilmente el nombre de las columnas del dataframe. vuelos <- rename(vuelos, retraso_salida == dep_delay, tiempo_vuelo == air_time) colnames (vuelos) #####Mutate(): permite crear variables/columnas nuevas en los datos # Calcular la duración del vuelo y crear una nueva columna llamada atraso_vuelo mutate(vuelos, atraso_vuelo = dep_delay + arr_delay) # Calcular el retraso total en horas mutate(vuelos, atraso_hora = (dep_delay + arr_delay)/60) #####Summarize(): permite crear un nuevo dataframe con estadisticas resumidas #summarize(dataframe, nueva_columna = función(columna_existente)) # Suele utilizarse junto con group_by para calcular las estadísticas por grupo # Calcular la media del retraso en la llegada summarize(vuelos, mean(arr_delay, na.rm = TRUE)) #tenia NA, por eso daba que la media era NA, con na.rm = TRUE se limpia # Contar el número total de vuelos summarize(vuelos, total_vuelos = n()) # Cuantas aerolineas distintas hay en el dataset + media de retraso de la llegada summarize(vuelos, n_distinct(carrier), mean(arr_delay, na.rm = TRUE) ) # Puedo calcular varias estadísticas a la vez. min(), max(), mean(), median(), sum(), var(), sd() summarize(vuelos, min_retraso_salida = min(dep_delay, na.rm = TRUE), max_retraso_salida = max(dep_delay, na.rm = TRUE), media_retraso_salida = mean(dep_delay, na.rm = TRUE), mediana_retraso_salida = median(dep_delay, na.rm = TRUE), suma_retraso_salida = sum(dep_delay, na.rm = TRUE), var_retraso_salida = var(dep_delay, na.rm = TRUE), sd_retraso_salida = sd(dep_delay, na.rm = TRUE) ) #Si queremos ver las estadisticas por grupo, necesitamos usar group_by # Calculemos el retraso en la llegada por aerolinea vuelos_agrupados <- group_by(vuelos, carrier) class(vuelos_agrupados) summarize(vuelos_agrupados, mean(arr_delay, na.rm = TRUE)) # Podemos agrupar por más de una variable. # Agrupar el dataframe por 'carrier' y 'month' vuelos_agrupados <- group_by(vuelos, carrier, month) summarize(vuelos_agrupados, media_retraso_llegada = mean(arr_delay, na.rm = TRUE), maximo_retraso = max(arr_delay, na.rm = TRUE)) #calcular por carrier y por mes la media del retraso y el maximo retraso # Calcular el número de vuelos y la media del retraso en la llegada para cada grupo #####El operador pipe: #%>% #|> # f(x, y) se puede escribir como x |> f(y) z <- 15 exp( sin( z ) ) z |> sin() |> exp() # es útil para concatenar múltiples operaciones con verbos de dplyr. # Cada paso del pipeline toma el resultado del paso anterior como primer parametro. # Sin Pipelines # Por ejemplo, si quiero ver por aerolinea, la media del atraso total y la cantidad de vuelos del primer trimestre de 2014 vuelos_filtrados <- filter(vuelos, year == 2014, month >= 1 & month <= 3) vuelos_filtrados_transf <- mutate(vuelos_filtrados, retraso_total = dep_delay + arr_delay) vuelos_filtrados_agrupados <- group_by(vuelos_filtrados_transf, carrier) atraso_por_aerolinea <- summarise(vuelos_filtrados_agrupados, media_retraso = mean(retraso_total, na.rm = TRUE), numero_vuelos = n()) arrange(atraso_por_aerolinea, desc(numero_vuelos)) # Equivalentemente, utilizando pipes con control shift m vuelos %>% filter (year == 2014, month >= 1 & month <= 3) %>% mutate(retraso_total = dep_delay + arr_delay) %>% group_by(carrier) %>% summarise(media_retraso = mean(retraso_total, na.rm = TRUE), numero_vuelos = n()) %>% arrange(desc(numero_vuelos)) # NOTA: esta operación no crea ningún objeto adicional/auxiliar # Desafio: # Con pipelines muestra los 5 vuelos con mayor retraso total: # las columnas mostrar fecha, delay, origen y destino vuelos %>% mutate(retraso_total = dep_delay + arr_delay) %>% mutate() select(retraso_total, ) summarize(numero_vuelos = ) # Podriamos utilizar pipelines y encadenar un gráfico de ggplot. library(ggplot2) # la gramática de ggplot() tambien inicia con los datos # ggplot(DATOS) + goem_TIPO( MAPEO ) # podemos: comenzar con los datos, # realizar operaciones de transfomación con dplyr # graficar los datos transformados con ggplot # todo en un solo bloque de código # vuelos de larga distancia por origen vuelos %>% filter(distance > 2000) %>% ggplot() + geom_bar(aes(x = carrier)) # ver el retraso_total por origen vuelos %>% mutate(retraso_total = dep_delay + arr_delay) %>% ggplot() + geom_boxplot(aes(x = origin, y = retraso_total )) + scale_y_log10() # restraso_total (en logs) por origen y mes: medianas # Gráfiquemos la evolución a lo largo de los meses del atraso total promedio para las aerolineas US, AS y AA ----------- setwd('C:/Users/usuario/Desktop/Certificación') library(tidyverse) propinas <- read_csv("propina.csv") head(propinas) ggplot(data = propinas, aes(x = total, y = propina)) + geom_point() + theme(aspect.ratio = 1) #el dataset tiene que estar en dataframe. También el aspect ratio tiene que tener coherencia pa que no sea cualquier cosa aes(x = total, y = propina, colour = sexo) aes(x = total, y = propina, shape = sexo) aes(x = total, y = propina, size = cantidad) #Para agregar otras variables al gráfico podemos usar otros aes como color, forma o tamaño ggplot(data = propinas, aes(x = total, y = propina, colour = sexo)) + #color geom_point() + theme(aspect.ratio = 1) ggplot(data = propinas, aes(x = total, y = propina, shape = sexo)) + #forma geom_point() + theme(aspect.ratio = 1) ggplot(data = propinas, aes(x = total, y = propina, size = cantidad)) + geom_point(alpha = 1 / 3) + theme(aspect.ratio = 1) #tamanio alpha = 1/3 transparencia donde cada punto es 1/3 del color mpg <- mpg help(mpg) ggplot(data = mpg, aes(x = hwy, y = cty, colour = class)) + geom_jitter(alpha = 1 / 3) + facet_wrap(vars(class)) + #chetisimo theme(aspect.ratio = 1) + labs(x = "Ruta", y = "Ciudad", title = "Consumo de combustible en millas por galon") + scale_color_brewer(palette = 'dark2') ?facet_wrap ggplot(data = propinas, aes(x = sexo, fill = sexo)) + geom_bar() + labs(x = "Sexo", y = "Cantidad", fill = "Sexo") + theme( axis.text = element_text(size = 13, color ="grey")) #tamaño y color del theme, todo lo que no son datos de la gráfica ggplot(data = propinas, aes(x = sexo, fill = sexo)) + geom_bar() + labs(x = "Sexo", y = "Cantidad", fill = "Sexo") + theme( axis.title = element_text(size = 20), axis.text.x = element_text(size =15, color = "grey"), axis.text.y = element_text(size =15, color = 'grey')) #poner tamaños diferentes para la letra ggplot(data = propinas, aes(x = sexo, fill = sexo)) + geom_bar() + labs(x = "Sexo", y = "Cantidad", fill = "Sexo") + theme(legend.position = "top") #cambiar posición de la leyenda ggplot(data = propinas, aes(x = sexo, fill = sexo)) + geom_bar() + labs(x = "Sexo", y = "Cantidad", fill = "Sexo") + theme_grey() #tema ya predefinido ggplot(data = propinas, aes(x = total, y = propina)) + geom_point( aes(colour = fuma)) + scale_x_continuous() + #para transformar la x que es continua scale_y_continuous() + #para transformar la y que es continua scale_colour_discrete() #para transformar los puntos que son discretos ggplot(data = propinas, #siguiendo con lo anterior aes(x = total, y = propina)) + geom_point( aes(colour = fuma)) + scale_x_continuous(limits = c(-10, 60), breaks = seq(-10, 60, 5)) + #por ejemplo, cambiamos los limites del eje x y las separaciones entre marcas scale_y_continuous() + scale_colour_discrete() ggplot() + geom_point(data = propinas, aes(x = total, y = propina)) #este otro ejemplo ggplot() +#es igual a este, nada más que tiene más variables para editar layer( data = propinas, mapping = aes(x = total, y = propina), geom = "point", stat = "identity", position = "identity" ) + scale_x_continuous() + scale_y_continuous() + coord_cartesian() #en esta forma, se usa stat = 'identity' para transformar estadísticamente los valores. position es el metodo más usado para ajustar sobreploteo #como agregar varios conjuntos de datos ggplot() + #si pusiera la fuente de datos en ésta línea, tomaría para todos los aes los datos de ggplot. geom_point(data = propinas, aes(x = total, y = propina)) + #ponerlo en cada uno de éstos hace que puedas usar más de un dato geom_point(data = data.frame(x = 30, y = 6), aes(x, y), color = "red", size = 10) ggplot(data = propinas, aes(x = total, y = propina, color = sexo)) + geom_point() + theme(aspect.ratio = 1) + labs(x = "Total de la cuenta", y = "Propina", color = "Sexo") #agregando labs, ponemos las estiquetas que corresponden ggplot(data = propinas, aes(x = total, y = propina, color = sexo))+ geom_point() + theme(aspect.ratio = 1) + scale_x_continuous(name ="Total de la cuenta") + scale_y_continuous(name = "Propina") + scale_color_discrete(name = "Sexo") #también se pueden poner así, es más completo #uso del color. Para el daltonismo y si es para imprimir #tres usos fundamentales del color: Para distinguir grupos, para representar valores de los datos y para resaltar algo #para distinguir grupos se usa una escala cualitativa, que diferencien a los grupos, que no sobresalga uno por sobre otro y no debe crear la impresion de que hay un orden #tipos cualitativos: Okabe Ito, ColorBrewer Dark2 y ggplot2 hue #para representar valores de los datos se usa una escala secuencial, que indica que hay valores superiores e inferiores y cuanto, que varía uniformemente en su rango de vlaores y debe ser una sola tolanlidad o multiples tonalidades #tipo secuencial: ColorBrewer Blues, Heat y Viridis #tipo secuencial divergente (para visualizar desviacion de valores respecto a un punto medio neutral): CARTO Earth, ColorBrewer PiYG y Blue-Red #como herramienta para resaltar, se usa una escala de colores acentuada #tipo acentuada: Okabe Ito Accent, Grays with accents y ColorBrewer Accent #usar la página colorbrewer2.org #cambio de color manual propinas <- read_csv("propina.csv") ggplot(data = propinas, aes(x = total, y = propina, color = sexo)) + geom_point() + theme(aspect.ratio = 1) + labs(x = "Total de la cuenta", y = "Propina", color = "Sexo") + scale_color_manual(values=c("#ffb554", "#6cc0a1")) ggplot(data = propinas, aes(x = total, y = propina, #cambio de color con palette = 'Dark2' color = sexo)) + geom_point() + theme(aspect.ratio = 1) + labs(x = "Total de la cuenta", y = "Propina", color = "Sexo") + scale_colour_brewer(palette = "Dark2") ggplot(data = propinas, aes(x = sexo, fill = sexo)) + labs(x = "Sexo", y = "Cantidad", fill = "Sexo") + geom_bar() + scale_fill_manual(values=c("#ffb554", "#6cc0a1")) #acá el elemento estético es fill, no es colour #theme_bw = ggplot(data = propinas, aes(x = sexo, fill = sexo)) + geom_bar() + labs(x = "Sexo", y = "Cantidad", fill = "Sexo") + theme(aspect.ratio = 1, legend.position = "bottom", panel.background = element_rect(fill = "white"), panel.border = element_rect(colour = "grey20", fill = NA), panel.grid = element_line(colour = "grey92"), panel.grid.minor = element_line(size=rel(0.5)), strip.background = element_rect(fill="grey85", colour="grey20"), legend.key = element_rect(fill="white")) library(here) library(tidyverse) library(GGally) indiana <- read_csv(here('indiana_data.csv')) str(indiana) ---------- ts(vector, start = , end =, frequency = ) #esta funcion permite convertir un vector numerico en un objeto de serie de tiempo #la clase date() maneja fechas sin horas #la clase POSIXt permite fechas y horas con control de zonas horarias. #existen dos subclases: POSIXct, que representa valores de fecha y hora como el numero de segundos desde la medianoche GMT #y POSIXlt... #las complicaciones en la manipulacion de estas dos clases provocaron la aparicion de varios paquetes #en CRAN task view on Time series Analyisis tienetodos #Varios paquetes son utiles, como: zoo, xts, lubridate y Forecast. #sin embargo con los paquetes vienen clases de objetos y representaciones de datos diferentes #formato fecha y hora: parece facil, no lo es #primero: muchos formatos diferentes, reconocerlos y analizarlos es dificil #segundo: la aritmetica con fechas y horas es complicada #es dificil porque tienen que conciliar dos fenomeno fisicos: la rotacion de la tierra alrededor del sol #con fenomenos geopoliticos que incluyen meses, zonas horarias y horario de verano #paquete: lubridate #facil de capturar los problemas en formato fecha y hora fecha <- as.Date("2021/11/6") fecha class(fecha) as.Date("12/31/1999", format = "%n/%d/%Y") format(fecha, "%Y") as.numeric(format(fecha, "%Y")) weekdays(fecha) #que dia es seq( from = as.Date("2021/6/1"), to = as.Date ("2021/7/31"), by = "1 week" ) fecha_hora <- "2021-11-06 22:10:35" fecha_hora objetos <- as.POSIXct(fecha_hora) Sys.timezone() as.POSIXct("30-6-2021", format = '%d-%n-%Y %H:%M') library(lubridate) ymd(20221215) #me tira la fecha de una ymd_hm(202212151533) #fecha y hora de una mdy("Abril 13, 1978") dmy(248624) hoy <- Sys.time() #la hora del sistema hoy year(hoy) month(hoy) month(hoy, label = TRUE) wday(hoy, label = TRUE, abbr = FALSE) #con etiquetas y no haga abreviaciones yday(hoy) #dia del anio hour(hoy) week (hoy) ################# #pipa: shit+control+n ------------ install.packages("tidyverse") library("tidyverse") head(mtcars) filter(mtcars, mpg > 22) (dat_red <- filter(mtcars, mpg > 22)) #si le pones parentesis te printea el resultado filter(mtcars, mpg == 24.4 & gear == 4) #solo hay una observacion que plantea esto filter(mtcars, mpg == 24.4 | mpg == 22.8) #las filas que les pasa mpg = 24.4 o las de 22.8 filter(mtcars, mpg %in% c(24.4,22.8)) #Si quiero todas las filas donde mpg es uno de los valores del vector en la derecha, tengo que usar %in% filter(mpg, manufacturer %in% c("audi", "honda") & year == 1999 & cyl == 4) #que sea audi o honda, del 99 y cilindrada de 4 arrange(mtcars, mpg ) #ordename la fila por mpg arrange(mtcars, mpg, qsec) #ordename la fila al principio por mpg, y despues por qsec arrange(mtcars, desc(mpg) ) #ordename la fila por mpg pero al reves select(mtcars, ends_with("t")) #agarrame solo las columnas que terminan con "t" select(mtcars, wt:gear ) #tomame las columnas desde wt a gear select(mtcars, !(wt:gear) ) #agarrame las que no esten desde wt a gear. No usar el -, usar ! select(mtcars, carb, hp,everything() ) #tomame todas las columnas pero primero carb y hp mutate(mtcars, wtkg = wt*0.45359*1000) #mutate() se usa para crear o modificar variables (columna) como función de variables existentes. Siempre se agrega al final de data.frame() mutate(mtcars, wtkg = wt*0.45359*1000, .keep = "none") #i solamente queremos quedarnos con las nuevas variables debemos incluir .keep = "none" #rename() si queremos mantener todas las variables y solo renombrar algunas #relocate() para mover variables, si quiero llevar variables al frene o agruparlas (argumento .before o .after una variable particular) #group_by() toma los datos y introduce grupos para cada nivel de la variable de grupo #summarise() Crea resúmenes de data.frame() por grupos, el resultado es una fila para cada grupo de datos. mtcars |> group_by(cyl) |> summarise(cyl_n = n() ) #agrupalo por cantidad de cilindros y contame los n de cada grupo mtcars |> group_by(cyl) |> count( ) #lo mismo que arriba mtcars |> group_by(cyl,gear) |> summarise(cyl_n = n() ) #agrupalo por dos variables y tomame los que tengan ambas categorias mtcars |> group_by(cyl) |> summarise( mean_mpg = mean(mpg) ) #quiero la media de mpg, ordenala por cyl. Promedio de las millas por galon para cada cilindrada. mtcars |> group_by(cyl) |> summarise( media_mpg = mean(mpg) ) |> ggplot(aes(x = cyl, y = media_mpg)) + geom_point() #combinar lo anterior con un grafico mtcars |> group_by(cyl) |> summarise( media_mpg = mean(mpg) ) |> ggplot(aes(x = cyl, y = media_mpg)) + geom_point(color ="red", size = I(3))+ geom_point(data = mtcars, aes(x = cyl, y = mpg), alpha = 1/3) #mas lindo mtcars |> group_by(cyl) |> summarise( media_mpg = mean(mpg), se = sd(mpg)/sqrt(n()) #le sumas el error estandar ) |> ggplot(aes(x = cyl, y = media_mpg)) + geom_point(color ="red", size=3) + geom_point(data = mtcars, aes(x = cyl, y = mpg), alpha = 1/3)+ geom_errorbar(aes(ymin = media_mpg - 2*se, ymax = media_mpg + 2*se), #sumale las desviaciones width = .2) #aun mas lindo mpg |> select(class) |> table() #recodificar las clases. Queremos recodificar class, usamos case_match() library(tidyverse) mpg |> select(class) |> mutate(class = case_match(class, "2seater" ~ "2se", "compact" ~ "co", "midsize" ~ "mid", "minivan" ~ "mini", "pickup" ~ "pi", "subcompact" ~ "sub", "suv" ~ "su"))|> select(class) |> table() #se recodifican los nombres de la variable mpg |> select(cyl) |> table() #quiero cambiar los nombres de la variable cilindrada mpg |> select(cyl) |> mutate(cyl = case_match(cyl, 4 ~ 3, 5~ 3, 6 ~ 7, 8~ 5)) |> select(cyl) |> table() #mutar nos nombres de 4 a 3, de 5 a 3, etc. mpg |> select(cyl) |> mutate(cyl = case_when( cyl %in% c(4, 5) ~ 3, cyl %in% 6 ~ 7, cyl %in% 8~ 5)) |> select(cyl) |> table() #lo mismo que el anterior, es preferible el anterior mpg |> slice(n()) #selecciona filas por su posicion mpg |> slice(7:9) #selecciona las filas 7 a 9 # slice_head() y slice_tail() seleccionan la primera y la última fila # slice_min() y slice_max() seleccionan filas con el valor más grande o chico en una variable # slice_sample() selecciona filas aleatoriamente #perar en múltiples columnas al mismo tiempo mediante across(). across() hace sencillo aplicar la misma transformación a muchas columnas usando #la misma semántica que select() dentro de funciones como summarise() y mutate() #across tiene dos argumentos básicos: #las columnas que queremos seleccionar .cols, se pueden seleccionar variables por nombre, posición o tipo (tipo el usado en select()) #Segundo argumento de across() es .fns, que es una función o lista de ellas que se aplican a cada columna. Puede usarse con estilo fórmula mtcars |> group_by(cyl, disp) |> summarise( mwt = mean(wt), mmpg = mean(mpg), mdrat = mean(drat) ) #acá, con across va a ser más sencillo mtcars |> group_by(cyl, disp) |> summarise( across(.cols = c(wt,mpg,drat), .fns = mean)) #se aplica la media a tres variables distintas, porque le pusimos como transformacion mean mtcars |> group_by(cyl, disp) |> summarise(across(.cols = c(wt,mpg,drat), .fns = mean,na.rm = TRUE, .names = "{col}_mean") ) #ahora le sumas para que te salga el resumen con un nombre que tenga más sentido mtcars |> summarise(across(.cols = c(wt,mpg,drat), .fns = list(mean = mean, sd = sd), na.rm = TRUE)) #Podemos transformar cada variable con más de una función nombradas en una lista. Acá se hizo una lista con a media y los desvios mpg |> summarise(across(where(is.numeric), mean, na.rm = TRUE)) #quiero que me hagas todas las medias si las variables son numéricas. where() es una función de ayuda que selecciona las variables para las que una función retorna TRUE. mpg |> summarise(across(where(is.numeric), mean, na.rm = TRUE)) #es igual a #Equivalente mpg |> summarise(across(where(is.numeric), ~ mean(.x, na.rm = TRUE))) #esto #estructuracion de datos #pivot_longer() reestructura los datos moviendo columnas a filas. #pivot_wider() reestructura los datos moviendo filas a columnas. #separate divide columnas en múltiples variables. library(tidyverse) medico <- tibble(nombre = c("Pablo Gomez", "Mariana Mattos", "Laura Almo"), tratamientoa = c(NA, 4, 6), tratamientob = c(18, 1, 7)) #ejemplo #Necesitamos unir (pivot) estas columnas en un nuevo par de variables. Necesitamos #describir tres argumentos: #Las columnas cuyos nombres son valores no variables, en este caso tratamientoa y # tratamientob, argumento cols #Un nombre para la variable cuyo valor está en el nombre de la columna, en este caso le # podemos llamar tratamiento, argumento names_to #Un nombre para la variable cuyos valores están en las celdas, en este caso le podemos # llamar casos, argumento values_to #pivot_longer(data, cols, names_to, values_to,...) #data: data.frame a pivotar #cols: Columnas a pivotar en formato largo #names_to: un vector de tipo character que especifica el nombre de la columna o # columnas a crear con los datos contenidos en el nombre de la columna #values_to: un string especificando el nombre de la columna a crear con los datos # contenidos en las celdas #…: otros argumentos medico |> pivot_longer(cols = c("tratamientoa", "tratamientob"), names_to = "tratamiento" , values_to = "conteo") #modificamos la tabla en base a los argumentos. Pasa de columnas a filas medico |> pivot_longer(cols = starts_with("tratamiento"), names_to ="tratamiento" , values_to = "conteo") #equivalente medico |> pivot_longer(cols = 2:3, names_to ="tratamiento" , values_to = "conteo") #equivalente medico |> pivot_longer(cols = !nombre, names_to ="tratamiento" , values_to = "conteo") #equivalente pivotmed <-medico |> pivot_longer(cols = c("tratamientoa", "tratamientob"), names_to ="tratamiento" , values_to = "conteo") |> mutate(tratamiento = case_match(tratamiento, "tratamientoa" ~ "a", "tratamientob" ~ "b")) #modificación con cambio de nombres pivotmed |> pivot_wider(names_from = tratamiento, values_from = conteo) #reestructuración con pivot wider. Es para pasar filas a columnas #separate separa una columna en múltiples columnas. Por defecto cualquier símbolo no alfanumérico se usa para separar la columna, #Principales parámetros #data: data.frame. #col: el nombre de la columna o posición. #into: nombres de las nuevas variables para crear, vector tipo character. #sep: separador entre columnas #Formalmente si es de tipo character, sep es una expresión regular que veremos en más detalle luego. Si es numeric, sep es interpretado como una posición para separar contando de izquierda a derecha arranca en 1 y de derecha a izquierda de -1 tib <- tibble(x =c(NA, "a*b", "a.c", "a&d"), month_year = c(121999, 112005, 102001, 102001) ) #creando una tablita tib |> separate(col = x, into = c("V1", "V2")) #Separamos la columna 1 en dos variables, tomando los valores alfanumericos, los . # asteriscos los borran tib |> separate(col = month_year, into = c("month", "year"), sep = 2) #se separa en mes y año tib2 <- tibble(x =c(NA, "1*b", "3.c", "8&d"), month_year = c(121999, 112005, 102001, 102001) ) #nuevo ejemplo con números al principio tib2 |> separate(col = x, into = c("V1", "V2")) #me lo cambia a variable caracter el número tib2 |> separate(col = x, into = c("V1", "V2"), convert = TRUE) #de ésta forma se mantiene el formato numérico #unite() es el inverso de separate(). Pega múltiples columnas en una. tib3 <- tib |> separate(month_year, into = c("month", "year"), sep = 2) tib3 |> unite(col = v1, month, year ) #lo pegoteas de vuelta al month e year #JOINS #tipos de joins: Mutating joins y Filtering joins #Keys o claves son variables que permiten identificar de forma univoca un registro de otro #Una clave con una única variable puede ser la cédula, pero por ejemplo, pueden haber cedulas de varios paises, donde se puede repetir #el número pero ser personas diferentes. En ese caso, se obvservan combinaciones de claves. #Tipos de claves: primaria y foránea. La primaria es una variable o conjunto de variables que identifican cada observacion de forma única. #la clave foránea es una variable o conjunto de variables que corresponden a una clave primaria en otra tabla. #joins inner_join(x,y) #interseccion de dos conjuntos full_join(x,y) #union total de dos conjuntos left_join(x,y) #union por el grupo de la izquierda right_join(x,y) #union por el grupo de la derecha #ejemplo install.packages("nycflights13") library(nycflights13) library(dplyr) library(ggplot2) x <- tibble(key = 1:4, val_x = c("x1", "x2", "x3", "x4")) y <- tibble(key = c(1, 2, 5), val_y = c("y1", "y2", "y3")) left_join(x, y, by = "key") # left_join(y, x, by = "key") right_join(x, y, by = "key") #lo mismo por el inner_join(x, y, by = "key") full_join(x, y, by = "key") #filtering joins. Filtra observaciones de una base de datos en base a si mactchean o no entre tablas semi_join(x,y) #mantiene todas las observaciones en x que tienen una correspondencia en y anti_join(x, y) #elimina todas las observaciones en x que tienen una correspondencia en y #ejemplo x <- tibble(key = 1:4, val_x = c("x1", "x2", "x3", "x4")) y <- tibble(key = c(1, 4, 5, 6), val_y = c("y1", "y4", "y5", "y6")) semi_join(x, y, by = "key") inner_join(x, y, by = "key") anti_join(x, y, by = "key") #ejercicio manufacturer_info <- tibble(manufacturer = c("audi", "toyota", "ford", "chevrolet", "honda"), country = c("Germany", "Japan", "USA", "USA", "Japan"), founded_year = c(1909, 1937, 1903, 1911, 1948)) df <- mpg left_join(df, manufacturer_info) #se le suma las columnas relacionadas al pais y el anho right_join(df, manufacturer_info, by = "manufacturer") #lo mismo pero solo toma a los manufacturers de manufacturer_info semi_join (df, manufacturer_info, by = "manufacturer") ####### library} ----------- #####formato de fechas paquete base fecha <- as.Date("2021/11/6") fecha class(fecha) as.Date("12/31/1999", format = "%m/%d/%Y") format(fecha, "%Y") as.numeric(format(fecha, "%Y")) weekdays(fecha) seq(from = as.Date("2021/6/1"),to = as.Date("2021/7/31"),by = "1 week") fecha_hora <- "2021-11-06 22:10:35" fecha_hora class(fecha_hora) fecha_hora_clase_adecuada<-as.POSIXct(fecha_hora) Sys.timezone() as.POSIXct("30-6-2021 23:25", format = "%d-%m-%Y %H:%M") #paquete LUBRIDATE library(lubridate) class(ymd(20221215)) ymd_hm(202412151533) mdy("Abril 13, 1978") dmy(240624) hoy <- Sys.time() hoy year(hoy) month(hoy) month(hoy, label = TRUE) week(hoy) mday(hoy) wday(hoy) wday(hoy, label = TRUE)#, abbr = FALSE) yday(hoy) hour(hoy) minute(hoy) #ejemplo de datos de series de tiempo #importancia de la "dependencia" en el tiempo dolar <- read.csv("modulo3/dolar.csv",dec=",") View(dolar) class(dolar) str(dolar) library(lubridate) library(tidyverse) #CAMBIO BASE DE DATOS PARA LA FECHA EN FORMATO DATE dolar<- dolar %>% mutate(FECHA= dmy(FECHA)) #ordenar los datos #datos_ordenados<-sort(dolar_uruguay$CIERRE_BCU_BILLETE) #GRAFICO SERIE DE TIEMPO # RECORDAMOS FORMATO: ggplot(DATOS) + geom_TIPO( aes( MAPEO ) ) ggplot(dolar) + geom_line( aes(x=FECHA, y=CIERRE_BCU_BILLETE)) ggplot(dolar) + geom_line( aes(x=FECHA, y=MEJORES_OFERTAS_FONDO_COMPRA)) #OBSERVAR DIFERENTES COMPORTAMIENTOS DE LA SERIE TEMPORAL ggplot(dolar) + geom_line( aes(x=FECHA, y=CANTIDAD_OPERACIONES)) ggplot(dolar) + geom_line( aes(x=FECHA, y=CANTIDAD)) #¿¿¿POR QUÉ ES TAN INTERESANTE LA VARIABLE TIEMPO???? #INVENTO UNA NUEVA VARIABLE DENOMINADA "CIERRE_BCU_BILLETE_ORD" DONDE ORDENO LOS DATOS #GRAFICA DE SERIES DE TIEMPO dolar %>% mutate(CIERRE_BCU_BILLETE_ORD=sort(CIERRE_BCU_BILLETE)) %>% select(FECHA, CIERRE_BCU_BILLETE,CIERRE_BCU_BILLETE_ORD) %>% pivot_longer(2:3,names_to = "CIERRE",values_to = "COTIZACION") %>% group_by(CIERRE) %>% mutate(PROMEDIO=mean(COTIZACION)) %>% ggplot() + geom_line( aes(x=FECHA, y=COTIZACION))+ geom_line(aes(x=FECHA,y=PROMEDIO), color="blue")+ facet_wrap(~CIERRE,ncol = 1) #BOXPLOT DE DATOS DE "AMBAS VARIABLES" dolar %>% mutate(CIERRE_BCU_BILLETE_ORD=sort(CIERRE_BCU_BILLETE)) %>% select(FECHA, CIERRE_BCU_BILLETE,CIERRE_BCU_BILLETE_ORD) %>% pivot_longer(2:3,names_to = "CIERRE",values_to = "COTIZACION") %>% ggplot() + geom_boxplot( aes( y=COTIZACION),color=c("red","blue"))+ facet_wrap(~CIERRE) #HISTOGRAMA DE DATOS DE "AMBAS VARIABLES" dolar %>% mutate(CIERRE_BCU_BILLETE_ORD=sort(CIERRE_BCU_BILLETE)) %>% select(FECHA, CIERRE_BCU_BILLETE,CIERRE_BCU_BILLETE_ORD) %>% pivot_longer(2:3,names_to = "CIERRE",values_to = "COTIZACION") %>% ggplot() + geom_histogram( aes( x=COTIZACION),colour="blue", fill="white")+ facet_wrap(~CIERRE) --------- library(readxl) library(forecast) dolar_uruguay <- read_excel("modulo3/HistoricoDiario.xlsx") View(dolar_uruguay) class(dolar_uruguay) str(dolar_uruguay) #nos generamos el objeto ts en el paquete base time_serie_dolar<-ts(dolar_uruguay$CIERRE_BCU_BILLETE[858:1], frequency=252, start = c(2021, 1)) #grafico autoplot(time_serie_dolar ) #mostrar datos print(time_serie_dolar) #ventana de datos (sub intervalo) time_serie_dolar_sub <- window(time_serie_dolar, start=c(2022, 1), end=c(2023,126)) print(time_serie_dolar_sub) autoplot(time_serie_dolar_sub ) #propiedades de ts start(time_serie_dolar) end(time_serie_dolar) frequency(time_serie_dolar) #TRANSFORMACIONES # REZAGAR UN PERÍODO LA SERIE (sin instalar el tidyverse ) time_serie_dolar_lag1 <- lag(time_serie_dolar, 1) head(cbind(time_serie_dolar, time_serie_dolar_lag1)) # REZAGAR TRES PERÍODOS LA SERIE time_serie_dolar_lag3 <- lag(time_serie_dolar, 3) head(cbind(time_serie_dolar, time_serie_dolar_lag3)) # ADELANTAR UN PERÍODO LA SERIE time_serie_dolar_lead1 <- lag(time_serie_dolar, -1) head(cbind(time_serie_dolar, time_serie_dolar_lead1)) # PRIMERA DIFERENCIA DE LA SERIE time_serie_dolar_diff1 <- diff(time_serie_dolar, lag = 1) pd_tm <- cbind(time_serie_dolar, time_serie_dolar_diff1) head(pd_tm) plot.ts(pd_tm,main="PRIMERA DIFERENCIA DE LA SERIE") # DIFEERENCIA DE LA SERIE EN DOS PERIODOS time_serie_dolar_diff2 <- diff(time_serie_dolar, lag = 2) pd_tm_2 <- cbind(time_serie_dolar, time_serie_dolar_diff2) head(pd_tm_2) plot(pd_tm_2,main="DIFEERENCIA DE LA SERIE EN DOS PERIODOS") # LOGARITMO DE LA SERIE time_serie_dolar_log <- log(time_serie_dolar) log_tm <-cbind(time_serie_dolar, time_serie_dolar_log) plot.ts(log_tm, main="LOGARITMO DE LA SERIE") #PORCENTAJE DE CAMBIO DE UN PERIODO A OTRO (y_t/y_t-1) -1 time_serie_dolar_pch <- time_serie_dolar / lag(time_serie_dolar, -1) - 1 head(cbind(time_serie_dolar, time_serie_dolar_pch)) pc_tm <-cbind(time_serie_dolar, time_serie_dolar_pch) plot.ts(pc_tm, main="ORCENTAJE DE CAMBIO DE UN PERIODO A OTRO") #DIFERENCIA Y LOGARITMO SON COMBINADOS ENTRE ELLOS #log diferencia es una función muy util para hacer no-estacionaria en estacionaria (además de otras buenas propiedades) time_serie_dolar_dlog <- ts(diff(log(time_serie_dolar)), frequency=252, start = c(2021, 1)) pc_dl<-cbind(time_serie_dolar, time_serie_dolar_dlog) plot.ts(pc_dl,main="DIFERENCIA Y LOGARITMO SON COMBINADOS ENTRE ELLOS") #TRANSFORMACION BOX-COX #x^(lambda)-1 / lambda con (lambda diferente a 0) #log (x) con lambda =0 time_serie_dolar_BC <- BoxCox(time_serie_dolar, lambda = 0.5) pc_BC<-cbind(time_serie_dolar, time_serie_dolar_BC) plot.ts(pc_BC,main="BOX COX") #ENCONTRAR EL LAMBDA "OPTIMO" lambda_est <- BoxCox.lambda(time_serie_dolar) print(lambda_est) time_serie_dolar_BC_OPTIMO <- BoxCox(time_serie_dolar, lambda =lambda_est) pc_BC_OPTIMO<-cbind(time_serie_dolar, time_serie_dolar_BC_OPTIMO) plot.ts(pc_BC_OPTIMO,main="BOX COX") ------------- library(readxl) library(forecast) dolar_uruguay <- read_excel("modulo3/HistoricoDiario.xlsx") time_serie_dolar<-ts(dolar_uruguay$CIERRE_BCU_BILLETE[858:1], frequency=252, start = c(2021, 1)) #metodologia DECOMPOSE fit<-decompose(time_serie_dolar,type="additive") plot(fit) #serie desestacionalizada plot(time_serie_dolar, col='green') lines(seasadj(fit)) #metodologia STL fit_2<-stl(time_serie_dolar, s.window = 'periodic') plot(fit_2) #encontrar la serie "trend" fit_2$time.series[,2] #OBTENER LA SERIE TENDENCIA/CICLO #MEDIANTE MEDIAS MÓVILES library("fpp2") library("zoo") mm_5<-rollmean(time_serie_dolar, k = 5, fill = NA) mm_9<-rollmean(time_serie_dolar, k = 9, fill = NA) mm_15<-rollmean(time_serie_dolar, k = 15, fill = NA) mm_19<-rollmean(time_serie_dolar, k = 19, fill = NA) plot(time_serie_dolar) lines(mm_5, col='blue') lines(mm_9, col='green') lines(mm_15, col='red') lines(mm_19, col='orange') #OBTENER LA PROYECCION DE SERIE TENDENCIA/CICLO #MEDIANTE SUAVIZADO EXPONENCIAL #metodologia usual fit_ses<-ses(time_serie_dolar,h=40, initial ="simple", alpha=0.1) #ajuste vs real plot(fit_ses$fitted, col="red") lines(time_serie_dolar) #residuos hist(fit_ses$residuals) #proyecciones summary(fit_ses) plot(fit_ses) #MEDIANTE SUAVIZADO EXPONENCIAL #metodlogia Holt Winters m1 <- HoltWinters(time_serie_dolar,alpha = 0.75, beta = FALSE, gamma = FALSE) plot(time_serie_dolar,col ="blue", lwd = 3) lines(m1$fitted[,1], col ="red", lwd=1) #mirar los cambios al variar alpha m2 <- HoltWinters(time_serie_dolar,alpha = 0.25, beta = FALSE, gamma = FALSE) lines(m2$fitted[,1], col ="green", lwd=1) ---------- # Clase 4: modelo de regresión - series temporales # Repasamos: # manipulación de datos # formato de fechas # auto-correlacion y otros gráficos, # componentes de una serie # Modelos # regresión simple # regresion con componentes de la serie # prediccion de casos ####################################### # 1) Los datos ------------------------ library(tidyverse) # manejo de datos library(readxl) # leer datos de planillas install.packages("ggthemes") library(ggthemes) # aspectos gráficos # leer los datos desde la planilla getwd() setwd ("C:/Users/usuario/Desktop/Certificación/Series temporales") dd <- read_xlsx('1. Gasto_K.xlsx', range = 'A8:AL17') colnames(dd) # 9 filas - 38 columnas # columnas: nombres de la series, valor en cada trimestre en columnas # debemos transformar: # - cada serie a una columna # - cada fila corresponda un trimestre # - dar formato de fecha # Utilizamos herramientas de manipulación para ordenar los datos # pivot_longer() para llevar las columnas de valores a filas # seleccionar las columnas con datos # pivot_wider() para formar las columnas relevantres # set_names para definir los nombres de las columnas dd |> pivot_longer(cols = 6:38, names_to = 'fecha')|> #pasar las columnas de los valores de pib (6:38) a una fila select('...2', fecha, value) |> #seleccionando las variables estas pivot_wider(names_from = ...2, values_from = value) |> #giramos los valores a las filas set_names( nm = c('fecha', 'consumo', 'hogares', 'gobierno', 'fbk', 'fbkf', 've', 'xpor', 'impor', 'pib')) #cambiar nombres columnas # Le damos estructura temporal library(lubridate) # usar ym() para definir año mes y ver ejemplos con seq() ym('2016-03') # bibilotecas para series temporales install.packages("tsibble") library(tsibble) # manejo de datos temporales install.packages("fable") library(fable) # modelos y predicciones install.packages("feasts") library(feasts) # extraccion de señales # armamos la fecha: desde 2016.1, a 2024.1 seq(1, 10, by = .5) trs <- seq(ym('2016-03'), ym('2024-03'), by = '1 quarter') yearquarter(trs) # ponemos la fecha y armamos tsibble dts <- dt |> mutate(trimestre = seq(ym('2016-03'), ym('2024-03'), by = '1 quarter')) |> #me tiro error as_tsibble(index=trimestre) # 2) Gráficos ------------------------ # graficar la serie ggplot(dts) + geom_line(aes(trimestre, pib)) # auto-correlaciones y gráficos: ACF(), PACF(), gg_tsdisplay() # varias series juntas: seleccionamos, pivoteamos, graficamos # matriz de scatter-plots (pib, consumo, FBK, xport, import) # funcion ggpairs() library(GGally) # descomposicion con STL dts |> model( stl = STL(pib) ) |> components() |> autoplot() ####################################### # 3) Modelo de regresion ------------------------ # Relaciones: efectos sobre pib # TSLM para modelar # report() para ver resultados # gg_tsresiduals() para diagnóstico # m1: pib ~ consumo # agregamos otros factores, FBKfijo # un modelo solamente con componentes de pib # Predicción con el modelo, forecast(), para graficar autolayer() forecast(m3, h=3) forecast(m2, h=3) # necesitamos predecir las x!! # Predicciones bajo scenarios alternativos # base: datos 2023 trimestres 2 a 4, # armamos escenarios: aumenta o caida de 10% casos <- scenarios( aumento = dt.casos |> mutate(trimestre=trimestre+4, consumo=1.1*consumo, FBKfijo=1.1*FBKfijo), caida = dt.casos |> mutate(trimestre=trimestre+4, consumo=.9*consumo, FBKfijo=.9*FBKfijo), names_to = 'casos' ) pred.casos <- forecast(m2, new_data = casos ) -------- rm(list = ls()) # Ejemplo Regresion Lineal # Julio 2024 # mtcars contiene información sobre diversas características de diferentes modelos de automóviles # # 1. mpg: Millas por galón (Miles/(US) gallon). # 2. cyl: Número de cilindros. # 3. disp: Desplazamiento (pulgadas cúbicas). # 4. hp: Potencia bruta (caballos de fuerza). # 5. drat: Relación de transmisión trasera. # 6. wt: Peso del automóvil (en miles de libras). # 7. qsec: Tiempo de 1/4 de milla (en segundos). # 8. vs: Forma del motor (0 = en V, 1 = en línea). # 9. am: Tipo de transmisión (0 = automática, 1 = manual). # 10. gear: Número de marchas hacia adelante. # 11. carb: Número de carburadores. # Cargar las librerías necesarias library(ggplot2) library(Metrics) library(caret) # Cargar el dataset data("mtcars") # Establecer la semilla para reproducibilidad set.seed(123) # Subdividir el dataset en 80% entrenamiento y 20% prueba sample <- sample(seq_len(nrow(mtcars)), size = 0.8 * nrow(mtcars)) train <- mtcars[sample, ] test <- mtcars[-sample, ] # Ajustar el modelo de regresión lineal múltiple modelo_multiple <- lm(mpg ~ cyl + disp + hp + drat + wt + qsec + vs + am + gear + carb, data = train) # Resumen del modelo summary(modelo_multiple) # Hacer predicciones en el conjunto de prueba predicciones <- predict(modelo_multiple, test) # Calcular el MSE usando el paquete Metrics mse <- mse(test$mpg, predicciones) print(paste("MSE:", mse)) # Calcular R² usando el paquete caret r2 <- R2(predicciones, test$mpg) print(paste("R²:", r2)) # Calcular RSE manualmente rss <- sum((test$mpg - predicciones)^2) # Residual Sum of Squares rse <- sqrt(rss / df.residual(modelo_multiple)) # Residual Standard Error print(paste("RSE:", rse)) # Crear un dataframe con los valores observados y predichos resultados <- data.frame(Observado = test$mpg, Predicho = predicciones) # Crear el gráfico con ggplot2 ggplot(resultados, aes(x = Observado, y = Predicho)) + geom_point(color = "blue") + # Puntos de observación geom_abline(intercept = 0, slope = 1, color = "red", linetype = "dashed") + # Línea de referencia labs(title = "Valores Observados vs Predichos en el Conjunto de Prueba", x = "Valor Observado", y = "Valor Predicho") + theme_minimal() ---------- rm(list = ls()) # Ejemplo Logistic Regression # Julio 2024 # Descripción del Conjunto de Datos “titanic” # # El dataset “Boston” consta de 506 observaciones, 14 variables y describe información # sobre varios factores que afectan en los valores de las viviendas en Boston. # # 1. Survived: Indica si el pasajero sobrevivió. (0 = No, 1 = Sí) # 2. Pclass: Clase del boleto del pasajero.(1 = Primera clase, 2 = Segunda clase, 3 = Tercera clase) # 3. Name: Nombre del pasajero. # 4. Sex: Sexo del pasajero. (male, female) # 5. Age: Edad del pasajero en años. # 6. SibSp: Número de hermanos/esposos a bordo. (0, 1, 2, …) # 7. Parch: Número de padres/hijos a bordo. (0, 1, 2, …) # 8. Ticket: Número del boleto. # 9. Fare: Precio del boleto del pasajero. # 10. Cabin: Número de cabina. # 11. Embarked: Puerto de embarque. (C = Cherburgo, Q = Queenstown, S = Southampton) # Desafío Titanic # https://www.kaggle.com/competitions/titanic # Instalar y cargar el paquete titanic #install.packages("titanic") #install.packages("pROC") library(titanic) library(pROC) # Cargar el conjunto de datos data = read.csv("titanic.csv", sep = ",", dec = ".", fileEncoding="latin1") # Ver las primeras filas del conjunto de datos head(data) # Resumen de las variables summary(data) # Resumen algunas variables summary(as.factor(data$Survived)) # Valores únicos unique(data$Embarked) # Sustituyo valores vacios por NA data$Cabin[data$Cabin == ""] <- NA data$Embarked[data$Embarked == ""] <- NA # Valores faltantes sum(is.na(data)) # Calcular el número de NAs por cada variable na_counts <- sapply(data, function(x) sum(is.na(x))) # Convertir el resultado a una tabla na_table <- data.frame(Variable = names(na_counts), NAs = na_counts) na_table # Eliminar columnas innecesarias data <- data[, c("Survived", "Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked")] # Eliminar filas con valores NA data <- na.omit(data) # Factorizar variables data$SexFactor = as.factor(data$Sex) data$EmbarkedFactor = as.factor(data$Embarked) # Eliminar columnas innecesarias data <- data[, c("Survived", "Pclass", "SexFactor", "Age", "SibSp", "Parch", "Fare", "EmbarkedFactor")] # ------------------------------- SEPARO DATOS -------------------------------------------- # Subdividir el dataset en 80% entrenamiento y 20% prueba set.seed(128) sample <- sample(seq_len(nrow(data)), size = 0.8 * nrow(data)) train <- data[sample, ] test <- data[-sample, ] # ------------------------------- REGRESION LOGISTICA -------------------------------------------- # Ajustar el modelo de regresión logística model <- glm(as.factor(Survived) ~ ., data = train, family = binomial) model # Resumen del modelo summary(model) # ------------------------------- VALIDO CON MUESTRA TEST -------------------------------------------- # Hacer predicciones en el conjunto de prueba predictions <- predict(model, newdata = test) # Convertir las probabilidades en etiquetas de clase predicted_classes <- ifelse(predictions > 0.5, 1, 0) # Evaluación del modelo # Matriz de confusión confusion_matrix <- table(predicted_classes, test$Survived) print(confusion_matrix) # Calcular la precisión accuracy <- (confusion_matrix[1, 1] + confusion_matrix[2, 2])/(confusion_matrix[1, 1] + confusion_matrix[1, 2] + confusion_matrix[2, 1] + confusion_matrix[2, 2]) print(paste("Accuracy:", accuracy)) # Calcular la precisión, recall y F1 Score para VIDA (1) precision_vida <- confusion_matrix[2, 2] / (confusion_matrix[2, 1] + confusion_matrix[2, 2]) recall_vida <- confusion_matrix[2, 2] / (confusion_matrix[2, 2] + confusion_matrix[1, 2]) f1_score_vida <- 2 * precision_vida * recall_vida / (precision_vida + recall_vida) # Calcular la precisión, recall y F1 Score para MUERTE (0) precision_muerte <- confusion_matrix[1, 1] / (confusion_matrix[1, 1] + confusion_matrix[1, 2]) recall_muerte <- confusion_matrix[1, 1] / (confusion_matrix[1, 1] + confusion_matrix[2, 1]) f1_score_muerte <- 2 * precision_muerte * recall_muerte / (precision_muerte + recall_muerte) print(paste("Precision_vida:", precision_vida)) print(paste("Recall_vida:", recall_vida)) print(paste("F1 Score_vida:", f1_score_vida)) print(paste("Precision_muerte:", precision_muerte)) print(paste("Recall_muerte:", recall_muerte)) print(paste("F1 Score_muerte:", f1_score_muerte)) # Curva ROC y AUC roc_curve <- roc(test$Survived, predictions) plot(roc_curve) auc <- auc(roc_curve) print(paste("AUC:", auc)) ----------- rm(list = ls()) # Ejemplo Regresion Lineal # Julio 2024 # Descripción del Conjunto de Datos “Boston” # # El dataset “Boston” consta de 506 observaciones, 14 variables y describe información # sobre varios factores que afectan en los valores de las viviendas en Boston. # # 1. crim: Tasa de criminalidad per cápita por ciudad. # 2. zn: Proporción de terreno residencial dividido en lotes de más de 25,000 pies cuadrados. # 3. indus: Proporción de acres comerciales no minoristas por ciudad. # 4. chas: Variable ficticia de Charles River (= 1 si el tramo limita con el río; 0 en caso contrario). # 5. nox: Concentración de óxidos nítricos (partes por 10 millones). # 6. rm: Número medio de habitaciones por vivienda. # 7. age: Proporción de unidades ocupadas por sus propietarios construidas antes de 1940. # 8. dis: Distancias ponderadas a cinco centros de empleo en Boston. # 9. rad: Índice de accesibilidad a carreteras radiales. # 10. tax: Tasa de impuesto a la propiedad por cada $10,000. # 11. ptratio: Relación alumno-maestro por ciudad. # 12. black: 1000(Bk - 0.63)^2 donde Bk es la proporción de negros por ciudad. # 13. lstat: Porcentaje de la población con bajo estatus socioeconómico. # 14. medv: Valor medio de las viviendas ocupadas por sus propietarios en $1000. # Cargar las librerías necesarias library(MASS) # Para el dataset de Boston library(ggplot2) library(Metrics) library(caret) # Cargar el dataset data("Boston") # Ver las primeras filas del dataset head(Boston) # Resumen estadístico de los datos summary(Boston) # -------------------------- REGRESION LINEAL SIMPLE -------------------------- # Establecer la semilla para reproducibilidad set.seed(123) # Subdividir el dataset en 80% entrenamiento y 20% prueba sample <- sample(seq_len(nrow(Boston)), size = 0.8 * nrow(Boston)) train <- Boston[sample, ] test <- Boston[-sample, ] # Crear el modelo de regresión lineal simple modelo_simple <- lm(medv ~ rm, data=train) # Resumen del modelo summary(modelo_simple) # Hacer predicciones en el conjunto de prueba predicciones <- predict(modelo_simple, test) # Calcular el MSE usando el paquete Metrics mse <- mse(test$medv, predicciones) print(paste("MSE:", mse)) # Calcular R² usando el paquete caret r2 <- R2(predicciones, test$medv) print(paste("R²:", r2)) # Calcular RSE manualmente rss <- sum((test$medv - predicciones)^2) # Residual Sum of Squares rse <- sqrt(rss / (nrow(test) - 2)) # Residual Standard Error print(paste("RSE:", rse)) # Crear un dataframe con los valores observados y predichos resultados <- data.frame(RM = test$rm, Observado = test$medv, Predicho = predicciones) # Crear el gráfico con ggplot2 ggplot(resultados, aes(x = RM)) + geom_point(aes(y = Observado), color = "blue") + # Puntos de observación geom_line(aes(y = Predicho), color = "red") + # Línea de predicción labs(title = "Predicciones de la Regresión Lineal Simple", x = "Número de Habitaciones (rm)", y = "Valor Medio de las Viviendas (medv)") + theme_minimal() # -------------------------- REGRESION LINEAL MULTIPLE -------------------------- # Establecer la semilla para reproducibilidad set.seed(123) # Subdividir el dataset en 80% entrenamiento y 20% prueba sample <- sample(seq_len(nrow(Boston)), size = 0.8 * nrow(Boston)) train <- Boston[sample, ] test <- Boston[-sample, ] # Ajustar el modelo de regresión lineal múltiple modelo_multiple <- lm(medv ~ crim + rm + age + dis + rad + tax + ptratio + lstat, data = train) # Resumen del modelo summary(modelo_multiple) # Hacer predicciones en el conjunto de prueba predicciones <- predict(modelo_multiple, test) # Calcular el MSE usando el paquete Metrics mse <- mse(test$medv, predicciones) print(paste("MSE:", mse)) # Calcular R² usando el paquete caret r2 <- R2(predicciones, test$medv) print(paste("R²:", r2)) # Calcular RSE manualmente rss <- sum((test$medv - predicciones)^2) # Residual Sum of Squares rse <- sqrt(rss / df.residual(modelo_multiple)) # Residual Standard Error print(paste("RSE:", rse)) # Crear un dataframe con los valores observados y predichos resultados <- data.frame(Observado = test$medv, Predicho = predicciones) # Crear el gráfico con ggplot2 ggplot(resultados, aes(x = Observado, y = Predicho)) + geom_point(color = "blue") + # Puntos de observación geom_abline(intercept = 0, slope = 1, color = "red", linetype = "dashed") + # Línea de referencia labs(title = "Valores Observados vs Predichos en el Conjunto de Prueba", x = "Valor Observado", y = "Valor Predicho") + theme_minimal() ----------- rm(list = ls()) # Ejemplo Clasificación KNN # Julio 2024 # Descripción del Conjunto de Datos “Boston” # # El dataset “Boston” consta de 506 observaciones, 14 variables y describe información # sobre varios factores que afectan en los valores de las viviendas en Boston. # # 1. crim: Tasa de criminalidad per cápita por ciudad. # 2. zn: Proporción de terreno residencial dividido en lotes de más de 25,000 pies cuadrados. # 3. indus: Proporción de acres comerciales no minoristas por ciudad. # 4. chas: Variable ficticia de Charles River (= 1 si el tramo limita con el río; 0 en caso contrario). # 5. nox: Concentración de óxidos nítricos (partes por 10 millones). # 6. rm: Número medio de habitaciones por vivienda. # 7. age: Proporción de unidades ocupadas por sus propietarios construidas antes de 1940. # 8. dis: Distancias ponderadas a cinco centros de empleo en Boston. # 9. rad: Índice de accesibilidad a carreteras radiales. # 10. tax: Tasa de impuesto a la propiedad por cada $10,000. # 11. ptratio: Relación alumno-maestro por ciudad. # 12. black: 1000(Bk - 0.63)^2 donde Bk es la proporción de negros por ciudad. # 13. lstat: Porcentaje de la población con bajo estatus socioeconómico. # 14. medv: Valor medio de las viviendas ocupadas por sus propietarios en $1000. # Cargar las librerías necesarias library(MASS) # Para el dataset de Boston library(ggplot2) library(Metrics) library(caret) library(class) # Cargar el dataset data("Boston") # Ver las primeras filas del dataset head(Boston) # Resumen estadístico de los datos summary(Boston) data <- Boston data$crimLevels <- ifelse(data$crim <= 1, "bajo", ifelse(data$crim > 5, "alto", "medio")) data$crimLevels <- as.factor(data$crimLevels) summary(as.factor(data$crimLevels)) data <- data[, c("crimLevels", "zn", "indus", "chas", "nox", "rm", "age", "dis", "rad", "tax", "ptratio", "black", "lstat", "medv")] # -------------------------- KNN -------------------------- # Establecer la semilla para reproducibilidad set.seed(123) # Subdividir el dataset en 80% entrenamiento y 20% prueba sample <- sample(seq_len(nrow(data)), size = 0.8 * nrow(data)) train <- data[sample, ] test <- data[-sample, ] # train_X y train_Y train_X <- train[, c("zn", "indus", "chas", "nox", "rm", "age", "dis", "rad", "tax", "ptratio", "black", "lstat", "medv")] train_Y <- train[, c("crimLevels")] test_X <- test[, c("zn", "indus", "chas", "nox", "rm", "age", "dis", "rad", "tax", "ptratio", "black", "lstat", "medv")] test_Y <- test[, c("crimLevels")] # Crear el modelo de regresión lineal simple modelo_knn <- knn(train = train_X, test = test_X, cl= train_Y, k=23) # Resumen del modelo summary(modelo_knn) # Hacer predicciones en el conjunto de prueba confusion_matrix <- table(modelo_knn, test$crimLevels) print(confusion_matrix) # Calcular la precisión, recall y F1 Score para alto precision_alto <- confusion_matrix[1, 1] / (confusion_matrix[1, 1] + confusion_matrix[1, 2] + confusion_matrix[1, 3]) recall_alto <- confusion_matrix[1, 1] / (confusion_matrix[1, 1] + confusion_matrix[2, 1] + confusion_matrix[3, 1]) f1_score_alto <- 2 * precision_alto * recall_alto / (precision_alto + recall_alto) # Calcular la precisión, recall y F1 Score para bajo precision_bajo <- confusion_matrix[2, 2] / (confusion_matrix[2, 1] + confusion_matrix[2, 2] + confusion_matrix[2, 3]) recall_bajo <- confusion_matrix[2, 2] / (confusion_matrix[1, 2] + confusion_matrix[2, 2] + confusion_matrix[3, 2]) f1_score_bajo <- 2 * precision_bajo * recall_bajo / (precision_bajo + recall_bajo) # Calcular la precisión, recall y F1 Score para medio precision_medio <- confusion_matrix[3, 3] / (confusion_matrix[3, 1] + confusion_matrix[3, 2] + confusion_matrix[3, 3]) recall_medio <- confusion_matrix[3, 3] / (confusion_matrix[1, 3] + confusion_matrix[2, 3] + confusion_matrix[3, 3]) f1_score_medio <- 2 * precision_medio * recall_medio / (precision_medio + recall_medio) ----------