【问题标题】:How to use apply instead of for-loop to check every column in every row如何使用 apply 而不是 for-loop 来检查每一行中的每一列
【发布时间】:2016-09-22 07:47:31
【问题描述】:

我正在尝试检查 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,但我已经想通了。

【问题讨论】:

  • 您能否在PyxixjPyxi 的这些子集上使用dput,以便更容易重现它们?
  • 想要的人的数据cnts2&lt;-matrix(c(0,0,1,0, 0,0,0,1, 0,0,1,0, 0,0,1,0, 0,0,1,1), nrow=5,ncol=4,byrow=TRUE) colnames(cnts2)&lt;-c("A","B","C","D") cnts2&lt;-as.data.frame(cnts2) Pyxixj&lt;-matrix(c(0,0,0,0, 0,0,0,0, 0,0,0,0.001804403, 0,0,0.001804403,0), nrow=4,ncol=4,byrow=TRUE) colnames(Pyxixj)&lt;-c("A","B","C","D") rownames(Pyxixj)&lt;-c("A","B","C","D") Pyxi&lt;-matrix(c(0,0,0.00086701,0.000250439),nrow=4) rownames(Pyxi)&lt;-c("A","B","C","D")
  • 你试过用 ForEach 并行运行吗?
  • 另请参阅这篇文章,了解如何使用 apply():stackoverflow.com/questions/23980984/…

标签: r for-loop apply


【解决方案1】:

这是一个更快但可能需要更多内存的解决方案,因为它会创建一些非常长的数据帧,我创建了一个不同的 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))

【讨论】:

  • 嘿,这很好用,现在我只需要正确组合概率表 Pyxixj。稍后将尝试这需要多快。谢谢!
  • 如果你制作一个对称矩阵,其中 AA 是 A 的概率,它会起作用。或者只是从头开始制作一个三列矩阵,列是,第一个字母,第二个字母,概率。
【解决方案2】:

您可以从 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]]
   }
}

【讨论】:

    猜你喜欢
    • 2019-09-19
    • 1970-01-01
    • 1970-01-01
    • 2020-09-19
    • 1970-01-01
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    • 2016-04-15
    相关资源
    最近更新 更多