Home > Back-end >  Adjust function to generate mode in R
Adjust function to generate mode in R

Time:02-18

The code below generates the mode between columns df1 to df3. See, when there is no mode, the function is as NA. However, instead of being NA, I would like to enter "-". Another thing, is there a more "elegant" way to write this code to generate the mode?

library(dplyr)

result<-structure(list(n = c(7, 8, 9, 10, 11, 12, 13, 14, 15, 
    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 
    32, 33, 34, 35), df1 = c(9L, 29L, 28L, 27L, 25L, 26L, 24L, 20L, 
    21L, 22L, 23L, 15L, 12L, 17L, 18L, 19L, 16L, 13L, 14L, 5L, 6L, 
    7L, 8L, 1L, 10L, 11L, 4L, 2L, 3L), df2 = c(3, 29, 28, 27, 26, 
    25, 24, 23, 22, 21, 20, 15, 12, 19, 18, 17, 16, 14, 13, 11, 10, 
    9, 8, 7, 6, 5, 4, 1, 2), df3 = c(1L, 29L, 28L, 27L, 25L, 26L, 
    24L, 20L, 21L, 22L, 23L, 15L, 12L, 17L, 18L, 19L, 16L, 13L, 14L, 
    5L, 6L, 7L, 8L, 9L, 10L, 11L, 4L, 2L, 3L)), row.names = c(NA, 
    -29L), class = "data.frame")

ModeFunc <- function(Vec) {
   tmp <- sort(table(Vec),decreasing = TRUE)
   Nms <- names(tmp)
   if(max(tmp) > 1) {
     as.numeric(Nms[1])
   } else NA
 }
result <- result |> rowwise() |> 
   mutate(Mode = ModeFunc(c_across(df1:df3)))
data.frame(result)

    n df1 df2 df3 Mode
1   7   9   3   1   NA
2   8  29  29  29   29
3   9  28  28  28   28
4  10  27  27  27   27
5  11  25  26  25   25
6  12  26  25  26   26
7  13  24  24  24   24
8  14  20  23  20   20
9  15  21  22  21   21
10 16  22  21  22   22
11 17  23  20  23   23
12 18  15  15  15   15
13 19  12  12  12   12
14 20  17  19  17   17
15 21  18  18  18   18
16 22  19  17  19   19
17 23  16  16  16   16
18 24  13  14  13   13
19 25  14  13  14   14
20 26   5  11   5    5
21 27   6  10   6    6
22 28   7   9   7    7
23 29   8   8   8    8
24 30   1   7   9   NA
25 31  10   6  10   10
26 32  11   5  11   11
27 33   4   4   4    4
28 34   2   1   2    2
29 35   3   2   3    3

CodePudding user response:

I am not sure if it is more elegant, but you could use purrr as follows:

library(tidyverse)

result %>%
  mutate(modeVecs = pmap(list(df1, df2, df3), ~ c(..1, ..2, ..3)),
         modeNum = as.character(map(modeVecs, ~ unique(.[duplicated(.)]))),
         mode = recode(modeNum, 'numeric(0)' = '-')) %>%
  select(-5, -6)
         
#     n df1 df2 df3 mode
# 1   7   9   3   1    -
# 2   8  29  29  29   29
# 3   9  28  28  28   28
# 4  10  27  27  27   27
# 5  11  25  26  25   25
# 6  12  26  25  26   26
# 7  13  24  24  24   24
# 8  14  20  23  20   20
# 9  15  21  22  21   21
# 10 16  22  21  22   22
# 11 17  23  20  23   23
# 12 18  15  15  15   15
# 13 19  12  12  12   12
# 14 20  17  19  17   17
# 15 21  18  18  18   18
# 16 22  19  17  19   19
# 17 23  16  16  16   16
# 18 24  13  14  13   13
# 19 25  14  13  14   14
# 20 26   5  11   5    5
# 21 27   6  10   6    6
# 22 28   7   9   7    7
# 23 29   8   8   8    8
# 24 30   1   7   9    -
# 25 31  10   6  10   10
# 26 32  11   5  11   11
# 27 33   4   4   4    4
# 28 34   2   1   2    2
# 29 35   3   2   3    3

Or you could stick with rowwise().

library(tidyverse)

result %>%
  rowwise() %>%
  mutate(modeNum = as.character(list(unique(c(df1, df2, df3)[duplicated(c(df1, df2, df3))]))),
         mode = recode(modeNum, 'numeric(0)' = '-')) %>%
  select(-modeNum)

# # A tibble: 29 x 5
# # Rowwise: 
#        n   df1   df2   df3 mode 
#    <dbl> <int> <dbl> <int> <chr>
#  1     7     9     3     1 -    
#  2     8    29    29    29 29   
#  3     9    28    28    28 28   
#  4    10    27    27    27 27   
#  5    11    25    26    25 25   
#  6    12    26    25    26 26   
#  7    13    24    24    24 24   
#  8    14    20    23    20 20   
#  9    15    21    22    21 21   
# 10    16    22    21    22 22   
# # … with 19 more rows  
  •  Tags:  
  • r
  • Related