0

我有一组对象,假设 ID 为“A”到“J”。我有两个数据框,看起来如下(如您所见,第二个数据框是对称的):

df1 <- data.frame(ID = LETTERS[1:5], Var = c(9,13,15,11,28))
df2 <- as.data.frame(matrix(data = c(NA,42,83,74,84,42,NA,26,69,9,83,26,NA,67,95,74,69,67,NA,6,84,9,95,6,NA), ncol = 5, nrow = 5, dimnames = list(df1$ID, df1$ID)))

例如,以对象“B”和“E”为例。我想知道:13+28(来自df1)是否小于 9(来自df2)?我想知道所有成对的对象。输出应该是

(a) 一个逻辑数据帧,其结构类似于df2

(b) “真”值的数量。

大多数时候我只需要结果(b),但有时我也需要(a)。因此,如果可以在没有 (a) 的情况下计算 (b) 并且这会明显更快,那么我希望同时拥有这两种算法,以便根据我需要回答特定问题的输出来选择合适的算法。

我正在比较大约 2000 个对象,所以算法应该相当快。到目前为止,我只能用两个for非常慢的嵌套循环来实现这一点。我敢打赌,有更好的方法可以做到这一点,也许是利用矢量化。

这是它目前的样子:

df3 <- as.data.frame(matrix(data = NA, ncol = nrow(df1), nrow = nrow(df1),
                            dimnames = list(df1$ID, df1$ID)))

for (i in 2:nrow(df3)){
  for (j in 1:(i-1)){
    sum.val <- df1[df1$ID == rownames(df3)[i], "Var"] + df1[df1$ID == names(df3)[j], "Var"]
    df3[i,j] <- sum.val <= df2[i,j]
  }
}

#

4

3 回答 3

3

这是你想要的吗?

df3 <- outer(df1$Var, df1$Var, "+")
df3

df4 <- df3 < df2
df4

sum(df4, na.rm = TRUE)
于 2013-09-04T15:15:20.393 回答
1

这是一种方法...

#  Get row and column indices
ind <- t( combn( df1$ID , 2 ) )

#  Get totals
tot <- with( df1 , Var[ match( ind[,1] , ID ) ] + Var[ match( ind[,2] , ID ) ] )

#  Make df2 a matrix
m <- as.matrix( df2 )

#  Total number of values is simply
sum( m[ ind ] > tot )
#[1] 7

#  Find which values in upper triangle part of the matrix exceed those from df1 (1 = TRUE)
m[upper.tri(m)] <- m[ ind ] > tot
#   A  B  C  D  E
#A NA  1  1  1  0
#B 42 NA  1  0  1
#C 83 26 NA  1  1
#D 74 69 67 NA  0
#E 84  9 95  6 NA
于 2013-09-04T15:06:03.530 回答
1

这将做你想要的。

# Generate the data
df1 <- data.frame(ID = LETTERS[1:5], Var = c(9,13,15,11,28))
df2 <- as.data.frame(matrix(data = c(NA,42,83,74,84,42,NA,26,
                                     69,9,83,26,NA,67,95,74,69,
                                     67,NA,6,84,9,95,6,NA),
                            ncol = 5, nrow = 5,
                            dimnames = list(df1$ID, df1$ID)))

# Define a pairwise comparison index matrix using 'combn'
idx <- combn(nrow(df1), 2)

# Create a results matrix
res <- matrix(NA, ncol = ncol(df2), nrow = nrow(df2))

# Loop through 'idx' for each possible comparison (without repeats)
for(i in 1:ncol(idx)){
  logiTest <- (df1$Var[idx[1,i]] + df1$Var[idx[2,i]]) < df2[idx[1,i], idx[2,i]]
  res[idx[1,i], idx[2, i]] <- logiTest
  res[idx[2,i], idx[1, i]] <- logiTest
}

# Count the number of 'true' comparisons
nTrues <- sum(res, na.rm = TRUE)/2

该代码仅使用成对比较索引 (idx) 来定义 df1 和 df2 中的哪些元素将在“for 循环”的每次迭代中使用。然后它使用这个相同的索引来定义逻辑测试的答案在“res”矩阵中的哪个位置被写入。

注意 如果 df1 和 df2 中的元素顺序不同,此代码将崩溃。在这种情况下,使用实际字母来定义要比较的值是合适的。

于 2013-09-04T15:38:56.667 回答