Lod
Lod

Reputation: 639

Create descending ranks for a set of columns using dplyr

How do you use dplyr to create ranks for each column based on descending values for multiple columns? The code below seemingly does not consider the desc parameter in the arrange_at

rank_f <- function(ds, cols, fs){
          ds %>%arrange_at(desc(vars(!!!cols)))%>%
            mutate_at(vars(!!!cols), funs(!!!fs))
        }


USArrests %>%tibble::rownames_to_column()%>%
     rank_f(quos((Murder:Rape)),quos(min_rank))->ranked


head(USArrests) 
#              Murder Assault UrbanPop Rape
# Alabama      13.2     236       58 21.2
# Alaska       10.0     263       48 44.5
# Arizona       8.1     294       80 31.0
# Arkansas      8.8     190       50 19.5
# California    9.0     276       91 40.6
# Colorado      7.9     204       78 38.7

head(ranked)
#        rowname Murder Assault UrbanPop Rape
# 1    Alabama     44      35       16   29
# 2     Alaska     35      43        7   49
# 3    Arizona     29      47       39   43
# 4   Arkansas     31      31        9   24
# 5 California     32      44       50   48
# 6   Colorado     28      33       38   47

The higher the rate, the lower the rank should be, which is not the case.

Upvotes: 4

Views: 2654

Answers (1)

akrun
akrun

Reputation: 887038

We need to place this inside the funs

out1 <- USArrests %>%
           tibble::rownames_to_column() %>% 
           arrange_at(vars(Murder:Rape), funs(desc)) 

Checking with applying desc on each column

out2 <-  USArrests %>% 
             tibble::rownames_to_column() %>% 
             arrange(desc(Murder), desc(Assault), desc(UrbanPop), desc(Rape))
identical(out1, out2)
#[1] TRUE

Based on the above, we can make changes in the rank_f

out3 <-  out2 %>%
             mutate_at(vars(Murder:Rape), min_rank) 
rank_f <- function(ds, cols, fs){
          ds %>%
               arrange_at(vars(!!!cols), funs(desc))%>%
               mutate_at(vars(!!!cols), funs(!!!fs))
        }
out4 <- USArrests %>%
             tibble::rownames_to_column()%>%
             rank_f(quos((Murder:Rape)),quos(min_rank))

identical(out3, out4)
#[1] TRUE

Update

Based on the comments from OP, we don't need to do any arrange, we can directly apply min_rank by converting the column values to negative

USArrests %>% 
   tibble::rownames_to_column() %>% 
   mutate_at(vars(Murder:Rape), funs(min_rank(-.)))

Upvotes: 2

Related Questions