r - 如何从多个列中找到最常出现的值

  显示原文与译文双语对照的内容

我的数据帧如下所示:


S A B C D E 


1 N N N N N


2 N Y Y N N


3 Y N Y N N


4 Y N Y Y Y



我需要创建一个新的列F,它的中包含多个列A 。B 。C 。D 和E 中最多的字符。

输出应类似于以下内容:


 S A B C D E F


 1 N N N N N N


 2 N Y Y N N N


 3 Y N Y N N N


 4 Y N Y Y Y Y



时间:

我们可以创建一个 Mode 函数并在行上应用


df1$F <- apply(df1[-1], 1, Mode)


df1


# S A B C D E F


#1 1 N N N N N N


#2 2 N Y Y N N N


#3 3 Y N Y N N N


#4 4 Y N Y Y Y Y



或者另一个选项是


df1$F <- c('N', 'Y')[max.col(table(c(row(df1[-1])), unlist(df1[-1])), 'first')]



哪里


Mode <- function(x) {


 ux <- unique(x)


 ux[which.max(tabulate(match(x, ux)))]


}



或者使用 tidyverse


library(tidyverse)


df1 %>% 


 mutate(F = pmap_chr(.[-1], ~ Mode(c(...))))



或者另一个选项是


gather(df1, key, F, - S) %>% 


 group_by(S, F) %>% 


 summarise(n = n()) %>% 


 slice(which.max(n)) %>% 


 ungroup %>% 


 dplyr::select(F) %>% 


 bind_cols(df1,. )



或者转换数据集,对每个列应用 Mode,然后将输出作为新列绑定到原始数据集


t(df1[-1]) %>%


 as.data.frame %>% 


 summarise_all(Mode) %>% 


 unlist %>%


 bind_cols(df1, F =. )



或者带有 data.table的选项


library(data.table)


setDT(df1)[, F := names(which.max(table(unlist(.SD)))), S][]



注意:这些是常规方法,而不是仅仅检查单个实例

如果我们需要一个有效的方法,没有任何 ifelse,我们也可以通过


df1$F <- c("Y","N")[(rowSums(df1[-1] =="N")> 2) + 1]


df1$F


#[1]"N""N""N""Y"



或者用 Reduce


c("Y","N")[(Reduce(`+`, lapply(df1[-1], `==`,"N"))> 2) + 1]



或者另一种方法是


c("Y","N")[(str_count(do.call(paste0, df1[-1]),"N")> 2) + 1]



数据


df1 <- structure(list(S = 1:4, A = c("N","N","Y","Y"), B = c("N", 


"Y","N","N"), C = c("N","Y","Y","Y"), D = c("N","N","N", 


"Y"), E = c("N","N","N","Y")), class ="data.frame", row.names = c(NA, 


-4L))



一个 dplyr 可能是:


df %>%


 mutate(F = ifelse(rowSums(.[2:length(.)] =="N")> 2,"N","Y"))



 S A B C D E F


1 1 N N N N N N


2 2 N Y Y N N N


3 3 Y N Y N N N


4 4 Y N Y Y Y Y



它假定仅有 NY 值,列的数量为 5.

正如 @Sotos 所注意到的,它可以轻松地重写为 base R 表单:


df$F <- ifelse(rowSums(df[2:length(df)] =="N")> 2,"N","Y")



或者没有关于列数的假设( 基于 @TinglTanglBob):


df %>%


 mutate(F = ifelse(rowMeans(.[2:length(.)] =="N")> 0.5,"N","Y"))



基本 R 相同:


df$F <- ifelse(rowMeans(df[2:length(df)] =="N")> 0.5,"N","Y")



另一种不同的方式


x$F <- unlist(do.call(Map, c(function(...) names(sort(-table(c(...)), partial=1)[1]), x[,-1])))


x


# S A B C D E F


# 1 1 N N N N N N


# 2 2 N Y Y N N N


# 3 3 Y N Y N N N


# 4 4 Y N Y Y Y Y



也许我只是想现在产生晦涩的代码。

我意识到这可能比绝对必要。 无论行之间存在多少不同的东西,它都会找到最常见的"事情"。

sort(..., partial=1) 在第一次传递后停止排序。

...