1

我想创建一个脚本,使用移动窗口将函数应用于整个数据框中的空间点子集。

给定一个包含纬度位置列和经度位置列的数据矩阵,我想获得整个数据集中每 5 个连续位置的弯曲度测量值(即将该函数应用于从开始到结束的每组 5 个位置)。弯曲度是沿一系列点移动的实际距离与起点和终点之间移动的直线距离的比率。

示例数据:

df <- structure(list(IndexNo = 1:13, Latitude = c(52.363205, 52.640715, 
52.940366, 53.267749, 53.512608, 53.53215, 53.536443, 53.553523, 
53.546862, 53.55095, 53.571766, 53.587558, 53.592084), Longitude = c(3.433247, 
3.305727, 3.103194, 2.973257, 2.966621, 3.013587, 3.002674, 3.004011, 
2.98778, 2.995589, 3.004867, 3.003511, 2.999092)), .Names = c("IndexNo", "Latitude", "Longitude"), class = "data.frame", row.names=c(NA,-13L))

期望的输出:

IndexNo       Latitude  Longitude   Sinuosity
1             52.36321  3.433247    NA
2             52.64072  3.305727    1.0085
3             52.94037  3.103194    1.0085
4             53.26775  2.973257    1.0085
5             53.51261  2.966621    1.0085
6             53.53215  3.013587    1.9392
7             53.53644  3.002674    1.9392
8             53.55352  3.004011    1.9392
9             53.54686  2.987780    1.9392
10            53.55095  2.995589    1.0669
11            53.57177  3.004867    1.0669
12            53.58756  3.003511    1.0669
13            53.59208  2.999092    1.0669

初始尝试(在用于计算 5 个位置的单个部分的弯曲度的代码中):

# To create a subset of the first 5 locations in the data frame
subset<- bird[1:5, c("Latitude", "Longitude","IndexNo")]
library(trip)

# To calculate the straight-line distance between the beginning and end point of a 5-point sequence
straightd<- trackDistance(subset[1,2], subset[1,1], subset[5,2], subset[5,1], longlat=TRUE)

# To calculate the distance between each pair of consecutive points (for a 5-point sequence)
d1<- trackDistance(subset[1,2], subset[1,1], subset[2,2], subset[2,1], longlat=TRUE)
d2<- trackDistance(subset[2,2], subset[2,1], subset[3,2], subset[3,1], longlat=TRUE)
d3<- trackDistance(subset[3,2], subset[3,1], subset[4,2], subset[4,1], longlat=TRUE)
d4<- trackDistance(subset[4,2], subset[4,1], subset[5,2], subset[5,1], longlat=TRUE)
# To return the actual distance between the beginning and end point of a 5-point sequence
actd<- sum(d1,d2,d3,d4)

# Function to calcualte the sinuosity (ratio between the actual distance and the straight-line distance)
sinuosity <- function (x, y) {
  x/y
}
new <- sinuosity(actd, straightd)

# To add a sinuosity column to the 5 rows of locations on which the sinuosity index was measured
subset$Sinuosity <- rep(new, nrow(subset))
4

3 回答 3

2

您可以按照以下方式设置循环 -

for(i in seq(1,(dim(df)[1]), by = 4)
{
subset<- bird[i:(i+4), c("Latitude", "Longitude","IndexNo")]
straightd<- trackDistance(subset[i,(i+1)], subset[i,i], subset[(i+4),(i+1)], subset[(i+4),i], longlat=TRUE)
# etc.
}

将其与您发布的代码进行比较,您应该会看到发生了什么。这只是一个指南,您应该能够将此逻辑外推到函数的其余部分。

于 2013-10-17T19:20:38.937 回答
1

你选择了一个很好的标题并且遇到了一个有趣的问题,但细节过多(让你的问题对其他人有用)。据我了解,您需要

  1. 在表格行之间执行成对操作(在您的情况下 - 距离)
  2. 使用某些条件(邻居点)折叠此操作的结果
  3. 对许多元素重复它(对于每个点)

我很喜欢data.table 包,所以这是我的(有点通用和次优的)解决方案

0)将数据表与自身合并并计算每对之间的距离

library(data.table)
dt <- as.data.table(df)
setkey(dt[, k := 1], k)
dt2 <- merge(dt, dt, allow.cartesian = T]

k 是获得完全交叉连接的人工索引(在您的情况下过度,但很简单)

1) 计算距离

dt2[IndexNo != IndexNo.1
   , dist := trackDistance(Longitude, Latitude, Longitude.1, Latitude.1
   , longlat = T) ]

2)应用您的条件(总结相邻点之间的距离)

sinuosity <- function(start, end) {
  long.dist <- dt2[IndexNo %in% c(start:end) & IndexNo.1 %in% c(start:end) 
                                             & IndexNo == IndexNo.1 - 1
                  , sum(dist, na.rm = T) ]
  short.dist <- dt2[IndexNo == start & IndexNo.1 == end, dist]
  res <- long.dist/short.dist
  return(res)
}

3)对每个点重复

dt2[IndexNo > IndexNo.1 - 5 & IndexNo <= IndexNo.1
    ,  list(Latitude, Longitude, sinuosity(IndexNo, IndexNo + 4))
    , by = c("IndexNo", "IndexNo.1")] 

给出你想要的(我猜)

    IndexNo IndexNo.1 Latitude Longitude       V3
 1:       1         1 52.36321  3.433247 1.008512
 2:       1         2 52.36321  3.433247 1.008512
 3:       1         3 52.36321  3.433247 1.008512
 4:       1         4 52.36321  3.433247 1.008512
 5:       1         5 52.36321  3.433247 1.008512
 6:       2         2 52.64072  3.305727 1.033964
 7:       2         3 52.64072  3.305727 1.033964
 8:       2         4 52.64072  3.305727 1.033964
 ......

我建议花一些时间来熟悉一下data.table,它可以为你节省很多以后的时间。此外,对于您的特定情况,如果您有大表(> 1000 行),您应该避免完全交叉连接并将 dt 与 IndexNo == IndexNo - 1 上的自身合并

于 2013-10-17T21:46:45.837 回答
1

如您所见,有很多方法可以走。我认为您可以使用@Codoremifa 向您展示的一系列循环或一些方便的附加包(例如data.table@RInatM 引导您完成)来做到这一点。我做了一个使用sapply函数循环数据的示例。

首先,我根据您的代码为整个数据集按顺序计算了每对点之间的距离。我过去常常with避免使用美元符号或提取函数[。您可以看到向量输出pairdist比数据集中的行数短 1 个单位。

pairdist = sapply(2:nrow(bird), function(x) with(bird, trackDistance(Longitude[x-1], Latitude[x-1], 
                                 Longitude[x], Latitude[x], longlat=TRUE) ))

然后我通过类似的步骤将每组四对距离相加,以获得总距离的度量。您可以看到这对于您的示例数据集只有三个值,因为它应该。

totdist= sapply(seq(1,length(pairdist)-3, by = 4), function(x) sum(pairdist[x:(x+3)]))

接下来计算第一个和第五个点,第五个和第九个点之间的直线距离等。

straight = sapply(seq(1, nrow(bird)-4, by = 4), function(x) with(bird,trackDistance(Longitude[x],
                                                                    Latitude[x], 
                                 Longitude[x+4], Latitude[x+4], longlat=TRUE) ))

最后,您要计算比率并将其添加回原始数据集,其中第一个点为 NA,之后每组四个点都具有相同的值。为了使这更适用于各种长度的数据集,如果需要,我用 NA 填充末尾。该代码可能看起来令人困惑,但这只是一些数学运算,可以根据您将点分组在一起的方式来计算需要多少填充。

bird$Sinuosity = c(NA, rep(totdist/straight, each = 4), 
                rep(NA, length(pairdist)-4*floor(length(pairdist)/4)))
于 2013-10-17T22:45:05.353 回答