如何使用 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]]
}
}
我正在尝试检查 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]]
}
}