7.6: Clasificación, volteo y fusión de datos
- Page ID
- 151579
\( \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}\)En esta sección discuto algunas operaciones útiles que siento que están vagamente relacionadas entre sí: ordenar un vector, ordenar un marco de datos, unir dos o más vectores juntos en un marco de datos (o matriz), y voltear un marco de datos (o matriz) de su lado. Todas son tareas bastante sencillas, al menos en comparación con algunos de los problemas de manejo de datos más odiosos que aparecen en la vida real.
Ordenar un vector numérico o de caracteres
Una cosa que a menudo quieres hacer es ordenar una variable. Si se trata de una variable numérica, es posible que desee ordenar en orden creciente o decreciente. Si se trata de un vector de caracteres, es posible que desee ordenar alfabéticamente, etc. La función sort ()
proporciona esta capacidad.
numbers <- c(2,4,3)
sort( x = numbers )
## [1] 2 3 4
Puedes pedir R para ordenar en orden decreciente en lugar de aumentar:
sort( x = numbers, decreasing = TRUE )
## [1] 4 3 2
Y puedes pedirle que ordene los datos de texto en orden alfabético:
text <- c("aardvark", "zebra", "swing")
sort( text )
## [1] "aardvark" "swing" "zebra"
Eso es bastante sencillo. Dicho esto, es importante señalar que estoy pasando por alto algo aquí. Cuando aplicas sort ()
a un vector de caracteres, no se ordena estrictamente en orden alfabético. R en realidad tiene una noción ligeramente diferente de cómo se ordenan los caracteres (ver Sección 7.8.5 y Tabla 7.3), que está más estrechamente relacionada con cómo las computadoras almacenan datos de texto que con cómo se ordenan las letras en el alfabeto. Sin embargo, ese es un tema que discutiremos más adelante. Por ahora, lo único que debo señalar es que la función sort ()
no altera la variable original. Más bien, crea una nueva variable ordenada como salida. Entonces, si inspecciono mi variable de texto
original:
text
## [1] "aardvark" "zebra" "swing"
Puedo ver que se ha mantenido sin cambios.
Clasificación de un factor
También puedes ordenar factores, pero la historia aquí es un poco más sutil porque hay dos formas diferentes de ordenar un factor: alfabéticamente (por etiqueta) o por nivel de factor. La función sort ()
usa esta última. Para ilustrar, veamos los dos ejemplos diferentes. Primero, vamos a crear un factor de la manera habitual:
fac <- factor( text )
fac
## [1] aardvark zebra swing
## Levels: aardvark swing zebra
Ahora vamos a ordenarlo:
sort(fac)
## [1] aardvark swing zebra
## Levels: aardvark swing zebra
Esto parece que está ordenado las cosas en orden alfabético, pero eso es sólo porque los niveles de los factores en sí mismos pasan a estar ordenados alfabéticamente. Supongamos que defino deliberadamente los niveles de los factores en un orden no alfabético:
fac <- factor( text, levels = c("zebra","swing","aardvark") )
fac
## [1] aardvark zebra swing
## Levels: zebra swing aardvark
Ahora, ¿qué pasa cuando intentamos ordenar fac
esta vez? La respuesta:
sort(fac)
## [1] zebra swing aardvark
## Levels: zebra swing aardvark
Ordena los datos en el orden numérico implícito por los niveles de los factores, no el orden alfabético implícito por las etiquetas adjuntas a esos niveles. Normalmente nunca se nota la distinción, porque por defecto los niveles de los factores se asignan en orden alfabético, pero es importante conocer la diferencia:
Ordenar un marco de datos
La función sort ()
no funciona correctamente con los marcos de datos. Si desea ordenar un marco de datos, el consejo estándar que encontrará en línea es usar la función order () (
no descrita en este libro) para determinar en qué orden deben ordenarse las filas, y luego usar corchetes para hacer el barajado. No hay nada intrínsecamente malo en este consejo, solo lo encuentro tedioso. Para ello, el paquete lsr
incluye una función llamada sortFrame ()
que puedes usar para hacer la clasificación. El primer argumento de la función se llama (x
), y debe corresponder al marco de datos que desea ordenar. Después de eso, todo lo que haces es escribir una lista de los nombres de las variables que quieres usar para hacer la clasificación. Por ejemplo, si escribo esto:
sortFrame( garden, speaker, line)
## speaker utterance line
## case.4 makka-pakka pip 7
## case.5 makka-pakka onk 9
## case.3 tombliboo ee 5
## case.1 upsy-daisy pip 1
## case.2 upsy-daisy pip 2
lo que hace R es primero ordenar por hablante
(orden de nivel de factor). Cualquier vínculo (es decir, datos del mismo orador) se ordena entonces en orden de línea
(aumentando el orden numérico). Puede usar el signo menos para indicar que las variables numéricas deben ordenarse en orden inverso:
sortFrame( garden, speaker, -line)
## speaker utterance line
## case.5 makka-pakka onk 9
## case.4 makka-pakka pip 7
## case.3 tombliboo ee 5
## case.2 upsy-daisy pip 2
## case.1 upsy-daisy pip 1
A partir de la escritura actual, la función sortFrame ()
está en desarrollo. Empecé a introducir funcionalidad para permitirle usar el signo -
a variables no numéricas o hacer una distinción entre factores de clasificación alfabéticamente o por nivel de factor. La idea es que deberías poder escribir algo como esto:
sortFrame( garden, -speaker)
y que la salida corresponda a una especie de marco de datos del jardín
en orden alfabético inverso (o orden de nivel de factor inverso) del hablante
. Tal como están las cosas en este momento, esto realmente funcionará y producirá una salida sensata:
sortFrame( garden, -speaker)
## speaker utterance line
## case.1 upsy-daisy pip 1
## case.2 upsy-daisy pip 2
## case.3 tombliboo ee 5
## case.4 makka-pakka pip 7
## case.5 makka-pakka onk 9
Sin embargo, no estoy completamente convencido de que haya configurado esto de la manera ideal, así que esto puede cambiar un poco en el futuro.
Vectores de unión juntos
Una tarea no infrecuente que podrías encontrarte necesitando emprender es combinar varios vectores. Por ejemplo, supongamos que tenemos los dos vectores numéricos siguientes:
cake.1 <- c(100, 80, 0, 0, 0)
cake.2 <- c(100, 100, 90, 30, 10)
Los números aquí podrían representar la cantidad de cada uno de los dos pasteles que quedan en cinco momentos diferentes. Al parecer el primer pastel es más sabroso, ya que ese se devora más rápido. Ya hemos visto un método para combinar estos vectores: podríamos usar la función data.frame ()
para convertirlos en un marco de datos con dos variables, así:
cake.df <- data.frame( cake.1, cake.2 )
cake.df
## cake.1 cake.2
## 1 100 100
## 2 80 100
## 3 0 90
## 4 0 30
## 5 0 10
Otros dos métodos a los que quiero referirme brevemente son las funciones rbind ()
y cbind ()
, que convertirán los vectores en una matriz. Discutiré las matrices correctamente en la Sección 7.11.1 pero los detalles no importan demasiado para nuestros propósitos actuales. La función cbind ()
(“column bind”) produce una salida de aspecto muy similar al ejemplo del marco de datos:
cake.mat1 <- cbind( cake.1, cake.2 )
cake.mat1
## cake.1 cake.2
## [1,] 100 100
## [2,] 80 100
## [3,] 0 90
## [4,] 0 30
## [5,] 0 10
pero sin embargo es importante tener en cuenta que cake.mat1
es una matriz en lugar de un marco de datos, y así tiene algunas diferencias con respecto a la variable cake.df
. La función rbind ()
(“row bind”) produce una salida algo diferente: une los vectores juntos por filas en lugar de columnas, por lo que la salida ahora se ve así:
cake.mat2 <- rbind( cake.1, cake.2 )
cake.mat2
## [,1] [,2] [,3] [,4] [,5]
## cake.1 100 80 0 0 0
## cake.2 100 100 90 30 10
Puedes agregar nombres a una matriz usando las funciones rownames ()
y colnames ()
, y también debo señalar que hay una función más elegante en R llamada merge ()
que admite la fusión más complicada de “database like” de vectores y marcos de datos, pero no voy a entrar en detalles aquí.
Enlazar múltiples copias del mismo vector
A veces es muy útil unir múltiples copias del mismo vector. Podrías hacer esto usando las funciones rbind
y cbind
, usando comands como este
fibonacci <- c( 1,1,2,3,5,8 )
rbind( fibonacci, fibonacci, fibonacci )
## [,1] [,2] [,3] [,4] [,5] [,6]
## fibonacci 1 1 2 3 5 8
## fibonacci 1 1 2 3 5 8
## fibonacci 1 1 2 3 5 8
pero eso puede ser bastante molesto, sobre todo si necesitas muchas copias. Para que esto sea un poco más fácil, el paquete lsr
tiene dos funciones adicionales RowCopy
y ColCopy
que hacen el mismo trabajo, pero todo lo que tienes que hacer es especificar el número de copias que deseas, en lugar de escribir el nombre una y otra vez. Los dos argumentos que necesitas especificar son x
, el vector a copiar, y times
, indicando cuántas copias se deben crear: 117
rowCopy( x = fibonacci, times = 3 )
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 1 1 2 3 5 8
## [2,] 1 1 2 3 5 8
## [3,] 1 1 2 3 5 8
Por supuesto, en la práctica no es necesario nombrar los argumentos todo el tiempo. Por ejemplo, aquí hay un ejemplo usando la función colCopy ()
con los nombres de los argumentos omitidos:
colCopy( fibonacci, 3 )
## [,1] [,2] [,3]
## [1,] 1 1 1
## [2,] 1 1 1
## [3,] 2 2 2
## [4,] 3 3 3
## [5,] 5 5 5
## [6,] 8 8 8
Transposición de una matriz o marco de datos
load("./rbook-master/data/cakes.Rdata" )
cakes
## time.1 time.2 time.3 time.4 time.5
## cake.1 100 80 0 0 0
## cake.2 100 100 90 30 10
## cake.3 100 20 20 20 20
## cake.4 100 100 100 100 100
Y solo para asegurarte de que me crees que esto es en realidad una matriz:
class( cakes )
## [1] "matrix"
Bien, ahora transpongamos la matriz:
cakes.flipped <- t( cakes )
cakes.flipped
## cake.1 cake.2 cake.3 cake.4
## time.1 100 100 100 100
## time.2 80 100 20 100
## time.3 0 90 20 100
## time.4 0 30 20 100
## time.5 0 10 20 100
La salida aquí sigue siendo una matriz:
class( cakes.flipped )
## [1] "matrix"
En este punto deberías tener dos preguntas: (1) ¿cómo hacemos lo mismo con los marcos de datos? y (2) ¿por qué deberíamos preocuparnos por esto? Empecemos con la pregunta de cómo. Primero, debo señalar que puedes transponer un marco de datos bien usando la función t ()
, pero eso tiene la consecuencia un poco incómoda de convertir la salida de un marco de datos a una matriz, que no suele ser lo que quieres. Es bastante fácil volver a convertir la salida, claro, 118 pero odio escribir dos comandos cuando puedo hacerlo con uno. Para ello, el paquete lsr
tiene una función simple de “conveniencia” llamada tFrame ()
que hace exactamente lo mismo que t ()
pero convierte la salida en un marco de datos para usted. Para ilustrar esto, transpongamos el marco de datos itng
que usamos anteriormente. Aquí está el marco de datos original:
itng
## speaker utterance
## 1 upsy-daisy pip
## 2 upsy-daisy pip
## 3 upsy-daisy onk
## 4 upsy-daisy onk
## 5 tombliboo ee
## 6 tombliboo oo
## 7 makka-pakka pip
## 8 makka-pakka pip
## 9 makka-pakka onk
## 10 makka-pakka onk
y esto es lo que sucede cuando lo transpones usando tFrame ()
:
tFrame( itng )
## V1 V2 V3 V4 V5 V6
## speaker upsy-daisy upsy-daisy upsy-daisy upsy-daisy tombliboo tombliboo
## utterance pip pip onk onk ee oo
## V7 V8 V9 V10
## speaker makka-pakka makka-pakka makka-pakka makka-pakka
## utterance pip pip onk onk
Un punto importante a reconocer es que transponer un marco de datos no siempre es algo sensato de hacer: de hecho, iría tan lejos como para argumentar que generalmente no es sensato. Depende mucho de si los “casos” de tu marco de datos original tendrían sentido como variables, y pensar en cada una de tus “variables” originales como casos. Creo que eso enfáticamente no es cierto para nuestro marco de datos itng
, así que no aconsejaría hacerlo en esta situación.
Dicho esto, a veces es realmente cierto. Por ejemplo, si hubiéramos almacenado originalmente nuestra variable cakes
como un marco de datos en lugar de una matriz, ¡entonces sería absolutamente sensato voltear el marco de datos! 119 Hay algunas situaciones en las que es útil voltear tu marco de datos, así que es bueno saber que puedes hacerlo. En efecto, esa es la razón principal por la que he pasado tanto tiempo hablando de este tema. Muchas herramientas estadísticas hacen la suposición de que las filas de su marco de datos (o matriz) corresponden a observaciones, y las columnas corresponden a las variables. Eso no es irrazonable, claro, ya que esa es una convención bastante estándar. No obstante, piensa en nuestro ejemplo de pasteles
aquí. Esta es una situación en la que quizás quieras hacer un análisis de los diferentes pasteles (es decir, pasteles como variables, puntos de tiempo como casos), pero igualmente podrías querer hacer un análisis donde pienses que los tiempos son las cosas de interés (es decir, tiempos como variables, pasteles como casos). Si es así, entonces es útil saber cómo voltear una matriz o un marco de datos.