Decreasing iteration time through better vectorization

Viewed 99

I'm trying to substantially decrease computing time for my code.

I have 2 data.frames:

1.NewCus_withGeo

head(newCus)
      U_ID    U_LAT    U_LONG
  31902101 47.57080 -52.69588
  26428781 45.50141 -73.55854
  26428801 45.40768 -73.95121
  28130841 45.44952 -73.82955
  26428961 45.54130 -73.47751
  26428981 45.35496 -75.67068

2.localD

head(localD)
           ID    D_ID    D_LAT    D_LONG
1533582_23821 1533582 45.40462 -75.62618
1533582_97592 1533582 45.21759 -75.71293
1533582_23811 1533582 46.83400 -71.28574
4126692_23811 4126692 46.79560 -71.27572
4134402_23811 4134402 46.74568 -71.44606
4135162_23811 4135162 46.82987 -71.23739
4138752_23841 4138752 46.34229 -72.54294

I want to get for every U_ID the 5 D_ID with smallest euclidean distance but only if that distance is under 0.3.

I want as a result another data.frame containing for each U_ID with close enough D_ID the 5 closest D_ID and the distance between U_ID and D_ID which would look like this:

head(result_df)
         U_ID    D_ID         dist
     26428781 4244252 0.0008656102
     26428781 4088692 0.0055139426
     26428781 4177752 0.0060150366
     26428781 4182572 0.0067220964
     26428781 4191862 0.0076759495
     26428801 4135212 0.0455715423
     26428801 4216202 0.0726350403

I came up with this code to do it:

EDIT Thanks to Rui Barradas who improved function's performance

EDIT 2 to further improve function's performance we can use data.table to improve time on subseting

library(data.table)
newCus = data.table(newCus)

distance <- function(x,y){
 # Subsetting newCus to get only one U_ID
 tb <- newCus[U_ID == x]

 # distance calculations
 dist = (tb$U_LAT - y$D_LAT)^2 + (tb$U_LONG - y$D_LONG)^2

 if(min(dist) <= 0.3^2){

   # Putting the data.frame together
   NewCus_dist <- data.frame(U_ID = tb$U_ID, D_ID = y$D_ID, dist = dist)
   # Keeping top 5 D_ID
   NewCus_dist <- NewCus_dist[order(dist)[1:5], ]
   NewCus_dist$dist <- sqrt(NewCus_dist$dist)

 } else {
   NewCus_dist <- NULL
 }
 NewCus_dist
}

Then using this function in a do.call and lapply function to iterate over the U_ID and get the result in a data.frame

 result_df = do.call("rbind", lapply(newCus$U_ID, distance, localD))

Is there a better and faster way to code this?

2 Answers
Related