如何成对比较引用不同格式的两个矩阵中的不同元素的值?

时间:2013-09-04 13:06:20

标签: r dataframe

我有一组对象,让我们说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)“TRUE”值的数量。

大多数时候我只需要结果(b),但有时我也需要(a)。因此,如果(b)可以在没有(a)的情况下计算,并且如果这将显着更快,那么我想要两种算法以便选择合适的算法,这取决于我需要回答特定问题的输出。

我正在比较大约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]
  }
}

3 个答案:

答案 0 :(得分:3)

这是你想要的吗?

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

df4 <- df3 < df2
df4

sum(df4, na.rm = TRUE)

答案 1 :(得分: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

答案 2 :(得分: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'矩阵中要写入逻辑测试的答案的位置。

N.B。如果df1和df2中的元素顺序不相同,则此代码将被分解。在这种情况下,使用实际字母来定义要比较的值是合适的。