16  CREACIÓN Y TRANSFORMACIÓN DE VARIABLES

¿¡Variable!?

Si partimos de la siguiente identidad:

\[ a=3, \]

resulta natural afirmar que \(a\) es una variable que vale 3.

En R, un escenario similar se logra mediante la siguiente asignación:

a <- 3

No obstante, en este contexto puede resultar confuso —y no del todo preciso— afirmar que a es una variable, ya que su valor no cambia, a menos que se le reasigne explícitamente.

En R es más común referirse a este tipo de entes como objetos, y suele identificárseles por su clase. En este caso se diría que el objeto a es un vector de clase numeric, cuyo valor es 3.

A pesar de esta distinción, en esta sección utilizaremos el término variable —con fines netamente didácticos— para referirnos a los objetos de R, en línea con el uso común de este término en el contexto de análisis de datos.

16.1 Manipulación básica de variables

Para crear una variable en R, basta con elegir un nombre sintácticamente válido (cf. capítulo 12) y asignarle la expresión deseada.

Considérese la siguiente asignación:

a <- 25

Esta instrucción crea una variable llamada a, cuyo valor es 25, a partir de la asignación directa del correspondiente valor numérico.

También es posible crear una variable con base en el valor de alguna otra variable creada previamente. Podría usarse, por ejemplo, la variable a para crear una nueva variable, así:

Código 16.1
raíz.a <- sqrt(a)

La instrucción anterior crea la variable raíz.a, mediante la extracción de la raíz cuadrada de la variable a. Tanto a (con valor 25) como raíz.a (con valor 5) quedan disponibles en el ambiente de trabajo y podrían usarse posteriormente.

Para actualizar el valor de una variable ya existente, basta con asignarle un nuevo valor, así:

a <- 81

La variable a, creada anteriormente, cuyo valor era 25, ahora vale 81.

¡No hay cambios automáticos!

El cambio de a de 25 a 81 no genera un cambio automático de raíz.a. Puesto que la instrucción raíz.a <- sqrt(a) se ejecutó cuando a valía 25, raíz.a sigue valiendo 5.

No obstante, al interior de una función sí podrían incorporarse instrucciones que verificaran cualquier cambio en a y actualizaran raíz.a.

La actualización del valor de una variable podría estar basada en el valor previo de la variable, así:

Código 16.2
contador <- 18
contador <- contador + 1

La línea 1 crea la variable contador con un valor inicial de 18.

La línea 2 le reasigna un valor a contador, tomando como base su valor previo (18). Tras ejecutar esta línea, el valor de contador se actualiza a 19.

También es posible crear una nueva variable, combinando dos o más variables, tal y como se ilustra a continuación para el cálculo del índice de masa corporal.

peso  <- 65
talla <- 1.65
imc   <- peso/talla^2
¿¡Actualizar o crear nuevas variables!?

Cuando se usa una variable como insumo para la creación de otra variable, dando un nombre diferente a la última (cf. código 16.1), se crea una nueva variable.

Cuando se usa una variable como insumo para la creación de otra variable, dándole el mismo nombre a la última (cf. código 16.2), se actualiza el contenido de la variable.

16.2 Manipulación de variables dentro de data frames

En el contexto de análisis de datos, la información suele estructurarse en data frames, en los que las variables aparecen organizadas en cada uno de sus vectores. A menudo se requiere transformar todos los valores de una variable, es decir, cada una de las observaciones de un vector particular de un data frame.

En este proceso también pueden crearse nuevas variables o actualizarse las existentes, dependiendo de si la expresión se asigna a un objeto nuevo o a uno ya existente.

Considérense las siguientes instrucciones:

Código 16.3
datos <- data.frame(a = seq(1, 21, 2), b = rnorm(11))
c <- log(datos$a) + (datos$b)^2

La línea 1 crea un data frame, con dos variables o vectores: a, compuesto por la secuencia de números del 1 al 21, con incrementos de 2, y un segundo vector, llamado b, que contiene 11 números aleatorios generados a partir de la distribución normal estándar (cf. capítulo 17).

La línea 2 crea un vector llamado c, resultante de combinar los vectores a y b, acorde con la expresión allí definida.

¡No la deje sola!

Cuando se aplican transformaciones o se crean nuevas variables es esencial que la variable no quede aislada en el ambiente de trabajo, sino que se integre al data frame que contiene las demás variables.

La definición de la nueva variable en la línea 2 del código 16.3 deja a c por fuera del data frame datos, el cual sigue estando conformado únicamente por a y b.

Existen múltiples maneras de evitar esta situación indeseable, las cuales se ilustran en el marco de la creación de la nueva variable del código 16.3, reescribiendo únicamente la segunda línea.

Cualquiera de las siguientes instrucciones da lugar al mismo resultado: dentro del data frame datos se crea una columna llamada c, a partir de la expresión indicada.

datos$c <- log(datos$a) + (datos$b)^2
datos$c <- with(datos, log(a) + b^2)
datos   <- within(datos, c <- log(a) + b^2)
datos   <- transform(datos, c = log(a) + b^2)

La primera forma (línea 1), no obstante ser la más directa, exige referenciar cada una de las variables antecedida por el nombre del data frame y el símbolo $, lo cual puede recargar el código; en especial, si se usa una expresión compleja.

El uso de with en la parte derecha de la asignación (línea 2) crea un entorno dentro del data frame datos, que permite invocar las variables directamente por su nombre, sin necesidad de que estén antecedidas por el nombre del data frame y el signo $. En la parte izquierda de la asignación sí es necesario definir la ubicación de la nueva variable, antecediendo su nombre con el del datra frame contenedor y el símbolo $. Esto asegura que la nueva variable se agregue al data frame datos.

Las dos últimas opciones (líneas 3 y 4) funcionan de manera similar, creando un data frame temporal al que se le añade la nueva variable, el cual se sobrescribe al data frame original.

¡Préstele atención al operador de asignación!

Dentro de la función within es necesario utilizar <- como operador de asignación.

Dentro de la función transform debe utilizarse = como operador de asignación.

Tanto within como transform permiten realizar múltiples definiciones de manera simultánea. No obstante, es necesario prestar atención a las particularidades del formato de aplicación de cada una de estas.

Cuando se usa la función within para realizar múltiples asignaciones, las diferentes definiciones se encierran entre llaves y obligatoriamente deben ubicarse en líneas diferentes, aunque la primera definición podría ir en la misma linea de apertura de las llaves.

En este caso, las diferentes definiciones se evalúan en el orden de aparición, lo que permite generar definiciones basadas en resultados que aparezcan previamente en la misma instrucción, tal y como se ilustra en el siguiente fragmento de código en el que se define d con base en c, que se crea en la línea anterior, pero en la misma instrucción.

datos <- within(datos, {
  c <- a + b
  d <- c^2
}) 

Cuando se usa transform para realizar múltiples asignaciones, las diferentes definiciones se separan con comas. Internamente se evalúan de manera simultánea —sin importar el orden en el que se presenten—, lo que impide que una variable pueda definirse a partir de otra que también se esté creando en esa misma instrucción.

datos <- transform(datos, c = a + b, d = a/b)

Aunque no es obligatorio, también es común que, al usar transform para realizar múltiples definiciones, estas se ubiquen en líneas diferentes, en particular cuando se realizan muchas definiciones. Esto facilita su visualización:

datos <- transform(datos,
                   c = a + b,
                   d = a/b,
                   e = log(a),
                   f = (log(b + 5)))
Resumen y recomendaciones
  • En programación es común actualizar una variable con base en sus valores previos. En tales casos, se mantiene el nombre de la variable, lo que da lugar a su sobreescritura, tal y como se ilustra en el código 16.2.

  • Otra situación en la que es común la sobreescritura de una variable es cuando se modifica su clase.

    Un caso bastante frecuente se da cuando es necesario definir una variable o una serie de variables como factores (cf. sección 10.4):

    datos <- transform(datos,
                       tratamientos = factor(tratamientos),
                       bloques = factor(bloques))
  • En el contexto del análisis de datos, donde cada una de las columnas del data frame representa una variable, es necesario asegurar que las nuevas variables que se creen queden incluidas en el mismo data frame.

  • Cuando se trasforma una variable, se desaconseja la escritura de la variable original, pues, además de la posible confusión que esto puede generar, se pierde la trazabilidad del proceso. En consecuencia, siempre que se transforme una variable, se recomienda guardar el resultado en una nueva variable:

    datos <- transform(datos, severidad.t = log(severidad))