¿Cómo clasifico un vector en función de los valores de otro?


112

Tengo un vector x, que me gustaría ordenar según el orden de los valores en el vector y. Los dos vectores no tienen la misma longitud.

x <- c(2, 2, 3, 4, 1, 4, 4, 3, 3)
y <- c(4, 2, 1, 3)

El resultado esperado sería:

[1] 4 4 4 2 2 1 3 3 3

Respuestas:


70

Aquí hay un trazador de líneas ...

y[sort(order(y)[x])]

[editar:] Esto se desglosa de la siguiente manera:

order(y)             #We want to sort by y, so order() gives us the sorting order
order(y)[x]          #looks up the sorting order for each x
sort(order(y)[x])    #sorts by that order
y[sort(order(y)[x])] #converts orders back to numbers from orders

1
Eso es muy sucinto, pero me está costando entender qué está pasando allí. Podrías elaborar un poco?
Matt Parker

3
Esto es bonito y muestra una buena comprensión de las funciones integradas de R. +1
Godeke

6
En general, uno puede querer hacer esto incluso si y no es una permutación de 1: longitud (y). En ese caso, esta solución no funciona, pero la siguiente solución de gd047, x [order (match (x, y))], sí.
Rahul Savani

5
De hecho, estoy desconcertado de por qué esto tiene 40 votos a favor. Falla por tantas variaciones simples en xy y. x <- c(1,4,2); y <- c(1,2,4)por ejemplo.
thelatemail

1
@thelatemail estoy de acuerdo. ¡Detén la locura y rechaza esta respuesta!
Ian Fellows

184

que hay de este

x[order(match(x,y))]

29
Esto es muy bueno, mejor que la respuesta aceptada en mi humilde opinión, ya que es más general.
fmark

2
Me atrevería a decir que esto debería estar en GNU-R base.
falla catastrófica

Esta respuesta me funcionó bien al usar vectores de caracteres tanto para x como para y. Agregar una descomposición / ligera elaboración como en la respuesta aceptada sería bueno
mavericks

4

Podría convertir xen un factor ordenado:

x.factor <- factor(x, levels = y, ordered=TRUE)
sort(x)
sort(x.factor)

Obviamente, cambiar sus números en factores puede cambiar radicalmente la forma en que reacciona el código aguas abajo x. Pero como no nos dio ningún contexto sobre lo que sucederá a continuación, pensé en sugerir esto como una opción.


1
esta debería ser la mejor respuesta ya que funcionaría para casos no enteros; o también funciona cuando hay valores que xno están en el vector de clasificación ycon un ligero cambio:x <- c(2, 2, 3, 4, 1, 4, 4, 3, 3, 6); y <- c(4, 2, 1, 3); as.numeric(as.character(sort(factor(x, unique(c(y, x))))))
rawr

2

¿Qué tal si?:

rep(y,table(x)[as.character(y)])

(El de Ian probablemente sea aún mejor)


2

En caso de que necesite ordenar en "y" sin importar si son números o caracteres:

x[order(ordered(x, levels = y))]
4 4 4 2 2 1 3 3 3

Por pasos:

a <- ordered(x, levels = y) # Create ordered factor from "x" upon order in "y".
[1] 2 2 3 4 1 4 4 3 3
Levels: 4 < 2 < 1 < 3

b <- order(a) # Define "x" order that match to order in "y".
[1] 4 6 7 1 2 5 3 8 9

x[b] # Reorder "x" according to order in "y".
[1] 4 4 4 2 2 1 3 3 3

1

[ Editar: Claramente Ian tiene el enfoque correcto, pero dejaré esto para la posteridad].

Puede hacer esto sin bucles indexando en su vector y. Agregue un valor numérico creciente ay y combínelos:

y <- data.frame(index=1:length(y), x=y)
x <- data.frame(x=x)
x <- merge(x,y)
x <- x[order(x$index),"x"]
x
[1] 4 4 4 2 2 1 3 3 3

0
x <- c(2, 2, 3, 4, 1, 4, 4, 3, 3)
y <- c(4, 2, 1, 3)
for(i in y) { z <- c(z, rep(i, sum(x==i))) }

El resultado en z: 4 4 4 2 2 1 3 3 3

Los pasos importantes:

  1. for (i in y): recorre los elementos de interés.

  2. z <- c (z, ...) - Concatena cada subexpresión a su vez

  3. rep (i, sum (x == i)) - Repite i (el elemento actual de interés) sum (x == i) veces (el número de veces que encontramos i en x).


0

También puedes usarlo sqldfy hacerlo mediante una joinfunción sqlcomo la siguiente:

library(sqldf)
x <- data.frame(x = c(2, 2, 3, 4, 1, 4, 4, 3, 3))
y <- data.frame(y = c(4, 2, 1, 3))

result <- sqldf("SELECT x.x FROM y JOIN x on y.y = x.x")
ordered_x <- result[[1]]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.