ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
12
返回列表 发新帖
楼主: 松野

[求助] 求两组坐标经纬度的最小距离并匹配到位置点和距离

[复制链接]

TA的精华主题

TA的得分主题

发表于 2022-12-12 10:11 | 显示全部楼层
这样计算时间节省到1/4,还是很有效的。

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-12 21:41 | 显示全部楼层
grf1973 发表于 2022-12-12 10:09
考虑到经度差和纬度差都非常小,可以考虑在平面内近似。即相当于平面内两个点取最近距离,然后还原球面距离

这个算出来结果不一样

TA的精华主题

TA的得分主题

发表于 2022-12-12 22:49 | 显示全部楼层
for循环和CalcDistance把application优化掉。For i = 1 To UBound(brr)中就可以把最小值 和索引算出来,crr没啥用。把CalcDistance代码合并到循环中可以减少参数传递和转换。CalcDistance中的常量可以在找到最小值后再乘。arr,brr也可以先转换成double数组。优化一下应该能快很多。

TA的精华主题

TA的得分主题

发表于 2022-12-13 13:50 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
松野 发表于 2022-12-12 21:41
这个算出来结果不一样

嗯,细看了一下,数据源861条,正确的有829条。

TA的精华主题

TA的得分主题

发表于 2022-12-13 15:19 | 显示全部楼层
小改了一下,略有提高,可以忽略不计。
常量后置影响更小。
360截图20221212100719369.jpg

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2022-12-14 09:24 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
  1. Sub js()
  2. Dim i, j As Long
  3. Dim arr, brr, crr, drr

  4. Dim t As Double
  5. Dim d1 As Double
  6. Dim d2 As Double
  7. Dim d3 As Double

  8. Dim td As Double
  9. Dim d As Double
  10. Dim twc As Double

  11. Dim imin As Long
  12. arr = Sheet1.Range("d2:f" & Cells(Rows.Count, "f").End(xlUp).Row)
  13. brr = Sheet1.Range("a2:c" & Cells(Rows.Count, "c").End(xlUp).Row)
  14. t = Timer

  15. ReDim crr(1 To UBound(brr), 1 To 3)
  16. ReDim drr(1 To UBound(arr), 1 To 4)
  17. For i = 1 To UBound(brr)
  18.    twc = Cos(Radians(brr(i, 3)))
  19.   
  20.    crr(i, 1) = twc * Cos(Radians(brr(i, 2)))
  21.    crr(i, 2) = twc * Sin(Radians(brr(i, 2)))
  22.    
  23.    crr(i, 3) = Sin(Radians(brr(i, 3)))
  24. Next
  25. For j = 1 To UBound(arr)
  26.    twc = Cos(Radians(arr(j, 3)))
  27.   
  28.     d1 = twc * Cos(Radians(arr(j, 2)))
  29.     d2 = twc * Sin(Radians(arr(j, 2)))
  30.    
  31.     d3 = Sin(Radians(arr(j, 3)))
  32.     d = (d1 - crr(1, 1)) * (d1 - crr(1, 1)) + (d2 - crr(1, 2)) * (d2 - crr(1, 2)) + (d3 - crr(1, 3)) * (d3 - crr(1, 3))
  33.     imin = 1
  34.    
  35.     For i = 2 To UBound(crr)
  36.       
  37.         td = (d1 - crr(i, 1)) * (d1 - crr(i, 1)) + (d2 - crr(i, 2)) * (d2 - crr(i, 2)) + (d3 - crr(i, 3)) * (d3 - crr(i, 3))
  38.         
  39.         If td < d Then
  40.            d = td
  41.            imin = i
  42.         End If
  43.         
  44.     Next
  45.    
  46.     drr(j, 1) = brr(imin, 1)
  47.    
  48.      drr(j, 2) = brr(imin, 2)
  49.     drr(j, 3) = brr(imin, 3)
  50.     'drr(j, 4) = CalcDistance(brr(imin, 3), brr(imin, 2), arr(j, 3), arr(j, 2))
  51.     drr(j, 4) = 6378137 * 2 * Application.Asin(Sqr(d) / 2)
  52. Next
  53. Sheet1.Range("o2").Resize(UBound(arr), 4) = drr
  54. Sheet1.Range("s1") = Timer - t

  55.    
  56. End Sub
复制代码


基于计算的优化,如果数据量很大,运算速度达不到要求,就要选择其他方法了

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2022-12-14 11:01 | 显示全部楼层
Sub js()
Dim i, j As Long
Dim arr, brr, crr, drr

Dim t As Double
Dim d1 As Double
Dim d2 As Double
Dim d3 As Double

Dim td As Double
Dim d As Double
Dim twc As Double

Dim imin As Long
arr = Sheet1.Range("d2:f" & Cells(Rows.Count, "f").End(xlUp).Row)
brr = Sheet1.Range("a2:c" & Cells(Rows.Count, "c").End(xlUp).Row)
t = Timer

ReDim crr(1 To UBound(brr), 1 To 3)
ReDim drr(1 To UBound(arr), 1 To 4)
For i = 1 To UBound(brr)
   twc = Cos(Radians(brr(i, 3)))
  
   crr(i, 1) = twc * Cos(Radians(brr(i, 2)))
   crr(i, 2) = twc * Sin(Radians(brr(i, 2)))
   
   crr(i, 3) = Sin(Radians(brr(i, 3)))
Next
For j = 1 To UBound(arr)
   twc = Cos(Radians(arr(j, 3)))
  
    d1 = twc * Cos(Radians(arr(j, 2)))
    d2 = twc * Sin(Radians(arr(j, 2)))
   
    d3 = Sin(Radians(arr(j, 3)))
    d = (d1 - crr(1, 1)) * (d1 - crr(1, 1)) + (d2 - crr(1, 2)) * (d2 - crr(1, 2)) + (d3 - crr(1, 3)) * (d3 - crr(1, 3))
    imin = 1
   
    For i = 2 To UBound(crr)
      
        td = (d1 - crr(i, 1)) * (d1 - crr(i, 1)) + (d2 - crr(i, 2)) * (d2 - crr(i, 2)) + (d3 - crr(i, 3)) * (d3 - crr(i, 3))
        
        If td < d Then
           d = td
           imin = i
        End If
        
    Next
   
    drr(j, 1) = brr(imin, 1)
   
     drr(j, 2) = brr(imin, 2)
    drr(j, 3) = brr(imin, 3)
    'drr(j, 4) = CalcDistance(brr(imin, 3), brr(imin, 2), arr(j, 3), arr(j, 2))
    drr(j, 4) = 6378137 * 2 * Application.Asin(Sqr(d) / 2)
Next
Sheet1.Range("o2").Resize(UBound(arr), 4) = drr
Sheet1.Range("s1") = Timer - t

   
End Sub

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-16 17:03 | 显示全部楼层
lxdexcel 发表于 2022-12-14 09:24
基于计算的优化,如果数据量很大,运算速度达不到要求,就要选择其他方法了

这个优化后速度很快,1万匹配1万条数据(1亿次循环)测试结果比原来快了11倍;距离结果值的小数点后10位不一样,不过已经不影响了,在我的电脑上运行需要把Radians替换为worksheetfunction.Radians,不然会报错,可能是我的模块里面自定义了Radians函数。

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-16 17:25 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
我把最终的结果分享出来并加入了进度条,测试数据为5000条匹配5000条,可以很明显看出来算法3速度快好几倍

求两组坐标的最小距离.rar

389.47 KB, 下载次数: 15

TA的精华主题

TA的得分主题

发表于 2022-12-19 04:13 | 显示全部楼层
这样弄弄会更快一点,主要是减少For i = 2 To UBound(crr)中的计算量
Sub js3()
Dim i, j As Long
Dim arr, brr, crr, drr

Dim t As Double
Dim d1 As Double
Dim d2 As Double
Dim d3 As Double

Dim td As Double
Dim d As Double
Dim twc As Double

Dim imin As Long
Dim w As Double
Dim ZDK As Integer
tm = Timer
'''''''''''''进度条'''''''''''''''''''''''
'UserForm1.Show 0
'ZDK = UserForm1.TextBox1.Width
'UserForm1.TextBox2.SetFocus '焦点设置在文本框2防止闪烁
'''''''''''''进度条'''''''''''''''''''''''
arr = Sheet1.Range("d2:f" & Cells(Rows.Count, "f").End(xlUp).Row)
brr = Sheet1.Range("a2:c" & Cells(Rows.Count, "c").End(xlUp).Row)
t = Timer

ReDim crr(1 To UBound(brr), 1 To 3) As Double
ReDim drr(1 To UBound(arr), 1 To 4)

Dim b2 As Double, b3 As Double
For i = 1 To UBound(brr)
   
    b2 = brr(i, 3) * PI
    b3 = brr(i, 3) * PI
   twc = Cos(b3)
   

   crr(i, 1) = twc * Cos(b2)
   crr(i, 2) = twc * Sin(b2)
   
   crr(i, 3) = Sin(b3)
Next

Dim a2 As Double, a3 As Double, x As Double, y As Double, z As Double, iubc As Long, iuba As Long, p As Long, p0 As Double
iuba = UBound(arr)
iubc = UBound(crr)
p0 = 100 / iuba
For j = 1 To iuba
    a2 = arr(j, 2) * PI
    a3 = arr(j, 3) * PI
   
    twc = Cos(a3)
    d1 = twc * Cos(a2)
    d2 = twc * Sin(a2)
    d3 = Sin(a3)
   
    x = d1 - crr(1, 1)
    y = d2 - crr(1, 2)
    z = d3 - crr(1, 3)
    d = x * x + y * y + z * z
    imin = 1
   
   
    For i = 2 To iubc
         x = d1 - crr(i, 1)
         y = d2 - crr(i, 2)
         z = d3 - crr(i, 3)
         
        td = x * x + y * y + z * z

        If td < d Then
           d = td
           imin = i
        End If
    Next
   
    drr(j, 1) = brr(imin, 1)
   
     drr(j, 2) = brr(imin, 2)
    drr(j, 3) = brr(imin, 3)
    'drr(j, 4) = CalcDistance(brr(imin, 3), brr(imin, 2), arr(j, 3), arr(j, 2))
    drr(j, 4) = 6378137 * 2 * Application.Asin(Sqr(d) * 0.5)
'''''''''''进度条''''''''''''''''''''''
   
'    If j * p0 > p + 5 Then
'        p = j * p0
'        UserForm1.Label1.Width = ZDK * p / 100
'        UserForm1.Label2.Caption = p & "%"
        DoEvents
'    End If
'''''''''''进度条''''''''''''''''''''''
Next
Sheet1.Range("g2").Resize(UBound(arr), 4) = drr
Unload UserForm1
MsgBox "恭喜,计算完成" & ",耗时:" & Timer - tm, vbOKOnly Or 64, "提示"
End Sub

评分

1

查看全部评分

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-20 06:36 , Processed in 0.042284 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表