R-数据框中的条件更新坐标列

时间:2019-04-16 17:19:49

标签: r coordinates spatial

我试图用相同方式从同一数据框中的其他列中填充数据,这取决于是否填充了两个新的空列。

我正在尝试填充HIGH_PRCN_LAT和HIGH_PRCN_LON的值(以前称为F_Lat和F_Lon),它们表示这些行的最终纬度和经度,这将基于表中其他列的值。

情况1:使用大号填充Lat / Lon2(如ID 1和ID 2)    圈算法,应计算它们之间的中点,    然后放入F_Lat和F_Lon。

情况2:Lat / Lon2为空,则应放置Lat / Lon1的值    进入F_Lat和F_Lon(与ID 3和4一样)。

我的代码如下,但不起作用(请参阅以前的版本,已在编辑中删除)。

我使用的预备代码如下:

incidents <- structure(list(id = 1:9, StartDate = structure(c(1L, 3L, 2L, 
2L, 2L, 3L, 1L, 3L, 1L), .Label = c("02/02/2000 00:34", "02/09/2000 22:13", 
"20/01/2000 14:11"), class = "factor"), EndDate = structure(1:9, .Label = c("02/04/2006 20:46", 
"02/04/2006 22:38", "02/04/2006 23:21", "02/04/2006 23:59", "03/04/2006 20:12", 
"03/04/2006 23:56", "04/04/2006 00:31", "07/04/2006 06:19", "07/04/2006 07:45"
), class = "factor"), Yr.Period = structure(c(1L, 1L, 2L, 2L, 
2L, 3L, 3L, 3L, 3L), .Label = c("2000 / 1", "2000 / 2", "2000 /3"
), class = "factor"), Description = structure(c(1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L), .Label = "ENGLISH TEXT", class = "factor"), 
    Location = structure(c(2L, 2L, 1L, 2L, 2L, 2L, 2L, 1L, 1L
    ), .Label = c("Location 1", "Location 1 : Location 2"), class = "factor"), 
    Location.1 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L), .Label = "Location 1", class = "factor"), Postcode.1 = structure(c(1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "Postcode 1", class = "factor"), 
    Location.2 = structure(c(2L, 2L, 1L, 2L, 2L, 2L, 2L, 1L, 
    1L), .Label = c("", "Location 2"), class = "factor"), Postcode.2 = structure(c(2L, 
    2L, 1L, 2L, 2L, 2L, 2L, 1L, 1L), .Label = c("", "Postcode 2"
    ), class = "factor"), Section = structure(c(2L, 2L, 3L, 1L, 
    4L, 4L, 2L, 1L, 4L), .Label = c("East", "North", "South", 
    "West"), class = "factor"), Weather.Category = structure(c(1L, 
    2L, 4L, 2L, 2L, 2L, 4L, 1L, 3L), .Label = c("Animals", "Food", 
    "Humans", "Weather"), class = "factor"), Minutes = c(13L, 
    55L, 5L, 5L, 5L, 522L, 1L, 11L, 22L), Cost = c(150L, 150L, 
    150L, 20L, 23L, 32L, 21L, 11L, 23L), Location.1.Lat = c(53.0506727, 
    53.8721035, 51.0233529, 53.8721035, 53.6988355, 53.4768766, 
    52.6874562, 51.6638245, 51.4301359), Location.1.Lon = c(-2.9991256, 
    -2.4004125, -3.0988341, -2.4004125, -1.3031529, -2.2298073, 
    -1.8023421, -0.3964916, 0.0213837), Location.2.Lat = c(52.7116187, 
    53.746791, NA, 53.746791, 53.6787167, 53.4527824, 52.5264907, 
    NA, NA), Location.2.Lon = c(-2.7493169, -2.4777984, NA, -2.4777984, 
    -1.489026, -2.1247029, -1.4645023, NA, NA)), class = "data.frame", row.names = c(NA, -9L))

#gpsColumns is used as the following line of code is used for several data frames.
gpsColumns <- c("HIGH_PRCN_LAT", "HIGH_PRCN_LON")
incidents [ , gpsColumns] <- NA

#create separate variable(?) containing a list of which rows are complete
ind <- complete.cases(incidents [,17])

#populate rows with a two Lat/Lons with great circle middle of both values
incidents [ind, c("HIGH_PRCN_LON_2","HIGH_PRCN_LAT_2")] <- 
  with(incidents [ind,,drop=FALSE],
       do.call(rbind, geosphere::midPoint(cbind.data.frame(Location.1.Lon, Location.1.Lat), cbind.data.frame(Location.2.Lon, Location.2.Lat))))

#populate rows with one Lat/Lon with those values
incidents[!ind, c("HIGH_PRCN_LAT","HIGH_PRCN_LON")] <- incidents[!ind, c("Location.1.Lat","Location.1.Lon")]

我将根据http://r.789695.n4.nabble.com/Midpoint-between-coordinates-td2299999.html处的建议使用geosphere :: midPoint函数。

不幸的是,在几种情况下,似乎没有这种填充列的方法可以工作。

当前抛出的错误是:

Error in `$<-.data.frame`(`*tmp*`, F_Lat, value = integer(0)) : 
  replacement has 0 rows, data has 178012

编辑:也发布到reddit:https://www.reddit.com/r/Rlanguage/comments/bdvavx/conditional_updating_column_in_dataframe/

编辑:增加了我不理解的代码部分的清晰度。

#replaces the F_Lat2/F_Lon2 columns in rows with a both sets of input coordinates 
dataframe[ind, c("F_Lat2","F_Lon2")] <-
#I am unclear on what this means, specifically what the "with" function does and what "drop=FALSE" does and also why they were used in this case.
  with(dataframe[ind,,drop=FALSE],
#I am unclear on what do.call and rbind are doing here, but the second half (geosphere onwards) is binding the Lats and Lons to make coordinates as inputs for the gcIntermediate function.
       do.call(rbind, geosphere::gcIntermediate(cbind.data.frame(Lat1, Lon1),
                                                cbind.data.frame(Lat2, Lon2), n = 1)))

1 个答案:

答案 0 :(得分:1)

尽管您的代码对我而言不起作用,并且我无法计算出您期望的精确值,但我怀疑可以通过以下步骤解决您看到的错误。 (数据在这里位于底部。)

  1. 预先填充空列。
  2. 预先计算complete.cases步骤,可以节省时间。
  3. cbind.data.frame内部使用gcIntermediate

我从

推断
gcIntermediate([dataframe...
               ^
               this is an error in R

您将这些列绑定在一起,所以我将使用cbind.data.frame。 (使用cbind本身会从geosphere发出一些可忽略的警告,因此您可以使用它来代替,甚至可以使用suppressWarnings,但是该功能有点强大,因为它也可以掩盖其他警告)

此外,由于似乎您希望每对坐标一个中间值,所以我添加了gcIntermediate(..., n=1)参数。

使用do.call(rbind, ...)是因为gcIntermediate返回一个list,所以我们需要将它们放在一起。

dataframe$F_Lon2 <- dataframe$F_Lat2 <- NA_real_
ind <- complete.cases(dataframe[,4])

dataframe[ind, c("F_Lat2","F_Lon2")] <- 
  with(dataframe[ind,,drop=FALSE],
       do.call(rbind, geosphere::gcIntermediate(cbind.data.frame(Lat1, Lon1),
                                                cbind.data.frame(Lat2, Lon2), n = 1)))
dataframe[!ind, c("F_Lat2","F_Lon2")] <- dataframe[!ind, c("Lat1","Lon1")]
dataframe
#   ID     Lat1      Lon1     Lat2      Lon2    F_Lat     F_Lon   F_Lat2    F_Lon2
# 1  1 19.05067 -3.999126 92.71332 -6.759169 55.88200 -5.379147 55.78466 -6.709509
# 2  2 58.87210 -1.400413 54.74679 -4.479840 56.80945 -2.940126 56.81230 -2.942029
# 3  3 33.02335 -5.098834       NA        NA 33.02335 -5.098834 33.02335 -5.098834
# 4  4 54.87210 -4.400412       NA        NA 54.87210 -4.400412 54.87210 -4.400412

更新,使用新的incidents数据并切换到geosphere::midPoint

尝试一下:

incidents$F_Lon2 <- incidents$F_Lat2 <- NA_real_
ind <- complete.cases(incidents[,4])

incidents[ind, c("F_Lat2","F_Lon2")] <- 
  with(incidents[ind,,drop=FALSE],
       geosphere::midPoint(cbind.data.frame(Location.1.Lat,Location.1.Lon),
                           cbind.data.frame(Location.2.Lat,Location.2.Lon)))
incidents[!ind, c("F_Lat2","F_Lon2")] <- dataframe[!ind, c("Lat1","Lon1")]

一个(较大的)区别是geosphere::gcIntermediate(..., n=1)返回结果列表,而geosphere::midPoint(...)(无n=)仅返回矩阵,因此不需要rbind ing。


数据:

dataframe <- read.table(header=T, stringsAsFactors=F, text="
ID Lat1       Lon1       Lat2      Lon2      F_Lat       F_Lon
1  19.0506727 -3.9991256 92.713318 -6.759169 55.88199535 -5.3791473
2  58.8721035 -1.4004125 54.746791 -4.47984  56.80944725 -2.94012625
3  33.0233529 -5.0988341 NA        NA        33.0233529  -5.0988341
4  54.8721035 -4.4004125 NA        NA        54.8721035  -4.4004125")