Tăng tốc trường dấu thời gian tính toán Python trong ArcGIS Desktop?


9

Tôi chưa quen với Python và đã bắt đầu tạo tập lệnh cho quy trình công việc ArcGIS. Tôi tự hỏi làm thế nào tôi có thể tăng tốc mã của mình để tạo trường số kép "Giờ" từ trường dấu thời gian. Tôi bắt đầu với một shapefile bản ghi điểm theo dõi (đường dẫn bánh mì) được tạo bởi DNR Garmin, với trường dấu thời gian LTIME (trường văn bản, độ dài 20) khi mỗi bản ghi điểm theo dõi được thực hiện. Kịch bản tính toán sự khác biệt về Giờ giữa mỗi dấu thời gian liên tiếp ("LTIME") và đặt nó vào một trường mới ("Giờ").

Bằng cách đó tôi có thể quay lại và tổng hợp bao nhiêu thời gian tôi đã dành cho một khu vực / đa giác cụ thể. Phần chính là sau print "Executing getnextLTIME.py script..." đây là đoạn mã:

# ---------------------------------------------------------------------------
# 
# Created on: Sept 9, 2010
# Created by: The Nature Conservancy
# Calculates delta time (hours) between successive rows based on timestamp field
#
# Credit should go to Richard Crissup, ESRI DTC, Washington DC for his
# 6-27-2008 date_diff.py posted as an ArcScript
'''
    This script assumes the format "month/day/year hours:minutes:seconds".
    The hour needs to be in military time. 
    If you are using another format please alter the script accordingly. 
    I do a little checking to see if the input string is in the format
    "month/day/year hours:minutes:seconds" as this is a common date time
    format. Also the hours:minute:seconds is included, otherwise we could 
    be off by almost a day.

    I am not sure if the time functions do any conversion to GMT, 
    so if the times passed in are in another time zone than the computer
    running the script, you will need to pad the time given back in 
    seconds by the difference in time from where the computer is in relation
    to where they were collected.

'''
# ---------------------------------------------------------------------------
#       FUNCTIONS
#----------------------------------------------------------------------------        
import arcgisscripting, sys, os, re
import time, calendar, string, decimal
def func_check_format(time_string):
    if time_string.find("/") == -1:
        print "Error: time string doesn't contain any '/' expected format \
            is month/day/year hour:minutes:seconds"
    elif time_string.find(":") == -1:
        print "Error: time string doesn't contain any ':' expected format \
            is month/day/year hour:minutes:seconds"

        list = time_string.split()
        if (len(list)) <> 2:
            print "Error time string doesn't contain and date and time separated \
                by a space. Expected format is 'month/day/year hour:minutes:seconds'"


def func_parse_time(time_string):
'''
    take the time value and make it into a tuple with 9 values
    example = "2004/03/01 23:50:00". If the date values don't look like this
    then the script will fail. 
'''
    year=0;month=0;day=0;hour=0;minute=0;sec=0;
    time_string = str(time_string)
    l=time_string.split()
    if not len(l) == 2:
        gp.AddError("Error: func_parse_time, expected 2 items in list l got" + \
            str(len(l)) + "time field value = " + time_string)
        raise Exception 
    cal=l[0];cal=cal.split("/")
    if not len(cal) == 3:
        gp.AddError("Error: func_parse_time, expected 3 items in list cal got " + \
            str(len(cal)) + "time field value = " + time_string)
        raise Exception
    ti=l[1];ti=ti.split(":")
    if not len(ti) == 3:
        gp.AddError("Error: func_parse_time, expected 3 items in list ti got " + \
            str(len(ti)) + "time field value = " + time_string)
        raise Exception
    if int(len(cal[0]))== 4:
        year=int(cal[0])
        month=int(cal[1])
        day=int(cal[2])
    else:
        year=int(cal[2])
        month=int(cal[0])
        day=int(cal[1])       
    hour=int(ti[0])
    minute=int(ti[1])
    sec=int(ti[2])
    # formated tuple to match input for time functions
    result=(year,month,day,hour,minute,sec,0,0,0)
    return result


#----------------------------------------------------------------------------

def func_time_diff(start_t,end_t):
    '''
    Take the two numbers that represent seconds
    since Jan 1 1970 and return the difference of
    those two numbers in hours. There are 3600 seconds
    in an hour. 60 secs * 60 min   '''

    start_secs = calendar.timegm(start_t)
    end_secs = calendar.timegm(end_t)

    x=abs(end_secs - start_secs)
    #diff = number hours difference
    #as ((x/60)/60)
    diff = float(x)/float(3600)   
    return diff

#----------------------------------------------------------------------------

print "Executing getnextLTIME.py script..."

try:
    gp = arcgisscripting.create(9.3)

    # set parameter to what user drags in
    fcdrag = gp.GetParameterAsText(0)
    psplit = os.path.split(fcdrag)

    folder = str(psplit[0]) #containing folder
    fc = str(psplit[1]) #feature class
    fullpath = str(fcdrag)

    gp.Workspace = folder

    fldA = gp.GetParameterAsText(1) # Timestamp field
    fldDiff = gp.GetParameterAsText(2) # Hours field

    # set the toolbox for adding the field to data managment
    gp.Toolbox = "management"
    # add the user named hours field to the feature class
    gp.addfield (fc,fldDiff,"double")
    #gp.addindex(fc,fldA,"indA","NON_UNIQUE", "ASCENDING")

    desc = gp.describe(fullpath)
    updateCursor = gp.UpdateCursor(fullpath, "", desc.SpatialReference, \
        fldA+"; "+ fldDiff, fldA)
    row = updateCursor.Next()
    count = 0
    oldtime = str(row.GetValue(fldA))
    #check datetime to see if parseable
    func_check_format(oldtime)
    gp.addmessage("Calculating " + fldDiff + " field...")

    while row <> None:
        if count == 0:
            row.SetValue(fldDiff, 0)
        else:
            start_t = func_parse_time(oldtime)
            b = str(row.GetValue(fldA))
            end_t = func_parse_time(b)
            diff_hrs = func_time_diff(start_t, end_t)
            row.SetValue(fldDiff, diff_hrs)
            oldtime = b

        count += 1
        updateCursor.UpdateRow(row)
        row = updateCursor.Next()

    gp.addmessage("Updated " +str(count+1)+ " rows.")
    #gp.removeindex(fc,"indA")
    del updateCursor
    del row

except Exception, ErrDesc:
    import traceback;traceback.print_exc()

print "Script complete."

1
chương trình tốt đẹp Tôi chưa thấy gì để tăng tốc tính toán. Máy tính trường mất mãi mãi !!
Brad Nesom

Câu trả lời:


12

Con trỏ luôn thực sự chậm trong môi trường xử lý địa lý. Cách dễ nhất để giải quyết vấn đề này là chuyển một khối mã Python vào công cụ xử lý địa lý tính toán tính toán.

Một cái gì đó như thế này sẽ hoạt động:

import arcgisscripting
gp = arcgisscripting.create(9.3)

# Create a code block to be executed for each row in the table
# The code block is necessary for anything over a one-liner.
codeblock = """
import datetime
class CalcDiff(object):
    # Class attributes are static, that is, only one exists for all 
    # instances, kind of like a global variable for classes.
    Last = None
    def calcDiff(self,timestring):
        # parse the time string according to our format.
        t = datetime.datetime.strptime(timestring, '%m/%d/%Y %H:%M:%S')
        # return the difference from the last date/time
        if CalcDiff.Last:
            diff =  t - CalcDiff.Last
        else:
            diff = datetime.timedelta()
        CalcDiff.Last = t
        return float(diff.seconds)/3600.0
"""

expression = """CalcDiff().calcDiff(!timelabel!)"""

gp.CalculateField_management(r'c:\workspace\test.gdb\test','timediff',expression,   "PYTHON", codeblock)

Rõ ràng là bạn phải sửa đổi nó để lấy các trường và chẳng hạn như các tham số, nhưng nó sẽ khá nhanh.

Lưu ý rằng mặc dù các chức năng phân tích cú pháp ngày / giờ của bạn thực sự nhanh hơn chức năng strptime (), thư viện tiêu chuẩn hầu như không có nhiều lỗi hơn.


Cảm ơn David. Tôi đã không nhận ra rằng CompateField nhanh hơn; Tôi sẽ cố gắng để kiểm tra điều này. Vấn đề duy nhất tôi nghĩ có thể là bộ dữ liệu có thể bị lỗi. Nhân dịp này, điều này xảy ra. Có cách nào để sắp xếp tăng dần trên trường LTIME trước và sau đó áp dụng tính toán tính toán, hoặc để báo cho tính toán tính toán để thực hiện theo một thứ tự nhất định?
Russell

Chỉ cần một lưu ý, gọi các chức năng gp đóng hộp trước sẽ nhanh hơn hầu hết thời gian. Tôi đã giải thích lý do tại sao trong một bài viết trước gis.stackexchange.com/questions/8186/ triệt
Ragi Yaser Burhum

+1 để sử dụng gói tích hợp datetime , vì nó cung cấp chức năng tuyệt vời và gần như thay thế các gói thời gian / lịch
Mike T

1
thật không thể tin được Tôi đã thử mã của bạn và tích hợp nó với đề xuất "trong bộ nhớ" của @OptizesPrime và thời gian chạy trung bình của tập lệnh từ 55 giây đến 2 giây (810 bản ghi). Đây chính xác là thứ mà tôi đang tìm kiếm. Cảm ơn bạn rất nhiều. Tôi đã học được rất nhiều.
Russell

3

@David đã cho bạn một giải pháp rất sạch sẽ. +1 để sử dụng các điểm mạnh của cơ sở mã arcgisscripting.

Một tùy chọn khác, là sao chép tập dữ liệu vào bộ nhớ bằng cách sử dụng:

  • gp.CopyFeatureclass ("đường dẫn đến nguồn của bạn", "in_memory \ tên tính năng được sao chép") - cho Lớp tính năng Geodatabase, shapefile hoặc,
  • gp.CopyRows ("đường dẫn đến nguồn của bạn",) - cho bảng Cơ sở dữ liệu địa lý, dbf, v.v.

Điều này loại bỏ chi phí phát sinh khi bạn yêu cầu một con trỏ từ cơ sở mã COM ESRI.

Chi phí hoạt động đến từ việc chuyển đổi các loại dữ liệu python thành các loại dữ liệu C và truy cập vào cơ sở mã ESRI COM.

Khi bạn có dữ liệu trong bộ nhớ, bạn sẽ giảm nhu cầu truy cập đĩa (một quy trình chi phí cao). Ngoài ra, bạn giảm nhu cầu thư viện python và C / C ++ để truyền dữ liệu, khi bạn sử dụng arcgisscripting.

Hi vọng điêu nay co ich.


1

Một thay thế tuyệt vời cho việc sử dụng UpdateCoder kiểu cũ từ arcgisscripting, đã có sẵn từ ArcGIS 10.1 cho Desktop, là arcpy.da.UpdateCoder .

Tôi đã thấy rằng những thứ này thường nhanh hơn khoảng 10 lần.

Những điều này sẽ / có thể không phải là một lựa chọn khi câu hỏi này được viết nhưng không nên bỏ qua cho bất cứ ai đọc Q & A này ngay bây giờ.

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.