2012-04-01 23 views
14

All:Cách phân vùng khi xếp hạng trên một cột cụ thể?

Tôi có một khung dữ liệu như follow.I biết tôi có thể làm một trật tự thứ hạng toàn cầu như thế này:

dt <- data.frame(
    ID = c('A1','A2','A4','A2','A1','A4','A3','A2','A1','A3'), 
    Value = c(4,3,1,3,4,6,6,1,8,4) 
); 
> dt 
    ID Value 
1 A1  4 
2 A2  3 
3 A4  1 
4 A2  3 
5 A1  4 
6 A4  6 
7 A3  6 
8 A2  1 
9 A1  8 
10 A3  4 
dt$Order <- rank(dt$Value,ties.method= "first") 
> dt 
    ID Value Order 
1 A1  4  5 
2 A2  3  3 
3 A4  1  1 
4 A2  3  4 
5 A1  4  6 
6 A4  6  8 
7 A3  6  9 
8 A2  1  2 
9 A1  8 10 
10 A3  4  7 

Nhưng làm thế nào tôi có thể thiết lập một trật tự thứ hạng cho một ID riêng thay vì thứ tự xếp hạng toàn cầu. Làm thế nào tôi có thể làm được điều này? Trong T-SQL, chúng ta có thể thực hiện việc này theo cú pháp sau:

RANK() OVER ([ <partition_by_clause> ] <order_by_clause>) 

Bất kỳ ý tưởng nào?

Trả lời

4

Cách của tôi nhưng có khả năng tốt hơn. Không bao giờ sử dụng thứ hạng, thậm chí không biết về nó. Cảm ơn, có thể hữu ích.

#Your Data 
dt <- data.frame(
    ID = c('A1','A2','A4','A2','A1','A4','A3','A2','A1','A3'), 
    Value = c(4,3,1,3,4,6,6,1,8,4) 
) 
dt$Order <- rank(dt$Value,ties.method= "first") 

#My approach 
dt$id <- 1:nrow(dt) #needed for ordering and putting things back together 
dt <- dt[order(dt$ID),] 
dt$Order.by.group <- unlist(with(dt, tapply(Value, ID, function(x) rank(x, 
    ties.method = "first")))) 
dt[order(dt$id), -4] 

Sản lượng:

ID Value Order Order.by.group 
1 A1  4  5    1 
2 A2  3  3    2 
3 A4  1  1    1 
4 A2  3  4    3 
5 A1  4  6    2 
6 A4  6  8    2 
7 A3  6  9    2 
8 A2  1  2    1 
9 A1  8 10    3 
10 A3  4  7    1 

EDIT:

Nếu bạn không quan tâm đến việc bảo tồn trật tự ban đầu của dữ liệu sau đó làm việc này với mã ít:

dt <- dt[order(dt$ID),] 
dt$Order.by.group <- unlist(with(dt, tapply(Value, ID, function(x) rank(x, 
    ties.method= "first")))) 

    ID Value Order.by.group 
1 A1  4    1 
5 A1  4    2 
9 A1  8    3 
2 A2  3    2 
4 A2  3    3 
8 A2  1    1 
7 A3  6    2 
10 A3  4    1 
3 A4  1    1 
6 A4  6    2 
+0

Cảm ơn bạn, Tyler. – RobinMin

13

Nhiều tùy chọn.

Sử dụng ddply từ plyr gói:

library(plyr) 
ddply(dt,.(ID),transform,Order = rank(Value,ties.method = "first")) 
    ID Value Order 
1 A1  4  1 
2 A1  4  2 
3 A1  8  3 
4 A2  3  2 
5 A2  3  3 
6 A2  1  1 
7 A3  6  2 
8 A3  4  1 
9 A4  1  1 
10 A4  6  2 

Hoặc nếu hiệu suất là một vấn đề (tức là dữ liệu rất lớn) bằng cách sử dụng gói data.table:

library(data.table) 
DT <- data.table(dt,key = "ID") 
DT[,transform(.SD,Order = rank(Value,ties.method = "first")),by = ID] 
     ID Value Order 
[1,] A1  4  1 
[2,] A1  4  2 
[3,] A1  8  3 
[4,] A2  3  2 
[5,] A2  3  3 
[6,] A2  1  1 
[7,] A4  1  1 
[8,] A4  6  2 
[9,] A3  6  2 
[10,] A3  4  1 

hoặc trong tất cả chi tiết đẫm máu của nó là một giải pháp R cơ bản sử dụng splitlapplydo.callrbind:

do.call(rbind,lapply(split(dt,dt$ID),transform, 
       Order = rank(Value,ties.method = "first"))) 
+0

Cảm ơn bạn, Joran. – RobinMin

+2

Câu trả lời hay, như thường lệ. Để có được hiệu suất tốt nhất từ ​​data.table, tốt nhất nên tránh '.SD', khi bạn có thể. Điều này sẽ nhanh hơn đối với các tệp dữ liệu lớn (là nơi bạn có nhiều khả năng sử dụng gói nhất ngay từ đầu!): 'DT <- data.table (dt, key = c (" ID "," Value ")); DT [, list (Value, Order = seq_len (.N)), bởi = ID] ' –

+0

Tôi đã cố gắng triển khai giải pháp data.table của bạn nhưng xếp hạng chỉ là 1 cho mỗi hàng. Tôi đã sử dụng mã của bạn gần như từ cho từ chỉ thay đổi tên biến. Bạn có ý tưởng về một lỗi có thể xảy ra mà tôi có thể làm không? Tôi biết bạn không thể nhìn thấy mã vì vậy đó là một câu hỏi khó nhưng tôi không muốn đặt câu hỏi lặp lại. – Kory

6

Dưới đây là một số cách tiếp cận:

ave Điều này sẽ mất mỗi tập hợp các số Giá trị có cùng ID và áp dụng xếp hạng riêng cho từng bộ như vậy. Không có gói nào được sử dụng.

Rank <- function(x) rank(x, ties.method = "first") 
transform(dt, rank = ave(Value, ID, FUN = Rank)) 

cho:

ID Value rank 
1 A1  4 1 
2 A2  3 2 
3 A4  1 1 
4 A2  3 3 
5 A1  4 2 
6 A4  6 2 
7 A3  6 2 
8 A2  1 1 
9 A1  8 3 
10 A3  4 1 

Lưu ý rằng giải pháp trên giữ trật tự hàng gốc. Nó có thể được sắp xếp sau đó nếu đó là mong muốn.

sqldf với RPostgreSQL

# see FAQ #12 on the sqldf github home page for info on sqldf and PostgreSQL 
# https://cran.r-project.org/web/packages/sqldf/README.html 

library(RPostgreSQL) 
library(sqldf) 

sqldf('select 
      *, 
      rank() over (partition by "ID" order by "Value") rank 
     from "dt" 
') 

Giải pháp này sắp xếp lại các hàng. Giả sử rằng đó là ok vì giải pháp ví dụ của bạn đã làm điều đó (nhưng nếu không thêm cột số thứ tự vào dt và thêm một thứ tự thích hợp theo mệnh đề để sắp xếp lại kết quả vào thứ tự số thứ tự).

+0

Tôi biết điều này đã được từ lâu, nhưng bạn có thể xây dựng trên phương pháp đầu tiên của bạn? Dường như cho tôi một thứ hạng cho mỗi mục nhập trong bảng của tôi. Tôi chỉ có cột tôi muốn nhóm theo thứ hai và cột tôi muốn xếp hạng trong đối số đầu tiên như bạn có ở đây. – Kory

+0

Tôi đã thêm một số giải thích và đầu ra. –

0

Bạn có thể sử dụng gói data.table.

setDT(dt) dt[, Order := rank(Value, ties.method = "first"), by = "ID"] dt <- as.data.frame(dt)

đưa ra các đầu ra mong muốn:

ID Value Order 
1 A1  4  1 
2 A2  3  2 
3 A4  1  1 
4 A2  3  3 
5 A1  4  2 
6 A4  6  2 
7 A3  6  2 
8 A2  1  1 
9 A1  8  3 
10 A3  4  1 
Các vấn đề liên quan