Find nearest bearing on compass going both directions; into existing formula

邮差的信 提交于 2019-12-11 05:16:49

问题


Mandar has graciously written this code for me from this Q/A in r, how to assess the two vectors based on other vectors

names(df) <- c("a","b","c","d")
df_backup <- df
df$newcol <- NA

used <- c()
for (i in seq(1,length(df$a),1)){
  print("######## Separator ########")
  print(paste("searching right match that fits criteria for ",df$a[i],"in column 'a'",sep=""))
  valuea <- df[i,1]
  orderx <- order(abs(df$b-valuea))

  index=1
  while (is.na(df$newcol[i])) {
    j=orderx[index]
    if (df$b[j] %in% used){
      print(paste("passing ",df$b[j], "as it has already been used",sep=""))
      index=index+1
      next
    } else {
      indexb <- j
      valueb <- df$b[indexb]
      print(paste("trying ",valueb,sep=""))

      if (df$c[i] != df$d[indexb]) {
        df$newcol[i] <- df$b[indexb]
        print(paste("using ",valueb,sep=""))
        used <- c(used,df$b[indexb])
      } else {
        df$newcol[i] <- NA
        print(paste("cant use ",valueb,"as the column c (related to index in a) and d (related to index in b) values are matching",sep=""))
      }

      index=index+1
    }
  }
}

this is what my data look like

a   b   c   d
12.9722051  297.9117268 1   1
69.64816997 298.1908749 2   2
318.8794557 169.0386352 3   3
326.1762208 169.3201391 4   4
137.5400592 336.6595313 5   5
358.0600171 94.70890334 6   6
258.9282428 94.77530919 7   7
98.57513917 290.1983195 8   8
98.46303072 290.4078981 9   9
17.2276417  344.383796  10  10
316.6442074 148.786547  11  11
310.7370168 153.3287735 12  12
237.3270752 107.8397117 13  13
250.6538555 108.0570571 14  14
337.0954288 180.6311769 15  15
137.0336521 1.0294907   16  16
301.2277242 185.2062845 17  17
332.935301  185.9792236 18  18
340.841266  220.4043846 19  19

the values in column a and b are compass bearings. currently, the formula looks at a value in column a and compares it to all values in column b and finds the closest one. but what i realized i need it to do is look at a value in column b, but not only find the nearest value based on absolute difference, but also take into account that it is a compass bearing. for example: for the value in column a of 358.0600171 the current formula would return a value from column b of 344.383796, which is ~14 degrees away from 358.060171; however, the actual closest bearing value from column b should be 1.0294907 which is only 3 degrees away from 358.0600171. i would like to incorporate a function that that accounts for this compass bearing issue into the current formula: which does all my other needed evaluation, filtering, and column creation.

There a similar query here(Finding the closest difference between 2 degrees of a compass - Javascript), but I need assistance on whether the function will work in R, and how to incorporate it into the existing formula.


回答1:


The geosphere package has a few functions that incorporate distance between spherical points.

ftp://cran.r-project.org/pub/R/web/packages/geosphere/geosphere.pdf

I'm not sure it will be what you're looking for - you may have to figure out how the compass bearings in your data translate to the inputs you need.

I notice the problem you're having is that it treats absolute distance as numerical difference, not accounting for the fact that you should be resetting to 0 at 360. You might be able to account for this by writing a function that stipulates to sum (difference between the co-ordinate and 360) and (other co-ordinate).

Eg: - c1 is the input co-ordinate - c2 is the co-ordinate you're comparing it to

if c1 - c2 > 180 { (360 - c1) + c2 }

I don't fully understand what you're trying to do so not sure if this is right but hope it helps.




回答2:


we can find the nearest compass bearings like this:

nearest = function(i,df){
  diff = abs(df[i, 1] - df[, 2])
  diff = pmin(diff, 360-diff)
  which.min(diff)
}

df$nearest_b = sapply(1:NROW(df), nearest, df[1:2])
df$nearest_a = sapply(1:NROW(df), nearest, df[2:1])

#            a          b nearest_b nearest_a
# 1   12.97221 297.911727        16        17
# 2   69.64817 298.190875         6        17
# 3  318.87946 169.038635         5         5
# 4  326.17622 169.320139         5         5
# 5  137.54006 336.659531        11        15
# 6  358.06002  94.708903        16         9
# 7  258.92824  94.775309         8         9
# 8   98.57514 290.198320         7        17
# 9   98.46303 290.407898         7        17
# 10  17.22764 344.383796        16        19
# 11 316.64421 148.786547         2         5
# 12 310.73702 153.328774         2         5
# 13 237.32708 107.839712        19         8
# 14 250.65386 108.057057        19         8
# 15 337.09543 180.631177         5         5
# 16 137.03365   1.029491        11         6
# 17 301.22772 185.206285         2         5
# 18 332.93530 185.979224         5         5
# 19 340.84127 220.404385        10        13

The data

df = read.table(text =
"a   b   c   d
12.9722051  297.9117268 1   1
69.64816997 298.1908749 2   2
318.8794557 169.0386352 3   3
326.1762208 169.3201391 4   4
137.5400592 336.6595313 5   5
358.0600171 94.70890334 6   6
258.9282428 94.77530919 7   7
98.57513917 290.1983195 8   8
98.46303072 290.4078981 9   9
17.2276417  344.383796  10  10
316.6442074 148.786547  11  11
310.7370168 153.3287735 12  12
237.3270752 107.8397117 13  13
250.6538555 108.0570571 14  14
337.0954288 180.6311769 15  15
137.0336521 1.0294907   16  16
301.2277242 185.2062845 17  17
332.935301  185.9792236 18  18
340.841266  220.4043846 19  19",
header = T)[,1:2]



回答3:


Check this code : Just changed how orderx is defined with ifelse Now if the abs difference between angles is > 180, then use the 360-difference (which is lower value); otherwise if the difference is already <=180 use the smaller difference itself

setwd("~/Desktop/")
df <- read.table("trial.txt",header=T,sep="\t")
names(df) <- c("a","B","C","D")
df_backup <- df
df$newcol <- NA

used <- c()
for (i in seq(1,length(df$a),1)){
  print("######## Separator ########")
  print(paste("searching right match that fits criteria for ",df$a[i],"in column 'a'",sep=""))
  valueA <- df[i,1]
  # orderx <- order(abs(df$B-valueA))
  orderx <- order(ifelse(360-abs(df$B-valueA) > 180, abs(df$B-valueA) ,360-abs(df$B-valueA)))

  index=1
  while (is.na(df$newcol[i])) {
    j=orderx[index]
    if (df$B[j] %in% used){
      print(paste("passing ",df$B[j], "as it has already been used",sep=""))
      index=index+1
      next
    } else {
      indexB <- j
      valueB <- df$B[indexB]
      print(paste("trying ",valueB,sep=""))

      if (df$C[i] != df$D[indexB]) {
        df$newcol[i] <- df$B[indexB]
        print(paste("using ",valueB,sep=""))
        used <- c(used,df$B[indexB])
      } else {
        df$newcol[i] <- NA
        print(paste("cant use ",valueB,"as the column C (related to index in A) and D (related to index in B) values are matching",sep=""))
      }

      index=index+1
    }
  }
}


来源:https://stackoverflow.com/questions/41880973/find-nearest-bearing-on-compass-going-both-directions-into-existing-formula

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!