ArcGIS Desktop'ta Python hesaplanmış zaman damgası alanını hızlandırıyor musunuz?


9

Python'da yeniyim ve ArcGIS iş akışları için komut dosyaları oluşturmaya başladım. Ben bir zaman damgası alanından bir "Saat" çift sayısal alan oluşturmak için kodumu hızlandırmak nasıl merak ediyorum. DNR Garmin tarafından oluşturulan bir iz noktası günlüğü (kırıntı izi) şekil dosyasıyla başlayıp, her iz noktası kaydının alındığı zaman için bir LTIME zaman damgası alanı (bir metin alanı, uzunluk 20) ​​ile başlıyorum. Komut dosyası, birbirini izleyen her zaman damgası ("LTIME") arasındaki Saat farkını hesaplar ve bunu yeni bir alana ("Saat") yerleştirir.

Bu şekilde geri dönüp belirli bir alanda / çokgene ne kadar zaman harcadığımı özetleyebilirim. Ana bölüm print "Executing getnextLTIME.py script..." İşte kod aşağıdadır:

# ---------------------------------------------------------------------------
# 
# 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
güzel bir program! Hesaplamayı hızlandıracak hiçbir şey görmedim. Alan hesap makinesi sonsuza kadar sürer !!
Brad Nesom

Yanıtlar:


12

İmleç, coğrafi işlem ortamında her zaman çok yavaştır. Bunu yapmanın en kolay yolu bir Python kod bloğunu CalculateField coğrafi işleme aracına geçirmektir.

Böyle bir şey işe yaramalı:

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)

Açıkçası, alanları ve parametreleri gibi almak için bunu değiştirmeniz gerekir, ancak oldukça hızlı olmalıdır.

Tarih / saat ayrıştırma işlevleriniz aslında strptime () işlevinden daha hızlı bir saç olmasına rağmen, standart kitaplığın hemen hemen her zaman daha fazla hatasız olduğunu unutmayın.


Teşekkürler David. CalculateField'in daha hızlı olduğunu fark etmedim; Bunu test etmeye çalışacağım. Bence olabilir tek sorun veri kümesinin bozuk olabilir. Bazen olur. Önce LTIME alanında Artan Sıralama ve sonra CalculateField uygulamak veya CalculateField belirli bir sırayla yürütmek söylemek için bir yolu var mı?
Russell

Sadece bir not, önceden konserve gp fonksiyonlarını çağırmak çoğu zaman daha hızlı olacaktır. Neden önceki bir yazıda gis.stackexchange.com/questions/8186/…
Ragi Yaser Burhum

Harika bir işlevsellik sunduğu ve zaman / takvim paketlerinin neredeyse yerini aldığı için datetime yerleşik paketini kullanmak için +1
Mike T

1
bu inanılmazdı! Kodunuzu denedim ve @OptimizePrime'ın "bellekte" önerisiyle entegre ettim ve komut dosyasının ortalama çalışma süresini 55 saniyeden 2 saniyeye (810 kayıt) aldı. Bu tam da aradığım şey. Çok teşekkür ederim. Çok öğrendim.
Russell

3

@David size çok temiz bir çözüm sundu. Arcgisscripting kod tabanının güçlü yönlerini kullanmak için +1.

Başka bir seçenek, veri kümesini aşağıdakileri kullanarak belleğe kopyalamaktır:

  • gp.CopyFeatureclass ("kaynağınızın yolu", "in_memory \ kopyalanan özellik adı") - bir Geodatabase Feature Class, shapefile veya,
  • gp.CopyRows ("kaynağınızın yolu",) - bir Geodatabase tablosu, dbf vb. için

Bu, ESRI COM kod tabanından bir imleç istediğinizde oluşan ek yükü kaldırır.

Genel gider, python veri türlerinin C veri türlerine dönüştürülmesinden ve ESRI COM kod tabanına erişimden kaynaklanır.

Verilerinizi belleğe aldığınızda, diske erişim gereksinimini azaltırsınız (yüksek maliyetli bir işlem). Ayrıca, arcgisscripting kullandığınızda, veri aktarmak için python ve C / C ++ kitaplıklarına olan gereksinimi azaltırsınız.

Bu yardımcı olur umarım.


1

Arcgiscripting'ten eski stil UpdateCursor'ı kullanmak için mükemmel bir alternatif olan ArcGIS 10.1, Masaüstü için arcpy.da.UpdateCursor olduğundan kullanılabilir .

Bunların tipik olarak yaklaşık 10 kat daha hızlı olduğunu gördüm.

Bu soru yazılırken bunlar bir seçenek olabilirdi / olmayabilirdi, ancak şimdi bu Soru-Cevap'yı okuyan kimse tarafından gözden kaçırılmamalıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.