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

时间:2016-09-22 07:47:32

标签: r for-loop apply

我试图检查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))

我过去用来引用概率的表

表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

表Pyxi

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循环完成了它,但运行大约100万行需要6小时。

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,但我已经弄明白了。

2 个答案:

答案 0 :(得分:0)

这是一个更快但可能需要更多ram的解决方案,因为它会创建一些非常长的数据帧,我创建了一个不同的Pyxixj数据帧,因为我的解决方案不需要另一个表。

此解决方案的关键是将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))

答案 1 :(得分:0)

您可以从for循环中移除表格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]]
   }
}