Преобразование геокоординат от степени к десятичной
Я хочу преобразовать свои географические координаты из градусов в десятичные числа, мои данные таковы:
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]))}
Функция преобразования работает, но код, в котором я прошу цикл выполнить эту работу для меня, не работает.
Любое предложение apperciated.
Ответы
Ответ 1
Используйте пакет measurements
из CRAN, у которого уже есть функция преобразования единиц, поэтому вам не нужно создавать свои собственные:
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)
Как только ваш data.frame настроен, выполните следующие действия:
# 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
Попробуйте использовать функцию char2dms
в библиотеке sp
. Он имеет другие функции, которые дополнительно выполняют десятичное преобразование.
library("sp")
?char2dms
Ответ 3
Немного векторизации и манипуляции с матрицами сделает вашу функцию намного проще:
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()
с шаблоном regex "[°\\.]"
- это строка, разделенная на один шаг
-
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
Отказ от ответственности: я не проверял вашу математику. Используйте по своему усмотрению.
Ответ 4
Как прокомментировал Джим Льюис, прежде чем кажется, что вы используете минуты с плавающей запятой. Затем вы объединяете только два элемента на
= с декабрем (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)
}
добавив альтернативу для отрицательных координат и отлично работает для меня. Я до сих пор не понимаю, почему функция char2dms
в библиотеке sp
не работала для меня.
Спасибо
Ответ 5
Другой менее элегантный вариант с использованием подстроки вместо 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))
Ответ 6
Спасибо за ответы @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