¡Hola! Bienvenides a este espacio de formación en el software R. En este primer encuentro vamos a introducirnos al software; conocer su sintaxis y los elementos que forman parte de ella; objetos, tipos de vectores, matrices, data frames y operadores lógicos. Al inicio del módulo recibirán vía mail la bibliografía utilizada en todas las clases.
Siguiendo a Chambers (2008):
Todo lo que existe en R es un objeto
Todo lo que ocurre en R es el resultado de función
Los nombres tienen objetos, pero los objetos no tienen nombres
Particularidad de los objetos:
Polimorfismo: Darle una orden a distintos objetos y que cada uno responda de su propia manera
Abstracción: La libertad de crear objetos
Herencia: Los atributos que heredan los objetos del primer objeto construido
Encapsulamiento: Pese a que los objetos se comuniquen entre ellos, cada uno mantiene su estructura. Eso le asigna autonomía a su procesamiento
Previamente instalemos la libreria lobstr que nos provee una serie de herramientas para inspeccionar y entender la estructura de R y sus objetos.
https://cran.r-project.org/web/packages/lobstr/index.html
# install.packages("lobstr")
library(lobstr)
# Objetos con valores numéricos
a <- 1
a = 1 # es lo mismo
object.size(a)
#56 bytes
obj_addr(a)
#0x1ab9e8fc198
b <- a
object.size(b)
# 56 bytes
obj_addr(b)
#0x1ab9e8fc198
c <- b
object.size(c)
#56 bytes
obj_addr(c)
#0x1ab9e8fc198
Aquí vemos que b y c tiene un valor indexado hacia a, y su dirección de almacenamiento es la misma. Es decir que no hay tres valores por separado.
Por lo tanto, son el mismo objeto porque tiene el mismo valor, la misma dirección de almacenamiento, pero con un identificador distinto
a <- 2
obj_addr(a)
#0x1aba24202e8
Pero aquí cuando anexamos otro valor al identificador “a”, a será otro objeto. Con esto queremos remarcar que aunque tengan el mismo identificador su valor está almacenado en otro lugar. Veamos algunos objetos más:
# Objetos con valores de cadena de caracteres
saludos <- "Hola mundo!"
saludos
# "Hola mundo!"
numero1 <- "numero 1"
numero1 <- "1"
Numero1 <- "1"
obj_addr(numero1)
#0x1aba03263b8
obj_addr(Numero1)
#0x1aba1987e48
Recordemos cuán sensibles son los caracteres en R. Una misma palabra, pero con una variación de mayúsculas genera un identificador distinto, y por lo tanto objetos distintos. Veamos algunas cuestiones al designar identificadores a los valores:
. No debe haber espacios en los nombres
. No deben comenzar por numeros
. No deben comenzar con _ * / & u otros caracteres especiales
. Es sugerible que sean nombres cortos
. Que cuando sean significados compuestose esten separados por _ o .
. Que mantengan un criterio único de mayúsculaes o minúsculas
objeto 1 <- 1
123Numero <- 123
Esto_ES_Unobjeto <- "dificil para entender y trabajar"
Esto_tamb.bien.pued_Ser <- 1243
esto_es_claro <- "un poco mejor"
esc <- "pueden ser abreviaciones tambien"
eph <- "eph"
## Error: <text>:2:8: unexpected numeric constant
## 1:
## 2: objeto 1
## ^
# La funcion c() permite concatenar valores
x <- c(1,2,3)
x
# 1 2 3
is.numeric(x)
# TRUE
y <- c("estos", "son valores", "concatenados")
y
#"estos" "son valores" "concatenados"
is.character(y)
# TRUE
v <- c(TRUE, TRUE, FALSE)
v # TRUE TRUE FALSE
is.logical(v)
# TRUE
z <- c(100L, 200L,300L)
z
# 100 200 300
is.integer(z)
# TRUE
# y si no lo son?
is.character(x)
# FALSE
# Transformamos y evaluamos
typeof(numero1)
# "character"
as.numeric(numero1)
# 1
typeof(numero1)
## [1] "character"
¿Qué vemos? ¡numero1 sigue siendo caracter! ¿Por qué? Porque no hemos asignado al objeto su nuevo valor, Si evocamos unicamente la funcion estaremos conociendo el valor que le asignaria la funcion pero no esta indexando el identificador con su nuevo valor
numero1 <- as.numeric(x = numero1)
numero1
## [1] 1
¿Qué hicimos?
En orden:
Estamos llamando al objeto -numero1- que contiene el valor en formato de carácter de 1
Estamos evocando la flecha (función) que indexa
Estamos llamando a la función as.numeric, al argumento que permite evocar objetos, y nuevamente al objeto
Ahora si se expresa en valor numérico/doble
Veamos algunas funciones para detectar clase de objetos
class(numero1) # no hace la diferencia si es decimal o no
## [1] "numeric"
mode(numero1) # no hace la diferencia si es decimal o no
## [1] "numeric"
typeof(numero1) # si hace la diferencia si es decimal o no
## [1] "double"
Por otro lado tenemos a los objetos sin valores, los NAs
# Objetos con valores NAs
NAs <- NA
NAs
## [1] NA
vector_nas <- c(NA, 5, NA, 10)
is.na(vector_nas)
## [1] TRUE FALSE TRUE FALSE
1 Crear un vector con 5 valores de caracter separados y consultar que tipo de vector es
2 Crear un vector con 5 valores numericos separados y consultar que tipo de vector es
3 Transformar uno de estos vectores en otro formato y consultar que tipo es
4 Crear un vector con 6 valores, 3 numericos y 3 de caracter
Luego de que vimos que todo en R es un objeto y una función veamos la forma que se pueden agrupan los vectores
matriz <- matrix(data = 1:6, nrow = 3, ncol = 2) # Los argumentos consisten en datos, numero de filas y numero de columnas
matriz
# Fila 1, columna 1; el primer espacio es para las filas, el segundo para las columnas
matriz[1,1]
# Fila 1, columna 2
matriz[1,2]
# Fila 3, columna 1
matriz[3,1]
# Fila 1, todas las columnas; el espacio vacio asume que se toman todas lass columnas
matriz[1,]
# Columna 1, toda las filas
matriz[,1]
# Eliminando la primera columna
matriz[,-1]
# Asignando nombres a las columnas
colnames(matriz) <- c("Durkheim","Weber")
matriz
# Asignando nombres a las filas
rownames(matriz) <- c("Fila1", "Fila2", "Fila3")
matriz
# Si queremos manipular los datos:
# Estamos seteando el dato de la primera fila y la segunda columna a 17
matriz[1,2] = 17
matriz
# Estamos seteando el dato de la segunda fila y la primera columna a 17
matriz[2,1] = 17
matriz
Veamos ahora algunas funciones para inspeccionar los datos:
# dim() Para conocer las dimensiones de la base
# t() Invierte el formato de la tabla. Las columnas pasan a ser filas y las filas a columnas
# rownames() colnames() # Para inspeccionar y/o sus datos
# str() Para conocer el tipo de vectores, cantidad de filas y columnas
# rbind() Para pegar filas
# colbin() Para pegar columnas
dim(x = matriz) # 3 filas y dos columnas
t(matriz)
str(matriz)
rownames(matriz)
colnames(matriz)
Las funciones siempre se leen desde su interior hacia el exterior. Aca le estamos pidiendo a R que pegue el vector con los valores 7 y 8 y que luego la pegue con la funcion rbind() junto a nuestro objeto matriz
Fila4 <- c(7:8)
rbind(matriz,Fila4)
# sino, en vez de crear un objeto. Lo hacemos todo dentro de una sola funcion
rbind(matriz,(matrix(7:8,nrow=1,ncol=2)))
Le estamos pidiendo a R que:
1 Cree una matriz con una fila y dos columnas con la funcion matrix()
2 Con la funcion rbind(), primero evocamos nuestro objeto que creamos antes y se llama matriz, luego llamamos a la funcion matrix con la que señalamos la matriz, que queremos crear, y así incorporamos un objeto dentro de otro
Ahora pasemos a crear un Data Frame. Para ello podemos hacerlo de dos formas.
La primera es creando de manera independiente nuestros vectores y luego incorporandolos mediante una función
numero_mes <- 1:12
nombre_mes <- c("Enero","Febrero","Marzo", "Abril", "Mayo", "Junio",
"Julio", "Agosto","Septiembre","Octubre","Noviembre","Diciembre")
estacion_mes <- c("Verano","Verano","Verano-Otonio","Otonio","Otonio","Otonio-Invierno",
"Invierno","Invierno","Invierno-Primavera","Primavera","Primavera","Primavera-Verano")
datos_mes <- data.frame(numero_mes,nombre_mes,estacion_mes)
La otra forma puede ser:
datos_mes <- data.frame(numero_mes=1:12,
nombre_mes=c("Enero","Febrero","Marzo", "Abril", "Mayo", "Junio",
"Julio", "Agosto","Septiembre","Octubre","Noviembre","Diciembre"),
estacion_mes=c("Verano","Verano","Verano-Otonio","Otonio","Otonio","Otonio-Invierno",
"Invierno","Invierno","Invierno-Primavera","Primavera","Primavera","Primavera-Verano"))
# ¿Qué funciones se les ocurren para conocer qué tipos de vectores son?
Con la primera forma estamos creando 3 objetos de manera independiente. Esto significa que continuaran existiendo aunque se incorporen al data frame y estaríamos ocupando mas memoria en el sistema. Tambien estamos llevando a cabo un paso de mas llegar a lo mismo.
# Conozcamos sus campos, filas, registros y mas...
dim(datos_mes) # sus dimensiones
nrow(datos_mes) # numero de filas
ncol(datos_mes) # numero de columnas
head(datos_mes) # primeros registros de cada uno de sus campos y filas
str(datos_mes) # informacion de la clase de los valores registrados en sus filas
summary(datos_mes) # resumen estadistico de algunas medidas de tendencia central como la mediana, moda, valores max y min
names(datos_mes) # nombres de los campos
subset(datos_mes, estacion_mes=="Otonio") # Filtramos segun un criterio
datos_mes[1,] # la primera fila y todas las columnas
datos_mes[1,2] # la primera fila y la segunda columna
datos_mes[,c(1,2)] # la columna 1 y 2, y todas las filas
datos_mes[1:2,c(1,2)] # desde la columna 1 hasta la segunda, y todas lass filas
colnames(datos_mes)[1] <- "cambio_de_nombre" # Aplicamos la funcion colnames(dataset)[x] seleccionamos la columna, y asignamos el nuevo nombre
datos_mes$numero_mes # con el simbolo $ estamos insepccionando sus campos
unique(datos_mes$estacion_mes) # Unique(), mas el concatenador para seleccionar un campo, nos devuelve una distincion de cada uno de los valores
datos_mes$nuevos_valores <- 13:24 # tambien podemos agregar un nuevo campo
datos_mes <- datos_mes[,-4] # nos arrepentimos de aniadirlo
1 Crear una matriz numérica que vaya desde 1 hasta 20, Con 4 columnas y 5 filas
2 Asignarle un nombre a cada columna y cada fila
3 Inspeccionar sus elementos con []
4 Modificar algún valor de ellos
1 Crear un Data Frame propio de dos columnas y 5 filas
2 Inspeccionar sus elementos
3 Agregar una nueva columna con nuevos valores
4 Eliminar esta columna
# Existen 3 clases de operadores. Siempre se leen de izquierda a derecha
x <- 10
y <- 5
# 1. Logicos
x < 5 # ?Es el objeto x, con valor de 10, menor a 5?
x > 5 # ?Es el objeto x, con valor de 10, mayor a 5?
x >= 5 # ?Es el objeto x, con valor de 10, mayor o igual a 5?
x <= 5 # ?Es el objeto x, con valor de 10, menor o igual a 5?
x == 5 # ?Es el objeto x, con valor de 10, igual a 5?
# 2. Aritmeticos
x + 5
x - 5
x * 5
x / 5
x ^ 5 # Potencia: Alt + 94
# 3. De comparacion
# & condicion + y SHIFT 6
# ! condicion - y SHIFT 1
# | condicion o y SHIFT LIGUILLA (AL LADO DEL 1)
# %in% condicion dentro de y SHIFT 5
# Ejemplos
# Si le queremos pedir que del data set datos_mes, dentro del campo numero_mes nos traiga aquellos valores mayores a 5, y todas las columnas
datos_mes[datos_mes$numero_mes>5,]
# Si le queremos pedir que nos traiga del campo nombre_mes aquel valor que sea igual a Enero, y todas las columnas
datos_mes[datos_mes$nombre_mes=="Enero",]
# Si le queremos pedir del campo numero_mes aquellos valores 1 y 2 que esten contenido en el campo numero_mes, y todas las columnas
datos_mes[datos_mes$numero_mes %in% 1:2,]
# Si le queremos pedir del campo numero_mes aquellos valores 1, 7 , y todas las columnas
datos_mes[datos_mes$numero_mes %in% c(1, 7),]
# Si le queremos pedir del campo numero_mes aquellos valores de 2, de nombre Febrero, y todas las columnas. Con el operador | se agrega mas linea de codigo
datos_mes[datos_mes$numero_mes==2 | datos_mes$nombre_mes=="Febrero",]
# Si le queremos pedir del campo numero_mes que no nos traigan aquellos valores que van desde 1 hacia 10, y todas las columnas
datos_mes[datos_mes$numero_mes==5:10,]
# Si le queremos pedir del campo estacion_mes que nos traigan aquellos valores que forman las palabras Febrero y Verano
datos_mes[datos_mes$estacion_mes %in% c("Febrero", "Verano"),]
1 Le queremos pedir a nuestro data set de datos_mes los valores pertencientes al campo numero_mes que sean menor a 5
2 Le queremos pedir aquel valor del mes de Mayo, y que podamos ver todas las columnas
3 Le queremos pedir que nos traigan aquellos valores que solo vayan desde el mes 5 al 10, y solo el campo 1
4 Le queremos pedir aquello 3 primeros meses del anio en formato numerico y caracter, y solo las dos primeras columnas
Veamos algunas funciones aritméticas:
# Si queremos conocer aquellos registros que aparecen al menos una vez en los campos de un data set
# Con la funcion unique()
unique(datos_mes$estacion_mes)
# Si queremos conocer la sumatoria de todoss los registros numericos de manera acumulada
# Con la funcion sum()
sum(datos_mes$numero_mes)
# Si queremos conocer el valor minimo de todos los registros numericos
# Con la funcion min()
min(datos_mes$numero_mes)
# Si queremos conocer el valor maximo de todos los registros numericos
# Con la funcion max()
max(datos_mes$numero_mes)
# Si queremos conocer el valor promedio de todos los registros numericos
# Con la funcion min()
mean(datos_mes$numero_mes)
Vemos que no podemos evocar de la siguiente manera aquellas estaciones que son de primavera… datos_mes[datos_mes$estacion_mes %in% “era”,3]
# Llamamos a la funcion grep(), invocamos el valor que queremos, y seleccionamos el campo donde pensamos que puede estar
grep("era",datos_mes$estacion_mes)
# Sin embargo aqui nos indica unicamente sus numeros de fila. Pensemos como indagar dentro del data set
# Llamemos aquellos registros que figuran como Primavera, y todas sus columnas
datos_mes[grep("Primavera",datos_mes$estacion_mes),]
# Llamemos aquellos registros que figuran como Primavera, y su campo 2
datos_mes[grep("Febrero", datos_mes$nombre_mes),2]
# También podemos recurrir a la funcion subset() que filtra filas también según los criterios elegidos.
# Aqui podemos llamar directamente a la función.
# Pidamosle el registro de aquellos meses que están por arriba del numero_mes (ID) 5 y cuyo registro en estacion_mes unicamente expresa "Primavera"
subset(datos_mes, numero_mes >= 5 & estacion_mes=="Primavera")
# Vemos que nos faltan aquellos que son "Invierno-Primavera" y "Primavera-Verano". Incorporemoslo
subset(datos_mes, numero_mes >= 5 & estacion_mes %in% c("Primavera","Invierno-Primavera","Primavera-Verano"))
A partir de la Encuesta Anual de Hogares que se realiza en la Ciudad de Buenos Aires, realizada en el 2019 por la Direccion General de Estadisticas y Censos, descargaremos la base con los 14319 hogares encuestados. Queremos indagar todos los registros pertenecientes a las comunas 1 y 8, cuya persona entrevistada haya sido varón, y donde los ingresos per cápita de los hogares sea mayor o igual al promedio, y que además me traiga las columnas desde la 1 a la 7, y también la 22
De aquí la descargaremos: https://data.buenosaires.gob.ar/dataset/encuesta-anual-hogares
A partir de esto. Que funciones se les ocurre que pueden aplciarse para conocer un poco mas la base?
# Levantando del portal. Sobre la tecla Descargar de la pagina, click derecho y "copiar direccion de enlace"
eah <- read.csv("https://cdn.buenosaires.gob.ar/datosabiertos/datasets/direccion-general-de-estadisticas-y-censos/encuesta-anual-hogares/encuesta-anual-hogares-2019.csv", check.names = FALSE)
# En caso que lo tengamos descargado
# eah <- read.csv("C:/Users/User/Desktop/Quehaceres sociologicos/Proyecto 1/encuesta-anual-hogares-2019.csv")
str(eah)
summary(eah)
head(eah)
eah[eah$comuna %in% c(1,8) & eah$sexo == "Varon" &
eah$ingreso_per_capita_familiar >= 26192.01, c(1:7, 22)]
# Si se animan, en el objeto creado (EAH) pueden explorar que tipos de datos son, cambiar el nombre de las columnas, seleccionar aquellas filas que sean mayores, menores, o iguales a X valor, o que no aparezca X valor, que aparezca uno u otro, pueden crear una nuevo campo con los valores que ustedes deseen, tambien pueden crear sus propios data sets!
# Animensen!
# Y de YAPA el PIPE |> (CONCATENADOR DE FUNCIONES!)
# CTRL + SHIFT + M
eah[eah$comuna %in% c(1,8) & eah$sexo == "Varon" &
eah$ingreso_per_capita_familiar >= 26192.01, c(1:7, 22)] |>
str()
Respecto al pipe sugerimos la incorporación de la configuración nativa de R. Es decir, el que puede utilizarse sin recurrir a ningún paquete. Para eso:
Herramientas/Tools
Opciones Globales/Global Optiones
Código/Code
Usar el operador de pipe nativo / Use native pipe operator
¡y listo!