5 votos

Selecciona aleatoriamente un registro para actualizarlo usando arcpy.da.UpdateCursor

Esta pregunta está relacionada con Uso correcto de un contador usando arcpy.da.UpdateCursor . Lo que quiero hacer es utilizar un cursor con una cláusula where para seleccionar un número de registros. Para cada fila, los valores en dos campos, TYPE_A y TYPE_B debe ser comparado. Si esos dos valores no son iguales, el campo NUM_ID debe actualizarse con el valor actual del contador.

Una vez hecho esto, todos menos uno del resto de los registros de la selección debe actualizarse con el valor del contador incrementado.

Algunos datos de ejemplo:

FEATURE 1 :NUM_ID = 4   TYPE_A = NEW   TYPE_B = NEW
FEATURE 2 :NUM_ID = 4   TYPE_A = NEW   TYPE_B = EXISTING
FEATURE 3 :NUM_ID = 4   TYPE_A = NEW   TYPE_B= NEW
FEATURE 4 :NUM_ID = 4   TYPE_A = NEW   TYPE_B= NEW
FEATURE 5 :NUM_ID = 11  TYPE_A = NEW   TYPE_B = EXISTING
FEATURE 6 :NUM_ID = 14  TYPE_A = NEW   TYPE_B = NEW
FEATURE 7 :NUM_ID = 11  TYPE_A = NEW   TYPE_B = EXISTING

Las 4 características con NUM_ID = 4 se seleccionaría y la característica 2 recibiría el NUM_ID 21, ya que sus valores para TYPE_A y TYPE_B son diferentes. El siguiente paso sería actualizar todos menos uno de los otros 3 registros incrementando el contador. La siguiente selección serían las 2 características con NUM_ID = 11 . Como los dos registros tienen valores diferentes para ambos campos, ambos se actualizarán. La última selección será para NUM_ID = 4. Como sus dos valores para los campos son los mismos, y es el único registro en su conjunto de selección, no es necesario actualizarlo.

El resultado:

FEATURE 1 :NUM_ID = 23   TYPE_A = NEW   TYPE_B = NEW
FEATURE 2 :NUM_ID = 21   TYPE_A = NEW   TYPE_B = EXISTING
FEATURE 3 :NUM_ID = 22   TYPE_A = NEW   TYPE_B= NEW
FEATURE 4 :NUM_ID = 4   TYPE_A = NEW   TYPE_B= NEW
FEATURE 5 :NUM_ID = 11  TYPE_A = NEW   TYPE_B = EXISTING
FEATURE 6 :NUM_ID = 14  TYPE_A = NEW   TYPE_B = NEW
FEATURE 7 :NUM_ID = 25  TYPE_A = NEW   TYPE_B = EXISTING

El código que tengo:

getNum("%Selected Features%")

def getNum(ftr):
  lst = [4, 11, 14, 15] #values for SQL expression
  x = 20
  fields = ('TYPE_A', 'TYPE_B', 'NUM_ID')
  assert "NUM_ID" in [f.name for f in arcpy.ListFields(ftr)], "NUM_ID field no in feature class"
  for l in lst:
    y = x + 1
   whereclause = "%(sql_name)s = '%(l)s' """ {"sql_name":arcpy.AddFieldDelimiters(ftr, "NUM_ID"), "l":l}
    with arcpy.da.UpdateCursor(ftr, fields, whereclause) as cursor:
      for row in cursor:
        if row[0] ! = row[1]:
          row[2] = y
        #some condition here
        cursor.updateRow(row)
    y += 1

TYPE_A sólo tiene un valor para todas las características, es decir NEW . TYPE_B puede tener cualquier valor. No importa qué característica se actualiza entre las que tienen los mismos valores para ambos campos ( NEW ), siempre que uno de ellos mantenga el valor original de NUM_ID. Aunque este código actualiza correctamente la fila en la que los dos campos no coinciden, no sé cómo dejar que uno de los registros mantenga el valor original, mientras que el resto debería actualizarse.

2voto

auramo Puntos 161

De acuerdo, creo que entiendo a dónde quieres llegar, así que he actualizado mi respuesta; creo que ahora produce el resultado esperado dados tus datos de muestra.

import arcpy
from pprint import pprint

def getNum(ftr):
    lst = [4, 11, 15] #values for SQL expression
    x = 20
    fields = ('TYPE_A', 'TYPE_B', 'NUM_ID')
    assert "NUM_ID" in [f.name for f in arcpy.ListFields(ftr)], "NUM_ID field no in feature class"
    y = x + 1
    for l in lst:
        # Check whether we need to do anything with this recordset at all; if there are no records where TYPE_A <> TYPE_B then we need not do anything
        whereclauseFilter = "%(num_id)s = %(l)s AND %(type_a)s <> %(type_b)s" % {"num_id":arcpy.AddFieldDelimiters(ftr, "NUM_ID"), "type_a":arcpy.AddFieldDelimiters(ftr, "TYPE_A"), "type_b":arcpy.AddFieldDelimiters(ftr, "TYPE_B"), "l":l}
        rowcountFilter = int(arcpy.GetCount_management(arcpy.SelectLayerByAttribute_management(arcpy.MakeTableView_management(ftr), where_clause=whereclauseFilter)).getOutput(0))
        if rowcountFilter > 0:
            # Okay, yes we do need to do something, but we take off the TYPE_A <> TYPE_B check so we can update the other records as well
            whereclauseNoFilter = "%(num_id)s = %(l)s" % {"num_id":arcpy.AddFieldDelimiters(ftr, "NUM_ID"), "l":l}
            rowcountNoFilter = int(arcpy.GetCount_management(arcpy.SelectLayerByAttribute_management(arcpy.MakeTableView_management(ftr), where_clause=whereclauseNoFilter)).getOutput(0))
            # Added ORDER BY postfix so that (hopefully) the records with different TYPE_A and TYPE_Bs are visited first
            with arcpy.da.UpdateCursor(ftr, fields, whereclauseNoFilter, sql_clause=("","ORDER BY TYPE_A, TYPE_B")) as cursor:
                z = 0 # Keep track of where we are within this record set
                for row in cursor:
                    # If we are on the last (or only) record in the record set, do not update it
                    if z == rowcountNoFilter - 1:
                        break
                    row[2] = y
                    cursor.updateRow(row)
                    y += 1
                    z += 1

def printTable(table):
    fieldnames = [field.name for field in arcpy.Describe(table).fields]
    tablelist = [[row.getValue(fieldname) for fieldname in fieldnames] for row in arcpy.SearchCursor(table)]
    pprint(fieldnames)
    pprint(tablelist)

if __name__ == "__main__":
    tbl1 = r"C:\GISData\test6.gdb\test3"
    tbl2 = r"C:\GISData\test6.gdb\test4"
    printTable(tbl1)
    arcpy.env.overwriteOutput = True
    arcpy.Copy_management(tbl1, tbl2)
    getNum(tbl2)
    printTable(tbl2)

Ejemplo de salida:

\[u'OBJECTID', u'NUM\_ID', u'TYPE\_A', u'TYPE\_B'\]
\[\[1, 4, u'NEW', u'NEW'\],
 \[2, 4, u'NEW', u'EXISTING'\],
 \[3, 4, u'NEW', u'NEW'\],
 \[4, 4, u'NEW', u'NEW'\],
 \[5, 11, u'NEW', u'EXISTING'\],
 \[6, 14, u'NEW', u'NEW'\],
 \[7, 11, u'NEW', u'EXISTING'\]\]
\[u'OBJECTID', u'NUM\_ID', u'TYPE\_A', u'TYPE\_B'\]
\[\[1, 22, u'NEW', u'NEW'\],
 \[2, 21, u'NEW', u'EXISTING'\],
 \[3, 23, u'NEW', u'NEW'\],
 \[4, 4, u'NEW', u'NEW'\],
 \[5, 24, u'NEW', u'EXISTING'\],
 \[6, 14, u'NEW', u'NEW'\],
 \[7, 11, u'NEW', u'EXISTING'\]\]

0voto

Hameno Puntos 129

Yo añadiría otro campo de tipo doble y ejecutaría la función R.random() de numpy sobre él. A continuación, podría identificar el valor más alto o más bajo seleccionado del campo aleatorio, y luego realizar la actualización basada en esos otros registros no más altos o más bajos seleccionados. Aquí está el ejemplo de código básico de numpy R.random():

import numpy.random as R

def getRandomValue():
    return R.random()

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X