मान लीजिए हमारे पास नीचे जैसा मैट्रिक्स है,

A <- matrix(c(1,7,13,19,9,5,8,14,20,10,3,4,15,21,1,2,4,16,22,2,8,3,17,23,1,6,3,18,24,2), nrow=5)
 A
       [,1]   [,2]   [,3]   [,4]   [,5]   [,6]
 [1,]    1      5      3      2      8      6
 [2,]    7      8      4      4      3     3
 [3,]    13     14     15     16     17     18
 [4,]    19     20     21     22     23     24
 [5,]    9      10     1      2      1      2

dist फ़ंक्शन dist(A, method = "maximum") का उपयोग करके मैट्रिक्स A और वापसी दूरी मैट्रिक्स D की प्रत्येक पंक्ति के बीच अधिकतम पूर्ण दूरी की गणना कर सकता है। D[i,j] = \max_{k}(|A[i,k]-A[j,k]|) उदाहरण के लिए,

 D[1,2] = max( abs( A[1,] - A[2,] ) ) = max(6, 3, 1, 2, 5, 3) = 6 

हालांकि, मेरे मामले में, मुझे सबसे पहले i, j तत्व, यानी D[i,j] = \max_{k not equal to i or j}(|A[i,k]-A[j,k]|) को हटाना होगा, उदाहरण के लिए, उपरोक्त उदाहरण में, उत्तर

 D[1,2] = max( abs( A[1,] - A[2,] ) ) = max( 1, 2, 5, 3) = 5

मुझे नहीं पता कि इसे कुशल तरीके से कैसे किया जाए, मुझे पता है कि मैं लूप के लिए उपयोग कर सकता हूं, लेकिन डेटा सेट बड़ा है, क्योंकि लूप बेहद धीमा है।

1
kevin 26 अक्टूबर 2020, 08:49

2 जवाब

सबसे बढ़िया उत्तर

मान लें कि आपके वास्तविक मैट्रिक्स में पंक्तियों से अधिक कॉलम हैं। आपके इच्छित फ़ंक्शन का आधार R कार्यान्वयन यहां दिया गया है:

max_dist <- function(mat, i, j) {
  mat <- mat[c(i, j), -c(i, j)]
  max(abs(mat[1L, ] - mat[2L, ]))
}

dist1 <- function(mat) {
  n <- nrow(mat)
  ids <- do.call(rbind, lapply(2:n, function(i, e) cbind(i:e, rep.int(i - 1L, e - i + 1L)), n))
  out <- apply(ids, 1L, function(i) max_dist(mat, i[[1L]], i[[2L]]))
  attributes(out) <- list(
    Size = n, Labels = dimnames(mat)[[1L]], Diag = FALSE, 
    Upper = FALSE, method = "dist1", call = match.call(), 
    class = "dist"
  )
  out
}

यदि आपको लगता है कि R आपके मामले के लिए पर्याप्त तेज़ नहीं है, तो आप पैकेज parallelDist का उपयोग कर सकते हैं, जो उपयोगकर्ता द्वारा परिभाषित C++ दूरी के कार्यों की अनुमति देता है। निम्नलिखित कार्यान्वयन पर विचार करें:

library(parallelDist)
library(RcppXPtrUtils)
library(RcppArmadillo)

mydist_ptr <- cppXPtr("double mydist(const arma::mat &A, const arma::mat &B) {
  arma::uvec ids = {0, (unsigned int)A(0, 0), (unsigned int)B(0, 0)};
  arma::mat A_ = A, B_ = B;
  A_.shed_cols(ids); B_.shed_cols(ids); 
  return abs((A_ - B_)).max();
}", depends = "RcppArmadillo")

dist2 <- function(mat) {
  # prepend row numbers to the matrix
  # this later allows cpp function `mydist` to identify which rows to drop 
  parDist(cbind(seq_len(nrow(mat)), mat), method = "custom", func = mydist_ptr) 
}

निम्नलिखित मैट्रिक्स के साथ परीक्षण करें (small_m आपकी पोस्ट में उदाहरण है):

small_m <- matrix(c(1,5,3,2,8,6,7,8,4,4,3,3,13,14,15,16,17,18,19,20,21,22,23,24,9,10,1,2,1,2), 5, 6, byrow = TRUE)
large_m <- matrix(rnorm(1000000), 10, 100000)

बेंचमार्क

# no real difference between these two implementations when the input matrix is small
> microbenchmark::microbenchmark(dist1(small_m), dist2(small_m))
Unit: microseconds
           expr   min     lq    mean median     uq   max neval cld
 dist1(small_m)  77.4  87.10 112.403  106.5 125.95 212.2   100  a 
 dist2(small_m) 145.5 160.25 177.786  170.2 183.80 286.7   100   b

# `dist2` is faster with large matrix input. However, the efficiency of `dist1` is also acceptable IMO.
> microbenchmark::microbenchmark(dist1(large_m), dist2(large_m))
Unit: milliseconds
           expr      min       lq      mean   median       uq      max neval cld
 dist1(large_m) 129.7531 139.3909 152.13154 143.0549 149.5870 322.0173   100   b
 dist2(large_m)  48.8025  52.5081  55.84333  55.5175  58.6095  67.6470   100  a 

आउटपुट इस प्रकार है

> dist1(small_m)
   1  2  3  4
2  5         
3 14 15      
4 18 21  6   
5  5  3 16 22
> dist2(small_m)
   1  2  3  4
2  5         
3 14 15      
4 18 21  6   
5  5  3 16 22
1
ekoam 26 अक्टूबर 2020, 12:40

यहां dist + combn + as.dist का उपयोग करते हुए एक आधार R विकल्प दिया गया है

r <- diag(0,nrow(m))
r[lower.tri(r)] <- combn(1:nrow(m),2,function(k) max(abs(do.call(`-`,asplit(m[k,],1)))[-k]))
out <- as.dist(r)

जो देता है

   1  2  3  4
2  5
3 14 15
4 18 21  6
5  5  3 16 22

डेटा

> dput(m)
structure(c(1, 7, 13, 19, 9, 5, 8, 14, 20, 10, 3, 4, 15, 21, 
1, 2, 4, 16, 22, 2, 8, 3, 17, 23, 1, 6, 3, 18, 24, 2), .Dim = 5:6)
0
ThomasIsCoding 26 अक्टूबर 2020, 13:05