Double for-loop operation in R (with an example)

后端 未结 5 850
無奈伤痛
無奈伤痛 2021-01-06 00:02

Please look at the following small working example:

#### Pseudo data
nobs1 <- 4000
nobs2 <- 5000
mylon1 <- runif(nobs1, min=0, max=1)-76
mylat1 <         


        
5条回答
  •  盖世英雄少女心
    2021-01-06 00:12

    Here are two solutions, one is partly vectorised that uses sapply, and I think the other is fully vectorised, but I've written a couple of functions for part of the vector calculations so there may be a better way.

    I also only ran these for nobs1 = 4, 40 & 400 and nobs2 = 5, 50 & 500 as my laptop struggles for memory with large matrices.

    Solution - sapply

    R <- 6371 # Earth mean radius [km]
    
    delta.lon <- sapply(mylon2, "-", mylon1)
    delta.lon <- sin(delta.lon/2)^2
    
    coslat2 <- cos(mylat2)
    coslat1 <- cos(mylat1)
    
    delta.lan <- sapply(mylat2, "-", mylat1)
    delta.lan <- sin(delta.lan/2)^2
    
    a <- delta.lan + t(sapply(coslat1, "*", coslat2) * t(delta.lon))
    b <- ifelse(sqrt(a)<1,sqrt(a),1)
    c <- asin(b)
    d <- 2 * c
    e <- R * d
    
    f <- c(t(e))
    

    And to check the output

    sum(f)
    sum(mydistance)
    
    all.equal(f, mydistance)
    
    
    > sum(f)
    [1] 647328856
    > sum(mydistance)
    [1] 647328856
    > all.equal(f, mydistance)
    [1] TRUE
    

    Solution - with functions

    R <- 6371 # Earth mean radius [km]
    
    #function to calculate the difference between each
    #element of different sized vectors and return a matrix
    vecEleDif <- function(vec1, vec2)
    {
        #the order of arguments is vec2 - vec1
        len1 <- length(vec1);len2 <- length(vec2)
        dummy1 <- matrix(rep.int(vec1, len2), nrow=len1)
        dummy2 <- matrix(rep.int(vec2, len1), nrow=len2)
        res <- t(dummy2 - t(dummy1))
    }
    
    #Function to calculate the product of each 
    #element of two different size vectors
    vecEleProd <- function(vec1, vec2)
    {
        #the order of the arguments is vec2 * vec1
        len1 <- length(vec1); len2 <- length(vec2)
        dummy1 <- matrix(rep.int(vec1, len2), nrow=len1)
        dummy2 <- matrix(rep.int(vec2, len1), nrow=len2)
        res <- t(dummy2 * t(dummy1))
    }
    
    ptm <- proc.time()
    
    delta.lon <- sin(vecEleDif(mylon2, mylon1)/2)^2
    delta.lan <- sin(vecEleDif(mylat2, mylat1)/2)^2
    cosprod <- vecEleProd(cos(mylat1), cos(mylat2))
    
    a <- delta.lan + (t(cosprod) * delta.lon)
    b <- ifelse(sqrt(a)<1,sqrt(a),1)
    c <- asin(b)
    d <- 2 * c
    e <- R * d
    f <- c((e))
    
    proc.time() - ptm
    

    and check the output:

    sum(f)
    sum(mydistance)
    
    all.equal(f, mydistance)
    
    > sum(f)
    [1] 647745044
    > sum(mydistance)
    [1] 647745044
    > 
    > all.equal(f, mydistance)
    [1] TRUE
    

提交回复
热议问题