我们可以创建一个“Mode”函数,并将其应用于行。
df1$F <- apply(df1[-1], 1, Mode)
df1
或者另一个选择是:
df1$F <- c('N', 'Y')[max.col(table(c(row(df1[-1])), unlist(df1[-1])), 'first')]
where
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
或者使用
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))
apply()
函数并指定边缘为1
。如果您不仅仅是为了使用管道和mutate
而加载dplyr
,那么它可能会更好。只需将其保留在基本的 R 中即可。此外,您还可以使2
动态化,例如ceiling(ncol(df) / 2)
。 - Sotos