Los números son entidades matemáticas que representan cantidades y se utilizan para medir, contar y calcular. La aritmética es la rama de las matemáticas que se centra en las operaciones básicas con números, como la suma, resta, multiplicación y división. Las asignaciones son procesos mediante los cuales se asignan valores a variables, permitiendo almacenar y manipular información en programas informáticos. Los vectores son conjuntos ordenados de números que pueden representarse en forma de listas unidimensionales y se utilizan en diversas áreas, desde la física hasta la informática, para representar magnitudes y direcciones.
Todas las operaciones aritméticas comunes y la funcionalidad matemática están listas para su uso en el indicador de la consola. Puede realizar sumas, restas, multiplicaciones y divisiones con los símbolos +, -, * y /, respectivamente. Puede crear exponentes (también denominados potencias o índices) usando ^, y controla el orden de los cálculos en un solo comando usando paréntesis, ().
En R, las reglas matemáticas estándar se aplican siguiendo el orden habitual de operaciones de izquierda a derecha, conocido como PEMDAS (paréntesis, exponentes, multiplicación, división, suma y resta).
Aquí hay un ejemplo en la consola:
#> 2+3
#[1] 5
#> 14/6
#[1] 2.333333
#> 14/6+5
#[1] 7.333333
#> 14/(6+5)
#[1] 1.272727
#> 3^2
#[1] 9
#> 2^3
#[1] 8
Puedes encontrar la raíz cuadrada de cualquier número no negativo con la función sqrt. Simplemente proporcione el número deseado a x como se muestra aquí:
#> sqrt(x=9)
#[1] 3
#> sqrt(x=5.311)
#[1] 2.304561
Al usar R, a menudo encontrará que necesita traducir una fórmula aritmética complicada en código para su evaluación (por ejemplo, al replicar un cálculo de un libro de texto o un trabajo de investigación). Los siguientes ejemplos proporcionan un cálculo expresado matemáticamente, seguido de su ejecución en R:
\[10^{2}+\frac{3\times60}{8}-3\]
\[\frac{5^{3}\times(6-2)}{61-3+4}\]
\[2^{2+1}-4+64^{-2^{2.25-\frac{1}{4}}}\]
\[(\frac{0.44\times(1-0.44)}{34})^{\frac{1}{2}}\]
Tenga en cuenta que algunas expresiones de R requieren paréntesis adicionales que no están presentes en las expresiones matemáticas. Los paréntesis faltantes o mal colocados son causas comunes de errores aritméticos en R, especialmente cuando se trata de exponentes. Si el exponente es en sí mismo un cálculo aritmético, siempre debe aparecer entre paréntesis. Por ejemplo, en la tercera expresión, necesita paréntesis alrededor de 2.25-1/4. También es necesario usar paréntesis si el número que se eleva a cierta potencia es un cálculo, como la expresión 2 2+1 en el tercer ejemplo. Tenga en cuenta que R considera un número negativo como un cálculo porque interpreta, por ejemplo, -2 como -1*2. Es por eso que también necesita los paréntesis alrededor de -2 en esa misma expresión. Es importante resaltar estos problemas desde el principio, ya que pueden pasarse por alto fácilmente en grandes fragmentos de código.
A menudo verá o leerá acerca de los investigadores que realizan una transformación de registro en determinados datos. Esto se refiere a cambiar la escala de los números de acuerdo con el logaritmo. Cuando se proporciona un número x dado y un valor denominado base, el logaritmo calcula la potencia a la que se debe elevar la base para llegar a x. Por ejemplo, el logaritmo de x = 243 en base 3 (escrito matemáticamente como log3 243) es 5, porque 35 = 243. En R, la transformación logarítmica se logra con la función log. El logaritmo se proporciona con el número que se va a transformar, asignado al valor x, y la base, asignada a la base, de la siguiente manera:
#> log(x=243,base=3)
#[1] 5
Estas son algunas cosas a tener en cuenta: • Tanto x como la base deben ser positivas. • El logaritmo de cualquier número x cuando la base es igual a x es 1. • El logaritmo de x = 1 es siempre 0, independientemente de la base. Hay un tipo particular de transformación logarítmica que se usa a menudo en matemáticas llamada logaritmo natural, que fija la base en un número matemático especial: el número de Euler. Esto se escribe convencionalmente como e y es aproximadamente igual a 2.718. El número de Euler da lugar a la función exponencial, definida como e elevado a la potencia de x, donde x puede ser cualquier número (negativo, cero o positivo). La función exponencial, f (x) = e x , a menudo se escribe como exp(x) y representa la inversa del logaritmo natural tal que exp(loge x) = loge exp(x) = x. El comando R para la función exponencial es exp:
#> exp(x=3)
#[1] 20.08554
El comportamiento predeterminado de log es asumir el log natural
#> log(x=20.08554)
#[1] 3
Debe proporcionar el valor de base usted mismo si desea utilizar un valor distinto de e. El logaritmo y las funciones exponenciales se mencionan aquí porque se vuelven importantes más adelante en el libro: muchos métodos estadísticos los usan debido a sus diversas propiedades matemáticas útiles.
Cuando R imprime números grandes o pequeños más allá de un cierto umbral de cifras significativas, establecido en 7 de forma predeterminada, los números se muestran utilizando la notación electrónica científica clásica. La notación electrónica es típica de la mayoría de los lenguajes de programación, e incluso de muchas calculadoras de escritorio, para permitir una interpretación más fácil de los valores extremos. En notación electrónica, cualquier número x puede expresarse como xey, que representa exactamente x × 10y . Consideremos el número 2.342.151.012.900. Podría, por ejemplo, representarse de la siguiente manera: • 2,3421510129e12, que equivale a escribir 2,3421510129 × 1012 • 234,21510129e10, que equivale a escribir 234,21510129 × 1010 Puede usar cualquier valor para la potencia de y, pero la notación electrónica estándar usa la potencia que coloca un decimal justo después del primer dígito significativo. En pocas palabras, para una potencia positiva +y, la notación electrónica se puede interpretar como “mover las posiciones decimales y hacia la derecha”. Para una potencia negativa −y, la interpretación es “mover las posiciones decimales y hacia la izquierda”. Así es exactamente como R presenta la notación electrónica:
#> 2342151012900
#[1] 2.342151e+12
#> 0.0000002533
#[1] 2.533e-07
En el primer ejemplo, R muestra solo los primeros siete dígitos significativos y oculta el resto. Tenga en cuenta que no se pierde información en ningún cálculo, incluso si R oculta dígitos; la notación electrónica es puramente para facilitar la lectura por parte del usuario, y los dígitos adicionales aún se almacenan en R, aunque no se muestren. Por último, tenga en cuenta que R debe imponer restricciones sobre lo extremo que puede ser un número antes de que se trate como infinito (para números grandes) o cero (para números pequeños). Estas restricciones dependen de su sistema individual, y discutiré los detalles técnicos un poco más en la Sección 6.1.1. Sin embargo, se puede confiar en que cualquier sistema de escritorio moderno sea lo suficientemente preciso de forma predeterminada para la mayoría de los esfuerzos computacionales y estadísticos en R
\[\frac{6a+42}{3^{4.2-3.62}}\]
cuando a = 2.3.
-4^2+2
(-4)^(2+2)
-4^(2+2)
Usando R, ¿cómo calcularías la raíz cuadrada de la mitad del promedio de los números 25.2, 15, 16.44, 15.3 y 18.6?
Encuentre loge 0.3.
Dada la expresión: \(\frac{6a + 42}{34.2 - 3.62}\), vamos a verificar que cuando \(a = 2.3\), el resultado es \(29.50556\).
# Definir el valor de a
a <- 2.3
# Calcular el lado izquierdo de la ecuación
lhs <- (6 * a + 42) / (3 ^ (4.2 - 3.62))
# Imprimir el resultado
cat("Lado izquierdo:", lhs, "\n")
## Lado izquierdo: 29.50556
# Punto B
# Resolver cada expresión
option_i <- (-4)^2 + 2
option_ii <- -4^2 + 2
option_iii <- (-4)^(2+2)
option_iv <- -4^(2+2)
# Mostrar los resultados
cat("Opción i:", option_i, "\n")
## Opción i: 18
cat("Opción ii:", option_ii, "\n")
## Opción ii: -14
cat("Opción iii:", option_iii, "\n")
## Opción iii: 256
cat("Opción iv:", option_iv, "\n")
## Opción iv: -256
# Punto C
# Calcular el promedio de los números
promedio <- mean(c(25.2, 15, 16.44, 15.3, 18.6))
# Calcular la mitad del promedio
mitad_promedio <- promedio / 2
# Calcular la raíz cuadrada
raiz_cuadrada <- sqrt(mitad_promedio)
# Mostrar el resultado
cat("Raíz cuadrada:", raiz_cuadrada, "\n")
## Raíz cuadrada: 3.008987
# Punto D.
# Calcular el logaritmo natural de 0.3
log_03 <- log(0.3)
# Mostrar el resultado
cat("log(0.3):", log_03, "\n")
## log(0.3): -1.203973
# Punto E
# Calcular la transformación exponencial
exp_log_03 <- exp(log_03)
# Mostrar el resultado
cat("exp(log(0.3)):", exp_log_03, "\n")
## exp(log(0.3)): 0.3
# Punto F
# Imprimir el número en la consola
numero <- -0.00000000423546322
cat("Representación científica:", numero, "\n")
## Representación científica: -4.235463e-09
Hasta ahora, R simplemente ha mostrado los resultados de los cálculos de ejemplo imprimiéndolos en la consola. Si desea guardar los resultados y realizar más operaciones, debe poder asignar los resultados de un cálculo determinado a un objeto en el espacio de trabajo actual. En pocas palabras, esto equivale a almacenar algún elemento o resultado bajo un nombre determinado para que se pueda acceder a él más tarde, sin tener que volver a escribir ese cálculo. En este libro, usaré los términos asignar y almacenar indistintamente. Tenga en cuenta que algunos libros de programación se refieren a un objeto almacenado como una variable debido a la capacidad de sobrescribir fácilmente ese objeto y cambiarlo a algo diferente, lo que significa que lo que representa puede variar a lo largo de una sesión. Sin embargo, usaré el término objeto a lo largo de este libro porque discutiremos las variables en la Parte III como un concepto estadístico claramente diferente. Puede especificar una asignación en R de dos maneras: mediante la notación de flecha (<-) y utilizando un único signo igual (=). Ambos métodos se muestran aquí:
#> x <- -5
#> x
#[1] -5
#> x = x + 1 # this overwrites the previous value of x
#> x
#[1] -4
#> mynumber = 45.2
#> y <- mynumber*x
#> y
#[1] -180.8
#> ls()
#[1] "mynumber" "x" "y"
Como puede ver en estos ejemplos, R mostrará el valor asignado a un objeto cuando escriba el nombre del objeto en la consola. Cuando utilice el objeto en operaciones posteriores, R sustituirá el valor que le asignó. Por último, si utiliza el comando ls (que vio en la Sección 1.3.1) para examinar el contenido del espacio de trabajo actual, revelará los nombres de los objetos en orden alfabético (junto con cualquier otro elemento creado anteriormente). Aunque = y <- hacen lo mismo, es prudente (por la pulcritud del código, por lo menos) ser coherente. Sin embargo, muchos usuarios optan por seguir con el <-, debido a la posibilidad de confusión en el uso de = (por ejemplo, claramente no quise decir que x es matemáticamente igual a x + 1 antes). En este libro, haré lo mismo y reservaré = para establecer argumentos de función, que comienza en la Sección 2.3.2. Hasta ahora solo ha utilizado valores numéricos, pero tenga en cuenta que el procedimiento de asignación es universal para todos los tipos y clases de objetos, que examinará en los próximos capítulos. Los objetos pueden ser nombrados casi cualquier cosa siempre y cuando el nombre comience con una letra (en otras palabras, no con un número), evite símbolos (aunque los guiones bajos y los puntos están bien) y evite el puñado de palabras “reservadas” como las que se usan para definir valores especiales (ver Sección 6.1) o para controlar el flujo de código (ver Capítulo 10). Puede encontrar un resumen útil de estas reglas de nomenclatura en la Sección 9.1.2.
# Crear el objeto
valor_a <- 32 * 4 + 1/8
# Sobrescribir el objeto
valor_a <- valor_a / 2.33
# Imprimir el resultado
print(valor_a)
## [1] 54.98927
# Crear el nuevo objeto
valor_c <- -8.2 * 10^-13
# Imprimir el resultado de la multiplicación
print(valor_a * valor_c)
## [1] -4.50912e-11
A menudo, querrá realizar los mismos cálculos o comparaciones en varias entidades, por ejemplo, si está cambiando la escala de las mediciones en un conjunto de datos. Podría hacer este tipo de operación una entrada a la vez, aunque esto claramente no es ideal, especialmente si tiene una gran cantidad de elementos. R proporciona una solución mucho más eficiente a este problema con vectores. Por el momento, para simplificar las cosas, seguirá trabajando solo con entradas numéricas, aunque muchas de las funciones de utilidad que se describen aquí también se pueden aplicar a estructuras que contienen valores no numéricos.
El vector es el bloque de construcción esencial para manejar múltiples elementos en R. En un sentido numérico, puedes pensar en un vector como una colección de observaciones o mediciones relativas a una sola variable, por ejemplo, la altura de 50 personas o el número de cafés que bebes diariamente. Las estructuras de datos más complicadas pueden constar de varios vectores. La función para crear un vector es la letra c simple, con las entradas deseadas entre paréntesis separadas por comas
#> myvec <- c(1,3,1,42)
#> myvec
#[1] 1 3 1 42
Las entradas vectoriales pueden ser cálculos o elementos previamente almacenados (incluidos los propios vectores).
#> foo <- 32.1
#> myvec2 <- c(3,-3,2,3.45,1e+03,64^0.5,2+(3-1.1)/9.44,foo)
#> myvec2
#[1] 3.000000 -3.000000 2.000000 3.450000 1000.000000 8.000000
#[7] 2.201271 32.100000
Este código creó un nuevo vector asignado al objeto myvec2. Algunas de las entradas se definen como expresiones aritméticas y es el resultado de la expresión que se almacena en el vector. El último elemento, foo, es un objeto numérico existente definido como 32.1. Veamos otro ejemplo.
#> myvec3 <- c(myvec,myvec2)
#> myvec3
#[1] 1.000000 3.000000 1.000000 42.000000 3.000000 -3.000000
#[7] 2.000000 3.450000 1000.000000 8.000000 2.201271 32.100000
Este código crea y almacena otro vector, myvec3, que contiene las entradas de myvec y myvec2 anexadas juntas en ese orden.
Aquí discutiré algunas funciones comunes y útiles asociadas con los vectores R: seq, rep, sort y length. Vamos a crear una secuencia igualmente espaciada de valores numéricos crecientes o decrecientes. Esto es algo que necesitará a menudo, por ejemplo, al programar bucles (consulte el Capítulo 10) o al trazar puntos de datos (consulte el Capítulo 7). La forma más fácil de crear una secuencia de este tipo, con valores numéricos separados por intervalos de 1, es usar el operador de dos puntos
#> 3:27
#[1] 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
El ejemplo 3:27 debe leerse como “de 3 a 27 (por 1)”. El resultado es un vector numérico como si hubieras enumerado cada número manualmente entre paréntesis con c. Como siempre, también puede proporcionar un valor almacenado previamente o un cálculo (estrictamente entre paréntesis) al usar el operador de dos puntos
#> foo <- 5.3
#> bar <- foo:(-47+1.5)
#> bar
#[1] 5.3 4.3 3.3 2.3 1.3 0.3 -0.7 -1.7 -2.7 -3.7 -4.7
#[12] -5.7 -6.7 -7.7 -8.7 -9.7 -10.7 -11.7 -12.7 -13.7 -14.7 -15.7
#[23] -16.7 -17.7 -18.7 -19.7 -20.7 -21.7 -22.7 -23.7 -24.7 -25.7 -26.7
#[34] -27.7 -28.7 -29.7 -30.7 -31.7 -32.7 -33.7 -34.7 -35.7 -36.7 -37.7
#[45] -38.7 -39.7 -40.7 -41.7 -42.7 -43.7 -44.7
Secuencias con seq También puede utilizar el comando seq, que permite crear secuencias de forma más flexible. Esta función lista para usar toma un valor from, un valor to y un valor by, y devuelve la secuencia correspondiente como un vector numérico.
#> seq(from=3,to=27,by=3)
#[1] 3 6 9 12 15 18 21 24 27
Esto le da una secuencia con intervalos de 3 en lugar de 1. Tenga en cuenta que este tipo de secuencias siempre comenzarán en el número de origen, pero no siempre incluirán el número de destino, dependiendo de lo que le esté pidiendo a R que las aumente (o disminuya). Por ejemplo, si estás aumentando (o disminuyendo) en números pares y tu secuencia termina en un número impar, el número final no se incluirá. Sin embargo, en lugar de proporcionar un valor by, puede especificar un valor length.out para producir un vector con esa cantidad de números, espaciados uniformemente entre los valores from y to.
#> seq(from=3,to=27,length.out=40)
#[1] 3.000000 3.615385 4.230769 4.846154 5.461538 6.076923 6.692308
#[8] 7.307692 7.923077 8.538462 9.153846 9.769231 10.384615 11.000000
#[15] 11.615385 12.230769 12.846154 13.461538 14.076923 14.692308 15.307692 #[22] 15.923077 16.538462 17.153846 17.769231 18.384615 19.000000 19.615385
#[29] 20.230769 20.846154 21.461538 22.076923 22.692308 23.307692 23.923077
#[36] 24.538462 25.153846 25.769231 26.384615 27.000000
Al establecer length.out en 40, hace que el programa imprima exactamente 40 números espaciados uniformemente del 3 al 27. Para secuencias decrecientes, el uso de by debe ser negativo. He aquí un ejemplo:
#> foo <- 5.3
#> myseq <- seq(from=foo,to=(-47+1.5),by=-2.4)
#> myseq
#[1] 5.3 2.9 0.5 -1.9 -4.3 -6.7 -9.1 -11.5 -13.9 -16.3 -18.7 -21.1
#[13] -23.5 -25.9 -28.3 -30.7 -33.1 -35.5 -37.9 -40.3 -42.7 -45.1
Este código usa el objeto foo almacenado previamente como el valor de from y usa el cálculo entre paréntesis (-47+1.5) como el valor to. Dados esos valores (es decir, con foo mayor que (-47+1.5)), la secuencia solo puede progresar en pasos negativos; Justo encima, establecemos que sea -2.4. Sin embargo, el uso de length.out para crear secuencias decrecientes sigue siendo el mismo (no tendría sentido especificar una “longitud negativa”). Para los mismos valores de origen y destino, puede crear fácilmente una secuencia decreciente de longitud 5, como se muestra aquí:
#> myseq2 <- seq(from=foo,to=(-47+1.5),length.out=5)
#> myseq2
#[1] 5.3 -7.4 -20.1 -32.8 -45.5
Las secuencias son extremadamente útiles, pero a veces es posible que desee simplemente repetir un determinado valor. Esto se hace usando rep.
#> rep(x=1,times=4)
#[1] 1 1 1 1
#> rep(x=c(3,62,8.3),times=3)
#[1] 3.0 62.0 8.3 3.0 62.0 8.3 3.0 62.0 8.3
#> rep(x=c(3,62,8.3),each=2)
#[1] 3.0 3.0 62.0 62.0 8.3 8.3
#> rep(x=c(3,62,8.3),times=3,each=2)
#[1] 3.0 3.0 62.0 62.0 8.3 8.3 3.0 3.0 62.0 62.0 8.3 8.3 3.0 3.0 62.0
#[16] 62.0 8.3 8.3
A la función rep se le asigna un valor único o un vector de valores como argumento x, así como un valor para los argumentos times y each. El valor de times proporciona el número de veces que se debe repetir x, y cada uno proporciona elnúmero de veces para repetir cada elemento de x. En la primera línea de arriba, simplemente repita un solo valor cuatro veces. Los otros ejemplos primero usan rep y times en un vector para repetir todo el vector, luego usan cada uno para repetir cada miembro del vector y, finalmente, usan ambos tiempos y cada uno para hacer ambas cosas a la vez. Si no se especifica ni times ni cada uno, el valor predeterminado de R es tratar los valores de times y each como 1 para que una llamada de rep(x=c(3,62,8.3)) simplemente devuelva la x suministrada originalmente sin cambios. Al igual que con seq, puede incluir el resultado de rep en un vector del mismo tipo de datos, como se muestra en el siguiente ejemplo:
#> foo <- 4
#> c(3,8.3,rep(x=32,times=foo),seq(from=-2,to=1,length.out=foo+1))
#[1] 3.00 8.30 32.00 32.00 32.00 32.00 -2.00 -1.25 -0.50 0.25 1.00
Aquí, he construido un vector en el que las entradas tercera a sexta (inclusive) se rigen por la evaluación de un comando rep: el valor único 32 veces foo repetidas (donde foo se almacena como 4). Las últimas cinco entradas son el resultado de una evaluación de seq, es decir, una secuencia de −2 a 1 de longitud foo+1 (5).
un vector en orden creciente o decreciente de sus elementos es otra operación sencilla que surge en las tareas cotidianas. La función sort convenientemente llamada hace precisamente eso
#> sort(x=c(2.5,-1,-10,3.44),decreasing=FALSE)
#[1] -10.00 -1.00 2.50 3.44
#> sort(x=c(2.5,-1,-10,3.44),decreasing=TRUE)
#[1] 3.44 2.50 -1.00 -10.00
#> foo <- seq(from=4.3,to=5.5,length.out=8)
#> foo
#[1] 4.300000 4.471429 4.642857 4.814286 4.985714 5.157143 5.328571 5.500000
#> bar <- sort(x=foo,decreasing=TRUE)
#> bar
#[1] 5.500000 5.328571 5.157143 4.985714 4.814286 4.642857 4.471429 4.300000
#> sort(x=c(foo,bar),decreasing=FALSE)
#[1] 4.300000 4.300000 4.471429 4.471429 4.642857 4.642857 4.814286 4.814286
#[9] 4.985714 4.985714 5.157143 5.157143 5.328571 5.328571 5.500000 5.500000
La función de clasificación es bastante sencilla. Se proporciona un vector a la función como argumento x, y un segundo argumento, decreciente, indica el orden en el que se desea ordenar. Este argumento toma un tipo de valor que aún no ha cumplido: uno de los valores lógicos más importantes. Un valor lógicopuede ser solo uno de los dos valores específicos que distinguen entre mayúsculas y minúsculas: TRUE o FALSE. En términos generales, las lógicas se utilizan para indicar la satisfacción o el fracaso de una determinada condición, y forman parte integral de todos los lenguajes de programación. Investigará los valores lógicos en R con mayor detalle en la Sección 4.1. Por ahora, en lo que respecta a la ordenación, establece dedecreasesing=FALSE para ordenar de menor a mayor, y dedecreasesing=TRUE ordena de mayor a menor.
Completaré esta sección con la función length, que determina cuántas entradas existen en un vector dado como argumento x.
#> length(x=c(3,2,8,1))
#[1] 4
#> length(x=5:13)
#[1] 9
#> foo <- 4
#> bar <- c(3,8.3,rep(x=32,times=foo),seq(from=-2,to=1,length.out=foo+1))
#> length(x=bar)
#[1] 11
Tenga en cuenta que si incluye entradas que dependen de la evaluación de otras funciones (en este caso, llamadas a rep y seq), length indica el número de entradas después de que se hayan ejecutado esas funciones internas.
Cree y almacene una secuencia de valores de 5 a −11 que progrese en pasos de 0,3.
Sobrescribir el objeto de (a) usando la misma secuencia con el orden invertido.
Repita el vector c(-1,3,-5,7,-9) dos veces, con cada elemento repetido 10 veces, y guarde el resultado. Muestra el resultado ordenado de mayor a menor.
Crear y almacenar un vector que contenga, en cualquier configuración, lo siguiente:
Una secuencia de números enteros de 6 a 12 (inclusive)
# Crear la secuencia
secuencia_a <- seq(5, -11, by = -0.3)
# Sobrescribir el objeto con la secuencia invertida
secuencia_a <- rev(secuencia_a)
# Crear el vector
vector_c <- rep(c(-1, 3, -5, 7, -9), each = 10)
# Ordenar el vector de mayor a menor
vector_c_ordenado <- sort(vector_c, decreasing = TRUE)
print(vector_c_ordenado)
## [1] 7 7 7 7 7 7 7 7 7 7 3 3 3 3 3 3 3 3 3 3 -1 -1 -1 -1 -1
## [26] -1 -1 -1 -1 -1 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -9 -9 -9 -9 -9 -9 -9 -9 -9 -9
# Obtener la longitud del vector creado en (c)
longitud_vector_c <- length(vector_c)
# Crear el vector
vector_d <- c(seq(6, 12), rep(5.3, times = 3), -3, seq(102, longitud_vector_c))
# Confirmar la longitud del vector
longitud_vector_d <- length(vector_d)
print(longitud_vector_d == 20)
## [1] FALSE
En todos los resultados que has visto impresos en la pantalla de la consola hasta ahora, habrás notado una característica curiosa. Inmediatamente a la izquierda de la salida hay un corchete [1]. Cuando la salida es un vector largo que abarca el ancho de la consola y se ajusta a la siguiente línea, aparece otro número entre corchetes a la izquierda de la nueva línea. Estos números representan el índice de la entrada directamente a la derecha. En pocas palabras, el índice corresponde a la posición de un valor dentro de un vector, y es precisamente por eso que el primer valor siempre tiene un [1] al lado (incluso si es el único valor y no forma parte de un vector más grande).
Estos índices le permiten recuperar elementos específicos de un vector, lo que se conoce como subconjunto. Supongamos que tiene un vector llamado myvec en su espacio de trabajo. Entonces habrá exactamente entradas de longitud (x = myvec) en myvec, con cada entrada con una posición específica: 1 o 2 o 3, hasta length(x = myvec). Puede acceder a elementos individuales pidiéndole a R que devuelva los valores de myvec en ubicaciones específicas, lo que se hace ingresando el nombre del vector seguido de la posición entre corchetes.
#> myvec <- c(5,-2.3,4,4,4,6,8,10,40221,-8)
#> length(x=myvec)
#[1] 10
#> myvec[1]
#[1] 5
#> foo <- myvec[2]
#> foo
#[1] -2.3
#> myvec[length(x=myvec)]
#[1] -8
Debido a que length(x=myvec) da como resultado el índice final del vector (en este caso, 10), al introducir esta frase entre corchetes se extrae el elemento final, -8. Del mismo modo, podría extraer el penúltimo elemento restando 1 de la longitud; Intentemos eso, y también asignemos el resultado a un nuevo objeto:
#> myvec.len <- length(x=myvec)
#> bar <- myvec[myvec.len-1]
#> bar
#[1] 40221
Como muestran estos ejemplos, el índice puede ser una función aritmética de otros números o valores previamente almacenados. Puede asignar el resultado a un nuevo objeto en su espacio de trabajo de la manera habitual con la notación <-. Usando tu conocimiento de secuencias, puedes usar la notación de dos puntos con la longitud de el vector específico para obtener todos los índices posibles para extraer un elemento particular en el vector:
#> 1:myvec.len
#[1] 1 2 3 4 5 6 7 8 9 10
También puede eliminar elementos individuales utilizando versiones negativas de los índices proporcionados entre corchetes. Continuando con los objetos myvec, foo, bar y myvec.len definidos anteriormente, considere las siguientes operaciones:
#> myvec[-1]
#[1] -2.3 4.0 4.0 4.0 6.0 8.0 10.0 40221.0 -8.0
Esta línea produce el contenido de myvec sin el primer elemento. Del mismo modo, el siguiente código asigna al objeto baz el contenido de myvec sin su segundo elemento:
#> baz <- myvec[-2]
#> baz
#[1] 5 4 4 4 6 8 10 40221 -8
De nuevo, el índice entre corchetes puede ser el resultado de un cálculo adecuado, así:
#> qux <- myvec[-(myvec.len-1)]
#> qux
#[1] 5.0 -2.3 4.0 4.0 4.0 6.0 8.0 10.0 -8.0
El uso del operador de corchetes para extraer o eliminar valores de un vector no cambia el vector original que está creando un subconjunto, a menos que sobrescriba explícitamente el vector con la versión del subconjunto. Por ejemplo, en este ejemplo, qux es un nuevo vector definido como myvec sin su penúltima entrada, pero en su espacio de trabajo, myvec en sí permanece sin cambios. En otras palabras, los vectores de subconjuntos de esta manera simplemente devuelven los elementos solicitados, que se pueden asignar a un nuevo objeto si lo desea, pero no alteran el objeto original en el espacio de trabajo. Ahora, supongamos que quieres volver a juntar myvec a partir de qux y bar. Puedes llamar a algo como esto:
#> c(qux[-length(x=qux)],bar,qux[length(x=qux)])
#[1] 5.0 -2.3 4.0 4.0 4.0 6.0 8.0 10.0 40221.0
#[10] -8.0
Como puedes ver, esta línea usa c para reconstruir el vector en tres partes: qux[-length(x=qux)], la barra de objetos definida anteriormente, y qux[length(x=qux)]. Para mayor claridad, examinemos cada parte por separado.
#qux[-length(x=qux)]
Este fragmento de código devuelve los valores de qux excepto su último elemento
#> length(x=qux)
#[1] 9
#> qux[-length(x=qux)]
#[1] 5.0 -2.3 4.0 4.0 4.0 6.0 8.0 10.0
Ahora tienes un vector que es el mismo que las primeras ocho entradas de myvec.
·bar Anteriormente, había almacenado bar de la siguiente manera:
#> bar <- myvec[myvec.len-1]
#> bar
#[1] 40221
Este es precisamente el penúltimo elemento de myvec que le falta a qux. Por lo tanto, colocará este valor después de qux[-length(x=qux)].
#qux[length(x=qux)]
Finalmente, solo necesita el último elemento de qux que coincida con el último elemento de myvec. Esto se extrae de qux (no se eliminó como antes) usando length.
#> qux[length(x=qux)]
#[1] -8
Ahora debería quedar claro cómo llamar a estas tres partes del código juntas, en este orden, es una forma de reconstruir myvec. Al igual que con la mayoría de las operaciones en R, no está restringido a hacer las cosas una por una. También puede crear subconjuntos de objetos utilizando vectores de índices, en lugar de índices individuales. Al usar myvec de nuevo desde antes, se obtiene lo siguiente:
#> myvec[c(1,3,5)]
#[1] 5 4 4
Esto devuelve el primer, tercer y quinto elemento de myvec de una sola vez. Otra herramienta de subconjuntos común y conveniente es el operador de dos puntos (discutido en la Sección 2.3.2), que crea una secuencia de índices. He aquí un ejemplo:
#> 1:4
#[1] 1 2 3 4
#> foo <- myvec[1:4]
#> foo
#[1] 5.0 -2.3 4.0 4.0
Esto proporciona los primeros cuatro elementos de myvec (recuerde que el operador de dos puntos devuelve un vector numérico, por lo que no es necesario envolverlo explícitamente usando c). El orden de los elementos devueltos depende enteramente del vector índice proporcionado entre corchetes. Por ejemplo, si se vuelve a usar foo, hay que tener en cuenta el orden del índice.
#> length(x=foo):2
#[1] 4 3 2
#> foo[length(foo):2]
#[1] 4.0 4.0 -2.3
Aquí se han extraído elementos empezando por el final del vector, trabajando hacia atrás. También puede usar rep para repetir un índice, como se muestra aquí:
#> indexes <- c(4,rep(x=2,times=3),1,1,2,3:1)
#> indexes
#[1] 4 2 2 2 1 1 2 3 2 1
#> foo[indexes]
#[1] 4.0 -2.3 -2.3 -2.3 5.0 5.0 -2.3 4.0 -2.3 5.0
Esto ahora es algo un poco más general que estrictamente “subconjunto”: mediante el uso de un vector de índice, puede crear un vector completamente nuevo de cualquier longitud que consta de algunos o todos los elementos del vector original. Como se mostró anteriormente, este vector de índice puede contener las posiciones deseadas de los elementos en cualquier orden y puede repetir índices. También puede devolver los elementos de un vector después de eliminar más de un elemento. Por ejemplo, para crear un vector después de eliminar el primer y tercer elemento de foo, puede ejecutar lo siguiente:
#> foo[-c(1,3)]
#[1] -2.3 4.0
Tenga en cuenta que no es posible mezclar índices positivos y negativos en un solo vector de índice. A veces será necesario sobrescribir ciertos elementos en un vector existente con nuevos valores. En esta situación, primero especifique los elementos que desea sobrescribir con corchetes y, a continuación, utilice el operador de asignación para asignar los nuevos valores. He aquí un ejemplo:
#> bar <- c(3,2,4,4,1,2,4,1,0,0,5)
#> bar
#[1] 3 2 4 4 1 2 4 1 0 0 5
#> bar[1] <- 6
#> bar
#[1] 6 2 4 4 1 2 4 1 0 0 5
Esto sobrescribe el primer elemento de bar, que originalmente era 3, con un nuevo valor, 6. Al seleccionar varios elementos, puede especificar un único valor para reemplazarlos todos o introducir un vector de valores que tenga la misma longitud que el número de elementos seleccionados para reemplazarlos uno por uno. Intentemos esto con el mismo vector de barras de antes.
#> bar[c(2,4,6)] <- c(-2,-0.5,-1)
#> bar
#[1] 6.0 -2.0 4.0 -0.5 1.0 -1.0 4.0 1.0 0.0 0.0 5.0
Aquí se sobrescriben los elementos segundo, cuarto y sexto con -2, -0,5 y -1, respectivamente; Todo lo demás sigue igual. Por el contrario, el código siguiente sobrescribe los elementos 7 a 10 (ambos incluidos) y los reemplaza todos por 100:
#> bar[7:10] <- 100
#> bar
#[1] 6.0 -2.0 4.0 -0.5 1.0 -1.0 100.0 100.0 100.0 100.0 5.0
Finalmente, es importante mencionar que esta sección se ha centrado en uno de los dos métodos principales, o “sabores”, de extracción de elementos vectoriales en R.
Cree un nuevo vector como una copia de (e) asignando (e) tal cual a un objeto recién nombrado. Con esta nueva copia de (e), sobrescriba el primero, el quinto al séptimo (inclusive) y el último elemento con los valores 99 a 95 (inclusive), respectivamente. # solucion ejercicio 2.4
Crear y almacenar un vector que contenga lo siguiente, en este orden:
# Crear el vector
vector_a <- c(seq(3, 6), rep(c(2, -5.1, -33), each = 2), 7, 42 + 2)
```r
# Extraer el primer y último elemento
primer_elemento <- vector_a[1]
ultimo_elemento <- vector_a[length(vector_a)]
# c. Almacenar como un tercer objeto los valores devueltos omitiendo el primer y último valores del vector de (a).
# Omitir el primer y último elemento del vector
vector_c <- vector_a[-c(1, length(vector_a))]
```r
# Reconstruir el vector a partir de (b) y (c)
vector_d <- c(primer_elemento, vector_c, ultimo_elemento)
```r
# Sobrescribir el vector a ordenado de menor a mayor
vector_a <- sort(vector_a)
```r
# Invertir el orden usando el operador de dos puntos
vector_e_reverse <- vector_a[length(vector_a):1]
# Confirmar si es idéntico a usar sort con decreasing=TRUE
identico <- all(sort(vector_a, decreasing = TRUE) == vector_e_reverse)
print(identico)
## [1] TRUE
```r
# Crear el vector según las especificaciones
#vector_g <- rep(c[3], times = 3)
#vector_g <- c(vector_g, rep(c[6], times = 4))
#vector_g <- c(vector_g, c[length(c)])
# Crear una copia del vector e
vector_h <- vector_a
# Sobrescribir los elementos específicos
vector_h[c(1, 5:7, length(vector_h))] <- c(99, 98, 97, 96, 95)
Los vectores son tan útiles porque permiten a R realizar operaciones en múltiples elementos simultáneamente con velocidad y eficiencia. Este comportamiento orientado a vectores, vectorizado o a elemento es una característica clave del lenguaje, que examinará brevemente aquí a través de algunos ejemplos de mediciones de reescalado. Comencemos con este sencillo ejemplo:
#> foo <- 5.5:0.5
#> foo
#[1] 5.5 4.5 3.5 2.5 1.5 0.5
#> foo-c(2,4,6,8,10,12)
#[1] 3.5 0.5 -2.5 -5.5 -8.5 -11.5
Este código crea una secuencia de seis valores entre 5,5 y 0,5, en incrementos de 1. De este vector, se resta otro vector que contiene 2, 4, 6, 8, 10 y 12. ¿Qué hace esto? Bueno, simplemente, R hace coincidir los elementos de acuerdo con sus respectivas posiciones y realiza la operación en cada par de elementos correspondiente. El vector resultante se obtiene restando el primer elemento de c(2,4,6,8,10,12) del primer elemento de foo (5,5 − 2 = 3,5), luego restando el segundo elemento de c(2,4,6,8,10,12) del segundo elemento de foo (4,5 − 4 = 0,5), y así sucesivamente. Por lo tanto, en lugar de recorrer cada elemento de forma poco elegante a su vez (como podría hacer a mano o usando explícitamente un bucle), R permite una alternativa rápida y eficiente utilizando un comportamiento orientado a vectores. La figura 2-1 ilustra cómo se puede entender este tipo de cálculo y destaca el hecho de que las posiciones de los elementos son cruciales en términos del resultado final; Los elementos en posiciones diferentes no tienen ningún efecto entre sí. La situación se complica cuando se utilizan vectores de diferentes longitudes, lo que puede ocurrir de dos maneras distintas. La primera es cuando la longitud del vector más largo se puede dividir uniformemente por la longitud del vector más corto. La segunda es cuando la longitud del vector más largo no se puede dividir por la longitud del vector más corto, esto generalmente no es intencional por parte del usuario. En ambas situaciones, R esencialmente intenta replicar, o reciclar, el vector más corto tantas veces como sea necesario para que coincida con la longitud del vector más largo, antes de completar la operación especificada. Por ejemplo, supongamos que desea alternar las entradas de foo mostradas anteriormente como negativas y positivo. Podrías multiplicar explícitamente foo por c(1,-1,1,-1,1,-1), pero no es necesario que escribas el último vector completo. En su lugar, puede escribir lo siguiente:
#> bar <- c(1,-1)
#> foo*bar
#[1] 5.5 -4.5 3.5 -2.5 1.5 -0.5
Aquí la barra se ha aplicado repetidamente a lo largo de foo hasta su finalización. El gráfico de la izquierda de la Figura 2-2 ilustra este ejemplo en particular. Ahora veamos qué sucede cuando las longitudes de los vectores no son divisibles uniformemente.
#> baz <- c(1,-1,0.5,-0.5)
#> foo*baz
#[1] 5.50 -4.50 1.75 -1.25 1.50 -0.50
#Warning message:
#In foo * baz :
#longer object length is not a multiple of shorter object length
Aquí puedes ver que R ha hecho coincidir los primeros cuatro elementos de foo con la totalidad de baz, pero no es capaz de repetir completamente el vector de nuevo. Se ha intentado la repetición, con los dos primeros elementos de baz emparejados con los dos últimos del foo más largo, aunque no sin una protesta de R, que notifica al usuario de las longitudes divisibles de manera desigual.
Como señalé en la Sección 2.3.3, puede considerar que los valores individuales son vectores de longitud 1, por lo que puede usar un solo valor para repetir una operación en todos los valores de un vector de cualquier longitud. Aquí hay un ejemplo, usando el mismo vector foo
#> qux <- 3
#> foo+qux
#[1] 8.5 7.5 6.5 5.5 4.5 3.5
Esto es mucho más fácil que ejecutar foo+c(3,3,3,3,3,3) o el más general foo+rep(x=3,times=length(x=foo)). Operar en vectores usando un solo valor de esta manera es bastante común, por ejemplo, si desea cambiar la escala o traducir un conjunto de medidas en una cantidad constante. Otra ventaja del comportamiento orientado a vectores es que se pueden utilizar funciones vectorizadas para completar tareas potencialmente laboriosas. Por ejemplo, si desea sumar o multiplicar todas las entradas en un vector numérico, puede usar una función integrada.
Recuerde foo, que se muestra anteriormente:
#> foo
#[1] 5.5 4.5 3.5 2.5 1.5 0.5
Puedes encontrar la suma de estos seis elementos con
#> sum(foo)
#[1] 18
y su producto con
#> prod(foo)
#[1] 162.4219
Lejos de ser solo convenientes, las funciones vectorizadas son más rápidas y eficientes que un enfoque iterativo codificado explícitamente como un bucle. La principal conclusión de estos ejemplos es que gran parte de la funcionalidad de R está diseñada específicamente para ciertas estructuras de datos, lo que garantiza la pulcritud del código y la optimización del rendimiento. Por último, como se mencionó anteriormente, este comportamiento orientado a vectores se aplica de la misma manera a sobrescribir varios elementos. De nuevo usando foo, examine lo siguiente:
#> foo
#[1] 5.5 4.5 3.5 2.5 1.5 0.5
#> foo[c(1,3,5,6)] <- c(-99,99)
#> foo
#[1] -99.0 4.5 99.0 2.5 -99.0 99.0
Verá cuatro elementos específicos sobrescritos por un vector de longitud 2, que se recicla de la misma manera con la que está familiarizado. De nuevo, la longitud del vector de reemplazos debe dividir uniformemente el número de elementos que se sobrescriben, o de lo contrario se emitirá una advertencia similar a la mostrada anteriormente cuando R no pueda completar un reciclaje completo.
Convierte el vector c(2,0.5,1,2,0.5,1,2,0.5,1) en un vector de solo 1s, usando un vector de longitud 3.
La conversión de una medición de temperatura en grados Fahrenheit F a Celsius C se realiza utilizando la siguiente ecuación
C = 5/9 (F - 32)
Use vector-oriented behavior in R to convert the temperatures 45, 77, 20, 19, 101, 120, and 212 in degrees Fahrenheit to degrees Celsius. c. Use the vector c(2,4,6) and the vector c(1,2) in conjunction with rep and * to produce the vector c(2,4,6,4,8,12). d. Overwrite the middle four elements of the resulting vector from (c) with the two recycled values -0.1 and -100, in that order.
# Vector inicial
vector_inicial <- c(2, 0.5, 1, 2, 0.5, 1, 2, 0.5, 1)
# Vector de longitud 3 con solo unos
vector_unos <- rep(1, length(vector_inicial) / 3)
# Temperaturas en grados Fahrenheit
temperaturas_fahrenheit <- c(45, 77, 20, 19, 101, 120, 212)
# Convertir a grados Celsius
temperaturas_celsius <- (5/9) * (temperaturas_fahrenheit - 32)
# Vectores iniciales
vector1 <- c(2, 4, 6)
vector2 <- c(1, 2)
# Producto de repeticiones
resultado_c <- vector1 * rep(vector2, each = length(vector1))
# Valores a sobrescribir
valores_sobrescribir <- c(-0.1, -100)
# Sobrescribir los valores
resultado_c[2:5] <- rep(valores_sobrescribir, length.out = 4)