A.3 Cap. 5: Programación funcional
- Reproduce el resultado del siguiente loop
for
, utilizando la funciónreplicate()
:
set.seed(123)
<- list() # Lista vacía
lista1 for (i in 1:3) { # Número de iteraciones = 5
= rnorm(6, 0, 1) # Conjunto aleatorio normal para cada iteración
lista1[[i]]
}
lista1# [[1]]
# [1] -0.56048 -0.23018 1.55871 0.07051 0.12929 1.71506
#
# [[2]]
# [1] 0.4609 -1.2651 -0.6869 -0.4457 1.2241 0.3598
#
# [[3]]
# [1] 0.4008 0.1107 -0.5558 1.7869 0.4979 -1.9666
Solución:
# Importante simplify = FALSE para obtener una lista
# de vectores y no un solo vector con todos los resultados
set.seed(123)
<- replicate(3, {
lista1 rnorm(6, 0, 1)
}, simplify = FALSE)
### Resultado
lista1# [[1]]
# [1] -0.56048 -0.23018 1.55871 0.07051 0.12929 1.71506
#
# [[2]]
# [1] 0.4609 -1.2651 -0.6869 -0.4457 1.2241 0.3598
#
# [[3]]
# [1] 0.4008 0.1107 -0.5558 1.7869 0.4979 -1.9666
- Crea la base de datos DF numérica (código ya definido en el siguiente chunk), que tiene las dimensiones 12 (filas) x 5 (columnas). Esta base contiene valores no deseados:
-999
. Crea y utiliza una función llamadacambiarNA()
que te permita cambiar estos valores porNA
.
# Base de datos DF
set.seed(123)
<- c(seq(0.5, 7.9, length = 10), -999, 5555)
secuencia <- data.frame(replicate(5,
DF sample(secuencia, 12, rep = TRUE)))
<- round(DF,2)
DF
# Darle nombre a sus columnas
colnames(DF) <- paste0("Var", 1:5)
# Revisar el contenido de DF
DF # Var1 Var2 Var3 Var4 Var5
# 1 2.14 3.79 7.08 7.90 6.26
# 2 2.14 2.14 2.14 5.43 5555.00
# 3 7.90 -999.00 2.97 -999.00 1.32
# 4 1.32 7.08 0.50 5555.00 0.50
# 5 4.61 5555.00 -999.00 3.79 7.08
# 6 -999.00 7.08 5.43 5.43 -999.00
# 7 3.79 7.08 3.79 3.79 7.08
# 8 2.97 2.14 5555.00 -999.00 4.61
# 9 4.61 6.26 7.90 4.61 3.79
# 10 7.08 7.90 5.43 7.08 7.08
# 11 7.90 5.43 7.08 1.32 7.90
# 12 -999.00 7.90 7.08 3.79 5555.00
Solución:
### Crear función
<- function(x) {
cambiarNA == -999] <- NA
x[x print(x)
}
### Usar la función
cambiarNA(DF)
# Var1 Var2 Var3 Var4 Var5
# 1 2.14 3.79 7.08 7.90 6.26
# 2 2.14 2.14 2.14 5.43 5555.00
# 3 7.90 NA 2.97 NA 1.32
# 4 1.32 7.08 0.50 5555.00 0.50
# 5 4.61 5555.00 NA 3.79 7.08
# 6 NA 7.08 5.43 5.43 NA
# 7 3.79 7.08 3.79 3.79 7.08
# 8 2.97 2.14 5555.00 NA 4.61
# 9 4.61 6.26 7.90 4.61 3.79
# 10 7.08 7.90 5.43 7.08 7.08
# 11 7.90 5.43 7.08 1.32 7.90
# 12 NA 7.90 7.08 3.79 5555.00
### Para guardar sus resultados permanentemente
<- cambiarNA(DF)
resultados # Var1 Var2 Var3 Var4 Var5
# 1 2.14 3.79 7.08 7.90 6.26
# 2 2.14 2.14 2.14 5.43 5555.00
# 3 7.90 NA 2.97 NA 1.32
# 4 1.32 7.08 0.50 5555.00 0.50
# 5 4.61 5555.00 NA 3.79 7.08
# 6 NA 7.08 5.43 5.43 NA
# 7 3.79 7.08 3.79 3.79 7.08
# 8 2.97 2.14 5555.00 NA 4.61
# 9 4.61 6.26 7.90 4.61 3.79
# 10 7.08 7.90 5.43 7.08 7.08
# 11 7.90 5.43 7.08 1.32 7.90
# 12 NA 7.90 7.08 3.79 5555.00
resultados# Var1 Var2 Var3 Var4 Var5
# 1 2.14 3.79 7.08 7.90 6.26
# 2 2.14 2.14 2.14 5.43 5555.00
# 3 7.90 NA 2.97 NA 1.32
# 4 1.32 7.08 0.50 5555.00 0.50
# 5 4.61 5555.00 NA 3.79 7.08
# 6 NA 7.08 5.43 5.43 NA
# 7 3.79 7.08 3.79 3.79 7.08
# 8 2.97 2.14 5555.00 NA 4.61
# 9 4.61 6.26 7.90 4.61 3.79
# 10 7.08 7.90 5.43 7.08 7.08
# 11 7.90 5.43 7.08 1.32 7.90
# 12 NA 7.90 7.08 3.79 5555.00
- Utilizando la base de datos DF creada inicialmente en el ejercicio 2, modifica la función
cambiarNA()
para que no solo cambie-999
aNA
, sino que cambie cualquier valor que tú le proporciones con un argumento. Llama a esta funcióncambiarNA2()
. Utilízala para reemplazar los valores5555
aNA
.
Solución:
# Crear la función con un argumento extra que te
# permita modificar el número a reemplazar por NA
<- function(x, valor) {
cambiarNA2 == valor] <- NA
x[x print(x)
}
# Usar la función
cambiarNA2(DF, 5555)
# Var1 Var2 Var3 Var4 Var5
# 1 2.14 3.79 7.08 7.90 6.26
# 2 2.14 2.14 2.14 5.43 NA
# 3 7.90 -999.00 2.97 -999.00 1.32
# 4 1.32 7.08 0.50 NA 0.50
# 5 4.61 NA -999.00 3.79 7.08
# 6 -999.00 7.08 5.43 5.43 -999.00
# 7 3.79 7.08 3.79 3.79 7.08
# 8 2.97 2.14 NA -999.00 4.61
# 9 4.61 6.26 7.90 4.61 3.79
# 10 7.08 7.90 5.43 7.08 7.08
# 11 7.90 5.43 7.08 1.32 7.90
# 12 -999.00 7.90 7.08 3.79 NA
- Utilizando la base de datos DF creada inicialmente en el ejercicio 2, modifica la función
cambiarNA2()
de tal manera que te permita definir más de un valor (un vector numérico) como elementos a ser reemplazados porNA
. Llama a esta funcióncambiarNA3()
. Cambia porNA
los valores-999
y5555
. Pista: Esta función deberá contener un loop para aplicarle la función de cambio por NA a un elemento del vector a la vez en cada iteración.
Solución:
### Crear la función con un argumento que admita
### un vector de varios elementos a cambiar por NA
<- function(x, vector) {
cambiarNA3 for (i in seq_along(vector)) {
== vector[i]] <- NA
x[x
}print(x)
}
### Usar la función
cambiarNA3(DF, c(5555, -999))
# Var1 Var2 Var3 Var4 Var5
# 1 2.14 3.79 7.08 7.90 6.26
# 2 2.14 2.14 2.14 5.43 NA
# 3 7.90 NA 2.97 NA 1.32
# 4 1.32 7.08 0.50 NA 0.50
# 5 4.61 NA NA 3.79 7.08
# 6 NA 7.08 5.43 5.43 NA
# 7 3.79 7.08 3.79 3.79 7.08
# 8 2.97 2.14 NA NA 4.61
# 9 4.61 6.26 7.90 4.61 3.79
# 10 7.08 7.90 5.43 7.08 7.08
# 11 7.90 5.43 7.08 1.32 7.90
# 12 NA 7.90 7.08 3.79 NA
- Crea un loop
for
que itere sobre los números del 1 al 50 y calcule el cubo de cada número, de manera que los resultados se vayan guardando en un vector llamadopreliminar
. Luego, crea un segundo loop que te permita identificar y almacenar solamente los números menores a la medianamedian()
del conjunto de datospreliminar
en un nuevo vector llamadofinal
.
Solución:
### Secuencia numérica
<- 1:50
secuencia
### Primer loop con for
<- c()
preliminar for(i in seq_along(secuencia)){
<- secuencia[i]^3
preliminar[i]
}
### Resultado preliminar
preliminar# [1] 1 8 27 64 125 216 343 512 729 1000 1331
# [12] 1728 2197 2744 3375 4096 4913 5832 6859 8000 9261 10648
# [23] 12167 13824 15625 17576 19683 21952 24389 27000 29791 32768 35937
# [34] 39304 42875 46656 50653 54872 59319 64000 68921 74088 79507 85184
# [45] 91125 97336 103823 110592 117649 125000
### Segundo loop con for
<- c()
final for( i in seq_along(preliminar)) {
if(preliminar[i] <= median(preliminar)){
<- c(final, preliminar[i])
final
}
}
### Resultado final
final# [1] 1 8 27 64 125 216 343 512 729 1000 1331 1728 2197
# [14] 2744 3375 4096 4913 5832 6859 8000 9261 10648 12167 13824 15625
- En R ya existe una función para calcular la varianza y es
var()
. Pero este ejercicio se trata de poner en juego lo que aprendiste sobre programación en R. La fórmula matemática de la varianza poblacional, con denominador \(n\), Ecuación (5.1). Pero la funciónvar()
de R contiene la fórmula matemática para calcular la varianza de muestras, no de poblaciones enteras. La fórmula matemática de la varianza muestral que usa R tiene como denominador \(n-1\), Ecuación (5.2). Crea una función llamadavar2()
que calcule la varianza del conjunto de datos llamadovector
. Finalmente, compara tus resultados con los obtenidos porvar()
.
\[\begin{align} \sigma^2 = \frac{1}{n}*{\displaystyle\sum_{i=1}^{n}(x_i - \mu)^2} \tag{5.1} \end{align}\]
\[\begin{equation} \sigma^2 = \frac{1}{n-1}*{\displaystyle\sum_{i=1}^{n}(x_i - \mu)^2} \tag{5.2} \end{equation}\]
set.seed(123)
<- rnorm(50, 21, 1.6) vector
Solución:
Dentro de la función necesitas:
- Un código que calcule el promedio de los valores de
vector
. - Una estructura que le reste el promedio a cada elemento de
vector
y eleve cada resta al cuadrado. - Sumar todos los cuadrados obtenidos.
- Identificar la longitud de
vector
(denotada porn
), y dividir la sumatoria de cuadrados entren
.
### Crear la función
<- function(x) {
var2 <- mean(x)
promedio <- c()
cuadrados for(i in seq_along(x)) {
<- (x[i] - promedio)^2
valor <- c(cuadrados, valor)
cuadrados
}<- length(x)
n <- sum(cuadrados)
sumatoria <- sumatoria / (n-1)
varianza return(varianza)
}
### Usar la función
var2(vector)
# [1] 2.195
### Comparar con la el resultado de var()
var(vector)
# [1] 2.195
Si necesitas en algún momento, ya conoces cómo crear la fórmula de la varianza poblacional en R.
- Carga la base de datos npk. Usando una función de la familia apply(), calcula la el promedio, mediana y desviación estándar de la columna
yield
para cada categoría (numérica) de la columnablock
. Con ello, se conocerá el promedio de producción que se obtuvo en cada bloque para un estudio de mejora fitogenética:
data("npk")
Solución:
tapply(npk$yield, npk$block, FUN = mean)
# 1 2 3 4 5 6
# 54.02 57.45 60.77 50.12 50.52 56.35
tapply(npk$yield, npk$block, FUN = median)
# 1 2 3 4 5 6
# 53.25 57.25 59.30 47.15 50.65 56.60
tapply(npk$yield, npk$block, FUN = sd)
# 1 2 3 4 5 6
# 7.269 2.044 6.790 8.150 1.486 2.435
- Ejecuta el siguiente código para crear una lista llamada
iris3Lista
a partir de la base de datos de ejemploiris3
(un array). Si revisasiris3Lista
, notarás que continene 3 elementos, cada uno de ellos es una matriz de datos de cuatro columnas (Sepal L.
,Sepal W.
,Petal L.
, yPetal W.
). Utilizando dos funciones de la familiaapply()
, calcula el promedio de cada columna de cada elemento de la listairis3Lista
.
### Cargar iris3
data("iris3")
### Convertirla a lista
<- list(setosa = iris3[,,1],
iris3Lista versicolor = iris3[,,2],
virginica = iris3[,,3])
Solución:
lapply(iris3Lista, FUN = function(x) {
apply(x, 2, mean)
})# $setosa
# Sepal L. Sepal W. Petal L. Petal W.
# 5.006 3.428 1.462 0.246
#
# $versicolor
# Sepal L. Sepal W. Petal L. Petal W.
# 5.936 2.770 4.260 1.326
#
# $virginica
# Sepal L. Sepal W. Petal L. Petal W.
# 6.588 2.974 5.552 2.026