добавление столбца в фрейм данных в R на основе ранга другого столбца

#r #dataframe

#r #фрейм данных

Вопрос:

Вот воспроизводимый пример моих данных. Для следующего фрейма данных:

 df <- data.frame(Subject = c('John', 'John', 'John', 'John','Mary', 'Mary', 'Mary', 'Mary'),
                 SNR = c(-4,-4,0,4,0,4,4,8))
  

Я хотел бы добавить столбец ‘rank’, который обеспечивает ранжирование SNR по теме, чтобы он выглядел так:

 Subject   SNR   Rank
John      -4    1
John      -4    1
John       0    2
John       4    3
Mary       0    1
Mary       4    2
Mary       4    2
Mary       8    3
  

Я пытался использовать:

 dfNew <- transform(df, Rank = ave(SNR, Subject, FUN = function(x) rank(x, ties.method = "first")))
  

Но я получаю следующее:

 Subject   SNR   Rank
John      -4    1
John      -4    2
John       0    3
John       4    4
Mary       0    1
Mary       4    2
Mary       4    3
Mary       8    4   
  

Я также пытался использовать разные варианты ties.method, но ни один из них не дает мне то, что я ищу (т. Е. ранжирование только с 1-3).

Любая помощь будет высоко оценена!

Комментарии:

1. Попробуйте с dplyr::dense_rank помощью . Или просто используйте его код, если вы не хотите использовать пакет; это всего две строки базового кода R.

2. function(x) as.numeric(factor(x)) сработает в вашей попытке. или просто factor(x) , поскольку ave в любом случае принудительно вернется к типу SNR

3. Спасибо @rawr, это сделало свое дело.

Ответ №1:

Использование aggregate и factor в базе R:

 ag <- aggregate(SNR~Subject, df, function(x) as.numeric(factor(x)))
df$rank <- c(t(ag[,-1]))

  Subject SNR rank
1    John  -4    1
2    John  -4    1
3    John   0    2
4    John   4    3
5    Mary   0    1
6    Mary   4    2
7    Mary   4    2
8    Mary   8    3
  

Ответ №2:

Другой базовый метод R:

 transform(df1, Rank = ave(SNR, Subject, FUN = function(x) cumsum(c(TRUE, head(x, -1) != tail(x, -1)))))
  

дает:

   Subject SNR Rank
1    John  -4    1
2    John  -4    1
3    John   0    2
4    John   4    3
5    Mary   0    1
6    Mary   4    2
7    Mary   4    2
8    Mary   8    3
  

Если ваш фрейм данных еще не упорядочен, вы должны сначала упорядочить его с df1 <- df1[order(df1$SNR),] помощью этого метода, чтобы получить правильный результат.

Ответ №3:

 library(dplyr)    
df %>%
     arrange(Subject, SNR) %>%
     group_by(Subject) %>%
     mutate(rank=dense_rank(SNR))
  

конечно, спасибо @rich-scriven за упоминание dense_rank()

Ответ №4:

Немного грязно, но, похоже, работает:

 library(dplyr)
df %>% group_by(Subject) %>% mutate(Rank = as.numeric(as.factor(SNR))) 

  Subject   SNR  Rank
   <fctr> <dbl> <dbl>
1    John    -4     1
2    John    -4     1
3    John     0     2
4    John     4     3
5    Mary     0     1
6    Mary     4     2
7    Mary     4     2
8    Mary     8     3
  

Комментарии:

1. Не мой голос, но я предполагаю, что это потому, что вам действительно не нужно загружать пакет для добавления столбца.

2. Ну, вам нужно загрузить dplyr, если вы не используете его регулярно, я считаю, что голосование против (не мной) было вызвано as.numeric(as.factor()) .. но все же это немного педантично