r-find two closest values in a vector

时间秒杀一切 提交于 2020-05-15 04:44:11

问题


I tried to find two values in the following vector, which are close to 10. The expected value is 10.12099196 and 10.63054170. Your inputs would be appreciated.

 [1]  0.98799517  1.09055728  1.20383713  1.32927166  1.46857509  1.62380423  1.79743107  1.99241551  2.21226576  2.46106916  2.74346924  3.06455219  3.42958354  3.84350238  4.31005838
[16]  4.83051356  5.40199462  6.01590035  6.65715769  7.30532785  7.93823621  8.53773241  9.09570538  9.61755743 10.12099196 10.63018180 11.16783243 11.74870531 12.37719092 13.04922392
[31] 13.75661322 14.49087793 15.24414627 16.00601247 16.75709565 17.46236358 18.06882072 18.51050094 18.71908344 18.63563523 18.22123225 17.46709279 16.40246292 15.09417699 13.63404124
[46] 12.11854915 10.63054170  9.22947285  7.95056000  6.80923943  5.80717982  4.93764782  4.18947450  3.54966795  3.00499094  2.54283599  2.15165780  1.82114213  1.54222565  1.30703661
[61]  1.10879707  0.94170986  0.80084308  0.68201911  0.58171175  0.49695298  0.42525021  0.36451350  0.31299262  0.26922281  0.23197860  0.20023468  0.17313291  0.14995459  0.13009730
[76]  0.11305559  0.09840485  0.08578789  0.07490387  0.06549894  0.05735864 

回答1:


I can't think of a way without using sort. However, you can speed it up by using partial sort.

x[abs(x-10) %in% sort(abs(x-10), partial=1:2)[1:2]]
# [1]  9.617557 10.120992

In case the same values are present more than once, you'll get all of them here. So, you can either wrap this with unique or you can use match instead as follows:

x[match(sort(abs(x-10), partial=1:2)[1:2], abs(x-10))]
# [1] 10.120992  9.617557

dput output:

dput(x)
c(0.98799517, 1.09055728, 1.20383713, 1.32927166, 1.46857509, 
1.62380423, 1.79743107, 1.99241551, 2.21226576, 2.46106916, 2.74346924, 
3.06455219, 3.42958354, 3.84350238, 4.31005838, 4.83051356, 5.40199462, 
6.01590035, 6.65715769, 7.30532785, 7.93823621, 8.53773241, 9.09570538, 
9.61755743, 10.12099196, 10.6301818, 11.16783243, 11.74870531, 
12.37719092, 13.04922392, 13.75661322, 14.49087793, 15.24414627, 
16.00601247, 16.75709565, 17.46236358, 18.06882072, 18.51050094, 
18.71908344, 18.63563523, 18.22123225, 17.46709279, 16.40246292, 
15.09417699, 13.63404124, 12.11854915, 10.6305417, 9.22947285, 
7.95056, 6.80923943, 5.80717982, 4.93764782, 4.1894745, 3.54966795, 
3.00499094, 2.54283599, 2.1516578, 1.82114213, 1.54222565, 1.30703661, 
1.10879707, 0.94170986, 0.80084308, 0.68201911, 0.58171175, 0.49695298, 
0.42525021, 0.3645135, 0.31299262, 0.26922281, 0.2319786, 0.20023468, 
0.17313291, 0.14995459, 0.1300973, 0.11305559, 0.09840485, 0.08578789, 
0.07490387, 0.06549894, 0.05735864)



回答2:


Another alternative could be allowing the user to control for the "tolerance" in order to set what "closeness" is, this can be done by using a simple function:

close <- function(x, value, tol=NULL){
  if(!is.null(tol)){
    x[abs(x-10) <= tol]
  } else {
    x[order(abs(x-10))]
  }
}

Where x is a vector of values, value is the value of comparison for closeness, and tol is logical, if it's NULL it returns all the "close" values ordered by "closeness" to value, otherwise it returns just the values meeting the condition given in tol.

> close(x, value=10, tol=.7)
[1]  9.617557 10.120992 10.630182 10.630542


> close(x, value=10)
 [1] 10.12099196  9.61755743 10.63018180 10.63054170  9.22947285  9.09570538 11.16783243
 [8]  8.53773241 11.74870531  7.95056000  7.93823621 12.11854915 12.37719092  7.30532785
[15] 13.04922392  6.80923943  6.65715769 13.63404124 13.75661322  6.01590035  5.80717982
[22] 14.49087793  5.40199462  4.93764782 15.09417699  4.83051356 15.24414627  4.31005838
[29]  4.18947450 16.00601247  3.84350238 16.40246292  3.54966795  3.42958354 16.75709565
[36]  3.06455219  3.00499094  2.74346924  2.54283599 17.46236358 17.46709279  2.46106916
[43]  2.21226576  2.15165780  1.99241551 18.06882072  1.82114213  1.79743107 18.22123225
[50]  1.62380423  1.54222565 18.51050094  1.46857509 18.63563523  1.32927166  1.30703661
[57] 18.71908344  1.20383713  1.10879707  1.09055728  0.98799517  0.94170986  0.80084308
[64]  0.68201911  0.58171175  0.49695298  0.42525021  0.36451350  0.31299262  0.26922281
[71]  0.23197860  0.20023468  0.17313291  0.14995459  0.13009730  0.11305559  0.09840485
[78]  0.08578789  0.07490387  0.06549894  0.05735864

In the first example I defined "closeness" to be at most a difference of 0.7 between value and each elements in x. In the second example the function close returns a vector of values where the firsts are the closest to the value given in value and the lasts are the farest values from value.

Since my solution does not provide an easy (practical) way to find tol as @Arun pointed out, one way to find the closest values would be seting tol=NULL and asking for the exact number of close values as in:

> close(x, value=10)[1:3]
[1] 10.120992  9.617557 10.630182

This shows the three values in x closest to 10.




回答3:


I'm not sure your question is clear, so here's another approach. To find the value closest to your first desired value, 10.12099196 , subtract that from the vector, take the absolute value, and then find the index of the closest element. Explicit:

delx <- abs( 10.12099196 - x)
min.index <- which.min(delx)  #returns index of first minimum if there are duplicates
x[min.index]   #gets you the value itself

Apologies if this was not the intent of your question.



来源:https://stackoverflow.com/questions/16446042/r-find-two-closest-values-in-a-vector

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