Curso R - Básico

Un curso para programadores y NO programadores

Francisco Javier Luna Vázquez \(^1\) & Osval A. Montesinos-López \(^2\)
\(^{12}\) Universidad de Colima
\(^1\) frahik@gmail.com

Hablemos de R

El objetivo de la diapositiva es proporcionar un punto de partida para las personas interesadas en aprender a usar R, esto con el fin de promover el conocimiento de manera sencilla, practica y entendible.

R se distribuye de manera gratuita, es usado comúnmente para análisis estadísticos, funcionando como programa y lenguaje de programación es considerado como una implementación del lenguaje S creado por los laboratorios AT&T Bell.

R está disponible en varias formas: el código fuente o como archivos binarios pre-compilados para Windows, Linux (Debian, RedHat, etc.) y Macintosh, se distribuye bajo los términos de GNU General Public Licence al igual que esta diapositiva.

Instalación de R

Empezaremos por lo más básico, Podemos instalar R desde el siguiente link: https://www.r-project.org/

Pero como muchos somos algo despistados, estas son las maneras más sencillas para instalar R en distintos Sistemas Operativos:

Sistema Operativo Método
Windows https://cran.itam.mx/bin/windows/base/R-3.3.2-win.exe
Debian y derivados sudo apt-get install r-base
Redhat y derivados sudo yum install R-core R-devel
Arch y derivados sudo pacman -S r
Mac https://www.youtube.com/watch?v=ICGkG7Gg6j0

Entornos de desarrollo para R

Primeros pasos

Para interactuar con R se dispone de una potente línea de comandos y en un principio, la manera más sencilla de ver R es que puede ser usado como una calculadora:

10+5 
## [1] 15

o

10/5 
## [1] 2

Pero su potencial va más allá...

Principalmente por que esta diapositiva fue diseñada en R y RMarkdown ;)

Establecer directorios de trabajo

Al ejecutar R, este establece un directorio de trabajo, es decir, establece una carpeta donde guardar los datos ejecutados en R, misma que será la carpeta que usara para buscar, leer y escribir los archivos (de ser requerido) durante la sesión (es decir, mientras se mantiene el programa abierto), por ello, para obtener el directorio de trabajo actual basta con usar el siguiente comando:

getwd()
## [1] "/home/frahik/Documentos/R-project/Curso"

dicho directorio va a variar dependiendo de la maquina, por ello, más de una vez será necesario modificarlo, para lo cual se usara el siguiente comando, el cual varia dependiendo del Sistema Operativo:

setwd("C:\\Usuario\\Documentos\\Curso") #Windows
setwd("~/Documentos/Curso") #Linux

Creación de objetos/variables

En R podemos crear y manipular objetos asignándole valores, cadenas de texto, funciones y un largo etc. Por ser el primer contacto con R, crearemos un objeto (izquierda del símbolo =), asignándole como valor la cadena de texto "Hola mundo"

saludo = "Hola mundo" 

Ahora para mostrar en consola lo que contiene la variable u objeto saludo, lo escribiremos tal cual y obtendremos una salida muy similar a la siguiente.

## [1] "Hola mundo"

NOTAS:

R es sensible a las MAYÚSCULAS y minúsculas, por lo que saludo no es igual a Saludo o a SALUDO.

R NO requiere explicitar que tipo de valores van a contener las variables.

Otra manera de asignar valores a las variables es mediante el símbolo <- que se compone de un menor que y el signo de menos.

x <- 10+5 

Es recomendable incluir un espacio simple a cada lado del operador de asignación para incrementar la legibilidad. Pero NO coloques un espacio entre el < y el - que forman la flecha, recuerda que a pesar de estar compuesto por dos caracteres es un único símbolo.

Es posible reasignar un valor a la variable que hemos creado, así como reutilizar el valor de la variable para realizar un calculo:

y <- x + 5 
y
## [1] 20

Recuerde que aunque pareciera algo matemático, los símbolos <- o = no funcionan como un «igual», si no, como un «equivale a» o una «asignación», por que a partir de ese momento, el valor de la derecha se le asigna al de la izquierda.

Estos son los operadores más populares que se utilizan en R para realizar distintos cálculos.

Aritméticos Lógicos Comparativos
+ Adición == Igual a & Y Lógico
- Substracción != Diferente de ! No Lógico
* Multiplicación < Menor que
/ División > Mayor que is.na(x) ¿Es NA?
^ Potencia <= Menor o igual a is.null(x) ¿Es Null?
%/% División de enteros >= Mayor o igual a is.nan(x) ¿Es NaN?

Vectores

Realmente hemos trabajado con vectores desde que empezamos con 10 + 5, lo que nos devuelve R es un vector de índice 1, estas son otras formas de crear vectores.

X <- c(1,2,3) 
X 
## [1] 1 2 3

La manera anterior es a través del método concatenar c( ), que une los elementos separados por una coma, otra forma de crear un vector (numérico en éste caso) es usando : que nos hace una lista de uno en uno desde el primero valor hasta el último.

X <- 1:3 
X 
## [1] 1 2 3

Por ultimo, cuando ya tenemos una lista o simplemente queremos repetir algo \(n\) veces, podemos usar la función rep(x,times=n), que repetirá un número definido de veces lo indicado como parámetro x.

rep(1, times=3)  
## [1] 1 1 1

Accediendo a los valores del vector

Partiendo de que tenemos un vector con la edad de los integrantes de una familia se podría observar como si fuera una tabla:

1 2 3 4 5
45 43 13 8 5

dónde, si queremos saber la edad del primer integrante, podemos observar que su edad es 45, y el promedio de todas las edades (es decir \(\sum_{i=1}^{5} x_i\)) es de 22.8 años.

Todos éstos cálculos se pueden hacer de manera rápida y en algunos casos son intuitivos, pero con grandes cantidades de datos, estas tareas se vuelven más complejas, así que continuemos con el mismo ejemplo en R.

Partiendo de la edad de los cinco integrantes, crearemos un vector con las edades de cada uno

edad_familia <- c(45,43,13,8,5)

para consultar la edad de un integrante \(i\) basta con poner la posición a la que queremos acceder, en éste caso, la primer posición, que pertenece al primer integrante:

edad_familia[1]
## [1] 45

Mientras que si buscamos calcular el promedio de edades basta con usar la función mean( )

mean(edad_familia)
## [1] 22.8

Nota:

En muchos lenguajes de programación, la primera posición de los vectores es 0, como se pudo observar en el caso anterior, en R la primera posición es 1.

Funciones

En R existen varias funciones ya definidas que nos permiten hacer varios cálculos, pero si el usuario requiere realizar una función para un determinado caso, las funciones se implementan de la siguiente manera:

Promedio <- function(vec) {
    return(sum(vec)/length(vec))
}

Promedio(c(1,2,3,4,5))
## [1] 3

Donde, vec es el parámetro que debe de ingresar el usuario para hacer uso de la función, en este caso, un vector de números.

Nota: Es recomendable declarar los parámetros con nombres que los puedan identificar, así si otra persona revisa el código, le será más fácil comprenderlo.

Existen muchas funciones ya predeterminadas en R, todo depende del usuario si requiere estas funciones o requiere hacer una a su medida.

Función Matemáticas Función Estadísticas
sqrt(x) Raíz de \(x\) mean(x) Media
exp(x) Exponencial de \(x\) sd(x) Desviación estándar
log(x) Logaritmo natural de \(x\) var(x) Varianza
log10(x) Logaritmo base 10 median(x) Mediana
sum(x) Suma de los elementos de \(x\) quantiles(x) Quantiles
prod(x) Producto de los elementos de \(x\) cor(x,y) Correlación
sin(x) Seno max(x) Valor máximo
cos(x) Coseno min(x) Valor mínimo
tan(x) Tangente range(x) Retorna el máximo y mínimo
round(x,n) Redondea a \(n\) dígitos sort(x) Ordena los elementos de \(x\)
cumsum(x) Calcula las sumas acumuladas summary Resumen de las variables
(\(x_1, x_1 + x_2, + x_1 +\ldots+x_n\)) choose(n,k) Combinatoria de \(n\) sobre \(k\)

Matrices

Para crear una matriz en R se utiliza la función

matrix(data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL)

donde matrix() corresponde al nombre de la función y todo lo que está dentro de los paréntesis son los argumentos de dicha función.

Argumentos Significado
data Es un vector de datos opcional
nrow Número deseado de filas
ncol Número deseado de columnas
byrow Valor lógico. Si es falso (valor por defecto), la matriz se llena por orden columna, de otra manera se llenará primero por filas.
dimnames Utilizado para darles nombres a las filas y a las columnas, respectivamente.

Al igual que con los vectores, existen varias formas de crear matrices, supongamos que tenemos un vector con 10 datos y queremos convertirlo a una matriz de 5 columnas por 2 filas

vec <- 1:10
matrix(vec, ncol=5, nrow=2)
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    3    5    7    9
## [2,]    2    4    6    8   10

Si en vez de querer llenar la matriz por fila y no por columna como está actualmente, basta con especificarlo con el parámetro byrow = TRUE.

matrix(vec, ncol=5, nrow=2, byrow = TRUE)
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    2    3    4    5
## [2,]    6    7    8    9   10

Otra manera, un poco más rustica, es ingresar los valores en la matriz:

matrix(c(1,2,3,4,5,6), ncol = 2, nrow=3)
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6

Es posible convertir los objetos de la clase Data frame a la clase matriz con el comando as.matrix(), aunque con ello perderá las propiedades de un DataFrame, para obtener las propiedades de una matriz.

Como se ha mencionado, una matriz en R es un «clase de objeto» , para conocer la clase de un objeto use class(objeto), en el caso anterior debera de retornar lo siguiente:

## [1] "matrix"

apply

La función apply(...) permite realizar un cálculo (como el promedio) por fila ó por columna (sin importar si es una matriz o un dataframe), el resultado de dicha operación será un vector de longitud \(p\) con el resultado de la operación realizada, ya sea por filas o por columnas.

Su implementación es la siguiente:

apply(X, MARGIN, FUN)

donde apply() corresponde al nombre de la función y todo lo que está dentro de los paréntesis son los argumentos de dicha función.

Argumentos Significado
X Es el vector o matriz original
MARGIN Indica donde se aplicara la función (1 indica fila, 2 indica columna)
FUN Es la función a aplicar (Suma, promedio, entre muchas otras)

Para ver un ejemplo, crearemos una matriz con 9 valores y sacaremos el promedio por columna.

x <- matrix(data = 1:9, nrow=3, ncol=3, byrow = TRUE)
x
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9
apply(x,2,mean)
## [1] 4 5 6

El argumento 2 en apply(x,2,mean) indica que el cálculo del promedio debe realizarse en la segunda dimensión, es decir, en las columnas.

Data Frames

Los dataframes, son una clase parecida a las matrices, sin embargo, poseen determinadas características que las hace más útiles en ciertas ocasiones.

Al igual que los vectores y matrices, existen varias formas de crear data frames, una forma sencilla de crearlos es especificar los datos de las columnas como en el ejemplo siguiente:

data.frame(w = 1, x = 1:5, y = LETTERS[1:5], z=runif(5))
##   w x y          z
## 1 1 1 A 0.69281687
## 2 1 2 B 0.01039399
## 3 1 3 C 0.61713636
## 4 1 4 D 0.15543613
## 5 1 5 E 0.15204348

así como es posible cambiar la clase de un dataframe a una matriz también se puede realizar de manera inversa con el siguiente comando:

matriz <- matrix(runif(10), ncol=5)
df <- as.data.frame(matriz)
df
##          V1        V2        V3        V4          V5
## 1 0.9967436 0.9398258 0.4723491 0.6872926 0.699612472
## 2 0.2816350 0.8904515 0.2483219 0.7878758 0.006966989

Para acceder a los datos de una columna de un dataframe, se puede usar el símbolo $ junto con el nombre de la columna

df <- data.frame(w = 1, x = 1:5, y = LETTERS[1:5], z=runif(5))
df$w
## [1] 1 1 1 1 1

otra opción es acceder mediante los nombres de la columna o fila o ambas.

df <- data.frame(Letras = LETTERS[1:5], Valores=runif(5))
df["Valores"]
##      Valores
## 1 0.48167592
## 2 0.67239090
## 3 0.44869428
## 4 0.94206075
## 5 0.09951161
df[4,"Letras"]
## [1] D
## Levels: A B C D E

Claro que si estas acostumbrado al método de acceso de las matrices, también existe ese método de acceso

df <- data.frame(Letras = LETTERS[1:5], Valores=runif(5))
df[1,]
##   Letras    Valores
## 1      A 0.07842335
df[,1]
## [1] A B C D E
## Levels: A B C D E
df[1,1]
## [1] A
## Levels: A B C D E

Escribir y leer archivos en R.

En algún momento, tendremos la necesidad de guardar o leer algo en un formato determinado, sea .csv o .Rdata, veamos unos ejemplos que podrán ser de utilidad.

CSV (Comma-separated values)

Un formato muy utilizado en R a parte de los .RData (que son archivos especiales de R), para exportar los datos en dicho formato:

df = data.frame(runif(10), runif(10), runif(10)) 
names(df) = c("dato1", "dato2", "dato3")

write.table(df, file = "dataframe1.csv", sep = ",",
col.names = NA, qmethod = "double") 

En caso de que no se quisiera exportar el nombre de las filas, basta con modificar un poco el código, como en el siguiente ejemplo:

write.table(df, file = "dataframe2.csv", sep = ",",
row.names = FALSE, qmethod = "double")

Ahora, si lo que buscamos es importar los datos usaremos el siguiente comando:

read.table("dataframe1.csv", header = TRUE, sep = ",",
row.names = 1) 

Y si no se quieren importar los nombres de las filas optaremos por el siguiente comando:

read.table("dataframe2.csv", header = TRUE, sep = ",")

La forma más sencilla de importar un .csv es a través del comando read.csv(...), cuya implementación es la siguiente:

read.csv(file, header = TRUE, sep = ",", dec = ".", ...)

Dónde:

Argumentos Significado o uso
file Ruta al archivo, en caso de estar en el mismo directorio de trabajo poner solo el nombre del archivo, de otro modo ingresar la ruta completa
header Valor lógico para determinar si el archivo incluye encabezados en la primera linea.
sep Este campo sirve para especificar el carácter de separación.
dec El carácter usado para los puntos decimales
... Ver la documentación para argumentos extras

Un ejemplo seria el siguiente:

csv <- read.csv("dataframe1.csv")

Guardar y cargar archivos .RData

Si tienes objetos que te gustaría guardar como tal para luego procesarlos o simplemente se te hace más sencillo comprenderlo sobre un .csv, los comandos serán los siguientes:

foo = "bar"
save(foo, file="nombre.RData")

Mientras que, para volver a cargar los datos:

load("nombre.RData")

Para llamar el objeto, basta con volver a introducir su variable, que, aunque no haya sido creada antes de usar la función load(), esta se encarga de crear el objeto y asignarle el valor que decidimos guardar en un principio.

foo
## [1] "bar"

Graficas

Hasta éste momento hemos mostrado todos los resultados en consola, lo cual, para muchos puede ser un poco tedioso, sin decir aburrido, por lo que, expresar los resultados en graficas sencillas, permiten comprender rápidamente el tema del que se habla, vaya, que «Una imagen vale más que mil palabras»

La función plot() es una de varias formas que se pueden utilizar para graficar, además al ser una función genérica permite seleccionar el tipo de grafico que buscamos.

plot(x, y, type="p", main ="Titulo", sub= "subtitulo", xlab="Eje x", ylab="Eje Y")

Donde:

Argumento Descripción
x Coordenadas de la variable independiente
y Coordenadas de la variable dependiente
type Tipo de grafico a dibujar, "p" es para puntos, "l" para líneas, "h" para histogramas, usar help(plot) para ver otros tipos.

Empezaremos viendo la función plot() de la manera más sencilla, Una persona ha estado realizando ejercicio últimamente y durante 7 semanas fue tomando su peso:

Semana 1 Semana 2 Semana 3 Semana 4 Semana 5 Semana 6 Semana 7
Peso 85 84 84.5 78 76.5 74.5 75

Por lo que, para graficar esto en R, los comandos a utilizar son los siguientes:

peso <- c(85,84,84.5,78,76.5,74.5,75)
plot(peso)

plot of chunk graficaPeso

Si en vez de tener una grafica de puntos, quisiéramos una con líneas, solo es necesario especificar el tipo con el parámetro type = "l", para ver otros posibles gráficos, ver la documentación de plot usando el comando help(plot).

peso <- c(85,84,84.5,78,76.5,74.5,75)
plot(peso, type="l")

plot of chunk graficaPesoLinea

Es posible modificar o añadir un título a los ejes para hacer más comprensible la grafica, así como añadirle un título a toda la grafica usando los siguientes comandos:

peso <- c(85,84,84.5,78,76.5,74.5,75)
plot(peso, type="l", ann = F)
title(main = "Un asombroso título", xlab="Semana", ylab = "Peso en Kg" )

plot of chunk graficaPesoLinea2

Note que en el comando plot(...) se añadió el parámetro ann=F.

Otra posible modificación en las graficas es renombrar los ejes, en vez de decir solamente el número, queremos que diga "Semana " y el número de la semana, para ello, será necesario añadir a la función plot(...) el parámetro xaxt="n" para que no agregue las notaciones originales, también es posible quitar las notaciones para el eje o para ambos ejes usando yaxt="n" o axes=F respectivamente. Y después añadirlos con el comando axis(...).

peso <- c(85,84,84.5,78,76.5,74.5,75)
plot(peso, type="l", ann = F, xaxt="n")
title(main = "Un asombroso título", ylab = "Peso en Kg" )
axis(1, at=1:length(peso), lab=c("Semana 1","Semana 2","Semana 3","Semana 4",
                                 "Semana 5","Semana 6","Semana 7"))

plot of chunk graficaPesoLinea3

A continuación veremos un ejemplo más complicado usando plot(...), partiendo de la siguiente tabla de animales rescatados en 4 meses, generaremos una grafica que muestre el comportamiento de los datos:

Enero Febrero Marzo Abril
Perro 10 8 12 7
Gato 12 3 3 9
Otros 5 5 2 1

Por lo que, en R, tendríamos:

animales <- matrix(c(10,8,9,7,7,5,5,4,5,3,3,7), nrow = 3, ncol = 4, 
                   dimnames = list(c("Perro", "Gato", "Otros"),
                                   c("Enero", "Febrero", "Marzo", "Abril")))
animales
##       Enero Febrero Marzo Abril
## Perro    10       7     5     3
## Gato      8       7     4     3
## Otros     9       5     5     7

Ahora, se busca graficar como se han comportado los rescates por cada animal en cada mes, por lo que un código podría ser el siguiente:

plot(x=1:4, y=animales[1,], type = "o", col="blue", axes=FALSE, ann=FALSE)
axis(1, at=1:4, lab=colnames(animales))
axis(2, las=1, at=1:12)
box()
lines(animales[2,], type="o", pch=22, lty=2, col="red")
lines(animales[3,], type="o", pch=22, lty=2, col="orange")
title(xlab="Mes", col.lab=rgb(0,0.5,0))
title(ylab="Rescatados", col.lab=rgb(0,0.5,0))
legend(2.2,9.9,c("Perros","Gatos","Otros"),lty=c(1,2,2),
       col=c("blue","red","Orange")) 

Como se están analizando 3 variables, es necesario identificarlas, por lo cuál se a agregado una legenda, donde los primeros dos valores es la posición en \(X\) y \(Y\); el tercer parámetro son los nombres; el cuarto parámetro, es el tipo de línea utilizado (1, es continua y 2 es punteada) y el quinto son los colores de dichas líneas. Note que, algunos de estos parámetros es posible usarlos en comandos anteriores.

Así se obtendría la grafica siguiente:

plot of chunk ejemploPlot3

R Tiene otras maneras de hacer gráficos sencillos, por ejemplo, para graficas de pastel, se puede usar el comando pie(). Por ejemplo:

gastos = c(Escuela=100, Alimentos=120, Recreación=90, Transporte=50) 
pie(gastos) 

plot of chunk pie

Condiciones (if-else)

Habrá momentos en los que ocuparemos tener en cuenta que queremos hacer si no sucede un evento, por ejemplo, saber si un número es par o no.

Para ello usaremos las condiciones, existen dos maneras:

if(10%%2==0){ 
  print("Es par") 
}else{ 
  print("Es impar") 
} 
## [1] "Es par"

Otra forma, única para el lenguaje de R es la siguiente.

set.seed(1)
val <- round(runif(1)*10,0)
val
## [1] 3
ifelse(val%%2==0,"Par","Impar")  
## [1] "Impar"

Nota:

set.seed(), es una función que permite que una función «aleatoria» devuelva el mismo número.

Ciclos, Repeticiones o Loops

Habrá momentos en las que ocuparemos realizar un número determinado de veces una misma rutina, para esto existe el ciclo for:

for(i in 1:5){ 
  print(i) 
} 
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

Y en ocasiones no sabremos hasta que momento queremos detener el ciclo, por lo que podemos usar:

i = 1 
while(i < 50){ 
  i = i * 2 
  print(i) 
} 
## [1] 2
## [1] 4
## [1] 8
## [1] 16
## [1] 32
## [1] 64

Paquetes

Los paquetes en R, son como «Extensiones» y nos sirven para evitar reinventar la rueda, existen muchos paquetes disponibles en el CRAN de R o GitHub y para instalarlos basta un comando en la propia terminal de R:

Para paquetes oficiales de CRAN

install.packages("NombreDelPaquete")
library(NombreDelPaquete) #Para usar el paquete

Para paquetes de GitHub

install.packages("devtools") #Correr solo si no se tiene el paquete "devtools" instalado.
devtools::install_github("usuario/repositorio")

Al agregar nuevos paquetes podremos expandir el potencial de R y a la vez facilitarnos el trabajo de «hacerlo por nosotros mismos».

Ayuda y documentación

R Nos proporciona toda la documentación de sus paquetes, así que si se nos olvida para que funciona un comando o por que la función no hace lo que uno escribe, revisar la documentación podrá evitar que pases horas frente al ordenador buscando el «punto y coma» que te falta, cuando en R los códigos no lo llevan.

help(nombre)

Donde nombre puede ser cualquier función o librería instalada de R.

ejemplos:

help(help)  #Sí, es posible
help(sum)   #Documentación de una función
help(slidify) #Documentación de un paquete

Preguntas para validar lo aprendido

¿Qué comando se usa para hacer una gráfica de pastel?

  1. pie()
  2. cake()
  3. plot()

Not hint available

pie()

Si tenemos el peso de 4 personas durante 3 semanas y queremos ver el promedio del peso por persona, ¿Qué comando deberíamos utilizar?

Persona 1 Persona 2 Persona 3 Persona 4
Semana 1 79 59 67.5 60
Semana 2 82.3 57.9 68.2 57.1
Semana 3 80 59.5 67 58.3
  1. apply(matriz,2,mean())
  2. apply(matriz,2,mean)
  3. apply(matriz,mean,2)

Ver sección sobre Apply()

Demostración:

df <- data.frame(W=c(79,82.3,80),X=c(59,57.9,59.5),
              Y=c(67.5,68.2,67),Z=c(60,57.1,58.3))
apply(df,2,mean)
##        W        X        Y        Z 
## 80.43333 58.80000 67.56667 58.46667

En una pista de carreras, se observan 3 autos dar 4 vueltas:

Civic Mazda Tsuru
Vuleta 1 110 km 125 km 95 km
Vuleta 2 140 km 130 km 105 km
Vuleta 3 135 km 125 km 115 km
Vuleta 4 135 km 115 km 120 km
  1. ¿A qué velocidad va el primer auto en promedio?
  2. ¿A qué velocidad va el segundo auto en promedio?
  3. ¿A qué velocidad va el tercer auto en promedio?
  1. 130
  2. 123.75
  3. 108.75

El profesor quiere conocer el rendimiento del semestre de sus 5 alumnos de maestría:

Alberto Francisco Juan Alejandro Oswaldo
Primera parcial 7 9 7.5 10 8.5
Segunda parcial 8.3 7.9 8.2 7.1 8.5
Tercera parcial 8 9.5 7 8.3 8.5
  1. ¿Cuál es el promedio de la calificación del grupo en el semestre?:
  2. ¿Cuál es el promedio de la calificación del grupo por parcial?:
  3. ¿Cuál es el promedio de la calificación de cada alumno en el semestre?:
  4. ¿Quíenes han reprobado la materia?
  1. 8.222
  2. 8.4,8,8.26
  3. 7.77,8.8,7.57,8.47,8.5
  4. "Alberto y Juan"