web-dev-qa-db-fra.com

Trier un facteur en fonction de la valeur dans une ou plusieurs autres colonnes

J'ai parcouru un certain nombre de messages sur les facteurs de commande, mais je n'ai pas encore trouvé de solution à mon problème. Malheureusement, ma connaissance de R est encore assez rudimentaire.

J'ai un sous-ensemble d'un catalogue d'artefacts archéologiques avec lequel je travaille. J'essaie de croiser les types d'artefacts historiques de diagnostic et les emplacements de test de site. Assez facile avec ddply ou tapply.

Mon problème est que je veux trier les types d'artefacts (un facteur) par leur date de diagnostic moyenne (nombre/année), et je continue de les obtenir par ordre alphabétique. Je sais que je dois en faire un facteur ordonné, mais je ne sais pas comment le commander par la valeur de l'année dans l'autre colonne.

IDENTIFY                                      MIDDATE
engine-turned fine red stoneware              1769
white salt-glazed stoneware, scratch blue     1760
wrought nail, 'L' head                        1760
yellow lead-glazed buff earthenware           1732
...

Qui doit être commandé:

IDENTIFY                                      MIDDATE
yellow lead-glazed buff earthenware           1732
white salt-glazed stoneware, scratch blue     1760
wrought nail, 'L' head                        1760
engine-turned fine red stoneware              1769
...

Le facteur (IDENTIFY) doit être commandé par la date (MIDDATE). Je pensais l'avoir avec

Catalog$IDENTIFY<-factor(Catalog$IDENTIFY,levels=Catalog$MIDDATE,ordered=TRUE)

Mais recevez l'avertissement:

In `levels<-`(`*tmp*`, value = if (nl == nL) as.character(labels) 
else paste0(labels,: duplicated levels will not be allowed 
in factors anymore

IDENTIFY a ~ 130 niveaux de facteur et beaucoup ont la même valeur pour MIDDATE, donc je dois commander IDENTIFY by MIDDATE et une autre colonne TYPENAME.

Un peu plus en détail:

J'ai un dataframe Catalog, qui se décompose (c'est-à-dire str(Catalog)) comme:

> str(Catalog)
'data.frame':   2211 obs. of  15 variables:
 $ TRENCH  : Factor w/ 7 levels "DRT 1","DRT 2",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ U_TYPE  : Factor w/ 3 levels "EU","INC","STP": 1 1 1 1 1 1 1 1 1 1 ...
 $ U_LBL   : Factor w/ 165 levels "001","005","007",..: 72 72 72 72 72 72 ...
 $ L_STRAT : Factor w/ 217 levels "#2-7/25","[3]",..: 4 4 4 4 4 4 89 89 89 89 ...
 $ START   : num  0 0 0 0 0 0 39.4 39.4 39.4 39.4 ...
 $ END     : num  39.4 39.4 39.4 39.4 39.4 39.4 43.2 43.2 43.2 43.2 ...
 $ Qty     : int  1 1 3 5 1 1 6 8 1 1 ...
 $ MATNAME : Factor w/ 6 levels "Ceramics","Chipped Stone",..: 1 1 1 5 5 6 ...
 $ TYPENAME: Factor w/ 9 levels "Architectural Hardware",..: 9 9 9 1 1 3 9 ...
 $ CATNAME : Factor w/ 32 levels "Biface","Bottle Glass",..: 24 29 29 6 24 ...
 $ IDENTIFY: Factor w/ 112 levels "amethyst bottle glass",..: 17 91 96 71 103 ...
 $ BEGDATE : int  1820 1820 1830 1835 1700 NA 1670 1762 1800 1720 ...
 $ ENDDATE : int  1900 1970 1860 1875 1820 NA 1795 1820 1820 1780 ...
 $ OCC_LBL : Ord.factor w/ 5 levels "Late 19th Century"<..: 2 1 2 2 4 5 4 3 ...
 $ MIDDATE : num  1860 1895 1845 1855 1760 ...

Je dois faire de IDENTIFY un facteur ordonné et réorganiser par MIDDATE -> TYPENAME -> alpha par IDENTIFY.

Ce que je ne comprends pas vraiment, c'est comment réorganiser les commandes combinées à partir de plusieurs colonnes.

Je le ferais simplement dans la base de données, mais une grande partie de ce que j'exécute sont des moyens pondérés dans toutes sortes de tableaux croisés (par exemple, les profondeurs moyennes pondérées sous la surface du sol pour les classes d'artefacts par emplacement) ...

... faisable dans Access, mais désordonné et imprévisible. Beaucoup plus facile et plus propre à gérer dans R, mais je préfère ne pas avoir à trier manuellement les tableaux résultants.

Ce que j'essaie de produire, c'est un certain nombre de choses dans ce sens:

>xtab.Catalog<-tapply(Catalog$Qty,list(Catalog$IDENTIFY,Catalog$TRENCH),sum)

IDENTIFY                        DRT1    DRT2    DRT3    DRT4    DRT5    DRT6
Staffordshire stoneware         4       NA      NA      NA      NA      NA  
undecorated delftware           6       4       NA      NA      NA      NA  
unidentified wrought nail       15      9       3       1       3       NA  
white salt-glazed stoneware     6       1       1       NA      2       1   
white salt-glazed scratch blue  1       NA      NA      NA      NA      NA  
white stoneware, slip-dipped    NA      NA      NA      NA      NA      NA  
wrought nail, 'L' head          2       NA      NA      NA      NA      NA  
wrought nail, 'rose' head       62      21      4       NA      1       1   
wrought nail, 'T' head          2       NA      1       NA      NA      1   
yellow lead-glazed              12      NA      NA      NA      1       3   
...

... mais j'en ai besoin pour trier dans l'ordre logique (c'est-à-dire chronologique/type) au lieu de l'ordre alphabétique.

31
Scard

Voici un échantillon reproductible, avec solution:

set.seed(0)
a = sample(1:20,replace=F)
b = sample(1:20,replace=F)
f = as.factor(letters[1:20])

> a
 [1] 18  6  7 10 15  4 13 14  8 20  1  2  9  5  3 16 12 19 11 17
> b
 [1] 16 18  4 12  3  5  6  1 15 10 19 17  9 11  2  8 20  7 13 14
> f
 [1] a b c d e f g h i j k l m n o p q r s t
Levels: a b c d e f g h i j k l m n o p q r s t

Maintenant pour le nouveau facteur:

fn = factor(f, levels=unique(f[order(a,b,f)]), ordered=TRUE)

> fn
 [1] a b c d e f g h i j k l m n o p q r s t
20 Levels: k < l < o < f < n < b < c < i < m < d < s < q < g < h < e < ... < j

Trié sur "a", "b" suivant et enfin "f" lui-même (bien que dans cet exemple, "a" n'ait pas de valeurs répétées).

40
Matthew Lundberg

Je recommande l'approche basée sur dplyr suivante (h/t daattali ) qui peut être étendue à autant de colonnes que vous le souhaitez:

library(dplyr)
Catalog <- Catalog %>%
  arrange(MIDDATE, TYPENAME) %>%               # sort your dataframe
  mutate(IDENTIFY = factor(IDENTIFY, unique(IDENTIFY))) # reset your factor-column based on that order
23
zach

La fonction fct_reorder2 fait exactement cela.

Veuillez noter la subtilité que fct_reorder est trié par ordre croissant pendant que fct_reordering2 est trié par ordre décroissant.

Code de la documentation:

df0 <- tibble::tribble(
  ~color,     ~a, ~b,
  "blue",      1,  2,
  "green",     6,  2,
  "purple",    3,  3,
  "red",       2,  3,
  "yellow",    5,  1

)

df0$color <- factor(df0$color)
fct_reorder(df0$color, df0$a, min)
 #> [1] blue   green  purple red    yellow
 #> Levels: blue red purple yellow green
fct_reorder2(df0$color, df0$a, df0$b)
0
YCR