web-dev-qa-db-fra.com

Pourquoi `Stack` ne peut pas travailler sur le résultat de` Tapply`?

En supposant que j'ai un cadre de données df

> dput(df)
structure(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

et générer une liste u1 comme ci-dessous

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

> 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(*, "dim")= int 3
 - attr(*, "dimnames")=List of 1
  ..$ : chr [1:3] "X" "Y" "Z"

Quand j'ai couru stack(u1), j'aurai l'erreur suivante

> stack(u1)
Error in stack.default(u1) : at least one vector element is required

Il semble que je ne puisse pas utiliser stack sur la sortie de tapply directement même s'il s'agit d'une liste nommée.

Cependant, lorsque j'utilise u2 <- Map(c,u1) pour post-traitement, les choses obtiennent des choses à nouveau

> 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

Comme nous pouvons le constater, dans str(u2), les attributs sont filtrés, ce qui semble résoudre le problème.


ma question est :

Pourquoi u1 A échoué mais u2 A réussi? Y a-t-il une autre façon que je puisse utiliser tapply sur u1 Sans post-traitement (comme Map(c, u1))?

2
ThomasIsCoding

Ou peut également utiliser as.vector/c Pour supprimer les attributs et convertir le 1d Vecteur à un vecteur sans attributs sombres

stack(lapply(u1, c))
  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

Selon ?stack

Notez que la pile s'applique à Vecteurs (comme déterminé par IS.Vector): Les colonnes non vectorielles (par exemple, facteurs) seront ignorées avec un avertissement.

Le is.vector retourne FALSE pour tous les éléments membres de 'U1'

> sapply(u1, is.vector)
    X     Y     Z 
FALSE FALSE FALSE 

Comme @Gregortoomas mentionné à propos de l'argument simplify dans tapply, il existe également une option simplify dans combn qui est vrai par défaut. Si nous spécifions que FALSE, il renvoie un list et devrait fonctionner

u1 <- with(
  df,
  tapply(y, x, FUN = function(u) combn(u, 2, FUN = toString, simplify = FALSE))
)
> stack(u1)
  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

Cependant, cela fonctionne avec enframe sur le 1d vecteur aussi

library(tibble)
library(tidyr)
enframe(u1) %>%
   unnest(value)
# A tibble: 7 × 2
  name  value
  <chr> <chr>
1 X     A, B 
2 X     A, C 
3 X     B, C 
4 Y     B, C 
5 Z     A, C 
6 Z     A, D 
7 Z     C, D 
1
akrun