ลองแบ่งมันเป็นชิ้น ๆ การทำเช่นนี้จะทำให้งานทั้งหมดสำเร็จในเพียงครึ่งโหลของรหัสที่ทดสอบได้ง่าย
ก่อนอื่นคุณจะต้องคำนวณระยะทาง เนื่องจากข้อมูลอยู่ในพิกัดทางภูมิศาสตร์นี่คือฟังก์ชันเพื่อคำนวณระยะทางในรูปทรงกลม (โดยใช้สูตร Haversine):
#
# Spherical distance.
# `x` and `y` are (long, lat) pairs *in radians*.
dist <- function(x, y, R=1) {
d <- y - x
a <- sin(d[2]/2)^2 + cos(x[2])*cos(y[2])*sin(d[1]/2)^2
return (R * 2*atan2(sqrt(a), sqrt(1-a)))
}
แทนที่สิ่งนี้ด้วยการนำไปใช้งานที่คุณชื่นชอบหากคุณต้องการ (เช่นอันที่ใช้ดาต้ารูปวงรี)
ต่อไปเราจะต้องคำนวณระยะทางระหว่าง "จุดฐาน" แต่ละจุด (กำลังตรวจสอบความมั่นคง) และพื้นที่ใกล้เคียงชั่วคราว นั่นเป็นเพียงเรื่องของการนำdist
ไปใช้กับพื้นที่ใกล้เคียง:
#
# Compute the distances between an array of locations and a base location `x`.
dist.array <- function(a, x, ...) apply(a, 1, function(y) dist(x, y, ...))
ประการที่สาม - นี่คือแนวคิดหลัก - พบจุดที่อยู่กับที่โดยตรวจจับย่านที่อยู่ใกล้เคียง 11 จุดที่มีอย่างน้อยห้าแถวติดต่อกันซึ่งระยะทางมีขนาดเล็กพอสมควร ให้เรานำสิ่งนี้ไปใช้โดยทั่วไปอีกเล็กน้อยโดยการกำหนดความยาวของการเรียงลำดับที่ยาวที่สุดของค่าที่แท้จริงภายในอาร์เรย์ตรรกะของค่าบูลีน:
#
# Return the length of the longest sequence of true values in `x`.
max.subsequence <- function(x) max(diff(c(0, which(!x), length(x)+1)))
(เราค้นหาที่ตั้งของค่าเท็จตามลำดับและคำนวณความแตกต่าง: นี่คือความยาวของการเรียงลำดับของค่าที่ไม่เป็นเท็จความยาวดังกล่าวที่ใหญ่ที่สุดจะถูกส่งคืน)
ประการที่สี่เรานำmax.subsequence
ไปใช้ในการตรวจสอบคะแนนนิ่ง
#
# Determine whether a point `x` is "stationary" relative to a sequence of its
# neighbors `a`. It is provided there is a sequence of at least `k`
# points in `a` within distance `radius` of `x`, where the earth's radius is
# set to `R`.
is.stationary <- function(x, a, k=floor(length(a)/2), radius=100, R=6378.137)
max.subsequence(dist.array(a, x, R) <= radius) >= k
นี่คือเครื่องมือทั้งหมดที่เราต้องการ
ตัวอย่างเช่นเรามาสร้างข้อมูลที่น่าสนใจที่มีจุดคงที่สองสามกลุ่ม ฉันจะใช้เวลาเดินสุ่มใกล้เส้นศูนย์สูตร
set.seed(17)
n <- 67
theta <- 0:(n-1) / 50 - 1 + rnorm(n, sd=1/2)
rho <- rgamma(n, 2, scale=1/2) * (1 + cos(1:n / n * 6 * pi))
lon <- cumsum(cos(theta) * rho); lat <- cumsum(sin(theta) * rho)
อาร์เรย์lon
และlat
มีพิกัดเป็นองศาของn
คะแนนตามลำดับ การใช้เครื่องมือของเราตรงไปตรงมาหลังจากเปลี่ยนเป็นเรเดียนครั้งแรก:
p <- cbind(lon, lat) * pi / 180 # Convert from degrees to radians
p.stationary <- sapply(1:n, function(i)
is.stationary(p[i,], p[max(1,i-5):min(n,i+5), ], k=5))
มีข้อโต้แย้งp[max(1,i-5):min(n,i+5), ]
ว่าจะมองไปไกลกลับเป็น 5 ขั้นตอนเวลาหรือไกลไปข้างหน้าเป็น 5 p[i,]
ขั้นตอนเวลาจากจุดฐาน รวมทั้งk=5
บอกว่าจะมองหาลำดับ 5 หรือมากกว่าในแถวที่อยู่ในระยะ 100 กม. จากจุดฐาน (ค่าของ 100 km ถูกตั้งค่าเป็นค่าเริ่มต้นในis.stationary
แต่คุณสามารถแทนที่ได้ที่นี่)
ผลลัพธ์p.stationary
เป็นเวกเตอร์แบบลอจิคัลที่บ่งบอกความคงอยู่: เรามีสิ่งที่เราต้องการ อย่างไรก็ตามเพื่อตรวจสอบขั้นตอนที่ดีที่สุดคือการพล็อตข้อมูลและผลลัพธ์เหล่านี้แทนที่จะตรวจสอบอาร์เรย์ของค่า ในพล็อตต่อไปนี้ฉันแสดงเส้นทางและจุดต่างๆ ทุกจุดที่สิบจะมีป้ายกำกับเพื่อให้คุณสามารถประมาณจำนวนที่อาจทับซ้อนกันภายในกลุ่มที่อยู่กับที่ จุดที่อยู่นิ่งจะถูกวาดใหม่ในสีแดงทึบเพื่อเน้นพวกเขาและล้อมรอบด้วยบัฟเฟอร์ 100 กิโลเมตรของพวกเขา
plot(p, type="l", asp=1, col="Gray",
xlab="Longitude (radians)", ylab="Latitude (radians)")
points(p)
points(p[p.stationary, ], pch=19, col="Red", cex=0.75)
i <- seq(1, n, by=10)
#
# Because we're near the Equator in this example, buffers will be nearly
# circular: approximate them.
disk <- function(x, r, n=32) {
theta <- 1:n / n * 2 * pi
return (t(rbind(cos(theta), sin(theta))*r + x))
}
r <- 100 / 6378.137 # Buffer radius in radians
apply(p[p.stationary, ], 1, function(x)
invisible(polygon(disk(x, r), col="#ff000008", border="#00000040")))
text(p[i,], labels=paste(i), pos=3, offset=1.25, col="Gray")
อื่น ๆ (สถิติ-based) วิธีการหาจุดหยุดนิ่งในการติดตามข้อมูลรวมทั้งรหัสการทำงานกรุณาเยี่ยมชม/mathematica/2711/clustering-of-space-time-data