使用R中的移动窗口将函数应用于数据帧中的数据子集

时间:2013-10-17 12:54:13

标签: r window dataframe distance subset

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

如果数据矩阵包含具有纬度位置的列和具有经度位置的列,我想获得整个数据集中每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))

3 个答案:

答案 0 :(得分: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.
}

将它与您发布的代码进行比较,您应该看到发生了什么。这只是一个指南,你应该能够将这个逻辑推断到你的其余功能。

答案 1 :(得分:1)

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

  1. 在表行之间执行成对操作(在您的情况下 - 距离)
  2. 使用某些条件(邻居点)
  3. 折叠此操作的结果
  4. 为许多元素重复它(对于每个点)
  5. 我对data.table package非常有乐趣,所以这是我的(有点一般和次优)解决方案

    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行),您应该避免完全交叉连接并在IndexNo上合并dt == IndexNo - 1

答案 2 :(得分: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)))