Rijen van dataframes ordenen volgens vector met een specifieke volgorde

Is er een eenvoudigere manier om ervoor te zorgen dat de rijen van een dataframe worden geordend volgens een “doel”-vector zoals die ik in het korte voorbeeld hieronder heb geïmplementeerd?

df <- data.frame(name = letters[1:4], value = c(rep(TRUE, 2), rep(FALSE, 2)))
df
#   name value
# 1    a  TRUE
# 2    b  TRUE
# 3    c FALSE
# 4    d FALSE
target <- c("b", "c", "a", "d")

Dit lijkt op de een of andere manier een beetje te “gecompliceerd” om de klus te klaren:

idx <- sapply(target, function(x) {
    which(df$name == x)
})
df <- df[idx,]
rownames(df) <- NULL
df 
#   name value
# 1    b  TRUE
# 2    c FALSE
# 3    a  TRUE
# 4    d FALSE

Antwoord 1, autoriteit 100%

Probeer match:

df <- data.frame(name=letters[1:4], value=c(rep(TRUE, 2), rep(FALSE, 2)))
target <- c("b", "c", "a", "d")
df[match(target, df$name),]
  name value
2    b  TRUE
3    c FALSE
1    a  TRUE
4    d FALSE

Het werkt zolang uw targetexact dezelfde elementen bevat als df$nameen geen van beide dubbele waarden bevat.

Van ?match:

match returns a vector of the positions of (first) matches of its first argument 
in its second.

Daarom vindt matchde rijnummers die overeenkomen met de elementen van target, en dan retourneren we dfin die volgorde.


Antwoord 2, autoriteit 11%

Ik gebruik liever ***_joinin dplyrwanneer ik gegevens moet matchen. Een mogelijke poging hiervoor

left_join(data.frame(name=target),df,by="name")

Houd er rekening mee dat de invoer voor ***_jointbls of data.frame vereist


Antwoord 3, autoriteit 9%

We kunnen de factorniveaus aanpassen op basis van targeten deze gebruiken in arrange

library(dplyr)
df %>% arrange(factor(name, levels = target))
#  name value
#1    b  TRUE
#2    c FALSE
#3    a  TRUE
#4    d FALSE

Of orderhet en gebruik het in slice

df %>% slice(order(factor(name, levels = target)))

Antwoord 4, autoriteit 7%

Deze methode is een beetje anders, het gaf me wat meer flexibiliteit dan het vorige antwoord.
Door er een geordende factor van te maken, kun je het mooi gebruiken in arrangeen dergelijke. Ik heb reorder.factor uit het pakket gdatagebruikt.

df <- data.frame(name=letters[1:4], value=c(rep(TRUE, 2), rep(FALSE, 2)))
target <- c("b", "c", "a", "d")
require(gdata)
df$name <- reorder.factor(df$name, new.order=target)

Gebruik vervolgens het feit dat het nu besteld is:

require(dplyr)
df %>%
  arrange(name)
    name value
1    b  TRUE
2    c FALSE
3    a  TRUE
4    d FALSE

Als je terug wilt naar de oorspronkelijke (alfabetische) volgorde, gebruik je gewoon as.character()om het terug te brengen naar de oorspronkelijke staat.


Antwoord 5

Als je geen bibliotheken wilt gebruiken en je hebt herhalingen in je gegevens, dan kun je whichook gebruiken met sapply.

new_order <- sapply(target, function(x,df){which(df$name == x)}, df=df)
df        <- df[new_order,]

Antwoord 6

Hier is een soortgelijk systeem voor de situatie waarin u een variabele hebt waarop u aanvankelijk wilt sorteren, maar vervolgens wilt sorteren op een secundaire variabele volgens de volgorde waarin deze secundaire variabele voor het eerst voorkomt bij de eerste sortering.

p>

In de onderstaande functie wordt de initiële sorteervariabele order_bygenoemd en de secundaire variabele order_along– zoals in “volgorde op deze variabele in de beginvolgorde”.

library(dplyr, warn.conflicts = FALSE)
df <- structure(
  list(
    msoa11hclnm = c(
      "Bewbush", "Tilgate", "Felpham",
      "Selsey", "Brunswick", "Ratton", "Ore", "Polegate", "Mile Oak",
      "Upperton", "Arundel", "Kemptown"
    ),
    lad20nm = c(
      "Crawley", "Crawley",
      "Arun", "Chichester", "Brighton and Hove", "Eastbourne", "Hastings",
      "Wealden", "Brighton and Hove", "Eastbourne", "Arun", "Brighton and Hove"
    ),
    shape_area = c(
      1328821, 3089180, 3540014, 9738033, 448888, 10152663, 5517102,
      7036428, 5656430, 2653589, 72832514, 826151
    )
  ),
  row.names = c(NA, -12L), class = "data.frame"
)

dit geeft me niet wat ik nodig heb:

df %>% 
  dplyr::arrange(shape_area, lad20nm)
#>    msoa11hclnm           lad20nm shape_area
#> 1    Brunswick Brighton and Hove     448888
#> 2     Kemptown Brighton and Hove     826151
#> 3      Bewbush           Crawley    1328821
#> 4     Upperton        Eastbourne    2653589
#> 5      Tilgate           Crawley    3089180
#> 6      Felpham              Arun    3540014
#> 7          Ore          Hastings    5517102
#> 8     Mile Oak Brighton and Hove    5656430
#> 9     Polegate           Wealden    7036428
#> 10      Selsey        Chichester    9738033
#> 11      Ratton        Eastbourne   10152663
#> 12     Arundel              Arun   72832514

Hier is een functie:

order_along <- function(df, order_along, order_by) {
  cols <- colnames(df)
  df <- df %>%
    dplyr::arrange({{ order_by }})
  df %>% 
    dplyr::select({{ order_along }}) %>% 
    dplyr::distinct() %>% 
    dplyr::full_join(df) %>% 
    dplyr::select(dplyr::all_of(cols))
}
order_along(df, lad20nm, shape_area)
#> Joining, by = "lad20nm"
#>    msoa11hclnm           lad20nm shape_area
#> 1    Brunswick Brighton and Hove     448888
#> 2     Kemptown Brighton and Hove     826151
#> 3     Mile Oak Brighton and Hove    5656430
#> 4      Bewbush           Crawley    1328821
#> 5      Tilgate           Crawley    3089180
#> 6     Upperton        Eastbourne    2653589
#> 7       Ratton        Eastbourne   10152663
#> 8      Felpham              Arun    3540014
#> 9      Arundel              Arun   72832514
#> 10         Ore          Hastings    5517102
#> 11    Polegate           Wealden    7036428
#> 12      Selsey        Chichester    9738033

Gemaakt op 2021-01-12 door het reprex-pakket(v0.3.0)

Other episodes