Укажіть рядки кадрів даних відповідно до вектора з конкретним порядком


158

Чи є більш простий спосіб забезпечити впорядкування рядків кадру даних відповідно до "цільового" вектора, як той, який я реалізував у короткому прикладі нижче?

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")

Це якось здається трохи надто "складним", щоб виконати роботу:

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

Відповіді:


232

Спробуйте 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

Він буде працювати до тих пір, поки ваш targetмістить точно такі самі елементи, як df$nameі не містить дублюючих значень.

Від ?match:

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

Тому matchзнаходимо номери рядків, що відповідають targetелементам, і повертаємося dfв тому порядку.


Чудово, це більше подобається і саме те, що я шукав! Велике спасибі
Раппстер

1
одне питання, що робити, якщо стовпець, з яким я хотів би відповідати, має значення повторення? як b,c,a,d,b,c,a,d. Я спробував, matchале це не працює добре.
Юлонг

@Yulong: Я думаю, вам доведеться чітко переконатися, що дублікати видалено перед запуском match(). Що спадає на думку duplicated(), unique()чи якийсь інший користувальницький розпорядок, який «утримує» бажані елементи, викидаючи інші. HTH
Раппстер

@Edward - це приємне рішення. Однак це також змінює показники. Як я можу також зберегти їх у порядку зростання (1, 2, 3, 4)?
Хасан Ікбал

2
не впевнений, що це найчистіший спосіб, але з лише базовими функціями це має спрацювати, якщо у вас є дублікати в df:df <- data.frame(name=letters[c(1:4, 1:4)], value=c(rep(TRUE, 2), rep(FALSE, 2),rep(TRUE, 2), rep(FALSE, 2) )) target <- c("b", "c", "a", "d") df[order(unlist(sapply(df$name, function(x) which(target == x)))),]
Erica

21

Я вважаю за краще використовувати ***_join в dplyrвипадках , коли мені потрібно , щоб відповідати даним. Одне можливе спробу цього

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

Зауважте, що для введення ***_joinпотрібні tbls або data.frame


Так, функції _ _ приєднання dplyrсправді приємні.
Нарешті,

У такому випадку рекомендуйте оголошувати цільовий порядок як таблицю, щоб уникнути перетворення data.frame () у фактори. target <- tibble(name = c("b", "c", "a", "d"))
Кропива

2
І з синтаксисом труби:df %>% right_join(tibble(name = target), by = "name")
Френк

18

Цей метод дещо інший, він надав мені трохи більшої гнучкості, ніж попередня відповідь. Перетворивши його в упорядкований фактор, ви зможете красиво використовувати його у arrangeподібному. Я використовував reorder.factor з gdataпакету.

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)

Далі, використовуйте той факт, що зараз замовлено:

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

Якщо ви хочете повернутися до початкового (алфавітного) замовлення, просто використовуйте as.character()для повернення його до початкового стану.


2
Хтось знає версію цього файлу data.table?
Рейльштейн

2
@Reilstein setDT(df)[ , name := factor(name, levels = target)]. Потім дивіться дві data.tableвідповіді тут
Генрік

4

Ми можемо коригувати рівні факторів на основі targetта використовувати їхarrange

library(dplyr)
df %>% arrange(factor(name, levels = target))

#  name value
#1    b  TRUE
#2    c FALSE
#3    a  TRUE
#4    d FALSE

Або orderце і використовувати його вslice

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

2
Найкраще рішення ІМО
stevec

1
Найкращі та найпростіші для мене рішення.
Matt_B

0

Якщо ви не хочете користуватися жодною бібліотекою, а у ваших даних повторне виникнення, ви можете також використовувати whichїх sapply.

new_order <- sapply(target, function(x,df){which(df$name == x)}, df=df)
df        <- df[new_order,]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.