Funciones en R

Como hemos visto anteriormente, las funciones permiten realizar las diferentes acciones. Existen funciones definidas (pueden ser modificadas), pero lo más importante es que R permite crear objetos del modo function, es decir nos permite construir nuevas funciones de R que realicen tareas que no estaban definidas en el momento de instalar el programa, que además pueden utilizar a su vez en expresiones posteriores ganando considerablemente en potencia, comodidad y elegancia. Estas nuevas funciones se incorporan al lenguaje y se utilizan posteriormente como las previamente existentes. Para leer la definición, basta con escribir el nombre de la función sin paréntesis.

Nota: Para obtener ayuda sobre qué es lo que hace una función utilizaremos la función help. Si necesita ejecutar un programa del sistema operativo puede utilizar la función system, que permite incluso salir al sistema operativo con la orden system(“cmd”).

Para obtener información del sistema utilizamos shell, por ejemplo en shell(“dir”). Las funciones tradicionales en cualquier lenguaje de uso matemático y estadístico, están definidas. Entre ellas se encuentran, entre otras, abs, sqrt, sin, cos, tan, asin, acos, atan, exp, log, log10, min, max, sum, prod, length, mean, range, median, var, cov, summary, sort, rev, order.

sin(1:5)
## [1]  0.8414710  0.9092974  0.1411200 -0.7568025 -0.9589243
sin(pi)
## [1] 1.224647e-16
sin(pi/2)
## [1] 1
sum(1:5)
## [1] 15
prod(1:5)
## [1] 120

Definición de una función

Una función se define asignando a un objeto la palabra “function” seguida de los argumentos que desee dar a la función, escritos entre paréntesis y separados por comas, seguida de la orden, entre llaves si son varias órdenes, que desee asignar a la misma. Entre los argumentos destaca que si utiliza tres puntos seguidos, …, ello indica que el número de argumentos es arbitrario.

\[nombre<-function(arg1, arg2, ...)expresion\]

La expresión es una fórmula o grupo de fórmulas que utilizan los argumentos para calcular su valor. El valor de dicha expresión es el valor que proporciona R en su salida y éste puede ser un simple número, un vector, una gráfica, una lista o un mensaje.

Para definir una función debe realizar una asignación de la forma anterior, donde expresión es una expresión de R que utiliza los argumentos “arg i” para calcular un valor que es devuelto por la función.

El uso de la función es normalmente de la forma NombreDeFuncion(expr 1,expr 2,…) y puede realizarse en cualquier lugar en que el uso de una función sea correcto.

Ejemplo de creación de una función

Función suma

funcion.suma<-function(A,B){
  A+B
}

si deseamos sumar los número 5 y 8, realizamos:

funcion.suma(5,8)
## [1] 13

Función media

Es una función de un solo argumento (si no se especifica lo tomaremos por NA (valor nulo) y el resultado sería NA). En caso de que se le suministre un argumento, no se comprueba si es válido o no, sino que suponiendo que es un vector, se eliminan del mismo los elementos correspondientes a NA. Para ello se utiliza la negación ! y la condición de ser un valor no disponible.

media<-function(x=NA){
 x<-x[!is.na(x)]
 sum(x)/length(x)
}

tomemos unos valores

media(c(2,4,1,3,6,7))
## [1] 3.833333
media(c(2,4,1,3,6,NA))
## [1] 3.2

Aunque R ya tiene implementada como vimos anteriormente la orden “mean” que calcula la media de los valores que le indiquemos.

mean(c(2,4,1,3,6,7))
## [1] 3.833333

Función varianza

Tenemos la opción de calcular la varianza de dos maneras:

La definición de la varianza poblacional como :

\[\sigma^2=\sum\frac{(x-\overline{x})^2}{n}\]

varianza<-function(x=NA) {
 n<-length(x)
 v<-sum((x-(sum(x)/n))^2)/n
 return(v)
}

Para algnos valores

varianza(1:4)
## [1] 1.25
varianza(c(2,4,1,3,6,7))
## [1] 4.472222

Hay que tener en cuenta que R tiene implementada la orden “var” que calcula la varianza muestral o cuasivarianza, por lo que divide por \(n-1\) en vez de por \(n\).

var(c(2,4,1,3,6,7))
## [1] 5.366667

Si lo que queremos es calcular la cuasivarianza muestral tenemos que modificar la anterior función.

Cuasivarianza<-function(x=NA) {
n<-length(x)
cv<-sum((x-(sum(x)/n))^2)/(n-1)
return(cv)
}

tomemos unos valores

Cuasivarianza(c(2,4,1,3,6,7))
## [1] 5.366667
var(c(2,4,1,3,6,7))
## [1] 5.366667

Vemos que ambas coinciden.

Función desviación típica

La definición de la desviación típicaa poblacional es:

\[\sigma=\sqrt{\sum\frac{(x-\overline{x})^2}{n}}\]

Por tanto la definición es:

DT<-function(x=NA)
 {
 n<-length(x)
v<-sqrt(sum((x-(sum(x)/n))^2)/n)
return(v)
}

Ejemplos:

DT(1:3)
## [1] 0.8164966
DT(c(1,3,4,2,6,4))
## [1] 1.598611

Ejercicios:

Todos los siguientes problemas, deben realizarse en una función:

  1. Cree una función donde los argumentos sean dos vectores \(a\), \(b\) y un número entero \(k\). Luego seleccione las posiciones \(a[k]\) y \(b[k]\) y realice la suma \(a[k]+b[k]\).

  2. Cree una función donde los argumentos sean dos vectores \(a\), \(b\) y un número entero \(k\). Luego seleccione las posiciones \(a[k]\) y \(b[k]\) y realice la operación \(\log(a[k])-\log(b[k])\).

  3. Del archivo “datos_poblacion.xlsx” que se puede descargar en el siguiente enlace:

https://docs.google.com/spreadsheets/d/1GMrNfV1dYTE_U4diDBd59AMOjOV2pMdJ0LzySdrAHHg/edit?usp=sharing

[Fuente de datos https://www.unescoetxea.org/ext/futuros/es/theme_c/mod13/uncom13t01s02.htm]

se desea encontrar un modelo exponencial para la población mundialentre el año 1900 a 2020. Para ello primero cargue los datos allí presentados y guardelo en un data frame llamado datos_poblacion. Después genere dos vectores \(t\) y \(P\), donde \(t\) es el tiempo en años y \(P\) es la cantidad de personas en el mundo dada en millones. Realice una función que:

  1. Ingrese dos vectores \(t\) y \(P\) y realice un gráfico plot de ellos.

\[plot(x,P,main="Población mundial",xlab="Tiempo en años",ylab="Población mundial (P en millones)")\]

  1. Encuentre una función exponencial que modele el crecimiento poblacional.

  2. Trace una gráfica de la función que encontró junto con la gráfica de los puntos datos.

  3. Use el modelo que usted encontró para predecir la población mundial en el año 2021 y 2030.

Elementos útiles a la hora de programar

Operadores de relación:

Con ! se indica la negación, con & la conjunción y con | la disyunción. Estos dos últimos, si se escriben repetidos tienen el mismo signicado, pero se evalúa primero la parte de la izquierda y, si ya se sabe el resultado (suponiendo que se pudiera calcular la expresión de la derecha) no se sigue evaluando, por lo que pueden ser más rápidos y eliminar errores. <, >,<=,>=,== son respectivamente los símbolos de menor, mayor, menor o igual, mayor o igual, e igual. Advierta que este último se escribe con dos signos de igualdad.

2<=4
## [1] TRUE
8==9
## [1] FALSE
z1<-1
z2<--8
z2<z1
## [1] TRUE
z1>=z2
## [1] TRUE
z1!=z2
## [1] TRUE

Estructuras condicionales.

Son aquellas que, según el resultado de una comparación, realizan una u otra acción. La primera estructura es if (condición) acción1 [else acción2]
Estructura del condicional if

SI esta condición es es cierta, ENTONCES haz estas operaciones, DE OTRO MODO haz estas otras operaciones.

El modelo para un if con un else es:

if(condición) {
  operaciones_si_la_condición_es_TRUE
} else {
  operaciones_si_la_condición_es_FALSE
}

Algunos ejemplos:

-Creamos una función que calcule el logaritmo de un número

 logaritmo<-function(x){
 if(is.numeric(x)&& min(x)>0)
 log(x)
 else{stop("x no es numérico o es menor que cero")}
 }

algunos calculos:

logaritmo(10)
## [1] 2.302585

sabemos que por la definición de la función logaritmo, \(log(1)=0\)

logaritmo(1)
## [1] 0
logaritmo(exp(1))
## [1] 1

-La segunda estructura es ifelse(condición, acción en caso cierto, acción en caso falso).

Inverso<-function(x)
ifelse(x==0,NA,1/x)

Ejemplo:

 Inverso(-2:2)
## [1] -0.5 -1.0   NA  1.0  0.5

Ejercicios:

  1. SI el promedio de un estudiante es igual o mayor a 3, ENTONCES mostrar “Aprobado”, DE OTRO MODO, mostrar “Reprobado”.

Solución:

promedio <- function(calificaciones) {
  media <- mean(calificaciones)
  texto <- paste0("Calificación: ", media, ", ")
  
  if(media >= 3) {
    print(paste0(texto, "aprobado"))
  } else {
    print(paste0(texto, "reprobado"))
  }
}

Pongamos a prueba nuestra función.

promedio(c(3, 3.5, 4, 4.5, 4))
## [1] "Calificación: 3.8, aprobado"
promedio(c(2.5, 4, 2.5, 3, 2.5))
## [1] "Calificación: 2.9, reprobado"
  1. Se considera el cálculo del valor en un punto \(x\) de una función definida por partes:

\[f(x)=\begin{cases}x & \text{ si } x<0\\ x^2 & \text{ si } x\geq0 \end{cases}\]

Con el comando plot, gráfique la función.

  1. Elabore una función que calcule la raíz cuadra de un número \(x\). Si \(x<0\), calcule el valor absoluto del número.

  2. Determinación del signo de un número: positivo, negativo o nulo.

  3. Solicitar al usuario un número de cliente. Si el número es el 1000, imprimir “Ganaste un premio”, si no, “Sigue intentando”.

Bucles FOR

Los bucles FOR son el tipo de bucle más utilizado en R. Estos toman una variable a la que se le asignan los elementos de un objeto (en general, vectores o listas) en forma sucesiva a medida que se van recorriendo los ciclos.

Diagrama del blucle for

Sintaxis del bucle for

for(<variable> in <objeto iterable>) {
  # código
  ...
}

Ejemplo:

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

Si queremos recorrer los elementos de un objeto podemos realizarlo directamente, o por su índice ayudándonos de la función seq_along(x), la cual genera una secuencia numérica que usaremos para indica los indices de los elementos de los objetos que queremos recorrer:

# Creamos un vector sobre el cual vamos a iterar
x <- c("a", "b", "c", "d")
seq_along(x)
## [1] 1 2 3 4
# Podemos iterar accediendo a los elementos por su índice
for(i in seq_along(x)) {
print(x[i])
}
## [1] "a"
## [1] "b"
## [1] "c"
## [1] "d"

En caso en que se quisiera recorrer una estructuras de más de una dimensión, como puede ser una matriz, simplemente anidamos bucles FOR:

x <- matrix(1:16, 4, 4)
x
##      [,1] [,2] [,3] [,4]
## [1,]    1    5    9   13
## [2,]    2    6   10   14
## [3,]    3    7   11   15
## [4,]    4    8   12   16
for(i in seq_len(nrow(x))) {
  for(j in seq_len(ncol(x))) {
    print(x[i, j])
  }
}
## [1] 1
## [1] 5
## [1] 9
## [1] 13
## [1] 2
## [1] 6
## [1] 10
## [1] 14
## [1] 3
## [1] 7
## [1] 11
## [1] 15
## [1] 4
## [1] 8
## [1] 12
## [1] 16

Otro ejemplo:

 x = seq(-10,10)
 plot(x,x,xlim=c(-10,10),ylim=c(-10,10))
 for(i in 0:10)
 abline(h=i,col=i)
 for(i in 0:10)
 abline(v=i,col=i)

Ejercicios

  1. Escribir un programa que pida al usuario una palabra y la muestre por pantalla 10 veces.

  2. Escribir un programa que pregunte al usuario su edad y muestre por pantalla todos los años que ha cumplido (desde 1 hasta su edad) con el año de su cumpleños.

  3. Escribir un programa que pida al usuario un número entero positivo y muestre por pantalla todos los números impares desde 1 hasta ese número separados por comas.

  4. Con la función runif genere 100 valores entre los número del 100 al 500. Escribir un programa que pida al usuario un número entero positivo y muestre por pantalla todos los números pares que genero la lista de 100 valores.

  5. Escribir un programa que pida al usuario un número entero positivo y muestre por pantalla la cuenta atrás desde ese número hasta cero separados por comas.

  6. Escribir un programa que pregunte al usuario una cantidad a invertir, el interés anual y el número de años, y muestre por pantalla el capital obtenido en la inversión cada año que dura la inversión.

WHILE

Los bucles WHILE comienzan comprobando una condición. Si esta es verdadera, entonces se entra al cuerpo del bucle. Una vez completada una ejecución de este bloque, se comprueba la condición nuevamente y así sucesivamente hasta que la comprobación de la condición de falso.

Diagrama del blucle while

Sintaxis ciclo while

while(<condicion>) {
  # código
  ...
}

Ejemplo:

cuente <- 0
while(cuente < 10) {
  print(cuente)
  cuente <- cuente + 1
}
## [1] 0
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9

Otro ejemplo, si queremos calcular qué número es el mayor cuyo cuadrado no excede de 1000, podemos hacer:

n=0
cuadrado = 0
while(cuadrado<=1000)
{
n<-n+1
cuadrado<-n^2
}
n
## [1] 32
cuadrado
## [1] 1024

¿Qué ha sucedido? El cuadrado de 32 excede 1000. En realidad, cuando \(n\) valía 31, su cuadrado (961) no excedía 1000, y el while() permitió entrar en el bucle, lo que hizo \(n=32\). El número correcto sería en este caso \(n-1 = 31\).

Ejercicios

  1. Escribir un programa que pida al usuario una palabra y la muestre por pantalla 10 veces.

  2. Escribir un programa que pida al usuario un número entero positivo y muestre por pantalla todos los números impares desde 1 hasta ese número.

  3. Encuentre un programa que genere una sucesión de tipo Fibonacci, para dos valores iniciales \(a\) y \(b\).

  4. Escribir un programa que pida al usuario un número entero y muestre por pantalla todos los números primos antes del ingresado.

  5. Realiza un programa que pida 2 números enteros, e imprima los números pares que existen entre los 2.

Programación básica

Resuleve dos de los siguientes problemas, usando function en la solución de los mimos:

Problema 0: Elabore un programa donde una persona está de pie en un barco en un mar en calma, entonces su estatura \(x\) en pies sobre el nvel del mar está relacionada con la distancia más lejana \(y\) en millas que puede ver, con la ecuación

\[y=\sqrt{1.5x +\left(\frac{x}{5280}\right)^2}\]

  1. Grafique la función para una persona que mide entre 1.50 m y 2 m.

  2. ¿ A qué altura debe estar para poder ver a 200 km?

Problema 1: Realice un programa que encuentre: Para dos puntos \(P(x_1, y_1)\) y \(Q(x_2, y_2)\) dos puntos en el plano de coordenadas.

  • Encuentre la distancia entre \(P\) y \(Q\).
  • Encuentre el punto medio del segmento \(PQ\).
  • Encuentre la pendiente de la recta que contenga a \(P\) y \(Q\).
  • Encuentre la ecuación para la circunferencia para el que el segmento \(PQ\) es un diámetro.

Problema 2: Un fabricante quiere realizar una lata que contiene de aceite, suponiendo que la lata tiene tapa arriba y abajo. Realice un programa que calcule la cantidad de material que se necesita para realizar la lata, dado el volmén de liquido que se quiera guardar y el radio de la misma.

Problema 3: Una jardinera tiene \(x\) metros de malla para instalar una cerca en un jardín rectangular de hortalizas, si desea que siempre la cerca tenga la base igual a \(\displaystyle \frac{2}{3}\) de la altura la misma. Elabore un programa que cálcule el área de dicha cerca dando la longitud de la cerca.

Problema 4: Se tiene un triángulo equilatero de lado \(l\). Elabore un programa que cálcule el área del triángulo y perímetro.

Problema 5: Elabore un programa que encuentre el área superficial \(S\) de un cubo en términos de su volumen \(V\).

Problema 6: Elabore un programa que encuentre realice la conjetura de Collatz, que dice lo siguiente:

  • Tómese un número entero positivo (1, 2, 3, etcétera)

  • Si es par, divídase entre 2

  • Si es impar, multiplíquese por 3 y súmele uno

Imprima todos la lista de números que genera hasta llegar a 1.

Problema 7: En un estacionamiento cobran \(\$\) 1.500 por hora o fracción. Diseñe un algoritmo que determine cuanto debe pagar un cliente por el estacionamiento de su vehículo, conociendo el tiempo de estacionamiento en:

  • minutos.

  • horas y minutos.

Problema 8: El algoritmo de Euclides. Deben ingresar dos números enteros positivos \(a\) y \(b\) y debe buscar un número \(q\) (cociente) y \(r\) (residuo) tales que \(a=qb+r\) con \(0\leq r<b\), la cual denominaremos expresión de Euclides.

Problema 9: Elabore un programa que calcula el factorial de un número entero mayor a cero invocando una función de forma iterativa.

Problema 10: Sumar todos los números del 1 al 100 de dos maneras: con un bucle (utilizando for) y utilizando la función sum. Luego elabore un programa que ingrese un número natural \(n\) y realice la suma de los números de \(1+2+3+\cdots+n\).