J'ai une variable factorielle qui est composée de deux sous-chaînes séparées par un _
, comme string1_string2
. Je veux définir les niveaux de facteur du préfixe ("string1") et du suffixe ("string2") séparément, puis définir un ensemble global de niveaux de facteur pour la chaîne concaténée. De plus, la priorité des niveaux dans la première par rapport à la deuxième sous-chaîne peut varier.
Un petit exemple de ce que je veux réaliser:
[1] DBO_A PH_A COND_A DBO_B PH_B COND_B DBO_C PH_C COND_C Levels: PH_B COND_B DBO_B PH_A COND_A DBO_A PH_C COND_C DBO_C
Si je ne définissez pas les niveaux de facteurs, ils seront classés par ordre alphabétique. Maintenant, je veux définir les niveaux des chaînes à gauche et à droite du séparateur _
, par exemple
De plus, je souhaite spécifier quel côté, LHS ou RHS, a priorité sur l'autre. Selon le côté qui a la priorité, l'ordre général des niveaux sera différent:
(1) Si les niveaux sur LHS sont précédents:
[1] DBO_A PH_A COND_A DBO_B PH_B COND_B DBO_C PH_C COND_C Levels: PH_B PH_A PH_C COND_B COND_A COND_C DBO_B DBO_A DBO_C
4 Réponses :
Que diriez-vous de quelque chose comme
x <- with(expand.grid(x = c("DBO", "PH", "COND"), y = c("A", "B", "C")), factor(paste(x, y, sep = "_"), levels = paste(x, y, sep = "_")))
Vous n'avez pas besoin d'écrire tous les niveaux possibles, juste les niveaux d'un côté et de l'autre.
Pouvez-vous dire comment non? Compte tenu de la façon dont vous avez utilisé expand.grid, coller sera ordonné d'abord par x et ensuite par y, c'est ainsi que j'ai compris ce dont vous aviez besoin.
L'essentiel n'est pas de savoir comment je produis mon x
. Ce sont juste des données reproductibles. Veuillez lire ma sortie attendue.
x
dans ma question est une donnée donnée. Ce que je veux, c'est comment utiliser x
pour obtenir les deux données attendues.
@DarrenTsai Je ne comprends pas, x
est donné, oui, et y
ne l'est pas? Vous voulez obtenir y
à partir de x
? La fonction dans ma réponse fait ce que vous décrivez dans la question.
Oui, tellement génial !! Merci beaucoup.
Mais comment puis-je obtenir ma deuxième sortie attendue? custom_fct2 (x, b, a)
?
Nous pouvons utiliser base R
pour ce faire. En utilisant sub
supprimer la sous-chaîne dans les niveaux
du vecteur, avec match
créer un index numérique en vérifiant les valeurs qui sont dans l'ordre personnalisé, réaffecter les niveaux
du facteur
par ordre
en suivant la séquence des niveaux
de vecteur en fonction de la correspondance
index
f1 <- function(vec, lvls1, lvls2, flag = "former") { i1 <- match(sub("_.*", "", levels(vec)), lvls1) i2 <- match(sub(".*_", "", levels(vec)), lvls2) if(flag == 'former') { factor(vec, levels = levels(vec)[seq_along(levels(vec))[order(i1, i2)]]) } else { factor(vec, levels = levels(vec)[seq_along(levels(vec))[order(i2, i1)]]) } } f1(x, c("PH", "COND", "DBO"), c("B", "A", "C")) #[1] DBO_A PH_A COND_A DBO_B PH_B COND_B DBO_C PH_C COND_C #Levels: PH_B PH_A PH_C COND_B COND_A COND_C DBO_B DBO_A DBO_C f1(x, c("PH", "COND", "DBO"), c("B", "A", "C"), flag = "latter") #[1] DBO_A PH_A COND_A DBO_B PH_B COND_B DBO_C PH_C COND_C #Levels: PH_B COND_B DBO_B PH_A COND_A DBO_A PH_C COND_C DBO_C
Pour le second cas, inversez simplement l'index dans order
factor(x, levels = levels(x)[seq_along(levels(x))[order(i2, i1)]])
Pour une utilisation répétée, peut être enveloppé dans une fonction
i1 <- match(sub("_.*", "", levels(x)), c("PH", "COND", "DBO")) i2 <- match(sub(".*_", "", levels(x)), c("B", "A", "C")) factor(x, levels = levels(x)[seq_along(levels(x))[order(i1, i2)]])
hé, votre méthode est excellente mais vous modifiez mes données d'origine. Vous pouvez comparer mes données attendues et votre sortie.
@DarrenTsai Désolé, j'ai oublié de vérifier la sortie. Merci d'avoir fait remarquer cela. Fixé
À l'aide des fonctions pratiques data.table
tstrsplit
et setorderv
.
Créez un vecteur de noms de colonnes (arbitraires) pour les sous-chaînes ( cols ). Convertissez le vecteur en
data.table
( d ). Divisez le vecteur en deux colonnes (
(cols): = tstrsplit (x, split = "_")
). Définissez les niveaux de facteur des sous-chaînes ( factor (V1, levels = l1)
). Triez les données soit par la première sous-chaîne puis la deuxième sous-chaîne, soit par la deuxième puis par la première ( setorderv (d, if (prec == 1) cols else rev (cols))
). Utilisez la colonne ordonnée 'x' de la table data.table comme niveaux de facteur du vecteur 'x' ( factor (x, levels = d $ x)
).
f2 <- function(x, l1, l2, prec){ m <- cbind(factor(sub("_.*", "", x), l1), factor(sub(".*_", "", x), l2)) i <- c(1, 2, 1)[prec:(prec + 1)] factor(x, levels = as.character(x)[order(m[ , i[1]], m[ , i[2]])])} f2(x, l1, l2, prec = 1) # [1] DBO_A PH_A COND_A DBO_B PH_B COND_B DBO_C PH_C COND_C # Levels: PH_B PH_A PH_C COND_B COND_A COND_C DBO_B DBO_A DBO_C f2(x, l1, l2, prec = 2) # [1] DBO_A PH_A COND_A DBO_B PH_B COND_B DBO_C PH_C COND_C # Levels: PH_B COND_B DBO_B PH_A COND_A DBO_A PH_C COND_C DBO_C
Une alternative base
, dans le même esprit, mais en plaçant des sous-chaînes dans une matrice à la place. Utilisez une expression régulière standard (voir par exemple ici ) pour récupérer des sous-chaînes. Convertir en facteur et définir les niveaux. Créez un index de colonne ( i ). Niveaux d'ordre de 'x' (
as.character (x) [order (m [ i [1]], m [ i [2]])])
).
library(data.table) f <- function(x, l1, l2, prec){ cols <- c("V1", "V2") d <- data.table(x) d[ , (cols) := tstrsplit(x, split = "_")] d[ , `:=`( V1 = factor(V1, levels = l1), V2 = factor(V2, levels = l2))] setorderv(d, if(prec == 1) cols else rev(cols)) factor(x, levels = d$x) } # First substring has precedence f(x, l1 = c("PH", "COND", "DBO"), l2 = c("B", "A", "C"), prec = 1) # [1] DBO_A PH_A COND_A DBO_B PH_B COND_B DBO_C PH_C COND_C # Levels: PH_B PH_A PH_C COND_B COND_A COND_C DBO_B DBO_A DBO_C # Second substring has precedence f(x, l1 = c("PH", "COND", "DBO"), l2 = c("B", "A", "C"), prec = 2) # [1] DBO_A PH_A COND_A DBO_B PH_B COND_B DBO_C PH_C COND_C # Levels: PH_B COND_B DBO_B PH_A COND_A DBO_A PH_C COND_C DBO_C
C'est ce dont j'ai besoin. Merci beaucoup pour cette réponse et la révision de ma question.
Je le vois. Cela fonctionne comme je veux. Je suis tellement reconnaissant de votre gentillesse.