Veri çerçevesi satırlarını belirli bir sırayla vektöre göre sıralayın


158

Bir veri çerçevesinin satırlarının aşağıdaki kısa örnekte uyguladığım gibi bir "hedef" vektöre göre sıralanmasını sağlamanın daha kolay bir yolu var mı?

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

Bu bir şekilde işi yapmak için biraz "karmaşık" gibi görünüyor:

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

Yanıtlar:


232

Deneyin 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

Sizin targetöğenizle tam olarak aynı öğeleri içerdiği sürece çalışır df$nameve yinelenen değerler içermez.

Gönderen ?match:

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

Bu nedenle match, targetöğelerinin öğelerine uyan satır numaralarını bulur ve sonra dfbu sırayla geri döneriz.


Harika, bu daha çok ve tam olarak aradığım şey! Çok teşekkürler
Rappster

1
bir soru, ne eşleştirmek istiyorum sütun tekrar değerleri varsa? gibi b,c,a,d,b,c,a,d. Denedim matchama iyi çalışmıyor.
Yulong

@Yulong: Ateş etmeden önce kopyaların kaldırıldığından emin olmanız gerektiğini düşünürdüm match(). Akla gelen şey duplicated(), unique()ya da diğerlerini atarken istenen öğeleri "tutan" başka bir özel rutindir. HTH
Rappster

@Edward güzel bir çözüm. Ancak, endeksleri de değiştirir. Ayrıca onları artan düzende nasıl saklayabilirim (1, 2, 3, 4)?
Hasan Iqbal

2
emin değilim en temiz yolu, ama sadece "temel" fonksiyonları ile, bu df çoğaltmaları varsa çalışması gerekir: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

Ben kullanımda tercih ***_join içinde dplyrben verileri eşleştirmek gerektiğinde. Bunun için olası bir deneme

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

İçin girişin ***_jointbls veya data.frame gerektirdiğini unutmayın


Evet, içerideki * _join fonksiyonları dplyrgerçekten çok güzel. Bunları şimdiye kadar da
çokça kullanın

Bu durumda, data.frame () öğelerinin faktörlere dönüştürülmesini önlemek için hedef siparişi bir tibble olarak bildirmenizi öneririz. target <- tibble(name = c("b", "c", "a", "d"))
Isırgan Otu 14'17

2
Ve boru sözdizimi ile:df %>% right_join(tibble(name = target), by = "name")
Frank

18

Bu yöntem biraz farklı, bana önceki yanıttan biraz daha esneklik sağladı. Düzenli bir faktör haline getirerek, bunu güzel bir şekilde kullanabilirsiniz arrange. Paketten reorder.factor kullandım 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)

Ardından, şimdi sipariş edildiği gerçeğini kullanın:

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

Orijinal (alfabetik) sıralamaya geri dönmek istiyorsanız as.character(), orijinal durumuna geri döndürmek için kullanın .


2
Bunun data.table sürümünü bilen var mı?
Reilstein

2
@Reilstein setDT(df)[ , name := factor(name, levels = target)]. Sonra iki bkz data.tablecevapları burada
Henrik

4

Biz dayalı faktör seviyelerini ayarlayabilirsiniz targetve kullanmakarrange

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

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

Ya orderda kullanın ve kullanınslice

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

2
En iyi çözüm IMO
stevec

1
Benim için en iyi ve en basit çözümler.
Matt_B

0

Herhangi bir kitaplık kullanmak istemiyorsanız ve verilerinizde tekrarlar varsa, whichile de kullanabilirsiniz sapply.

new_order <- sapply(target, function(x,df){which(df$name == x)}, df=df)
df        <- df[new_order,]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.