我是 R 的新手,但我听说使用 for
确实是个坏主意。循环。我有使用它们的工作代码,但我想改进它,因为大数据非常慢。我已经有了一些如何改进算法的想法,但我不知道如何将其矢量化,或者在没有 for
的情况下进行。循环。
我只是将 lat/lng 点分组为一个以半径为参数的圆圈。
该函数的示例输出(仅填充 circle_id 列中的值),半径设置为 100 米:
[1] "Locations: "
latitude longitude sensor_time sensor_time2 circle_id
48.15144 17.07569 1447149703 2015-11-10 11:01:43 1
48.15404 17.07452 1447149743 2015-11-10 11:02:23 2
48.15277 17.07514 1447149762 2015-11-10 11:02:42 3
48.15208 17.07538 1447149771 2015-11-10 11:02:51 1
48.15461 17.07560 1447149773 2015-11-10 11:02:53 4
48.15139 17.07562 1447149811 2015-11-10 11:03:31 1
48.15446 17.07517 1447149866 2015-11-10 11:04:26 2
48.15266 17.07330 1447149993 2015-11-10 11:06:33 5
所以我有 2 个 for 循环,loop1 遍历每一行,loop2 遍历每个以前的 circle_id,并检查 loop1 的当前位置是否在 loop2 的现有圆的半径内。每个 circle_id 的中心是在所有先前的半径之外找到的第一个位置。
这是代码:
init_circles = function(datfr, radius) {
cnt = 1
datfr$circle_id[1] = 1
longitude = datfr$longitude[1]
latitude = datfr$latitude[1]
circle_id = datfr$circle_id[1]
datfr2 <- data.frame(longitude, latitude, circle_id)
for (i in 2:NROW(datfr)) {
for (j in 1:NROW(datfr2)) {
tmp = distHaversine(c(datfr$longitude[i],datfr$latitude[i]) ,c(datfr2$longitude[j],datfr2$latitude[j]))
if (tmp < radius){
datfr$circle_id[i] = datfr2$circle_id[j]
break
}
}
if (datfr$circle_id[i]<1){
cnt = cnt +1
datfr$circle_id[i] = cnt
datfr2[nrow(datfr2)+1,] = c(datfr$longitude[i],datfr$latitude[i],datfr$circle_id[i])
}
}
return(datfr)
}
数据中心 是没有设置 circle_id 的输入数据帧, datfr2 是一个包含现有圆圈的临时数据框。
编辑:这是一个视觉输出:
您可以看到这些圆圈的用途,上面的红色圆圈还有 21 个其他位置适合其半径(21 + 1 原始 = 22)
非常感谢你的帮助,
阿莱娜
最佳答案
我假设我们有一个数据框 circles
每个圆的中心和半径,并且您问题中发布的示例数据位于名为 dat
的数据框中.下面的代码将距离的计算向量化并使用 lapply
计算每个点到每个圆中心的距离,并确定每个点是否在该圆的半径内。
library(geosphere)
# We'll check the distance of each data point from the center of each
# of these circles
circles = data.frame(ID=1:2, lon=c(17.074, 17.076), lat=c(48.1513, 48.15142),
radius=c(180,190))
datNew = lapply(1:nrow(circles), function(i) {
df = dat
df$dist = distHaversine(df[,c("longitude", "latitude")],
circles[rep(i,nrow(df)), c('lon','lat')])
df$in_circle = ifelse(df$dist <= circles[i, "radius"], "Yes", "No")
df$circle_id = circles[i, "ID"]
df
})
datNew = do.call(rbind, datNew)
datNew
latitude longitude sensor_time sensor_time2 time3 dist in_circle circle_id 1 48.15144 17.07569 1447149703 2015-11-10 11:01:43 126.47756 Yes 1 2 48.15404 17.07452 1447149743 2015-11-10 11:02:23 307.45048 No 1 3 48.15277 17.07514 1447149762 2015-11-10 11:02:42 184.24465 No 1 4 48.15208 17.07538 1447149771 2015-11-10 11:02:51 134.32601 Yes 1 5 48.15461 17.07560 1447149773 2015-11-10 11:02:53 387.15358 No 1 6 48.15139 17.07562 1447149811 2015-11-10 11:03:31 120.73138 Yes 1 7 48.15446 17.07517 1447149866 2015-11-10 11:04:26 362.34236 No 1 8 48.15266 17.07330 1447149993 2015-11-10 11:06:33 160.07179 Yes 1 9 48.15144 17.07569 1447149703 2015-11-10 11:01:43 23.13059 Yes 2 10 48.15404 17.07452 1447149743 2015-11-10 11:02:23 311.68096 No 2 11 48.15277 17.07514 1447149762 2015-11-10 11:02:42 163.29068 Yes 2 12 48.15208 17.07538 1447149771 2015-11-10 11:02:51 86.70762 Yes 2 13 48.15461 17.07560 1447149773 2015-11-10 11:02:53 356.34955 No 2 14 48.15139 17.07562 1447149811 2015-11-10 11:03:31 28.41890 Yes 2 15 48.15446 17.07517 1447149866 2015-11-10 11:04:26 343.97933 No 2 16 48.15266 17.07330 1447149993 2015-11-10 11:06:33 243.44024 No 2
所以我们现在有一个数据框告诉我们每个点是否在给定的圆内。数据框是长格式的,意思是有
n
原始数据框中每个点的行 dat
,其中 n
是 circles
中的行数数据框。从这里,您可以进行进一步处理,例如只为多个圆圈中的每个点保留一行,等等。这是一个例子。我们将返回一个数据框,列出一个点在哪个圆圈内,如果该点不在任何圆圈内,则返回“无”:
library(dplyr)
datNew %>%
group_by(latitude, longitude) %>%
summarise(in_which_circles = if(any(in_circle=="Yes")) paste(circle_id[in_circle=="Yes"], collapse=",") else "None")
latitude longitude in_which_circles <dbl> <dbl> <chr> 1 48.15139 17.07562 1,2 2 48.15144 17.07569 1,2 3 48.15208 17.07538 1,2 4 48.15266 17.07330 1 5 48.15277 17.07514 2 6 48.15404 17.07452 None 7 48.15446 17.07517 None 8 48.15461 17.07560 None
关于R - 根据位置将纬度/经度点的巨大数据帧分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40897882/