Đọc và phân loại lại hiệu quả nhiều trình quét trong R?


8

Tôi đã được giao nhiệm vụ tạo ra một phân tích phù hợp về điều kiện sóng ở Vịnh Mexico. Tôi có 2 nghìn tệp raster khoảng 8 MB mỗi tệp (2438 cột, 1749 hàng, kích thước ô 1km). Tham số trong các tệp raster là chu kỳ sóng và tôi muốn phân loại lại tất cả các raster sao cho nếu 4<= wave period <=9 then make cell = 1khác ô = 0. Sau đó tổng hợp tất cả các raster thành một raster cuối cùng và chia cho tổng số raster để cung cấp cho tổng tỷ lệ quan sát phù hợp và xuất kết quả sang một số định dạng tương thích ESRI ... có thể là thứ gì đó có thể hỗ trợ nổi nếu cần. Tôi đã không làm việc nhiều với Python hoặc R, nhưng sau khi tìm kiếm trực tuyến, có vẻ hợp lý khi thực hiện quy trình này bằng một trong những ngôn ngữ đó. Tôi đã đưa ra một số mã cho đến nay trong R, nhưng bối rối về cách làm cho nó hoạt động.

library(rgdal)
raster_data <- list.files(path=getwd())    #promt user for dir containing raster files
num_files <- length(raster_data)
for (i in raster_data) {                   #read in rasters
   my_data <- readGDAL(raster_data[i])

Tại thời điểm này, tôi bối rối không biết có nên phân loại lại và bắt đầu tổng hợp dữ liệu trong vòng lặp này hay không. Tôi đoán là có vì nếu không tôi nghĩ rằng tôi có thể sẽ hết bộ nhớ trên máy tính, nhưng không chắc chắn. Tôi cũng không chắc chắn về cách phân loại lại dữ liệu.

Trong nghiên cứu trực tuyến tôi nghĩ rằng tôi sẽ sử dụng reclass(my_data, c(-Inf,3,0, 4,9,1, 10,Inf,0)), nhưng điều đó có đúng không?

Và để tổng kết tôi sẽ sử dụng sum(stack(my_data))và bằng cách nào đó đầu ra đó. Ngoài ra ... nếu điều này có thể được thực hiện hoặc viết bằng Python hiệu quả hơn thì tôi cũng sẽ mở nó. Tôi thực sự là người mới bắt đầu khi nói đến lập trình.


Chỉ cần sử dụng python-gdal. Nó sẽ hiệu quả hơn nhiều trong trường hợp của bạn.
SS_Rebelious

Cảm ơn, Nổi loạn. Chỉ tò mò muốn biết tại sao python-gdal hiệu quả hơn trong tình huống này? Ngoài ra, có thể thấy một số bước trong mã cần thiết để làm điều này không? Cố gắng tìm ra cách tốt nhất để làm điều này trong khi sử dụng ít bộ nhớ và cpu, càng tốt ... thật khó hiểu khi viết mã để nó đọc trong dữ liệu, xử lý, lấy nó ra khỏi bộ nhớ và sau đó di chuyển đến raster tiếp theo.
Nigel

Tôi không thể cho bạn biết chính xác lý do tại sao, nhưng nguyên nhân chung là R được thiết kế cho các mục đích khác và được biết là hoạt động chậm theo chu kỳ. Ví dụ về mã, nếu không ai cung cấp nó, tôi sẽ chia sẻ với bạn sau khoảng 10 giờ khi tôi có quyền truy cập vào máy nơi lưu trữ tập lệnh tương ứng.
SS_Rebelious

Câu trả lời:


8

Đây là một cách ngắn gọn để làm điều đó trong R --- ở đây mà không cần các tệp trung gian:

library(raster)
raster_data <- list.files(path=getwd())    #promt user for dir containing raster files
s <- stack(raster_data)
f <- function(x) { rowSums(x >= 4 & x <= 9) }
x <- calc(s, f, progress='text', filename='output.tif')

1
+1 Điều này tốt cho các vấn đề nhỏ, nhưng hãy thực hiện phép toán cho vấn đề này: 2438 cột nhân với 1749 hàng lần 8 byte / giá trị lần 2 nghìn lưới = 63,6 GB, tất cả đều Rphải giữ RAM để tạo s. (Có thể cần gấp đôi RAM vì scó thể sẽ không thay thế raster_data.) Tôi hy vọng bạn có nhiều RAM! Giải pháp của bạn có thể được thực hiện bằng cách chia 2000 lưới thành các nhóm nhỏ hơn, thực hiện phép tính cho từng nhóm và sau đó kết hợp các phép tính đó.
whuber

2
@whuber: 's' là một đối tượng nhỏ, chỉ là một loạt các con trỏ tới các tệp. Hàm calc, giống như các hàm khác trong gói raster, sẽ không tải tất cả các giá trị vào bộ nhớ; nó sẽ xử lý chúng trong khối. Đó là, việc chia thành các nhóm như bạn đề xuất được thực hiện tự động, đằng sau hậu trường. Kích thước khối có thể được tối ưu hóa cho dung lượng RAM có sẵn thông qua rasterOptions ().
Robert Hijmans

1
Cảm ơn bạn đã giải thích điều đó! Tôi đã giả định, mà không kiểm tra, stackcalcđã làm việc như hầu hết các Rchức năng khác bằng cách trước tiên tải tất cả dữ liệu vào RAM.
whuber

+1 Thích sự kết hợp của R so với ví dụ Python được cung cấp ...
SlowLearner

5

Như tôi nhận thấy trong các bình luận, nói chung, bạn nên tránh sử dụng R cho các mục đích phi thống kê do các vấn đề về hiệu suất ở một số khía cạnh nhất định (làm việc với các chu kỳ là một ví dụ). Dưới đây là ví dụ mã cho bạn ở Pyhton (nhờ bài viết này ) để phân loại lại một tệp với một băng tần duy nhất. Bạn sẽ có thể sửa đổi nó dễ dàng để xử lý hàng loạt nếu bạn biết cách lấy tất cả các tệp từ thư mục . Lưu ý rằng các trình quét được biểu diễn dưới dạng mảng, vì vậy bạn có thể sử dụng các phương thức mảng để cải thiện hiệu suất khi áp dụng. Để làm việc với các mảng trong Python, xem tài liệu Numpy .

CẬP NHẬT: mã tôi đã đăng ban đầu là phiên bản rút gọn của bộ lọc tùy chỉnh cần cho mỗi xử lý pixel. Nhưng đối với câu hỏi này, việc sử dụng Numpy sẽ tăng hiệu suất (xem mã).

from osgeo import gdal
import sys
import numpy

gdalData = gdal.Open("path_to_file")
if gdalData is None:
  sys.exit("ERROR: can't open raster")

#print "Driver short name", gdalData.GetDriver().ShortName
#print "Driver long name", gdalData.GetDriver().LongName
#print "Raster size", gdalData.RasterXSize, "x", gdalData.RasterYSize
#print "Number of bands", gdalData.RasterCount
#print "Projection", gdalData.GetProjection()
#print "Geo transform", gdalData.GetGeoTransform()


raster = gdalData.ReadAsArray()
xsize = gdalData.RasterXSize
ysize = gdalData.RasterYSize

#print xsize, 'x', ysize

## per pixel processing
#for col in range(xsize):
#  for row in range(ysize):
#    # if pixel value is 16 - change it to 7
#    if raster[row, col] == 16:
#      raster[row, col] = 7

#reclassify raster values equal 16 to 7 using Numpy
temp = numpy.equal(raster, 16)
numpy.putmask(raster, temp, 7)

# write results to file (but at first check if we are able to write this format)
format = "GTiff"
driver = gdal.GetDriverByName(format)
metadata = driver.GetMetadata()
if metadata.has_key(gdal.DCAP_CREATE) and metadata[gdal.DCAP_CREATE] == "YES":
  pass
else:
  print "Driver %s does not support Create() method." % format
  sys.exit(1)
if metadata.has_key(gdal.DCAP_CREATECOPY) and metadata[gdal.DCAP_CREATECOPY] == "YES":
  pass
else:
  print "Driver %s does not support CreateCopy() method." % format
  sys.exit(1)

# we already have the raster with exact parameters that we need
# so we use CreateCopy() method instead of Create() to save our time
outData = driver.CreateCopy("path_to_new_file", gdalData, 0)
outData.GetRasterBand(1).WriteArray(raster)

4
"R chậm khi thực hiện chu kỳ (vòng lặp)" thường bị sử dụng sai làm lý do để tránh R. Có, nếu bạn lặp qua các ô của raster trong R thì sẽ chậm, nhưng gói raster hoạt động trên toàn bộ raster cùng một lúc và có rất nhiều mã C và do đó chạy ở tốc độ C. Đối với một raster có kích thước đó, hầu hết các công việc sẽ ở tốc độ C, chi phí vòng lặp sẽ không đáng kể.
Spainedman

@Spacesman, có 'raster' là một gói hữu ích (và tôi rất thích nó), nhưng tôi chưa bao giờ hài lòng với hiệu suất của nó ngay cả khi các vòng lặp không liên quan.
SS_Rebelious

2
Được rồi, hãy so sánh thời gian trong R với thời gian sử dụng Python. Bạn có thể không hoạt động trên một mảng toàn bộ thay vì lặp đi lặp lại?
Spainedman

@Spacesman, tôi vừa cập nhật câu trả lời.
SS_Rebelious

Rất cám ơn cả hai bạn. Tôi sẽ thử mày mò cả mã Python bạn đã cung cấp và một số R và xem những gì tôi có thể thực hiện. Tôi sẽ cập nhật với kết quả hoặc vấn đề.
Nigel

2
  1. Đừng sử dụng readGDAL. Nó đọc vào một đối tượng Spatial * có thể không phải là một ý tưởng tốt ..

  2. Sử dụng rastergói. Nó có thể đọc những thứ GDAL vào các đối tượng Raster. Đây là một điều tốt. r = raster("/path/to/rasterfile.tif")sẽ đọc nó vào r.

  3. Phân loại của bạn là sau đó t = r > 4 & r <= 9

  4. Câu hỏi lớn là liệu có xuất các tệp này sang các tệp raster mới hay không và sau đó thực hiện bước tóm tắt trong một vòng lặp khác. Nếu bạn đã có bộ nhớ, tôi sẽ ghi chúng vào các tệp mới chỉ vì nếu vòng lặp của bạn không thành công (vì một trong số 2000 tệp đó là rác), bạn sẽ phải bắt đầu lại. Vì vậy, sử dụng writeRasterđể tạo raster ngưỡng nếu bạn quyết định làm điều đó.

  5. Vòng lặp của bạn sau đó chỉ là một cái gì đó như

điều này.

count = raster(0,size of your raster)
for(i in 1:number of rasters){
  r = raster(path to binary raster file 'i')
  count = count + r
}
return(count)

Quản lý bộ nhớ của R có thể đánh bạn ở đây - khi bạn làm count=count+rR cũng có thể tạo một bản sao mới count. Vì vậy, đó có khả năng là 2000 bản sao của nó - nhưng bộ sưu tập rác sẽ hoạt động và dọn sạch, và ở đây, vòng lặp của R từng rất tệ.

Về mặt thời gian, trên PC 4yo của tôi, ngưỡng op mất khoảng 1,5 giây trên một raster có kích thước của các số ngẫu nhiên trong khoảng từ 0 đến 20. Lần 2000 = bạn làm toán. Như mọi khi, hãy tạo một bộ thử nghiệm nhỏ để phát triển mã, sau đó khởi chạy nó trên dữ liệu thực của bạn và đi uống cà phê.


Tôi tò mò về ý của bạn là "ngưỡng op." Trên hệ thống của tôi (chạy R2.15.0), đọc lưới 1.6 megapixel (ở định dạng dấu phẩy động ESRI gốc) mất 0,19 giây và thực hiện năm thao tác vòng lặp - hai so sánh, kết hợp, bổ sung và lưu trữ - sẽ thực hiện một thao tác khác 0,09 giây, trong 0,28 giây mỗi lần lặp. Thay vào đó, khi vòng lặp được thực hiện bằng cách lưu 100 lưới vào một mảng và sử dụng rowSumsđể thực hiện tổng số, việc sử dụng RAM tất nhiên tăng lên: nhưng, rõ ràng là không có bộ sưu tập rác. Thời gian giảm xuống chỉ còn 0,26 giây mỗi lần lặp.
whuber
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.