3.3: Vectores
- Page ID
- 55117
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)Los vectores (similares a las matrices de tipo único en otros lenguajes) son colecciones ordenadas de tipos simples, generalmente numéricos, enteros, caracteres o lógicas. Podemos crear vectores usando la función c ()
(para concatenar), que toma como parámetros los elementos a poner en el vector:

La función c ()
también puede tomar otros vectores como parámetros; “deconstruirá” todos los subvectores y devolverá un vector grande, en lugar de un vector de vectores.

Podemos extraer elementos individuales de un vector usando la sintaxis []
; aunque tenga en cuenta que, a diferencia de muchos otros lenguajes, el primer elemento está en el índice 1.

La función length ()
devuelve el número de elementos de un vector (o tipos similares, como listas, que cubriremos más adelante) como un entero:

Podemos usar esto para extraer el último elemento de un vector, por ejemplo.
Sin “datos desnudos”: los vectores tienen (a) clase
En lo que va de nuestra discusión sobre los tipos de datos de R, hemos estado haciendo una simplificación, o al menos hemos estado dejando algo fuera. Incluso los valores individuales como el 4.6
numérico son en realidad vectores de longitud uno. Es decir, gc_content <- 0.34
es equivalente a gc_content <- c (0.34)
, y en ambos casos, length (gc_content)
devolverá 1
, que en sí mismo es un vector de longitud uno. Esto se aplica a los números, enteros, lógicos y tipos de caracteres. Así, al menos comparado con otros lenguajes, R no tiene “datos desnudos”; el vector es la unidad de datos más básica que tiene R. Esto es un poco más confuso para los tipos de caracteres que otros, ya que cada elemento individual es una cadena de caracteres de cualquier longitud (incluyendo potencialmente la cadena “vacía” “”
).

Esto explica bastante sobre R, incluyendo algunas curiosidades como por qué print (gc_content)
imprime [1] 0.34
. Esta salida indica que gc_content
es un vector, cuyo primer elemento es 0.34
. Considere la función seq ()
, que devuelve un vector de números; toma tres parámetros: [1] (1) el número en el que comenzar, (2) el número en el que terminar, y (3) el tamaño del paso.

Cuando imprimimos el resultado, obtendremos una salida como la siguiente, donde la lista de números está formateada de tal manera que abarca el ancho de la ventana de salida.

Los números entre paréntesis indican que el primer elemento del vector impreso es 1.0
, el decimosexto elemento es 8.5
y el trigésimo primer elemento es 16.0
.
Por cierto, para producir una secuencia de enteros (en lugar de numéricos), se puede dejar el argumento de tamaño de paso, como en seq (1,20)
. Esto equivale a una taquigrafía comúnmente vista, 1:20
.
Si todos nuestros enteros, lógicas, etc. son realmente vectores, y podemos decir su tipo ejecutando la función class ()
en ellos, entonces los vectores deben ser las cosas de las que estamos examinando la clase. Entonces, ¿y si intentamos mezclar tipos dentro de un vector, por ejemplo, incluyendo un entero con algunas lógicas?

Ejecutar print (class (mix))
dará como resultado “integer”
. De hecho, si intentamos imprimir mezcla
con print (mix)
, encontraríamos que las lógicas se han convertido en enteros!

R ha optado por convertir TRUE
en 1
y FALSE
en 0
; estos son valores binarios estándar para true y false, mientras que no hay un valor lógico estándar para un entero dado. Del mismo modo, si se agrega un numérico, todo se convierte a numérico.

Y si se agrega una cadena de caracteres, todo se convierte en una cadena de caracteres (con 3.5
convirtiéndose en “3.5"
, TRUE
convirtiéndose en “TRUE”
, y así sucesivamente).

En resumen, los vectores son la unidad más básica de datos en R, y no pueden mezclar tipos: R autoconvertirá cualquier tipo mixto en un solo vector a un “denominador común más bajo”, en el orden de lógico (más específico), entero, numérico, carácter (más general). Esto a veces puede resultar en errores difíciles de encontrar, especialmente al leer datos de un archivo. Si un archivo tiene una columna de lo que parece ser números, pero un solo elemento no puede interpretarse como un número, todo el vector se puede convertir a un tipo de carácter sin advertencia ya que se lee el archivo. Discutiremos la lectura de datos de archivos de texto después de examinar los vectores y sus propiedades.
Subestablecimiento de Vectores, Sustitución Selectiva
Considere el hecho de que podemos usar la sintaxis []
para extraer elementos individuales de vectores:

Con base en lo anterior, sabemos que los 20
extraídos son un vector de longitud uno. El 2
utilizado entre corchetes también es un vector de longitud uno; así la línea anterior es equivalente a second_el <- nums [c (2)]
. ¿Significa esto que podemos usar vectores más largos para extraer elementos? ¡Sí!

De hecho, los elementos extraídos incluso se colocaron en el vector de dos elementos resultante en el orden en que se extrajeron (el tercer elemento seguido del segundo elemento). Podemos usar una sintaxis similar para reemplazar selectivamente elementos por índices específicos en vectores.

El reemplazo selectivo es el proceso de reemplazar elementos seleccionados de un vector (o estructura similar) especificando qué elementos reemplazar con []
sintaxis de indexación combinada con asignación <-
. [2]
Los vectores R (y muchos otros tipos de contenedores de datos) pueden ser nombrados, es decir, asociados con un vector de caracteres de la misma longitud. Podemos establecer y posteriormente obtener este vector de nombres usando la función names ()
, pero la sintaxis es un poco extraña.
Los vectores con nombre, cuando se imprimen, también muestran sus nombres. El resultado de arriba:

Los vectores nombrados pueden no parecer tan útiles ahora, pero el concepto será bastante útil más adelante. Los vectores con nombre nos dan otra forma de subconjunto y reemplazar selectivamente en vectores: por nombre.

Aunque R no lo hace cumplir, los nombres deben ser únicos para evitar confusiones a la hora de seleccionar o reemplazar selectivamente de esta manera. Al actualizar la puntuación de Estudiantes A y Estudiantes B, el cambio se refleja en la salida:

Hay una forma final y extremadamente poderosa de subestablecer y reemplazar selectivamente en un vector: por vector lógico. Al indexar con un vector de lógicas de la misma longitud que el vector a indexar, podemos extraer solo aquellos elementos donde el vector lógico tenga un valor VERDADERO
.

Si bien la indexación por número de índice y por nombre nos permite extraer elementos en cualquier orden dado, la indexación por lógica no nos brinda esta posibilidad.
También podemos realizar el reemplazo selectivo de esta manera; supongamos que Estudiantes A y C retoman sus cuestionarios y mejoran moderadamente sus puntajes.

Y la salida impresa:

En este caso, la longitud del vector de reemplazo (c (159, 169))
es igual al número de valores VERDADEROS
en el vector de indexación (c (VERDADERO, FALSO, VERDADERO)
); exploraremos si esto es un requisito a continuación.
En resumen, tenemos tres formas importantes de indexar en/seleccionar desde/reemplazar selectivamente en vectores:
- por vector de número de índice,
- por vector de caracteres (si se nombra el vector), y
- por vector lógico.
Operaciones vectorizadas, valores NA
Si los vectores son la unidad de datos más básica en R, todas las funciones y operadores con los que hemos estado trabajando, como.numeric ()
, *
e incluso comparaciones como >
—funcionan implícitamente sobre vectores enteros.

En este ejemplo, cada elemento del vector de caracteres se ha convertido, de modo que la clase (numérica)
devolverá “numérico”
. La cadena de caracteres final, “9b3x”
, no se puede convertir razonablemente a un tipo numérico, por lo que ha sido reemplazada por NA
. Cuando esto sucede, el intérprete produce un mensaje de advertencia: NA introducidos por coerción
.
NA
es un valor especial en R que indica datos faltantes o un cálculo fallido de algún tipo (como al intentar convertir “9b3x”
a un numérico). La mayoría de las operaciones que involucran valores
Un ejemplo canónico es la función NA
devuelven valores NA; por ejemplo, NA + 3
devuelve NA
, y muchas funciones que operan en vectores enteros devuelven un NA
si algún elemento es NA
.mean ()
.

Dichas funciones suelen incluir un parámetro opcional que podemos dar, na.rm = TRUE
, especificando que los valores NA
deben eliminarse antes de que se ejecute la función.

Si bien esto es conveniente, hay una manera de eliminar los valores de NA
de cualquier vector (ver más abajo).
Otros valores especiales en R incluyen NaN
, para “Not a Number”, devueltos por cálculos como la raíz cuadrada de -1, sqrt (-1)
e Inf
para “Infinity”, devueltos por cálculos como 1/0
. (Inf/Inf
, por cierto, devuelve NaN
.)
Volviendo al concepto de operaciones vectorizadas, también se vectorizan operaciones aritméticas simples como +
, *
,/
, -
, ^
(exponente) y%%
(módulo), lo que significa que una expresión como 3 * 7
es equivalente a c (3) * c (7)
. Cuando los vectores son más largos que un solo elemento, la operación se realiza elemento por elemento.


Si consideramos el operador *
, toma dos entradas (numéricas o enteras) y devuelve una salida (numérica o entera) para cada par de los vectores. Esto es bastante similar a la comparación >
, que toma dos entradas (numéricas o enteras o caracteres) y devuelve una lógica.

Reciclaje de vectores
¿Qué pasa si tratamos de multiplicar dos vectores que no tienen la misma longitud? Resulta que el más corto de los dos se reutilizará según sea necesario, en un proceso conocido como reciclaje vectorial, o la reutilización del vector más corto en una operación vectorizada.

Esto funciona bien cuando se trabaja con vectores de longitud uno contra vectores más largos, ya que el vector de longitud uno se reciclará según sea necesario.

Si la longitud del vector más largo no es un múltiplo de la longitud del más corto, sin embargo, el último reciclado irá solo a la mitad.

Cuando esto sucede, el intérprete imprime una advertencia: la longitud del objeto más larga no es un múltiplo de la longitud del objeto más corta
. Son pocas las situaciones en las que este tipo de reciclaje parcial no sea un accidente, y se debe evitar.
El reciclaje de vectores también se aplica al reemplazo selectivo; por ejemplo, podemos reemplazar selectivamente cuatro elementos de un vector con elementos de un vector de dos elementos:

Más a menudo reemplazaremos selectivamente elementos de un vector con un vector de longitud uno.

Estos conceptos, cuando se combinan con indexación vectorial de diversos tipos, son bastante poderosos. Considera que una expresión como valores > 35
es ella misma vectorizada, con el vector más corto (sosteniendo solo 35
) siendo reciclado de tal manera que lo que se devuelve es un vector lógico con valores VERDADEROS
donde los elementos de valores
son mayores que 35
. Podríamos usar este vector como vector de indexación para reemplazo selectivo si lo deseamos.

Más sucintamente, en lugar de crear una variable temporal para select_vec
, podemos colocar los valores de expresión > 35
directamente entre paréntesis.

Del mismo modo, podríamos usar el resultado de algo así como media (valores)
para reemplazar todos los elementos de un vector mayor que la media con 0
fácilmente, ¡sin importar el orden de los elementos!

Más a menudo, vamos a querer extraer dichos valores usando selección lógica.

Este tipo de selecciones vectorizadas, especialmente cuando se combinan con vectores lógicos, son una parte poderosa e importante de R, así que estudiarlas hasta que tengas confianza con la técnica.
Ejercicios
- Supongamos que tenemos
r
como un rango de números de 1 a 30 en pasos de 0.3;r<- seq (1, 30, 0.3)
. Usando solo lafunción.integer ()
, la indexación lógica y las comparaciones como>
, genera una secuenciar_decimales
que contiene todos los valores der
que no son enteros redondos. (Es decir, debe contener todos los valores der
excepto 1.0, 2.0, 3.0, y así sucesivamente. Debe haber 297 de ellos.) - Mencionamos brevemente el operador
%%
, o “módulo”, que devuelve el resto de un número después de la división entera (por ejemplo,4%% 3 == 1
y4%% 4 == 0
; también se vectoriza). Dado cualquier vectorr
, por ejemplor <- seq (1, 30, 0.3)
, producir un vectorr_every_other
que contiene todos los demás elementos der
. Es probable que desee usar%%
, la comparación de igualdad==
, y también puede que desee usarseq ()
para generar un vector de índices de la misma longitud quer
.Vuelva a hacer lo mismo, pero modifique el código para extraer cada tercer elemento de
r
en un vector llamador_every_third
. - Del capítulo 27, “Variables y Datos”, sabemos que las comparaciones como
==
,!
=,>=
también están disponibles. Además, ¡eso lo sabemos!
niega los valores de un vector lógico, mientras que&
combina dos vectores lógicos con “y” y|
combina dos vectores lógicos con “o”. Úselos, junto con el operador%%
discutido anteriormente, para producir un vectordiv_3_4
de todos los enteros entre 1 y 1,000 (inclusive) que son uniformemente divisibles por 3 y uniformemente divisibles por 4. (Hay 83 de ellos.) Crear otro,not_div_5_6
, de números que no sean divisibles uniformemente por 5 o 6. (Son 667 de ellos. Por ejemplo, no se debe incluir 1,000 porque es divisible por 5, y 18 no debe incluirse porque es divisible por 6, sino 34 debe ser porque no es divisible por ninguno.)
Funciones Vectoriales Comunes
Como los vectores (específicamente los vectores numéricos) son tan ubicuos, R tiene docenas (cientos, en realidad) de funciones que hacen cosas útiles con ellos. Si bien no podemos cubrirlos todos, podemos cubrir rápidamente algunos que serán importantes en futuros capítulos.
Primero, ya hemos visto las funciones seq ()
y length ()
; la primera genera un vector numérico que comprende una secuencia de números, y la segunda devuelve la longitud de un vector como un vector entero de un solo elemento.

Presentados sin un ejemplo, la media ()
, sd ()
y la mediana ()
devuelven la media, la desviación estándar y la mediana de un vector numérico, respectivamente. (Siempre que ninguno de los elementos de entrada sea NA
, aunque los tres aceptan el parámetro na.rm = TRUE
). Generalizando median ()
, la función quantile ()
devuelve el percentil Y de una función, o múltiples percentiles si el segundo argumento tiene más de un elemento.

La salida es un vector numérico con nombre:

La función unique ()
elimina duplicados en un vector, dejando los elementos restantes en orden de su primera aparición, y la función rev ()
invierte un vector.

Existe la función sort ()
, que ordena un vector (en orden natural para números y enteros, y orden lexicográfico (diccionario) para vectores de caracteres). Quizás más interesante es la función order ()
, que devuelve un vector entero de índices que describen dónde se necesitarían colocar los elementos originales del vector para producir un orden ordenado.

En este ejemplo, el vector de orden, 2 5 3 4 1
, indica que el segundo elemento de rev_uniq
vendría primero, seguido del quinto, y así sucesivamente. Así podríamos producir una versión ordenada de rev_uniq
con rev_uniq [order_rev_uniq]
(en virtud de la selección basada en índices de vectores), o más sucintamente con rev_uniq [order (rev_uniq)]
.

Es importante destacar que esto nos permite reorganizar múltiples vectores con un orden común determinado por uno único. Por ejemplo, dados dos vectores, id
y score
, que están relacionados por elementos, podríamos decidir reorganizar ambos conjuntos en orden alfabético para id
.

La función sample ()
devuelve un muestreo aleatorio a partir de un vector de un tamaño dado, ya sea con reemplazo o sin como se especifica con el parámetro replace =
(FALSE
es el valor predeterminado si no se especifica).

La función rep ()
repite un vector para producir un vector más largo. Podemos repetir de manera elemento por elemento, o sobre todo el vector, dependiendo de si se usa o no el parámetro each =
.

Por último (pero no menos importante) para esta discusión es la función is.na ()
: dado un vector con elementos que posiblemente sean valores NA
, devuelve un vector lógico elementos enteros son TRUE
en índices donde el original era NA
, permitiéndonos indicar fácilmente cuál elementos de vectores son NA
y los eliminan.

Observe el uso del signo de exclamación en lo anterior para negar el vector lógico devuelto por is.na ()
.
Generación de datos aleatorios
R sobresale en trabajar con distribuciones de probabilidad, incluyendo generar muestras aleatorias a partir de ellas. Muchas distribuciones son compatibles, incluyendo la Normal (Gaussiana), Log-Normal, Exponencial, Gamma, T de Student, y así sucesivamente. Aquí solo veremos generar muestras a partir de unas pocas para utilizarlas en ejemplos futuros.
Primero, la función rnorm ()
genera un vector numérico de una longitud dada muestreado a partir de la distribución Normal con media especificada (con media =
) y desviación estándar (con sd =
).

De manera similar, la función runif ()
muestrear a partir de una distribución uniforme limitada por un valor mínimo y máximo.

El rexp ()
genera datos a partir de una distribución exponencial con un parámetro de “tasa” dado, controlando la tasa de decaimiento de la función de densidad (la media de muestras grandes se acercará a 1.0/tasa
).


R incluye una gran cantidad de pruebas estadísticas, aunque no vamos a estar cubriendo mucho en la forma de las estadísticas que no sean algunos ejemplos de manejo. La función t.test ()
ejecuta una prueba t de student de dos lados comparando las medias de dos vectores. Lo que se devuelve es un tipo de datos más complejo con clase “htest”
.

Cuando se imprime, este complejo tipo de datos se formatea a sí mismo en una salida agradable y legible por humanos:

Lectura y Escritura de Datos Tabulares, Envoltura de Líneas Largas
Antes de ir mucho más allá, vamos a querer poder importar datos a nuestros programas R desde archivos externos (que asumiremos que son filas y columnas de datos en archivos de texto). Esto lo haremos con read.table ()
, y el resultado será un tipo de datos conocido como “data frame” (o data.frame
en código). Cubriremos los matices de los marcos de datos más adelante, pero tenga en cuenta por ahora que pueden considerarse como una colección de vectores (de igual longitud), uno por cada columna de la tabla.
Como ejemplo, supongamos que tenemos un archivo de texto separado por tabulaciones en nuestro directorio de trabajo actual llamado states.txt
. [3] Cada fila representa uno de los estados de Estados Unidos junto con información sobre población, ingreso per cápita, tasa de analfabetismo, tasa de homicidios (por 100,000), porcentaje de graduados de secundaria y región (todos medidos en la década de 1970). La primera fila contiene una línea de “encabezado” con nombres de columna.

Posteriormente en el expediente, alguien ha decidido anotar la línea de Michigan, indicándola como el estado “manopla”:

Como la mayoría de las funciones, read.table ()
toma muchos parámetros potenciales (23, de hecho), pero la mayoría de ellos tienen valores predeterminados razonables. Aún así, hay cinco más o menos que comúnmente necesitaremos establecer. Debido a la necesidad de establecer tantos parámetros, el uso de read.table ()
a menudo resulta en una larga línea de código. Afortunadamente, el intérprete R nos permite romper largas líneas sobre varias líneas, siempre y cuando cada línea termine en un carácter que no complete la expresión (así el intérprete sabe que necesita seguir leyendo las siguientes líneas antes de ejecutarlas). Las opciones de carácter común son la coma y el signo más. Cuando envolvemos una larga línea de esta manera, es costumbre sangrar las siguientes líneas para indicar su continuidad de manera visual.

Al leer states.txt
, el parámetro file =
especifica el nombre del archivo a leer, mientras que header = TRUE
indica al intérprete que la primera línea del archivo da los nombres de columna (sin él, los nombres de columna serán “V1"
, “V2"
, “V3"
y así sucesivamente). El parámetro sep = “\ t”
indica que los caracteres de tabulación se utilizan para separar las columnas en el archivo (el valor predeterminado es cualquier espacio en blanco), y comment.char = “#”
indica que #
caracteres y cualquier cosa posterior a ellos deben ser ignorados mientras se lee el archivo (lo cual es apropiado, como es evidente por la anotación # manopla
en el archivo). El parámetro stringsasFactors = FALSE
es más críptico: le dice al intérprete que deje las columnas character-vector (como region
en este ejemplo) como vectores de caracteres, en lugar de convertirlas al tipo de datos de factor
más sofisticado (para ser cubierto más adelante capítulos).
En este punto, la variable states
contiene el marco de datos que contiene las columnas (vectores) de datos. Podemos imprimirlo con print (states)
, pero el resultado es bastante de salida:

Podría tener más sentido extraer solo las primeras 10 filas de datos e imprimirlas, lo que podemos hacer con la función head ()
(head ()
también puede extraer solo los primeros elementos de un vector largo).

Las funciones nrow ()
y ncol ()
devuelven el número de filas y columnas de un marco de datos, respectivamente (que se prefiere sobre length ()
, que devuelve el número de columnas); la función dim ()
devuelve un vector de dos elementos con número de filas (en el índice 1) y número de columnas (en el índice 2).
Como se mencionó anteriormente, las columnas individuales de un marco de datos son (casi siempre) vectores. Para acceder a uno de estos vectores individuales, podemos usar una sintaxis $
especial, con el nombre de la columna siguiendo la $
.

Siempre y cuando el nombre de la columna sea lo suficientemente simple (en particular, siempre y cuando no tenga espacios), entonces las comillas alrededor del nombre de la columna pueden omitirse (y a menudo son) omitidas.

Aunque esta sintaxis se puede utilizar para extraer una columna de un marco de datos como un vector, tenga en cuenta que también se refiere al vector dentro del marco de datos. En cierto sentido, states$income
es el vector almacenado en el marco de datos de estados
. Así podemos usar técnicas como el reemplazo selectivo para trabajar con ellos al igual que cualquier otro vector. Aquí, reemplazaremos todas las instancias de “North Central” en el vector states$region
con solo el término “Central”, renombrando efectivamente la región. [4]

Escribir un marco de datos en un archivo separado por tabuladores se logra con la función write.table ()
. [5] Al igual que con read.table ()
, write.table ()
puede tomar bastantes parámetros, la mayoría de los cuales tienen valores predeterminados razonables. Pero hay seis más o menos que vamos a querer establecer con más frecuencia que otros. Escribamos el marco de datos de estados
modificados en un archivo llamado states_modified.txt
como un archivo separado por tabuladores.

Los dos primeros parámetros aquí son el marco de datos a escribir y el nombre del archivo en el que escribir. El parámetro quote = FALSE
especifica que las comillas no deben escribirse alrededor de los tipos de caracteres en la salida (por lo que la columna name
tendrá entradas como Alabama
y Alaska
en lugar de “Alabama”
y “Alaska”
). El sep = “\ t”
indica que las pestañas deben separar las columnas, mientras que fila.names = FALSE
indica que los nombres de fila no deben escribirse (porque no contienen ninguna información significativa para este marco de datos), y col.names = TRUE
indica que queremos la columna nombres de salida a la primera línea del archivo como una línea de “encabezado”.
R y la línea de comandos Unix/Linux
En el capítulo 26, “Una introducción”, mencionamos que los scripts R se pueden ejecutar desde la línea de comandos usando el #! /usr/bin/env Entorno ejecutable Rscript
. (Las versiones anteriores de R requerían que el usuario ejecutara un comando como R CMD BATCH Scriptname.r
, pero hoy se prefiere usar Rscript
). Dedicamos más discusión a interconectar Python con el entorno de línea de comandos que lo haremos R, en parte porque R no se usa con tanta frecuencia de esa manera, sino también porque es bastante fácil.
Al usar read.table ()
, por ejemplo, los datos se pueden leer desde la entrada estándar usando el nombre de archivo “stdin”
. Cualquier cosa que se imprima a partir de un script R va a la salida estándar por defecto. Debido a que R hace una buena cantidad de formato al imprimir, sin embargo, a menudo es más conveniente imprimir marcos de datos usando write.table ()
especificando file = “”
.
Finalmente, para obtener los parámetros de la línea de comandos en un script R como vector de caracteres, los args de línea <- CommandArgs (TrailingOnly = TRUE)
harán el truco. Aquí hay un script simple que leerá una tabla en la entrada estándar, la escribirá en la salida estándar y también leerá e imprimirá cualquier argumento de línea de comandos:

Intenta hacer que este script sea ejecutable en la línea de comandos, y ejecutarlo en p450s_blastp_yeast_top1.txt
con algo como cat p450s_blastp_yeast_top1.txt |. /stdin_stdout_ex.r arg1 'arg 2'
.
Ejercicios
- Supongamos que tenemos algún vector numérico de longitud impar (por ejemplo,
muestra<- c (3.2, 5.1, 2.5, 1.6, 7.9)
omuestra <- runif (25, min = 0, max = 1)
). Escribe algunas líneas de código que den como resultado la impresión de la mediana del vector, sin usar las funcionesmedian ()
oquantile ()
. Puede que le resulten útiles las funcioneslength ()
y as.integer ()
. - Si
muestra
es una muestra de una distribución exponencial, por ejemplo,muestra <- rexp (1000, tasa = 1.5)
, entonces la mediana de la muestra es generalmente menor que la media. Genere un vector,entre_median_media
, que contenga todos los valores demuestra
que sean mayores que (o iguales a) la mediana de la muestra, y menores que (o iguales a) la media de la muestra. - Lea en el archivo
states.txt
en un marco de datos como se describe. Extraiga un vector numérico llamadoasesino_lowincome
que contenga tasas de asesinato solo para aquellos estados con ingresos per cápita menores que la mediana del ingreso per cápita (puede usar la funciónmedian ()
esta vez). De igual manera, extraer un vector llamadoasesino_highincome
que contiene tasas de asesinato solo para aquellos estados con mayor que (o igual a) el ingreso per cápita medio. Ejecutar unaprueba t.test ()
de dos muestras para determinar si las tasas medias de homicidios son diferentes entre estos dos grupos. - Sea
estados
el marco de datos de información de estado descrito anteriormente. Describir lo que hacen las diversas operaciones a continuación en términos de indexación, reemplazo selectivo, reciclaje de vectores y los tipos de datos involucrados (por ejemplo, vectores numéricos y vectores lógicos). Para comenzar, la primera línea agrega una nueva columna al marco de datos deestados
llamada“newpop”
que contiene la misma información que la columna“population”
. - Determine el número de regiones únicas que se enumeran en el marco de datos de
estados
. Determinar el número de regiones únicas representadas por estados con ingresos mayores a la mediana. - ¿Qué informa la función
sum ()
para un vector numéricoc (2, 3, 0, 1, 0, 2
)
? ¿Qué tal parac (1, 0, 0, 1, 1, 0
)
? Y, finalmente, ¿qué tal para el vector lógicoc (VERDADERO, FALSO, FALSO, VERDADERO, CIERTO, FALSO
)
¿Cómo podría ser útil la funciónsum ()
en un contexto lógico?
- La mayoría de las funciones R toman una gran cantidad de parámetros, pero muchos de ellos son opcionales. En el siguiente capítulo, veremos cómo se ven estos parámetros opcionales y cómo obtener una extensa lista de todos los parámetros que pueden tomar las funciones R incorporadas.
-
El término “reemplazo selectivo” no es ampliamente utilizado fuera de este libro. En algunas situaciones se emplea el término “reemplazo condicional”, pero quisimos definir alguna terminología concreta para plasmar la totalidad de la idea.
-
Cuando se ejecuta en la línea de comandos, el directorio de trabajo actual se hereda del shell. En RStudio, el directorio de trabajo actual se establece en el directorio “proyecto” si el archivo forma parte de una carpeta de proyecto. En cualquier caso, es posible cambiar el directorio de trabajo desde dentro de R usando el directorio
setwd ()
, como ensetwd (“/home/username/rproject”)
en Unix/Linux ysetwd (“C: /Documents and settings/username/my documents/rproject”)
en Windows. También es posible especificar nombres de archivo por ruta absoluta, como en/home/username/rproject/states.txt
, sin importar el directorio de trabajo actual.
-
Si tiene alguna familiaridad con R, es posible que se haya topado con la función
attach ()
, que toma un marco de datos y da como resultado la creación de un vector separado para cada columna. Generalmente, “desmontar” un marco de datos de esta manera es una mala idea; después de todo, ¡las columnas de un marco de datos generalmente están asociadas entre sí por una razón! Además, esta función da como resultado la creación de muchas variables con nombres basados en los nombres de columna del marco de datos. Debido a que estos nombres no están claramente delimitados en el código, es fácil crear errores difíciles de encontrar y mezclar columnas de múltiples marcos de datos de esta manera.
- También hay funciones más especializadas tanto para leer como para escribir datos tabulares, como
read.csv ()
ywrite.csv ()
. Nos hemos centrado enread.table ()
ywrite.table ()
porque son lo suficientemente flexibles como para leer y escribir tablas en una variedad de formatos, incluyendo separados por comas, separados por tabuladores, etc.