在 df 上做条件求和比 for 循环更好的方法?
Better way to do conditional-sum on df than for-loop?
我正在使用 for 循环对数据帧求和。我知道在 R 中循环通常不是一个好主意,使用 sapply 或 aggregate 是更好的方法,但我只是不知道如何在我的案例中使用它。
我想以迭代的方式根据两列的条件对一列求和。
以下是我想以更好的方式让您理解的内容:
sample <- data.frame( ID = c("bli","bla","blou","qhq","bidi","bada","bodo"),
A = c(1,0,1,1,0,1,1) ,
B = c(0,1,1,0,0,1,0) ,
C = c(0,1,1,0,0,1,1)
)
g <- NULL
bli <- 1:length(sample)
for (j in 2:length(sample)) {
a <- sum(subset(sample,sample[,c(j) ] ==1 , c(j)))
for (i in 2:length(sample))
if (bli[j] != bli[i]) {
b <- sum(subset(sample,sample[,c(j)] ==1 & sample[,c(i) ] ==1 , c(i)))
c <- names(sample[j])
d <- names(sample[i])
e <- cbind(c,d,a,b)
f <- data.frame(e)
g <- rbind(g,f) }
else {
NULL
}
}
g
谢谢
您可以尝试 expand.grid
(@thelatemail 建议)。以下代码的摘要是:
- 创建一个 "index" 的列名(即 "nm1"),我们需要所有的组合
- 自己尝试
expand.grid
或 "nm1" (expand.grid(nm1, nm1)
)。语法 list(nm1)
有点笼统,因此您可以通过在 rep
. 中指定 times
来创建多路组合
- 删除相同的行("indx1")
- 使用
sapply
遍历 "indx1" 的行并根据循环中的行索引对 "sample" 数据集进行子集化。
- 根据"indx1"第一列的子集做
sum
,根据子集数据集的元素是否都为“1”sum
做sum
21=])
cbind
"indx1" 与 sapply
的转置 (t
) 并重命名输出数据集的列。
nm1 <- names(sample)[-1]
indx <- expand.grid(rep(list(nm1),2),stringsAsFactors=FALSE)
indx <- indx[,2:1]
indx1 <- indx[indx[,1]!=indx[,2],]
row.names(indx1) <- NULL
res <- cbind(indx1,t(sapply(seq_len(nrow(indx1)), function(i) {
x1 <- unlist(indx1[i,])
x2 <- sample[,x1]
c(sum(x2[,1]), sum(x2[,1]&x2[,2])) }))
)
names(res) <- names(g)
res
# c d a b
#1 A B 5 2
#2 A C 5 3
#3 B A 3 2
#4 B C 3 3
#5 C A 4 3
#6 C B 4 3
或者甚至不使用 sapply
(会更快),在两个子集数据集 "i1"、"i2" 上使用 colSums
。
i1 <- sample[indx1[,1]]
i2 <- sample[indx1[,2]]
a <- colSums(i1)
b <- colSums(i1 &i2)
#in case you have more than two columns
#b <- colSums(Reduce(`&`,list(i1, i2)))
res1 <- cbind(setNames(indx1, c('c', 'd')), a, b)
我正在使用 for 循环对数据帧求和。我知道在 R 中循环通常不是一个好主意,使用 sapply 或 aggregate 是更好的方法,但我只是不知道如何在我的案例中使用它。
我想以迭代的方式根据两列的条件对一列求和。
以下是我想以更好的方式让您理解的内容:
sample <- data.frame( ID = c("bli","bla","blou","qhq","bidi","bada","bodo"),
A = c(1,0,1,1,0,1,1) ,
B = c(0,1,1,0,0,1,0) ,
C = c(0,1,1,0,0,1,1)
)
g <- NULL
bli <- 1:length(sample)
for (j in 2:length(sample)) {
a <- sum(subset(sample,sample[,c(j) ] ==1 , c(j)))
for (i in 2:length(sample))
if (bli[j] != bli[i]) {
b <- sum(subset(sample,sample[,c(j)] ==1 & sample[,c(i) ] ==1 , c(i)))
c <- names(sample[j])
d <- names(sample[i])
e <- cbind(c,d,a,b)
f <- data.frame(e)
g <- rbind(g,f) }
else {
NULL
}
}
g
谢谢
您可以尝试 expand.grid
(@thelatemail 建议)。以下代码的摘要是:
- 创建一个 "index" 的列名(即 "nm1"),我们需要所有的组合
- 自己尝试
expand.grid
或 "nm1" (expand.grid(nm1, nm1)
)。语法list(nm1)
有点笼统,因此您可以通过在rep
. 中指定 - 删除相同的行("indx1")
- 使用
sapply
遍历 "indx1" 的行并根据循环中的行索引对 "sample" 数据集进行子集化。 - 根据"indx1"第一列的子集做
sum
,根据子集数据集的元素是否都为“1”sum
做sum
21=]) cbind
"indx1" 与sapply
的转置 (t
) 并重命名输出数据集的列。nm1 <- names(sample)[-1] indx <- expand.grid(rep(list(nm1),2),stringsAsFactors=FALSE) indx <- indx[,2:1] indx1 <- indx[indx[,1]!=indx[,2],] row.names(indx1) <- NULL res <- cbind(indx1,t(sapply(seq_len(nrow(indx1)), function(i) { x1 <- unlist(indx1[i,]) x2 <- sample[,x1] c(sum(x2[,1]), sum(x2[,1]&x2[,2])) })) ) names(res) <- names(g) res # c d a b #1 A B 5 2 #2 A C 5 3 #3 B A 3 2 #4 B C 3 3 #5 C A 4 3 #6 C B 4 3
times
来创建多路组合
或者甚至不使用 sapply
(会更快),在两个子集数据集 "i1"、"i2" 上使用 colSums
。
i1 <- sample[indx1[,1]]
i2 <- sample[indx1[,2]]
a <- colSums(i1)
b <- colSums(i1 &i2)
#in case you have more than two columns
#b <- colSums(Reduce(`&`,list(i1, i2)))
res1 <- cbind(setNames(indx1, c('c', 'd')), a, b)