Xác định các điểm liên tiếp trong một bộ đệm xác định


8

Tôi có một tệp điểm, di chuyển hàng giờ của một con vật và tôi muốn có thể đặt một bộ đệm xung quanh mỗi điểm và tính toán số điểm tiếp theo nằm trong vùng đệm. Tôi đang tìm kiếm một phương thức sẽ hoạt động dọc theo tệp điểm, giống như một cửa sổ di chuyển, nó sẽ chỉ tính những điểm tiếp theo nằm trong vùng đệm.

Chẳng hạn, tại điểm 10 tôi đặt một bộ đệm 1500m và tôi muốn biết liệu điểm 11 có nằm trong bộ đệm hay không và nếu vậy thì điểm 12 có nằm trong bộ đệm hay không. Tôi không muốn biết liệu điểm 52 có nằm trong vùng đệm hay không trừ khi tất cả các điểm trước đó nằm trong vùng đệm. Tôi cũng không muốn biết liệu điểm 9 hay 8, v.v. có nằm trong bộ đệm không.

Tôi đã tìm và thử một hộp công cụ bổ sung có tên là "phân tích điểm cửa sổ di chuyển" hoạt động như một cửa sổ di chuyển trên tệp điểm. Điều này hoạt động tốt, nhưng rất chậm và bao gồm tất cả các điểm nằm trong vùng đệm ngay cả khi chúng không phải là các điểm liên tiếp. Tôi không thể tìm ra cách để làm cho nó nhìn vào các điểm liên tiếp.

Tôi muốn một phương thức sẽ cung cấp một bảng đầu ra vì tôi có rất nhiều điểm dữ liệu để xem xét theo cách này.

Tôi đang sử dụng ArcGIS 10. Bất kỳ trợ giúp nào mà bất kỳ ai có thể cung cấp sẽ được đánh giá rất cao.


Điểm của bạn có khả năng bắt nguồn dưới dạng danh sách dữ liệu (x, y, thời gian). Bạn có sẵn sàng xử lý trước các dữ liệu này (bên ngoài ArcGIS) để có được thông tin mong muốn không?
whuber

Nếu điều đó làm cho nó dễ dàng hơn thì chắc chắn. Tôi cũng đang xử lý dữ liệu bằng AdehabitatLT trong R để tính toán khoảng cách và vòng bi, v.v. Tôi hiểu quy trình do Sylvester đề xuất bên dưới nhưng tôi đang loay hoay không biết bắt đầu từ đâu vì tôi không thực sự chắc chắn mình cần sử dụng công cụ nào.
James

Ah! Vì bạn đã sử dụng R, hãy khám phá các giải pháp dựa trên R sau đó.
whuber

Có một chức năng cửa sổ trượt trong AdehabitatLT "sliwinltr" nhưng tôi không biết cách sử dụng nó trong trường hợp này. Tôi thậm chí không biết nếu nó có thể được sử dụng theo cách này.
James

Câu trả lời:


8

Đưa ra một danh sách các vị trí điểm (tốt nhất là trong tọa độ dự kiến, để khoảng cách dễ tính toán), vấn đề này có thể được giải quyết bằng năm thao tác đơn giản hơn :

  1. Tính khoảng cách điểm-điểm.

  2. Đối với mỗi điểm i, i = 1, 2, ..., hãy xác định các chỉ mục của các điểm đó ở khoảng cách nhỏ hơn bán kính bộ đệm (chẳng hạn như 1500).

  3. Hạn chế các chỉ số là i hoặc lớn hơn.

  4. Chỉ giữ lại nhóm chỉ số liên tiếp đầu tiên không nghỉ.

  5. Xuất số đếm của nhóm đó.

Trong R, mỗi trong số này tương ứng với một hoạt động. Để áp dụng trình tự này cho từng điểm, thật thuận tiện để đóng gói hầu hết các công việc trong một chức năng mà chúng tôi xác định , do đó:

#
# forward(j, xy, r) counts how many contiguous rows in array xy, starting at index j,
#                   are within (Euclidean) distance r of the jth row of xy.
#
forward <- function(j, xy, r) {
  # Steps 1 and 2: compute an array of indexes of points within distance r of point j.
  i <- which(apply(xy, 1, function(x){sum((x-xy[j,])^2) <= r^2}))
  # Step 3: select only the indexes at or after j.
  i <- i[i >= j]
  # Steps 4 and 5: retain only the first consecutive group and count it.
  length(which(i <= (1:length(i) + j)))
}

(Xem bên dưới để biết phiên bản hiệu quả hơn của chức năng này.)

Tôi đã làm cho hàm này đủ linh hoạt để chấp nhận các danh sách điểm khác nhau ( xy) và khoảng cách bộ đệm ( r) làm tham số.

Thông thường, bạn sẽ đọc một tệp các vị trí điểm (và, nếu cần, sắp xếp chúng theo thời gian). Ở đây, để thể hiện điều này trong thực tế, chúng tôi sẽ chỉ tạo ngẫu nhiên một số dữ liệu mẫu :

# Create sample data
n<-16                                     # Number of points
set.seed(17)                              # For reproducibility
xy <- matrix(rnorm(2*n) + 1:n, n, 2) * 300
#
# Display the track.
plot(xy, xlab="x", ylab="y")
lines(xy, col="Gray")

Nhân vật

Khoảng cách thông thường của chúng là 300 * Sqrt (2) = khoảng 500. Chúng tôi thực hiện phép tính bằng cách áp dụng hàm này cho các điểm trong mảngxy (và sau đó xử lý kết quả của nó trở lại xy, bởi vì đây sẽ là định dạng thuận tiện để xuất sang GIS ):

radius <- 1500
z <- sapply(1:n, function(u){forward(u,xy,radius)})
result <- cbind(xy, z)                              # List of points, counts

Sau đó, bạn sẽ phân tích thêm resultmảng, bằng Rhoặc bằng cách ghi nó vào một tệp và nhập nó vào phần mềm khác. Đây là kết quả cho dữ liệu mẫu :

                        z
  [1,]   -4.502615  551.5413 4
  [2,]  576.108979  647.8110 3
  [3,]  830.103893 1087.7863 4
  [4,]  954.819620 1390.0754 3
...
 [15,] 4977.361529 4146.7291 2
 [16,] 4783.446283 4511.9500 1

(Hãy nhớ rằng các số đếm bao gồm các điểm mà chúng dựa vào, sao cho mỗi số phải là 1 hoặc lớn hơn.)


Nếu bạn có nhiều nghìn điểm, phương pháp này quá kém hiệu quả : nó tính toán quá nhiều khoảng cách điểm-điểm không cần thiết. Nhưng bởi vì chúng tôi đã gói gọn công việc trong forwardhàm, nên tính không hiệu quả rất dễ khắc phục. Đây là một phiên bản sẽ hoạt động tốt hơn khi có hơn vài trăm điểm:

forward <- function(j, xy, r) {
   n <- dim(xy)[1]     # Limit the search to the number of points in xy
   r2 <- r^2           # Pre-compute the squared distance threshold
   z <- xy[j,]         # Pre-fetch the base point coordinates
   i <- j+1            # Initialize an index into xy (just past point j)

   # Advance i while point i remains within distance r of point j.
   while(i <= n && sum((xy[i,]-z)^2) <= r2) i <- i+1

   # Return the count (including point j).
   i-j
}

Để kiểm tra điều này, tôi đã tạo các điểm ngẫu nhiên như trước đây nhưng thay đổi hai tham số: n(số lượng điểm) và độ lệch chuẩn của chúng (mã hóa cứng là 300 ở trên). Độ lệch chuẩn xác định số điểm trung bình trong mỗi bộ đệm ("trung bình" trong bảng bên dưới): càng có nhiều, thuật toán này càng mất nhiều thời gian để chạy. (Với các thuật toán phức tạp hơn, thời gian chạy sẽ không phụ thuộc nhiều vào số lượng điểm trong mỗi bộ đệm.) Dưới đây là một số thời gian:

 Time (sec)    n    SD  Average  Distances checked per minute
 1.30       10^3     3  291      13.4 million
 1.72       10^4    30   35.7    12.5
 2.50       10^5   300    3.79    9.1
16.4        10^6  3000    1.04    3.8

Đây có vẻ là giải pháp hoàn hảo. Tuy nhiên, mã không chạy từ "z <- sapply (1: n), function (u) {Forward (u, xy, radius)})" như nó nói: "không mong đợi", "trong" z <- sapply (1: n), "Nếu tôi xóa dấu phẩy thì nó báo: Lỗi: 'hàm' không mong muốn trong hàm" z <- sapply (1: n) "Bạn có biết tại sao điều này có thể như vậy không?
James

Lấy làm tiếc; có một lỗi đánh máy ở đó: Tôi sẽ xóa ")". (Tôi đã đơn giản hóa phút cuối cùng của mã này Nó được thử nghiệm nhiều lần hơn tôi chăm sóc phải thừa nhận.!)
whuber

1
Thật tuyệt, giờ nó đang chạy. Tôi chỉ tải dữ liệu của mình dưới dạng xy để đơn giản kiểm tra nó hoạt động. Phải mất một ít thời gian để chạy như bạn đã đề cập nhưng dường như đã làm tất cả một cách chính xác. Tôi sẽ tự kiểm tra lại một vài cái với bản đồ GIS của mình nhưng nó có vẻ tốt cho đến nay. Cảm ơn vì đã giúp tôi giải quyết vấn đề này, rất muốn học ở cả GIS và R và tôi đang trên đường học tập dốc.
James

1
Tôi đã chỉnh sửa trả lời để cung cấp một giải pháp với khả năng mở rộng được cải thiện đáng kể. Bây giờ nó có khả năng xử lý các đường dẫn chứa hàng triệu điểm.
whuber

1
Tôi đã chạy mã gốc với các tệp điểm gồm 2000 mục nhập mất vài giờ mỗi lần, như bạn nói có quá nhiều điểm không sử dụng đến các vị trí điểm kéo dài thời gian xử lý. Chỉnh sửa ở trên trông giống như một giải pháp gọn gàng và tôi sẽ thử điều này trên cùng một dữ liệu và xem nó nhanh hơn bao nhiêu. Cảm ơn những nỗ lực với việc sản xuất và chỉnh sửa chức năng.
James

1

Tôi nghĩ rằng đặt cược tốt nhất của bạn là kịch bản một thói quen nhỏ bằng ArcPy. Tôi sẽ tạo một cái gì đó giống như mã giả này:

Select all points sorted by location-id    
Iterate for each point:
    Select points by location using a distance (no need to create buffer geometry)
    Sort points by location-id
    Set a variable to the value of your reference id
    consecutive-counter = 0
        Iterate your selection:
            Is the location-id of the first (or next) point equal to variable + 1?
            if 'yes' increment consecutive-counter by 1
            Repeat until 'no'

Tôi không chắc bạn muốn làm gì với thông tin nhưng tôi cho rằng bạn có thể tạo một trường trong bảng của mình và cập nhật nó với số điểm liên tiếp (nếu vậy, hãy thêm trường trước).

Tôi sẽ khuyên bạn nên tạo các lớp đối tượng (như chế độ xem bảng cơ sở dữ liệu nhưng đối với các tính năng trong Arc). Tạo hai từ dữ liệu gốc và mở một con trỏ cập nhật trên tập đầu tiên chỉ định sắp xếp trên tất cả của bạn (vì ESRI không tôn trọng các truy vấn SQL đầy đủ). Sử dụng cái thứ hai để chọn theo vị trí và mở Con trỏ tìm kiếm trên bộ lựa chọn kết quả.

[CHỈNH SỬA YÊU CẦU CỦA Jame] Yêu cầu sử dụng Model Builder. Nếu bạn chưa sử dụng Model Builder trước đây, tất cả những gì bạn phải làm là nhấp chuột phải vào arcToolbox. Chọn 'Thêm hộp công cụ'. Nhấp chuột phải vào hộp công cụ mới và nhấp vào 'Mới-> kiểu máy'. Khi bạn có cửa sổ mô hình mới, hãy kéo và thả các công cụ và dữ liệu bạn cần vào cửa sổ và liên kết trực quan chúng với nhau (sử dụng công cụ mũi tên nhỏ). Khi bạn đã có được càng xa càng tốt (bạn sẽ không thể thêm con trỏ của mình vào đây), hãy sử dụng tùy chọn trong Menu Tệp của Trình tạo mô hình để xuất sang Python. Điều đó sẽ giúp bạn có được hầu hết các cách đó. Đó là mã được tạo tự động nên sẽ hơi khó chịu nhưng có chức năng. Sau đó sử dụng các liên kết trong câu trả lời của tôi ở trên để hiểu và thêm các con trỏ.

Nếu bạn chưa quen với Python, đừng sợ viết mã! Python là một ngôn ngữ kịch bản rất dễ dàng để có được kết quả nhanh chóng. Esri cũng có một số hướng dẫn về nó.

Nếu bạn gặp khó khăn với mã của mình, hãy đăng nó lên diễn đàn này và yêu cầu trợ giúp. Có rất nhiều người ở đây có thể giúp đỡ. Một cảnh báo - đảm bảo bạn sử dụng đúng trợ giúp từ ESRI. Họ đã thay đổi ồ ạt API Python giữa các phiên bản 9.x và 10 (tương ứng arcgisscripting và arcpy). Vì vậy, nếu bạn đang sử dụng ArcGIS 9.x, hãy tìm các liên kết tương đương với tôi!


Điều này trông giống như những gì tôi muốn làm. Tuy nhiên, tôi hiện không sử dụng mã trong ArcGIS, chỉ chọn từ các tùy chọn được xác định trước. Làm thế nào tôi có thể bắt đầu sử dụng / tạo phương thức được đề xuất ở trên? Tôi muốn đầu ra là một bảng mới hoặc một trường mới được thêm vào bảng với số điểm liên tiếp.
James

Xem chỉnh sửa của tôi để bài viết chính của tôi.
MappaGnosis

JTB, vui lòng đăng nhập bằng chính tài khoản bạn đã sử dụng để đăng câu hỏi này để bạn có thể đăng bình luận. (Để dễ dàng hơn, tôi đã hợp nhất tài khoản JTB với tài khoản James.)
whuber

Xin lỗi về việc thay đổi tài khoản. Tôi đã đăng câu hỏi ban đầu với tư cách là người dùng mới nhưng sau đó tôi không thể quay lại tài khoản đó vì tôi không có mật khẩu, v.v. Vì vậy, tôi đã tạo một tài khoản JTB khác mà tôi sẽ sử dụng từ bây giờ (hy vọng). Tôi sẽ khởi động trình xây dựng mô hình theo đề xuất của Sylvester, nhưng chưa bao giờ sử dụng nó trước khi nó có thể khiến tôi mất một ít thời gian để làm quen với nó và tìm ra công cụ nào để sử dụng. Tôi sẽ trở lại với sự tiến bộ và câu hỏi. Cảm ơn
James

Sylvester - Tôi nghĩ rằng tôi hiểu quy trình nhưng tôi không biết nên bắt đầu với công cụ nào. Khoảng cách? Đệm? Ở gần? Tôi thậm chí không biết nếu có một công cụ chính xác cho vấn đề này sẽ làm những gì đã được đề cập ở trên. Tôi rất muốn học nhưng lúc đầu rất nhiều.
James

1

Bạn có thể sử dụng trình xây dựng mô hình trong ArcGIS để tìm các giá trị ID liên tiếp. Tôi xuất mô hình của tôi dưới dạng một kịch bản python. Mã sẽ tạo một shp mới có giá trị ID liên tiếp. !TÔI! là trường ID cơ sở. Bạn sẽ phải cập nhật đường dẫn point2.shp, tên và tên trường ID để khớp với trường hợp của bạn.

# Import arcpy module
import arcpy


# Local variables:
point2_shp = "C:\\temp\\point2.shp"
point2_shp__2_ = "C:\\temp\\point2.shp"
point2_shp__4_ = "C:\\temp\\point2.shp"
Freq_dbf__2_ = "C:\\temp\\Freq.dbf"
point2_shp__5_ = "C:\\temp\\point2.shp"
point2__2_ = "C:\\temp\\point2.shp"
point2__4_ = "C:\\temp\\point2.shp"
Freq_dbf = "C:\\temp\\Freq.dbf"
PointConsecutive_shp = "C:\\temp\\PointConsecutive.shp"

# Process: Add Field
arcpy.AddField_management(point2_shp, "AUTOID", "LONG", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field
arcpy.CalculateField_management(point2__2_, "AUTOID", "autoIncrement()", "PYTHON_9.3", "rec=0\\ndef autoIncrement():\\n global rec\\n pStart = 1 #adjust start value, if req'd \\n pInterval = 1 #adjust interval value, if req'd\\n if (rec == 0): \\n  rec = pStart \\n else: \\n  rec = rec + pInterval \\n return rec\\n")

# Process: Add Field (2)
arcpy.AddField_management(point2_shp, "DIFF", "LONG", "", "", "", "", "NON_NULLABLE", "NON_REQUIRED", "")

# Process: Calculate Field (2)
arcpy.CalculateField_management(point2__4_, "DIFF", "!ID! - !AUTOID!", "PYTHON_9.3", "")

# Process: Frequency
arcpy.Frequency_analysis(point2_shp__2_, Freq_dbf, "DIFF", "")

# Process: Join Field
arcpy.JoinField_management(point2_shp__4_, "DIFF", Freq_dbf__2_, "DIFF", "")

# Process: Select
arcpy.Select_analysis(point2_shp__5_, PointConsecutive_shp, "\"FREQUENCY\" >1")

Tôi không chắc những gì mã ở trên làm và cách nó trả lời truy vấn của tôi. Tôi đánh giá cao sự giúp đỡ nhưng đây là điều hoàn toàn mới đối với tôi khi chưa bao giờ sử dụng Python hoặc trình xây dựng mô hình. Tôi có thay đổi trường ID cho từng quy trình được liệt kê thành ID trong tập dữ liệu không?
James

@James, Nó phụ thuộc nếu ID của bạn thay đổi. Để sử dụng mã, chỉ cần sao chép và dán mã ở trên và lưu nó vào một tệp txt trống. Cập nhật mã để khớp với tên và đường dẫn point.shp của bạn. Sau đó, thay đổi tên ID trong phần mã Trường tính toán (2) để khớp với trường ID point.shp của bạn. Lưu tệp txt và trong windows explorer đặt tên lại tệp với phần mở rộng .py. Nhấp chuột phải vào tệp và mở bằng python.exe để kiểm tra.
nghệ thuật21

Lý tưởng nhất, tập lệnh này có thể được cắm vào một công cụ tập lệnh, cũng xử lý việc chọn bộ đệm và tính năng. help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/
nghệ thuật21
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.