es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Por qué `stack` no puede funcionar en el resultado de `tapply`?

Suponiendo que tengo un marco de datos df

> dput(df) 
estructura(list(x = c("X", "X", "X", "Y", "Y", "Z", "Z", "Z"), y = c("A", "B", "C", "B", "C", "A", "C", "D")), class = "data.frame", row.names = c(NA, -8L)) 
> df 
  x y 
1 X A 
2 X B 
3 X C 
4 Y B 
5 Y C 
6 Z A 
7 Z C 
8 Z D

y generar una lista u1 como se muestra a continuación

u1 <- with(df, tapply(y, x, combn, 2, toString)) 

donde

> u1 
$ X 
[1] "A, B" "A, C" "B, C" 
$ Y 
[1] "B, C" 
$ Z 
[1] "A, C" "A, D" "C, D" 
> str(u1) 
List of 3 
 $ X: chr [1:3(1d)] "A, B" "A, C" "B, C" 
 $ Y: chr [1(1d)] "B, C" 
 $ Z: chr [1:3(1d)] "A, C" "A, D" "C, D" 
 - attr(<em>, "dim")= int 3 
 - attr(</em>, "dimnames")=List of 1 
  ..$ : chr [1:3] "X" "Y" "Z"

Cuando ejecuto stack(u1), obtendré el siguiente error

 > stack(u1) 
Error in stack.default(u1) : se requiere al menos un elemento del vector 

Parece que no puedo utilizar stack directamente sobre la salida de tapply, incluso si es una lista con nombres.

Sin embargo, cuando uso u2 <- Map(c, u1) para el postprocesamiento, las cosas vuelven a funcionar

> u2 <- Map(c, u1)

> u2 
$ X 
[1] "A, B" "A, C" "B, C" 
$ Y 
[1] "B, C" 
$ Z 
[1] "A, C" "A, D" "C, D" 

> str(u2) 
List of 3 
 $ X: chr [1:3] "A, B" "A, C" "B, C" 
 $ Y: chr "B, C" 
 $ Z: chr [1:3] "A, C" "A, D" "C, D" 

> stack(u2) 
 values ind 
1 A, B X 
2 A, C X 
3 B, C X 
4 B, C Y 
5 A, C Z 
6 A, D Z 
7 C, D Z 

Como podemos ver, en str(u2), los atributos se filtran, lo que parece solucionar el problema.

Mi pregunta es: ¿Por qué falla u1 pero tiene éxito u2? ¿Hay alguna otra forma en la que pueda usar tapply sobre u1 sin ningún postprocesamiento (como Map(c, u1))?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    La razón por la que stack(u1) falló es que tapply crea un arreglo multidimensional con atributos como dim y dimnames, que no es compatible con stack. Por otro lado, Map(c, u1) colapsa las dimensiones y elimina los atributos, convirtiéndolo en una lista regular con nombres que stack puede manejar.

    Si quieres evitar el procesamiento posterior y mantener los atributos, puedes usar unlist con el argumento recursive = FALSE para preservar las dimensiones como una lista nombrada:

    u3 <- with(
      df,
      tapply(y, x, combn, 2, toString)
    )
    
    u3 <- unlist(u3, recursive = FALSE)
    
    stack(u3)
    

    Esto debería producir el mismo resultado que stack(u2).

Comments are closed.