2012-04-01 3 views
14

Все:Как разделять при ранжировании по определенному столбцу?

У меня есть кадр данных, как follow.I знаю, что могу сделать глобальный порядок ранга, как это:

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 

Но как я могу установить порядок ранжирования для конкретного ID вместо глобальный порядок рангов. Как я могу это сделать? В T-SQL мы можем сделать это как следующий синтаксис:

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

Любая идея?

ответ

4

Мой путь, но есть вероятность, что лучше. Никогда не использовал ранг, даже не знал об этом. Спасибо, может быть полезно.

#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] 

Урожайность:

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:

Если вы не заботитесь о сохранении первоначального порядка данных, то это работает с меньшим количеством коды:

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

Спасибо, Тайлер. – RobinMin

13

Многие варианты.

ddply Использование из plyr пакет:

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 

Или, если производительность является проблемой (то есть очень большие данные), используя 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 

или в все его подробные сведения о базовом растворе R с использованием splitlapplydo.call и rbind:

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

Спасибо вам, Joran. – RobinMin

+2

Хороший ответ, как обычно. Чтобы получить максимальную производительность на data.table, лучше избегать '.SD', когда сможете. Это должно быть быстрее для больших data.tables (именно там вы, скорее всего, будете использовать пакет в первую очередь!): 'DT <- data.table (dt, key = c (" ID "," Value «)); DT [, list (Value, Order = seq_len (.N)), by = ID] ' –

+0

Я пытался реализовать ваше решение data.table, но ранг всего 1 для каждой строки. Я использовал ваш код почти слово в слово, только изменяя имена переменных. У вас есть идея о возможной ошибке, которую я мог бы сделать? Я знаю, что вы не видите код, так что это сложный вопрос, но я не хотел повторять вопрос. – Kory

6

Ниже представлены несколько подходов:

ave Это берет каждый набор номеров значений, имеющих один и тот же идентификатор, и применяет ранги отдельно для каждого такого набора. Пакеты не используются.

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

давая:

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 

Следует отметить, что указанный выше раствор сохраняет первоначальный порядок строк. Его можно было бы отсортировать впоследствии, если бы это было необходимо.

sqldf с 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" 
') 

Это решение переупорядочивает строки. Предполагается, что это нормально, так как ваше примерное решение выполнило это (но если не добавить столбец порядкового номера к dt и добавить соответствующее предложение, чтобы переупорядочить результат обратно в порядковый номер последовательности).

+0

Я знаю, что это было давно, но не могли бы вы рассказать о своем первом методе? Кажется, это дает мне оценку по одному для каждой записи в моем столе. У меня есть только столбец, который я хочу сгруппировать по секунде, и столбец, который я хочу ранжировать в первом аргументе, как вы здесь. – Kory

+0

Я добавил некоторые объяснения и вывод. –

0

Вы можете использовать пакет data.table.

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

дает желаемый результат:

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 
Смежные вопросы