R:插入数据框行对的中间值
R: Inserting Mid Values of Data Frame Row Pairs
我有一系列来自 Strava 的坐标,每 2.5 分钟记录一次,然后将它们添加到 QGIS 地图中。我想通过取每对经纬度的平均值来插入中间的点。
我知道我可以使用 for 循环,但我宁愿使用 apply 函数族之一。我知道我需要获取当前行,然后是除最后一行以外的所有行的下一行。
gpsSmall 是一个 data.frame 看起来像这样
activity_no lat lon
----------- --- ---
1 52.5111 -1.85222
1 52.5111 -1.86224
1 52.5111 -1.87226
... etc
2 52.6189 -1.85332
2 52.6284 -1.86332
2 52.6386 -1.87332
... etc
然后我编写了这些函数来创建额外的行,我将 rbind 到最后。
splitPoints <- function(point1, point2) {
meanLatitude = (point1$lat + point2$lat)/2
meanLongitude = (point1$lon + point2$lon)/2
point1$lat = meanLatitude
point1$lon = meanLongitude
point1
}
newPoints <- sapply(seq_len(nrow(gpsSmall) - 1),
function(i){
splitPoints(gpsSmall[i,], gpsSmall[i+1,])
})
但是,newPoints returns 矩阵 3(gpsSmall 中的列数)x 66(1 - gpsSmall 中的行数)。我做错了什么?
不使用应用函数,但像这样的东西可能会使它更容易一些。鉴于我认为您的问题是什么,应该这样做。我假设您希望 activity_no
成为一种分组机制。如果没有,那就更容易了。只需对整个数据集使用下面的 approx
函数,而不是先拆分它。
几个 tidyverse
包:
library(dplyr)
library(purrr)
加载您的数据片段:
dat <- tribble(
~activity_no, ~lat, ~lon,
1, 52.5111, -1.85222,
1, 52.5111, -1.86224,
1, 52.5111, -1.87226,
2, 52.6189, -1.85332,
2, 52.6284, -1.86332,
2, 52.6386, -1.87332
)
现在只需使用 ?approx
进行线性插值。将插值输出的长度设置为 n * 2 - 1 基本上表示在每次实际观察之间有 1 个新值。因为它是线性的,所以这将是平均值。如果需要,您可以调整输出并获得更高级别的插值。
dat %>%
split(dat$activity_no) %>%
map_dfr( ~ data.frame(activity_no = rep(.$activity_no[1], nrow(.) * 2 - 1),
lat = approx(.$lat, n = nrow(.) * 2 - 1)$y,
lon = approx(.$lon, n = nrow(.) * 2 - 1)$y))
activity_no lat lon
1 1 52.51110 -1.85222
2 1 52.51110 -1.85723
3 1 52.51110 -1.86224
4 1 52.51110 -1.86725
5 1 52.51110 -1.87226
6 2 52.61890 -1.85332
7 2 52.62365 -1.85832
8 2 52.62840 -1.86332
9 2 52.63350 -1.86832
10 2 52.63860 -1.87332
我有一系列来自 Strava 的坐标,每 2.5 分钟记录一次,然后将它们添加到 QGIS 地图中。我想通过取每对经纬度的平均值来插入中间的点。
我知道我可以使用 for 循环,但我宁愿使用 apply 函数族之一。我知道我需要获取当前行,然后是除最后一行以外的所有行的下一行。
gpsSmall 是一个 data.frame 看起来像这样
activity_no lat lon
----------- --- ---
1 52.5111 -1.85222
1 52.5111 -1.86224
1 52.5111 -1.87226
... etc
2 52.6189 -1.85332
2 52.6284 -1.86332
2 52.6386 -1.87332
... etc
然后我编写了这些函数来创建额外的行,我将 rbind 到最后。
splitPoints <- function(point1, point2) {
meanLatitude = (point1$lat + point2$lat)/2
meanLongitude = (point1$lon + point2$lon)/2
point1$lat = meanLatitude
point1$lon = meanLongitude
point1
}
newPoints <- sapply(seq_len(nrow(gpsSmall) - 1),
function(i){
splitPoints(gpsSmall[i,], gpsSmall[i+1,])
})
但是,newPoints returns 矩阵 3(gpsSmall 中的列数)x 66(1 - gpsSmall 中的行数)。我做错了什么?
不使用应用函数,但像这样的东西可能会使它更容易一些。鉴于我认为您的问题是什么,应该这样做。我假设您希望 activity_no
成为一种分组机制。如果没有,那就更容易了。只需对整个数据集使用下面的 approx
函数,而不是先拆分它。
几个 tidyverse
包:
library(dplyr)
library(purrr)
加载您的数据片段:
dat <- tribble(
~activity_no, ~lat, ~lon,
1, 52.5111, -1.85222,
1, 52.5111, -1.86224,
1, 52.5111, -1.87226,
2, 52.6189, -1.85332,
2, 52.6284, -1.86332,
2, 52.6386, -1.87332
)
现在只需使用 ?approx
进行线性插值。将插值输出的长度设置为 n * 2 - 1 基本上表示在每次实际观察之间有 1 个新值。因为它是线性的,所以这将是平均值。如果需要,您可以调整输出并获得更高级别的插值。
dat %>%
split(dat$activity_no) %>%
map_dfr( ~ data.frame(activity_no = rep(.$activity_no[1], nrow(.) * 2 - 1),
lat = approx(.$lat, n = nrow(.) * 2 - 1)$y,
lon = approx(.$lon, n = nrow(.) * 2 - 1)$y))
activity_no lat lon
1 1 52.51110 -1.85222
2 1 52.51110 -1.85723
3 1 52.51110 -1.86224
4 1 52.51110 -1.86725
5 1 52.51110 -1.87226
6 2 52.61890 -1.85332
7 2 52.62365 -1.85832
8 2 52.62840 -1.86332
9 2 52.63350 -1.86832
10 2 52.63860 -1.87332