每行获取最常见的值并考虑并列情况

5

样例数据:

df <- data.frame("ID" = 1:6, 
                 "Group1" = c("A", NA, "C", NA, "E", "C"), 
                 "Group2" = c("E", "C", "C", NA, "E", "E"),
                 "Group3" = c("A", "A", NA, NA, "C", NA),
                 "Group4" = c(NA, "C", NA, "D", "C", NA),
                 "Group5" = c("A", "D", NA, NA, NA, NA))

在每一行中,我想要计算每个值的数量,并将最常见的值存储在一个新变量New.Group中。在出现平局情况下,应选择该行中第一个出现的值。逻辑应用于以下示例:

第一行的New.Group取值A,因为它是该行中最常见的值,忽略了NA

第二行取值C,因为它也是最常见的值。

第三行与第二行相同。

第四行取值D,因为它是该行中唯一的值。

在第五行中,EC都有2次计数,但由于E在该行中先出现,所以选择E

第六行类似于第五行,CE的计数都是1次,但由于C在该行中先出现,所以选择C

期望的输出:

  ID Group1 Group2 Group3 Group4 Group5 New.Group
1  1      A      E      A   <NA>      A         A
2  2   <NA>      C      A      C      D         C
3  3      C      C   <NA>   <NA>   <NA>         C
4  4   <NA>   <NA>   <NA>      D   <NA>         D
5  5      E      E      C      C   <NA>         E
6  6      C      E   <NA>   <NA>   <NA>         C

1
列的优先级是如何定义的? - tmfmnk
第一列比第二列更重要,第二列比第三列重要,以此类推。 - Laura
1
相关但似乎没有处理“_在出现结论的情况下,选择第一个值_”:按行查找最频繁的值 - Henrik
@Henrik,针对我们内部的一个软件包,我已经编写了rowMode函数,您可以在其中设置该函数在处理并列值和缺失值时应该执行的操作。在这里发布了它 - Jaap
1
谢谢你提醒我,@Jaap。太好了! - Henrik
3个回答

6
我认为这可以达到您所寻求的目标。对于每一行,它创建了一个字母频率表并选择最大值,同时保留列顺序以处理平局。然后返回此表中第一列的名称。
感谢 Henrik 提出的改进建议。
df$New.Group <- apply(df[-1], 1, function(x) {
names(which.max(table(factor(x, unique(x)))))
})

df
#>   ID Group1 Group2 Group3 Group4 Group5 New.Group
#> 1  1      A      E      A   <NA>      A         A
#> 2  2   <NA>      C      A      C      D         C
#> 3  3      C      C   <NA>   <NA>   <NA>         C
#> 4  4   <NA>   <NA>   <NA>      D   <NA>         D
#> 5  5      E      E      C      C   <NA>         E
#> 6  6      C      E   <NA>   <NA>   <NA>         C

1
@Henrik 是的,那样更好。我以为我已经尝试过并因某种原因拒绝了它,但我认为它在逻辑上是相同的(而且更整洁)。谢谢。 - Allan Cameron
它也考虑到了平局。 - Laura

3

使用dplyrvctrs,可以使用vec_count()中的location参数(按键第一次出现的位置排序)来实现以下选项:

df %>%
 rowwise() %>%
 mutate(New.Group = na.omit(vec_count(c_across(starts_with("Group")), "location")) %>%
         slice_max(count, with_ties = FALSE) %>%
         pull(key))

     ID Group1 Group2 Group3 Group4 Group5 New.Group
  <int> <fct>  <fct>  <fct>  <fct>  <fct>  <fct>    
1     1 A      E      A      <NA>   A      A        
2     2 <NA>   C      A      C      D      C        
3     3 C      C      <NA>   <NA>   <NA>   C        
4     4 <NA>   <NA>   <NA>   D      <NA>   D        
5     5 E      E      C      C      <NA>   E        
6     6 C      E      <NA>   <NA>   <NA>   C 

或者:
df %>%
 rowwise() %>%
 mutate(New.Group = names(which.max(with(na.omit(vec_count(c_across(starts_with("Group")), "location")), setNames(count, key)))))

2
我们可以使用 Mode 函数。
Mode <- function(x) {
   ux <- unique(x)
  ux[which.max(tabulate(match(x, ux)))]
 }

df$New.Group <- apply(df[-1], 1, FUN = function(x) Mode(na.omit(x)))
df$New.Group
#[1] "A" "C" "C" "D" "E" "C"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接