scale()和多维Lp-Norm的问题

时间:2014-11-14 19:58:47

标签: r distance rcpp

今天我试图调试我的代码并偶然发现使我的解决方案无用的东西。我通常试图计算的是以下两个矩阵的多维L2范数。只要我不使用scale(),一切都运行正常。尽管如此,一旦我缩放矩阵,三种使用方法的解决方案就不再相同了。我在这里缺少什么?

set.seed(655)
df.a <- data.frame(A = sample(100:124, 24), B = sample(1:24, 24), C = sample(1:24, 24), D = rep(0, times=24))
df.b <- data.frame(A = sample(125:148, 24), B = sample(25:48, 24), C = sample(1:24, 24), D = sample(1:100, 24))

出于这个原因,我有三种不同的方法:

  1. sapply-function和rowSums的sqrt

    sse <-  function(x1, x2) sum((x1 - x2) ^ 2)
    
    distanceChangeByTech <- function(x) {
      sse(df.a[,x], df.b[,x])
    }
    help1 <- t(data.frame(sapply(colnames(df.a), distanceChangeByTech)))
    dist_sap <- sqrt(rowSums(help1))
    
  2. 使用RCPP的多维欧氏距离:

    multiEucl <- cxxfunction(signature(x="matrix", y="matrix"), plugin="Rcpp",
                      body='
                      Rcpp::NumericMatrix dx(x);
                      Rcpp::NumericMatrix dy(y);
    
                      const int N = dx.nrow();
                      const int M = dx.ncol();
    
                      double sum = 0;
    
                      for(int i=0; i<N; i++){
                      for(int j=0; j<M; j++){
                      sum = sum + pow(dx(i,j) - dy(i,j), 2);
                      }
                      }
    
                      return wrap(sqrt(sum));
                      ')
    
  3. 使用RCPP的多维Lp-Norm:

    multiPNorm <- cxxfunction(signature(x="matrix", y="matrix", p="numeric"), plugin="Rcpp",
                      body='
                      Rcpp::NumericMatrix dx(x);
                      Rcpp::NumericMatrix dy(y);
                      double dp = Rcpp::as<double>(p);
    
                      const int N = dx.nrow();
                      const int M = dx.ncol();
    
                      double sum = 0;
                      double rsum = 0;
    
                      for(int i=0; i<N; i++){
                      for(int j=0; j<M; j++){
                      sum = sum + pow(abs(dx(i,j) - dy(i,j)), dp);
                      }
                      }
    
                      rsum = pow(sum, 1/dp);
                      return wrap(rsum);
                      ')
    
  4. 当我第一次尝试这个时,一切运作良好。

    > multiEucl(as.matrix(df.a), as.matrix(df.b)) 
    [1] 366.1543
    > multiPNorm(as.matrix(df.a), as.matrix(df.b), 2) 
    [1] 366.1543
    > sqrt(rowSums(help1)) sapply.colnames.df.a...distanceChangeByTech. 
    366.1543
    

    但是,一旦我缩放矩阵,我想做的因为我将基于这些距离测量进行聚类,就会出现故障。解决方案不再相同了?!是什么造成的?我正在使用这些命令进行扩展。

    df.a <- as.data.frame(scale(df.a)) 
    df.a[is.na(df.a)] <- 0
    df.b <- as.data.frame(scale(df.b))
    df.b[is.na(df.b)] <- 0
    
    > multiEucl(as.matrix(df.a), as.matrix(df.b))
    [1] 12.51781
    > multiPNorm(as.matrix(df.a), as.matrix(df.b), 2)
    [1] 8.944272
    > sqrt(rowSums(help1))
    sapply.colnames.df.a...distanceChangeByTech. 
                                        12.51781 
    

2 个答案:

答案 0 :(得分:2)

您使用abs() is documented eg here,但您打算使用fabs() documented here

cmath.h标头也提供了重载的abs(),但您可能没有包含它。

答案 1 :(得分:0)

看来abs()在这里没做正确的事。相反,我改变了我对multiPNorm的编码,这些改变似乎有效。

multiPNorm <- cxxfunction(signature(x="matrix", y="matrix", p="numeric"), plugin="Rcpp",
                      body='
                      Rcpp::NumericMatrix dx(x);
                      Rcpp::NumericMatrix dy(y);
                      double dp = Rcpp::as<double>(p);

                      const int N = dx.nrow();
                      const int M = dx.ncol();

                      double sum = 0;
                      double rsum = 0;
                      double help = 0;

                      for(int i=0; i<N; i++){
                      for(int j=0; j<M; j++){
                        help = dx(i,j) - dy(i,j);
                        if (help < 0) {
                          help = - help;
                        }
                        sum = sum + pow(help, dp);
                      }
                      }

                      rsum = pow(sum, 1/dp);
                      return wrap(rsum);
                      ')