将地理坐标从度数转换为十进制数

27

我想将我的地理坐标从度数转换为十进制数,我的数据如下:

         lat     long
105252 30°25.264 9°01.331
105253 30°39.237 8°10.811
105255 31°37.760 8°06.040
105258 31°41.190 8°06.557
105259 31°41.229 8°06.622
105260 31°38.891 8°06.281

我有这段代码,但我看不出来为什么它不起作用:

convert<-function(coord){
tmp1=strsplit(coord,"°")
tmp2=strsplit(tmp1[[1]][2],"\\.")
dec=c(as.numeric(tmp1[[1]][1]),as.numeric(tmp2[[1]]))
return(dec[1]+dec[2]/60+dec[3]/3600) 
} 
don_convert=don1
for(i in 1:nrow(don1)){don_convert[i,2]=convert(as.character(don1[i,2]));              don_convert[i,3]=convert(as.character(don1[i,3]))}

转换函数有效,但我要求循环代替我完成该任务的代码无法运行。

欢迎提出任何建议。


3
看起来转换函数需要度数、分钟和秒数,但是你的输入似乎只有度数和带小数点的分钟数,没有秒数字段。而且它似乎不能正确处理负值。不确定这两个问题是否与你的问题有关。 - Jim Lewis
7个回答

29

使用 CRAN 中的 measurements 包,它已经有一个单位转换函数,因此您不需要自己编写:

x = read.table(text = "
   lat     long
105252 30°25.264 9°01.331
105253 30°39.237 8°10.811
105255 31°37.760 8°06.040
105258 31°41.190 8°06.557
105259 31°41.229 8°06.622
105260 31°38.891 8°06.281",
header = TRUE, stringsAsFactors = FALSE)

一旦你的数据框设置好了,那么:

# change the degree symbol to a space
x$lat = gsub('°', ' ', x$lat)
x$long = gsub('°', ' ', x$long)

# convert from decimal minutes to decimal degrees
x$lat = measurements::conv_unit(x$lat, from = 'deg_dec_min', to = 'dec_deg')
x$long = measurements::conv_unit(x$long, from = 'deg_dec_min', to = 'dec_deg')

最终产品的结果:

                    lat             long
105252 30.4210666666667 9.02218333333333
105253         30.65395 8.18018333333333
105255 31.6293333333333 8.10066666666667
105258          31.6865 8.10928333333333
105259         31.68715 8.11036666666667
105260 31.6481833333333 8.10468333333333

2
这可能是最简单的解决方案(而且您还可以免费获得其他坐标转换)。我只想补充一下,该功能现已移至“measurements”包中,并在“birk”中已弃用。 - Gord Stephen

9
尝试使用sp库中的char2dms函数。它还有其他功能可以进行十进制转换。
library("sp")
?char2dms

如果你想将类似于“35d8'2.222"E”的内容转换为35.13395,你需要在输出中使用“as.numeric()”函数,并且需要包含方向信息。 - seasmith

7
一点向量化和矩阵操作可以让你的函数更加简单:
x <- read.table(text="
       lat     long
105252 30°25.264 9°01.331
105253 30°39.237 8°10.811
105255 31°37.760 8°06.040
105258 31°41.190 8°06.557
105259 31°41.229 8°06.622
105260 31°38.891 8°06.281",
                header=TRUE, stringsAsFactors=FALSE)

x

这个函数本身使用了以下内容:

  • strsplit()和正则表达式模式"[°\\.]" - 这一步完成了字符串的分割。
  • sapply循环遍历向量。

试试这个:

convert<-function(x){
  z <- sapply((strsplit(x, "[°\\.]")), as.numeric)
  z[1, ] + z[2, ]/60 + z[3, ]/3600
} 

试一下:

convert(x$long)
[1] 9.108611 8.391944 8.111111 8.254722 8.272778 8.178056

免责声明:我没有核对您的数学。请自行决定使用。

正如问题评论所指出的那样,输入是度和十进制分钟,而不是度、分和秒。如果只在 ° 上拆分并删除 z[3, ]/3600 部分,则此答案有效。 - nniloc

2
感谢@Gord Stephen和@CephBirk的回答,确实帮了我很多。 我想提一下,我也发现measurements::conv_unit无法处理“E/W”、“N/S”的输入,它需要正/负度数。 我的坐标作为字符字符串"1 1 1W"出现,需要先转换为"-1 1 1"
我想分享一下我的解决方案。
df <- c("1 1 1E", "1 1 1W", "2 2 2N","2 2 2S")  
measurements::conv_unit(df, from = 'deg_min_sec', to = 'dec_deg')
[1] "1.01694444444444" NA                 NA                 NA  
Warning message:
In split(as.numeric(unlist(strsplit(x, " "))) * c(3600, 60, 1),  :
  NAs introduced by coercion

ewns <- ifelse( str_extract(df,"\\(?[EWNS,.]+\\)?") %in% c("E","N"),"+","-")
dms <- str_sub(df,1,str_length(df)-1)
df2 <- paste0(ewns,dms)

df_dec <- measurements::conv_unit(df2, 
                                  from = 'deg_min_sec', 
                                  to = 'dec_deg'))
df_dec
[1] "1.01694444444444"  "-1.01694444444444" "2.03388888888889"  "-2.03388888888889"
as.numeric(df_dec)
[1]  1.016944 -1.016944  2.033889 -2.033889

1

请查看包OSMscale中的命令degree


1
这是对我最有效的答案。非常感谢!请查看帮助文件中的一些示例:d <- read.table(header=TRUE, sep=",", text=" lat, long 52.366360, 13.024181 -32.599203, -55.809601") degree(lat, long, data=d) # 您也可以使用度符号和转义引号(\”)。 degree("52'21'58.9'N", "13'1'27.1'E") - Charles Santana

0

另一种不太优雅的选项是使用子字符串而不是strsplit。这只适用于所有位置具有相同位数的情况。对于负坐标,只需乘以-1即可得到正确的十进制度数。

x$LatDD<-(as.numeric(substring(x$lat, 1,2))
+ (as.numeric(substring(x$lat, 4,9))/60))
x$LongDD<-(as.numeric(substring(x$long, 1,1))
       + (as.numeric(substring(x$long, 3,8))/60))

0
正如Jim Lewis之前所评论的那样,似乎您正在使用浮点分钟。然后,您只需将两个元素连接起来即可。

dec=c(as.numeric(tmp1[[1]][1]),as.numeric(tmp2[[1]]))

以形式为43°21'8.02的度、分和秒,as.character()返回"43°21'8.02\"",我更新了您的函数为

convert<-function(coord){
  tmp1=strsplit(coord,"°")
  tmp2=strsplit(tmp1[[1]][2],"'")
  tmp3=strsplit(tmp2[[1]][2],"\"")
  dec=c(as.numeric(tmp1[[1]][1]),as.numeric(tmp2[[1]][1]),as.numeric(tmp3[[1]]))
  c<-abs(dec[1])+dec[2]/60+dec[3]/3600
  c<-ifelse(dec[1]<0,-c,c)
  return(c)
}

为负坐标添加替代方案,对我来说非常有效。我仍然不明白为什么 sp 库中的 char2dms 函数对我无效。

谢谢


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