如何使用 apply 而不是 for-loop 来检查每一行中的每一列

How to use apply instead of for-loop to check every column in every row

我正在尝试检查 data.table 中的每一行是否有某些元素(如果有,我将其声明为 1)。如果有,我想输出一个新列,显示从另一个 data.table.

引用的值(元素发生的概率)

这是输入

structure(list(A = c(0L, 0L, 0L, 0L, 0L), B = c(0L, 0L, 0L, 0L, 
0L), C = c(1L, 0L, 1L, 1L, 1L), D = c(0L, 1L, 0L, 0L, 1L)), .Names = c("A", 
"B", "C", "D"), class = "data.frame", row.names = c(NA, -5L))

我用来获取概率的参考表

Table Pyxixj

    A   B   C   D
 A  0   0   0   0
 B  0   0   0   0
 C  0   0   0   0.001804403
 D  0   0   0.001804403 0

Table 派西

A   0
B   0
C   0.00086701
D   0.000250439

这是输出

    A   B   C   D   prob
1   0   0   1   0   0.00086701
2   0   0   0   1   0.000250439
3   0   0   1   0   0.00086701
4   0   0   1   0   0.00086701
5   0   0   1   1   0.001804403

我已经使用下面的 for 循环完成了它,但是 运行 需要 6 小时才能获得大约 100 万行。

for (i in 1:nrow(cnts2))
{
    if ((rowSums(cnts2 == "1", na.rm = TRUE) == 1)[i])
    {
        cnts2$prob[i] <- Pyxi[colnames(cnts2)[which(cnts2[i, ] == 1)]]
    }
    else
    {
        cnts2$prob[i] <- Pyxixj[colnames(cnts2)[which(cnts2[i, ] == 1)][1], colnames(cnts2)[which(cnts2[i, ] == 1)][2]]
    }
}

一直在尝试 apply 但我已经弄明白了。

这是一个速度更快但可能需要更多内存的解决方案,因为它会创建一些非常长的数据帧,我创建了一个不同的 Pyxixj 数据帧,因为我的解决方案不需要其他 table。

此解决方案的关键是将您的 cnts2 数据框更改为可以保留概率的形式,并因此消除对循环或 lapply

的任何需要
library(dplyr);library(tidyr)
#probability data frame note use of X1
Pyxixj <- data.frame(X1=c("A", "B", "C", "D"), 
           matrix(data=sample(1:100, 16, replace=TRUE)/100, nrow= 4) ) %>% 
  setNames(c("X1", "A", "B", "C", "D"))


#Restructure the initial data frame
probmerge <-cnts2 %>%mutate(rowid= 1:nrow(.)) %>% 
  gather(., key=column, value=yesno,-rowid) %>%
  filter(yesno==1) %>% group_by(rowid) %>%
  mutate(order=make.names(cumsum(yesno))) %>%
  spread(key=order, value=column) %>%
  mutate(X2=ifelse(is.na(X2),X1,X2)) %>%ungroup


#Gather your probability dataframe
Pyxixj <-Pyxixj %>% gather(key="X2", value=prob,-X1)

#join the two new dataframes
probmerge<-left_join(probmerge, Pyxixj, by=c("X1", "X2"))

#bind onto the orignial dataframe
cnts2 <- bind_cols(cnts2, select(probmerge, prob))

您可以从 for 循环中删除对 table Pyxi 的查找以更快地循环

这在查找 Pyxi 时利用了 R 的函数应用向量化

 if (rowSums(cnts2 == "1", na.rm = TRUE) == 1)
    {
       cnts2$probs <- (Pyxi[rownames(Pyxi)=="A"]*cnts2$A
                  + Pyxi[rownames(Pyxi)=="B"]*cnts2$B
                  + Pyxi[rownames(Pyxi)=="C"]*cnts2$C
                  + Pyxi[rownames(Pyxi)=="D"]*cnts2$D)
     }  

然后在行数 >1 的地方执行循环

for (i in 1:nrow(cnts2))
{
   if ((rowSums(cnts2 == "1", na.rm = TRUE) > 1)[i])
   {cnts2$prob[i] <- Pyxixj[colnames(cnts2)[which(cnts2[i, ] == 1)][1], 
    colnames(cnts2)[which(cnts2[i, ] == 1)][2]]
   }
}