按行筛选行(dplyr中)符合行函数的要求

3

您能否帮忙将下面的最后一个命令中的过滤使用dplyr而不是apply来实现呢?这个问题是在这里提出的。

library(gtools)
n <- 8
dt <- permutations(n+1,6,v=0:n,repeats.allowed=TRUE)

SmplMode <- function(x) {
  tabSmpl <- tabulate(x)
  SmplMode <- which(tabSmpl == max(tabSmpl))
  if (sum(tabSmpl == max(tabSmpl)) > 1)
    SmplMode <- 0
  return(SmplMode)
}

res <- dt[apply(dt,1,function(x) {
  y <- rep(c(1,2,3,4,5,6),c(x[1],x[2],x[3],x[4],x[5],x[6]))
  return(mean(y)==3 & diff(range(y))==4 & median(y)==3.5 & SmplMode(y)==4)
  }),]
2个回答

3

rowwise 操作速度较慢,因此使用来自 matrixStats 包的行级操作提前过滤掉 SmplMode(y), mean(y), diff(range(y)) 条件可以很好地加快速度。在我的笔记本电脑上,下面的运行时间约为0.4秒,而您原来的解决方案和@shadow的解决方案都需要约70秒。

library(dplyr)
library(matrixStats)

df <- data.frame(dt)

df$m <- rowMaxs(dt)                                       #for SmplMode(y)  
S <- matrix(1:6, ncol=ncol(dt), nrow=nrow(dt), byrow=T)
Z <- S*(dt!=0)
Z[Z==0] <- NA
df$Range <- rowMaxs(Z, na.rm=TRUE)-rowMins(Z, na.rm=TRUE) #for diff(rang(y))
df$Mean <- rowSums(S*dt)/rowSums(dt)                      #for mean(y)

res <- df %>% 
  filter(X4  == m, (X1==m)+(X2==m)+(X3==m)+(X4==m)+(X5==m)+(X6==m)==1, 
         Range == 4, # range condition here
         Mean == 3) %>% #mean condition here
  rowwise() %>% 
  mutate(Med = median(rep(c(1,2,3,4,5,6), c(X1, X2, X3, X4, X5, X6)))) %>%
  filter(Med == 3.5) %>%   #median condition here 
  select(-m, -Range, -Mean, -Med) %>% # get rid of newcols
  as.matrix 

3

您可以使用rowwise来进行逐行操作,然后使用mutate来确定是否满足条件,并使用filter根据条件进行过滤。

res <- dt %>% 
  data.frame %>% # convert to data.frame, so you can use dplyr
  rowwise %>%    # for rowwise calculations
  mutate(cond = {y = rep(1:6, c(X1, X2, X3, X4, X5, X6)) # calculate condition
                 mean(y)==3 & diff(range(y))==4 & median(y)==3.5 & SmplMode(y)==4}) %>%
  filter(cond) %>%          # filter by condition
  mutate(cond = NULL) %>%   # remove condition
  as.matrix      # convert back to matrix

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