¿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
aprendiz
fuente

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
Becarios Ian
fuente
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))]
George Dontas
fuente
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.

Matt Parker
fuente
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)

Ben Bolker
fuente
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
Georgie Shimanovsky
fuente
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
Shane
fuente
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).

Godeke
fuente
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]]
Dios mio
fuente