특정 순서로 벡터에 따라 데이터 프레임 행 순서


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순서대로 반환 합니다.


좋아, 그게 더 좋았고 내가 찾던 것과 똑같아! 대단히 감사합니다
Rappster

1
한 가지 질문, 일치시키려는 열에 반복 값이 있으면 어떻게됩니까? 처럼 b,c,a,d,b,c,a,d. 시도 match했지만 제대로 작동하지 않습니다.
Yulong

@Yulong : 발사하기 전에 복제물을 제거했는지 명시 적으로 확인해야한다고 생각합니다 match(). 무엇을 마음에 오는 것은 duplicated(), unique()또는 다른 사람을 멀리 던지는 동안 원하는 요소를 "유지"몇 가지 다른 사용자 지정 루틴. HTH
랩 스터

@ 에드워드 그것은 좋은 해결책입니다. 그러나 인덱스도 변경됩니다. 어떻게 오름차순으로 유지할 수 있습니까 (1, 2, 3, 4)?
Hasan Iqbal 2016 년

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 Fary

21

내가 사용하는 것을 선호 ***_joindplyr나는 데이터와 일치해야 할 때마다. 이것에 대한 한 가지 가능한 시도

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

에 대한 입력 ***_join에는 tbls 또는 data.frame 이 필요합니다.


예, * _join 함수 dplyr는 정말 좋습니다. 뿐만 아니라 지금이 많은입니다를 사용하여 종료
Rappster

이 경우 data.frame ()을 요인으로 변환하지 않도록 대상 순서를 티 블로 선언하는 것이 좋습니다. target <- tibble(name = c("b", "c", "a", "d"))
쐐기풀

2
그리고 파이프 구문 :df %>% right_join(tibble(name = target), by = "name")
Frank

18

이 방법은 약간 다르므로 이전 답변보다 약간 더 유연합니다. 그것을 주문 된 요소로 만들면 잘 사용할 수 있습니다 arrange. gdata패키지 에서 reorder.factor를 사용했습니다 .

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 버전을 알고 있습니까?
Reilstein

2
@ 레일스 타인 setDT(df)[ , name := factor(name, levels = target)]. 그렇다면 두 가지 data.table답변을 보십시오
Henrik

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
최고의 솔루션 IMO
stevec

1
나에게 가장 좋고 가장 간단한 해결책.
Matt_B

0

라이브러리를 사용하지 않고 데이터에 재발하는 경우 which함께 사용할 수도 있습니다 sapply.

new_order <- sapply(target, function(x,df){which(df$name == x)}, df=df)
df        <- df[new_order,]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.