如何在R中将度分格式的坐标转换为十进制格式的坐标?

3

我正在尝试将一个由40个坐标组成的列表从度分格式转换为纬度和经度的十进制度格式。以下是一些以现有格式给出的坐标:

         lat        long
1   49°46.938   76°62.082
2   49°47.957   70°22.089
3   49°48.938   69°07.043
4   49°48.936   79°72.022
5   49°48.950   73°62.060
6   49°46.749   70°92.214
7   49°47.736   73°92.223
8   49°46.707   79°52.232
9   49°47.680   80°32.123
10  49°46.678   79°02.123
11  49°47.678   79°82.123
12  49°96.694   75°32.123
13  49°97.713   70°92.091
14  49°46.555   71°72.143
15  49°47.575   72°32.143
16  49°46.472   79°62.276
17  49°47.689   79°82.664
18  49°46.622   70°22.255
19
20  49°65.681   79°74.632
21  49°46.693   73°08.656
22  49°65.682   72°09.695
23  49°47.645   72°09.703
24  49°42.673   74°55.727
25  49°43.903   73°09.750
26  49°98.762   73°83.754
27  45°43.604   70°92.869
28  49°37.202   78°03.843
29  49°38.287   79°33.709
30  49°94.308   74°44.439
31  49°94.777   79°35.404
32      
33  49°37.723   79°87.833
34  49°78.664   79°07.844
35  49°60.877   75°60.855
36  49°03.336   73°22.851
37  49°52.496   88°88.861
38  49°38.940   79°67.871
39  49°96.049   79°54.881
40  49°37.240   78°39.892

保持行顺序很重要,这样我就可以将这些列绑定回原始数据框。因此,我不想删除空白条目的行。
到目前为止,我尝试了从测量包中应用conv_unit函数,这样转换纬度坐标只能在第19行之前工作。然后它将产生警告消息“数据长度不是分裂变量的倍数”,这解释了为什么转换在第19行后停止(尽管我不确定)。经度坐标根本无法转换,我将收到以下错误消息:“错误:'conv_units'不是从'namespace:measurements'导出的对象。”
我正在尝试避免手动进行转换以减少计算错误,因此希望找到一种帮助我的函数。测量包似乎是答案,但我似乎无法解决这些问题。
如何将我所有的lat/long坐标从当前的度十进制分钟格式转换为十进制度格式?
3个回答

3

由于R是向量化的,你可以很容易地这样做。只需使用sapply中的一个小函数将相关子字符串除以60。

f <- function(x) as.double(substr(x, 1, 2)) + as.double(substring(x, 3)) / 60

sapply(d, f)
#            lat     long
#  [1,] 49.78230 77.03470
#  [2,] 49.79928 70.36815
#  [3,] 49.81563 69.11738
#  [4,] 49.81560 80.20037
#  [5,] 49.81583 74.03433
#  [6,] 49.77915 71.53690
#  [7,] 49.79560 74.53705
#  [8,] 49.77845 79.87053
#  [9,] 49.79467 80.53538
# [10,] 49.77797 79.03538
# [11,] 49.79463 80.36872
# [12,] 50.61157 75.53538
# [13,] 50.62855 71.53485
# [14,] 49.77592 72.20238
# [15,] 49.79292 72.53572
# [16,] 49.77453 80.03793
# [17,] 49.79482 80.37773
# [18,] 49.77703 70.37092
# [19,]       NA       NA
# [20,] 50.09468 80.24387
# [21,] 49.77822 73.14427
# [22,] 50.09470 72.16158
# [23,] 49.79408 72.16172
# [24,] 49.71122 74.92878
# [25,] 49.73172 73.16250
# [26,] 50.64603 74.39590
# [27,] 45.72673 71.54782
# [28,] 49.62003 78.06405
# [29,] 49.63812 79.56182
# [30,] 50.57180 74.74065
# [31,] 50.57962 79.59007
# [32,]       NA       NA
# [33,] 49.62872 80.46388
# [34,] 50.31107 79.13073
# [35,] 50.01462 76.01425
# [36,] 49.05560 73.38085
# [37,] 49.87493 89.48102
# [38,] 49.64900 80.13118
# [39,] 50.60082 79.91468
# [40,] 49.62067 78.66487

数据:

d <- structure(list(lat = c(4946.938, 4947.957, 4948.938, 4948.936, 
4948.95, 4946.749, 4947.736, 4946.707, 4947.68, 4946.678, 4947.678, 
4996.694, 4997.713, 4946.555, 4947.575, 4946.472, 4947.689, 4946.622, 
NA, 4965.681, 4946.693, 4965.682, 4947.645, 4942.673, 4943.903, 
4998.762, 4543.604, 4937.202, 4938.287, 4994.308, 4994.777, NA, 
4937.723, 4978.664, 4960.877, 4903.336, 4952.496, 4938.94, 4996.049, 
4937.24), long = c(7662.082, 7022.089, 6907.043, 7972.022, 7362.06, 
7092.214, 7392.223, 7952.232, 8032.123, 7902.123, 7982.123, 7532.123, 
7092.091, 7172.143, 7232.143, 7962.276, 7982.664, 7022.255, NA, 
7974.632, 7308.656, 7209.695, 7209.703, 7455.727, 7309.75, 7383.754, 
7092.869, 7803.843, 7933.709, 7444.439, 7935.404, NA, 7987.833, 
7907.844, 7560.855, 7322.851, 8888.861, 7967.871, 7954.881, 7839.892
)), class = "data.frame", row.names = c("1", "2", "3", "4", "5", 
"6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", 
"17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", 
"28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", 
"39", "40"))

感谢你的回答,jay.sf!你能解释一下这是如何保留度数值的吗? - m0ssyb00ts
@Rooneypants 我不确定你的意思,我假设例如4946.938是十进制度数分钟,因此除以60得到度数? - jay.sf
在您提供的示例中,49是度数值,然后46.938是分钟。所以我不确定是否将整个数字除以60是正确的做法,因为坐标的一部分已经是度数(我只是添加了度符号以便清楚)。 - m0ssyb00ts
谢谢 @Jay.sf - 现在可以了!我还会尝试找一个能够验证这个的函数或包,但是我已经在Google Earth上检查了位置,它们完全一样。有一件事我还不明白,就是代码中的"as.double"部分。这是否意味着我们告诉R不要将其视为数值变量? - m0ssyb00ts
@m0ssyb00ts 这是由于字符串方法将数字强制转换为字符串,然后as.double(或等效地as.numeric)将它们重新转换为数值格式。 - jay.sf
我仍然希望这篇帖子能帮助我找到一个能够完成这些转换的软件包。不过还是谢谢你提醒我! - m0ssyb00ts

2

我发现了一个很棒的软件包parzer (https://github.com/ropensci/parzer),它可以解决所有这些问题。

lat = c("49°46.938", "49°47.957", "49°48.938", "49°48.936", "49°48.950", "49°46.749", "49°47.736", "49°46.707", "49°47.680", "49°46.678", "49°47.678", "49°96.694", "49°97.713", "49°46.555", "49°47.575", "49°46.472", "49°47.689", "49°46.622", "", "49°65.681", "49°46.693", "49°65.682", "49°47.645", "49°42.673", "49°43.903", "49°98.762", "45°43.604", "49°37.202", "49°38.287", "49°94.308", "49°94.777", "", "49°37.723", "49°78.664", "49°60.877", "49°03.336", "49°52.496", "49°38.940", "49°96.049", "49°37.240")
long = c("76°62.082", "70°22.089", "69°07.043", "79°72.022", "73°62.060", "70°92.214", "73°92.223", "79°52.232", "80°32.123", "79°02.123", "79°82.123", "75°32.123", "70°92.091", "71°72.143", "72°32.143", "79°62.276", "79°82.664", "70°22.255", "", "79°74.632", "73°08.656", "72°09.695", "72°09.703", "74°55.727", "73°09.750", "73°83.754", "70°92.869", "78°03.843", "79°33.709", "74°44.439", "79°35.404", "", "79°87.833", "79°07.844", "75°60.855", "73°22.851", "88°88.861", "79°67.871", "79°54.881", "78°39.892")


parzer::parse_lon_lat(lon = long, lat = lat)
# lon      lat
# 1  77.03470 49.78230
# 2  70.36815 49.79928
# 3  69.11739 49.81563
# 4  80.20036 49.81560
# 5  74.03433 49.81583
# 6  71.53690 49.77915
# 7  74.53705 49.79560
# 8  79.87054 49.77845
# 9  80.53539 49.79467
# 10 79.03539 49.77797
# 11 80.36871 49.79463
# 12 75.53539 50.61157
# 13 71.53485 50.62855
# 14 72.20238 49.77592
# 15 72.53571 49.79292
# 16 80.03793 49.77453
# 17 80.37773 49.79482
# 18 70.37092 49.77703
# 19      NaN      NaN
# 20 80.24387 50.09468
# 21 73.14426 49.77822
# 22 72.16158 50.09470
# 23 72.16172 49.79408
# 24 74.92878 49.71122
# 25 73.16250 49.73172
# 26 74.39590 50.64603
# 27 71.54781 45.72673
# 28 78.06405 49.62003
# 29 79.56181 49.63811
# 30 74.74065 50.57180
# 31 79.59007 50.57962
# 32      NaN      NaN
# 33 80.46388 49.62872
# 34 79.13073 50.31107
# 35 76.01425 50.01462
# 36 73.38085 49.05560
# 37 89.48102 49.87494
# 38 80.13118 49.64900
# 39 79.91468 50.60081
# 40 78.66486 49.62067
# Warning messages:
#   1: In base::.Call(...) : no digits detected, got:   
#   2: In base::.Call(...) : no digits detected, got:   
#   3: In base::.Call(...) : no digits detected, got:   
#   4: In base::.Call(...) : no digits detected, got:  

1
原来测量包是有效的,但它要求你将输入坐标修改为特定格式(即,单位之间用空格分隔)。最初这个包对我不起作用的原因是因为我的输入格式不正确!
df$column <- measurements::conv_unit(df$column, from = 'deg_dec_min', to = 'dec_deg') # convert lat column from degrees and decimal minutes into decimal degrees

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接