Veri çerçevesindeki gruplar içindeki satırları numaralandırma


163

Buna benzer bir veri çerçevesiyle çalışma:

set.seed(100)  
df <- data.frame(cat = c(rep("aaa", 5), rep("bbb", 5), rep("ccc", 5)), val = runif(15))             
df <- df[order(df$cat, df$val), ]  
df  

   cat        val  
1  aaa 0.05638315  
2  aaa 0.25767250  
3  aaa 0.30776611  
4  aaa 0.46854928  
5  aaa 0.55232243  
6  bbb 0.17026205  
7  bbb 0.37032054  
8  bbb 0.48377074  
9  bbb 0.54655860  
10 bbb 0.81240262  
11 ccc 0.28035384  
12 ccc 0.39848790  
13 ccc 0.62499648  
14 ccc 0.76255108  
15 ccc 0.88216552 

Her grup içinde numaralandırma ile bir sütun eklemeye çalışıyorum. Bu şekilde yapmak açıkça R'nin güçlerini kullanmaz:

 df$num <- 1  
 for (i in 2:(length(df[,1]))) {  
   if (df[i,"cat"]==df[(i-1),"cat"]) {  
     df[i,"num"]<-df[i-1,"num"]+1  
     }  
 }  
 df  

   cat        val num  
1  aaa 0.05638315   1  
2  aaa 0.25767250   2  
3  aaa 0.30776611   3  
4  aaa 0.46854928   4  
5  aaa 0.55232243   5  
6  bbb 0.17026205   1  
7  bbb 0.37032054   2  
8  bbb 0.48377074   3  
9  bbb 0.54655860   4  
10 bbb 0.81240262   5  
11 ccc 0.28035384   1  
12 ccc 0.39848790   2  
13 ccc 0.62499648   3  
14 ccc 0.76255108   4  
15 ccc 0.88216552   5  

Bunu yapmanın iyi bir yolu ne olabilir?


1
Bu ben bu soruyu nasıl bulduğunu olduğu gibi soru başlığında veya "çoğaltır boyunca sayma" "seviyeleri boyunca seq" gibi bir şey eklemek öneririm ve ben arıyordu tam olarak ne
crazysantaclaus

2
@crazysantaclaus Başlık olsaydı, aradığımı bulamazdım :-( Kelimenin tam anlamıyla "veri çerçevesindeki gruplar içindeki satırları nasıl numaralandıracağımı" arıyordum
Zimano

Yanıtlar:


280

Kullanım ave, ddply, dplyrveya data.table:

df$num <- ave(df$val, df$cat, FUN = seq_along)

veya:

library(plyr)
ddply(df, .(cat), mutate, id = seq_along(val))

veya:

library(dplyr)
df %>% group_by(cat) %>% mutate(id = row_number())

veya (içinde referans olarak atadığı gibi en verimli bellek DT):

library(data.table)
DT <- data.table(df)

DT[, id := seq_len(.N), by = cat]
DT[, id := rowid(cat)]

2
Burada avebir int yerine bir şamandıra veren bahsetmeye değer olabilir . Alternatif olarak, değişebilir df$valiçin seq_len(nrow(df)). Buraya yeni geldim: stackoverflow.com/questions/42796857/…
Frank

1
İlginçtir, bu data.tableçözüm kullanmaktan daha hızlı görünüyor frank: library(microbenchmark); microbenchmark(a = DT[, .(val ,num = frank(val)), by = list(cat)] ,b =DT[, .(val , id = seq_len(.N)), by = list(cat)] , times = 1000L)
hannes101

4
Teşekkürler! dplyrSolüsyon iyidir. Benim gibi, bu yaklaşımı çalışırken garip hatalar elde tutulur, Ama eğer arasındaki çatışmaları almıyorsanız emin olun plyrve dplyraçıklandığı gibi bu yazı içinde açıkça arayarak O önlenebilirdplyr::mutate(...)
EcologyTom

2
başka bir data.tableyöntemsetDT(df)[, id:=rleid(val), by=.(cat)]
chinsoon12

Sıralama val sütununu azalan sırada yapmak için nasıl değiştirilir library(plyr)ve library(dplyr)cevaplar verilir?
Przemyslaw Remin

26

Bunu yapmak için ile daha tam bir baz R 'alternatif soru sequenceve rle:

df$num <- sequence(rle(df$cat)$lengths)

amaçlanan sonucu verir:

> df
   cat        val num
4  aaa 0.05638315   1
2  aaa 0.25767250   2
1  aaa 0.30776611   3
5  aaa 0.46854928   4
3  aaa 0.55232243   5
10 bbb 0.17026205   1
8  bbb 0.37032054   2
6  bbb 0.48377074   3
9  bbb 0.54655860   4
7  bbb 0.81240262   5
13 ccc 0.28035384   1
14 ccc 0.39848790   2
11 ccc 0.62499648   3
15 ccc 0.76255108   4
12 ccc 0.88216552   5

Eğer df$catbir faktör değişkendir, sen onu sarmak için ihtiyaç as.characterbirinci:

df$num <- sequence(rle(as.character(df$cat))$lengths)

Az önce fark catettiğiniz gibi , bu çözümler sütunun sıralanmasını gerektiriyor mu?
zx8754

@ zx8754 evet, art arda meydana gelme sayısı ile numaralandırmak istemiyorsanızcat
Jaap

9

İşte forsatır yerine gruplara göre bir döngü kullanma seçeneği (OP gibi)

for (i in unique(df$cat)) df$num[df$cat == i] <- seq_len(sum(df$cat == i))

9

Grupların içinde 'val' türüne izin veren küçük bir iyileştirme hilesi:

# 1. Data set
set.seed(100)
df <- data.frame(
  cat = c(rep("aaa", 5), rep("ccc", 5), rep("bbb", 5)), 
  val = runif(15))             

# 2. 'dplyr' approach
df %>% 
  arrange(cat, val) %>% 
  group_by(cat) %>% 
  mutate(id = row_number())

Group_by öğesinden sonra sıralayamaz mısınız?
zcoleman

6

Ben sipariş değiştirmek için ek olasılık sağlar ve böylece çözüm biraz daha esnek hale getirir ve RDBMS satır_sayısı işlevlerine oldukça benzer işlevi data.tablekullanarak bir değişken eklemek istiyorum .rank()seq_len()

# Variant with ascending ordering
library(data.table)
dt <- data.table(df)
dt[, .( val
   , num = rank(val))
    , by = list(cat)][order(cat, num),]

    cat        val num
 1: aaa 0.05638315   1
 2: aaa 0.25767250   2
 3: aaa 0.30776611   3
 4: aaa 0.46854928   4
 5: aaa 0.55232243   5
 6: bbb 0.17026205   1
 7: bbb 0.37032054   2
 8: bbb 0.48377074   3
 9: bbb 0.54655860   4
10: bbb 0.81240262   5
11: ccc 0.28035384   1
12: ccc 0.39848790   2
13: ccc 0.62499648   3
14: ccc 0.76255108   4

# Variant with descending ordering
dt[, .( val
   , num = rank(-val))
    , by = list(cat)][order(cat, num),]

5

Başka bir dplyrolasılık şunlar olabilir:

df %>%
 group_by(cat) %>%
 mutate(num = 1:n())

   cat      val   num
   <fct>  <dbl> <int>
 1 aaa   0.0564     1
 2 aaa   0.258      2
 3 aaa   0.308      3
 4 aaa   0.469      4
 5 aaa   0.552      5
 6 bbb   0.170      1
 7 bbb   0.370      2
 8 bbb   0.484      3
 9 bbb   0.547      4
10 bbb   0.812      5
11 ccc   0.280      1
12 ccc   0.398      2
13 ccc   0.625      3
14 ccc   0.763      4
15 ccc   0.882      5

3
Yerine Bazı durumlarda 1:n()kullanarak seq_len(n())operasyonların sıranızdaki bir durum var olması halinde, güvenlidir n()döndürebilir 0, çünkü1:0 iken size uzunluğu iki vektör verir seq_len(0)böylece bir uzunluk uyumsuzluğu hatası kaçınarak, bir uzunluk sıfır vektörü verir mutate().
Brian Stamper

0

rowid()Fonksiyonu şurada kullanma data.table:

> set.seed(100)  
> df <- data.frame(cat = c(rep("aaa", 5), rep("bbb", 5), rep("ccc", 5)), val = runif(15))
> df <- df[order(df$cat, df$val), ]  
> df$num <- data.table::rowid(df$cat)
> df
   cat        val num
4  aaa 0.05638315   1
2  aaa 0.25767250   2
1  aaa 0.30776611   3
5  aaa 0.46854928   4
3  aaa 0.55232243   5
10 bbb 0.17026205   1
8  bbb 0.37032054   2
6  bbb 0.48377074   3
9  bbb 0.54655860   4
7  bbb 0.81240262   5
13 ccc 0.28035384   1
14 ccc 0.39848790   2
11 ccc 0.62499648   3
15 ccc 0.76255108   4
12 ccc 0.88216552   5

1
Cevabınız için teşekkürler, ancak @ mnel'in cevabındaki son öneri zaten ele alındı ​​gibi görünüyor
eli-k
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.