library(Dmisc)
# Datos sintéticos para los ejemplos.
set.seed(123)
<- data.frame(
df sex = rep(c('M', 'F'), each = 500),
age = c(sample(20:60, 500, TRUE), sample(30:70, 500, TRUE))
)
Al trabajar con datos, es frecuente encontrarse con la necesidad de analizar variables numéricas. En ciertos casos, resulta suficiente emplear medidas estadísticas básicas como la media, la suma, el valor mínimo y máximo, y otras similares, especialmente cuando se desea examinar la relación de estas variables con variables categóricas.
En la situación en la que se requiera comparar dos variables numéricas, podemos recurrir a métricas como la correlación, la regresión, la covarianza, entre otras, para establecer una relación entre ambas. Sin embargo, a menudo surge la necesidad de convertir estas variables numéricas en categóricas para capturar y resaltar las diferencias entre distintos grupos demográficos o poblacionales.
Para este propósito, el lenguaje de programación estadística R
proporciona la función cut
. Según su documentación, cut
es una función diseñada para convertir una variable numérica en un factor1.
Además, existen bibliotecas de terceros que expanden las capacidades de la función cut
, añadiendo más funcionalidades. Un ejemplo de esto es la función cut3
del paquete Dmisc
. A continuación, examinaremos cómo funcionan estas funciones y compararemos la utilidad y efectividad de cut3
con otras alternativas disponibles.
La primera y fundamental diferencia de cut3
, con el resto de las funciones diseñadas para estos fines, radica en que la primera es una función diseñada para trabajar sobre un data.frame, mientras que las otras están diseñadas para trabajar con el vector numérico de interés.
En términos de ventajas, esto puede significar una mayor flexibilidad y eficiencia en algunos casos. En lugar de tener que aislar un vector numérico y trabajar con él individualmente, cut3
permite al usuario operar directamente en el data.frame completo. Esto puede ser particularmente útil en situaciones donde se necesita manipular o analizar múltiples columnas simultáneamente, como se verá más adelante.
Sin embargo, esta funcionalidad también presenta algunas desventajas. La principal es que cut3
sobrescribe la variable en cuestión dentro del data.frame, y no es intuitiva la forma de asignarla en una nueva variable.2
Cortes
El más importante argumento de estas funciones, después de los datos, es breaks
. Este argumento consiste en una indicación de como se construyen los intervalos en la variable categórica resultante.
Un único número
Cuando el argumento breaks
consiste de un único número (entero y mayor o igual a 2)3. Este se interpreta como el número de cortes que se deben realizar en la variable numérica cuando se convierte en categórica.
<- df
df2 $age <- cut(df2$age, breaks = 4)
df2table(df2)
age
sex (19.9,32.5] (32.5,45] (45,57.5] (57.5,70]
F 31 171 144 154
M 155 159 150 36
En este caso, salvo un leve diferencia en términos de la sintaxis. El mismo resultado se pudiera lograr utilizando cut3
.
<- Dmisc::cut3(
df3
df, var_name = 'age',
breaks = 4
)table(df3)
age
sex (19.9,32.5] (32.5,45] (45,57.5] (57.5,70]
F 31 171 144 154
M 155 159 150 36
Un vector numérico
Cuando el argumento breaks
se pasa como un vector numérico, los valores contenidos en dicho vector se interpretan como los puntos de corte para la construcción de los intervalos en los que se va a dividir la variable en cuestión.
<- df
df2 $age <- cut(
df2$age,
df2breaks = c(0, 20, 40, 60, 80, 100)
)table(df2)
age
sex (0,20] (20,40] (40,60] (60,80] (80,100]
F 0 137 245 118 0
M 5 235 260 0 0
Nuevamente, lo mismo se puede conseguir utilizando la función cut3()
.
<- df
df3 <- cut3(
df3
df3, var_name = "age",
breaks = c(0, 20, 40, 60, 80, 100)
)table(df3)
age
sex (0,20] (20,40] (40,60] (60,80] (80,100]
F 0 137 245 118 0
M 5 235 260 0 0
Es importante destacar que este vector de valores debe contener un valor inicial menor que
el mínimo
de la variable y un último valor mayor o igual
al máximo
de la variable. Esto se debe a la forma en que se construyen los intervalos.
Observa en la etiqueta de la variable creada (0,20]
que el límite inferior del intervalo está abierto (
, lo que significa que solo se incluyen valores mayores que 0. Puedes cambiar este comportamiento y hacer que el primer rango sea cerrado utilizando el argumento include.lowest
. Mientras que el límite superior está cerrado ]
, lo que significa que se incluyen valores menores o iguales a 20.
Si el vector de valores no cumple con los criterios descritos anteriormente, los valores que no encajen en ningún intervalo se marcarán como NA
en la variable resultante. Además, en el caso de la función cut3()
, si el usuario establece el argumento .inf en True, los puntos de corte proporcionados se extenderán con -Inf e Inf. Esto significa que cualquier valor se incluirá en la variable resultante, incluso si está fuera del rango de los valores originales. Es una característica útil cuando no se conoce de antemano el valor máximo y mínimo de la variable y se desea incluir todos los valores sin tener que establecer límites específicos.
cut3(
df, var_name = "age",
breaks = c(0, 20, 40, 60, 80, 100)
# Dejará NAs
)
cut3(
df, var_name = "age",
breaks = c(20, 40, 60, 80),
include.lowest = T
# Dejará NAs
)
cut3(
df, var_name = "age",
breaks = c(20, 40, 60, 80),
.inf = F
# No dejará NAs )
Finalmente, es esencial que los valores de dicho vector sean únicos. Esto es fundamentalmente relevante cuando los puntos de corte no se asignan manualmente, sino que se utiliza alguna otra estrategia para los fines.
Funciones
Una de las principales novedades de cut3()
en comparación con cut()
es que el vector de breaks
puede ser una función que genera el vector numérico de los cortes. El caso de uso más común para esta funcionalidad es quizás cuando se quieren utilizar cuantiles para dividir la variable.
Para estos propósitos, se debe utilizar el argumento bf_args
en el que se especifican argumentos adicionales, los cuales deben pasarse a la función utilizada para construir los puntos de ruptura.
table(
cut3(
df, var_name = "age",
breaks = quantile
) )
age
sex (20,36] (36,45] (45,55] (55,70]
F 76 126 126 172
M 195 114 128 58
En el código de ejemplo anterior, la función cut3()
se utiliza para dividir la variable “age” en el data.frame df
en grupos o bins basados en cuantiles. Aquí, breaks
se establece como quantile
, lo que significa que los cuantiles de la distribución de “age” se utilizan para definir los puntos de ruptura.
Una característica interesante de este enfoque es que permite una mayor flexibilidad en la definición de los grupos. Por ejemplo, en lugar de dividir la variable en grupos de igual tamaño, puedes dividirla en grupos basados en la distribución de los datos. Esto puede ser particularmente útil cuando se trabaja con variables que tienen una distribución sesgada o que están altamente concentradas en ciertos rangos.
Además, al permitir que breaks
sea una función, cut3()
ofrece la posibilidad de generar puntos de ruptura de manera dinámica en función de los datos. Esto puede facilitar la creación de análisis más robustos y adaptables, ya que no es necesario definir los puntos de ruptura de antemano.
Por último, cabe mencionar que el argumento bf_args
permite pasar argumentos adicionales a la función de breaks
. Esto ofrece aún más flexibilidad, ya que puedes personalizar la función de breaks
para adaptarse a tus necesidades específicas. Por ejemplo, podrías cambiar los cuantiles utilizados para dividir la variable, o podrías utilizar una función completamente diferente para generar los puntos de ruptura.
Dmisc::cut3_quantiles
El paquete Dmisc ya incluye la función cut3_quantile
, que es una variante de cut3 diseñada específicamente para dividir una variable en cuantiles.
cut3_quantile toma un data.frame, una variable y un conjunto de probabilidades que definen los cuantiles. Si no se especifican las probabilidades, por defecto se utilizan el primer cuartil, la mediana y el tercer cuartil. Luego llama a cut3 con la función quantile de R como argumento para los puntos de ruptura.
table(
cut3_quantile(
df, var_name = "age"
) )
age
sex (-Inf,36] (36,45] (45,55] (55, Inf]
F 76 126 126 172
M 200 114 128 58
En el ejemplo de código anterior, cut3_quantile divide la variable “age” en el data.frame df en cuartiles.
Por lo tanto, si deseas dividir una variable en cuantiles, puedes utilizar directamente cut3_quantile en lugar de pasar quantile como argumento para breaks en cut3.
Grupos
Otra adición a cut3()
consiste en poder definir diferentes cortes para diferentes grupos. Esto es especialmente útil cuando los puntos de ruptura se especifican con funciones.
table(
cut3(
df, var_name = "age",
breaks = 4,
.inf = F
) )
age
sex (19.9,32.5] (32.5,45] (45,57.5] (57.5,70]
F 31 171 144 154
M 155 159 150 36
table(
cut3(
df, var_name = "age",
breaks = 4,
.inf = F,
groups = "sex"
) )
age
sex (20,30] (30,40] (40,50] (50,60] (60,70]
F 0 137 122 123 118
M 134 106 141 119 0
En el ejemplo de código anterior, cut3()
se utiliza para dividir la variable “age” en el data.frame tbl
en dos grupos, pero los cortes se definen de manera separada para cada valor de la variable “sex”. Esto significa que los grupos generados para “age” serán diferentes para hombres y mujeres, lo cual puede ser muy útil en análisis que requieran tener en cuenta las diferencias entre grupos.
Esta característica de cut3()
es muy poderosa, ya que permite adaptar los puntos de ruptura a las características específicas de cada grupo. En muchos casos, la distribución de una variable puede variar significativamente entre diferentes grupos, y usar los mismos puntos de ruptura para todos los grupos podría resultar en una representación inexacta de los datos.
Por ejemplo, imagina que estás analizando la edad de los participantes en un estudio y descubres que la distribución de las edades es muy diferente para hombres y mujeres. Si utilizas los mismos puntos de ruptura para ambos grupos, podrías terminar con bins que contienen muchas mujeres pero pocos hombres, o viceversa. Al permitir definir los puntos de ruptura por separado para cada grupo, cut3()
te permite evitar este problema y asegurar una representación más precisa de los datos para cada grupo.
Además, esta función es particularmente útil cuando los puntos de ruptura se especifican con funciones, ya que estas funciones pueden adaptarse a las características específicas de cada grupo. Por ejemplo, podrías utilizar cuantiles para definir los puntos de ruptura, lo que aseguraría que los bins contienen aproximadamente la misma proporción de observaciones para cada grupo, independientemente de las diferencias en las distribuciones de los datos.
Ponderadores
TODO
Etiquetas
Como quizás ya habrás notado en los ejemplos anteriores, las etiquetas de los datos de la variable resultante se construyen utilizando la notación de intervalo correspondiente. Sin embargo, este comportamiento puede ser modificado proporcionando el argumento labels = F
. En este caso, se utilizará un número autoincremental simple para nombrar los intervalos.
table(
cut3(
df, var_name = "age",
breaks = 4,
labels = F
) )
age
sex 1 2 3 4
F 31 171 144 154
M 155 159 150 36
Además, puedes proporcionar un vector especificando las etiquetas que quieres utilizar en la construcción de la variable. Las etiquetas se asignarán en el orden en que se especifican. Además, el número de etiquetas debe ser exactamente igual al número de bins resultantes.
table(
cut3(
df, var_name = "age",
breaks = 4,
labels = c(
"1 - 25 años",
"21 - 50 años",
"51 - 75 años",
"76 - 100 años"
)
) )
age
sex 1 - 25 años 21 - 50 años 51 - 75 años 76 - 100 años
F 31 171 144 154
M 155 159 150 36
Esto puede ser útil si deseas personalizar las etiquetas para hacerlas más descriptivas o más fáciles de entender. Por ejemplo, podrías usar etiquetas que describan las características de los individuos en cada grupo, o podrías usar etiquetas que sean más consistentes con la terminología utilizada en tu campo de estudio. Esto puede hacer que tus resultados sean más claros y más fáciles de interpretar, tanto para ti como para otras personas que puedan estar trabajando con tus datos.
Conclusión
La función cut3 del paquete Dmisc en R ofrece ventajas y desventajas. En comparación con funciones como cut, cut3 puede ofrecer mayor flexibilidad y eficiencia al trabajar directamente con data.frames en lugar de solo con vectores numéricos. Esto puede ser especialmente útil cuando se necesita manipular o analizar múltiples columnas a la vez.
Sin embargo, también presenta inconvenientes, como la sobrescritura de la variable original dentro del data.frame, y puede resultar menos intuitiva cuando se necesita asignar el resultado a una nueva variable. En términos de rendimiento, la elección entre cut y cut3 dependerá en gran medida del contexto y de las necesidades específicas de tu análisis.
Finalmente, siempre es recomendable entender las diferencias y peculiaridades de las distintas herramientas disponibles antes de tomar una decisión sobre qué método utilizar para convertir variables numéricas en categóricas.
Referencias
Notas
En R, un factor es una variable de tipo categórica. Es similar a una variable de tipo texto (character), pero que solo toma un conjunto finito de valores (levels).↩︎
Esto se puede lograr con solo crear una variable que sea copia de la original antes de hacer el corte.↩︎
Cuando
breaks
se especifica de esta forma la variable se divide en segmentos de igual longitud. Para más detalles, véase la documentación en la funcióncut()
.↩︎
Reutilización
Cómo citar
@online{e. de la rosa2023,
author = {E. de la Rosa, Daniel},
title = {Cut Cut Cut},
date = {2023-07-11},
url = {https://adatar.do/blog/Dmisc/cut3.html},
langid = {es}
}