4 votos

¿Sumar los valores de un campo basándose en los valores únicos de otro campo?

Tengo una capa hecha de un campo con valores de cadena repetidos ("edificio") y un campo con valores de flotación ("superficie plana"). Me gustaría escribir un script para hacer algunas operaciones aritméticas (como la suma, el máximo y el mínimo, etc.) sobre todos los valores de la columna B que están asociados a los mismos valores de la columna A, pero no funciona.

Conjunto de datos:

BUILDING       FLATSURF    SUM (wanted result)
    1           40.0       115 (i.e. 40+45+30 m^2)
    1           45.0       115
    1           30.0       115
    2          200.0       300 (i.e. 200+100 m^2)
    2          100.0       300
    3           60.0       140 (i.e. 60+80 m^2)
    3           80.0       140

Juicio en clave:

building=layer.dataProvider().fieldNameIndex('BUILDING')
flatssurface=layer.dataProvider().fieldNameIndex('FLATSURF')

uniquevalues=layer.uniqueValues(building,limit=10000)
for uv in uniquevalues:
    feat=layer.getFeatures()
    for f in feat:
      tot=sum([flatssurface])
      print tot

sin embargo, sólo devuelve el índice de la superficie de los planos de campo (f[1]). Para simplificar, descuidé la parte de añadir el campo pero sólo intenté imprimir los resultados, para comprobar si funcionaba. Si es posible, no necesito respuestas relacionadas con GroupStats ( ¿Calcular la suma de las partes de la columna en base a otra columna usando la Calculadora de Campo QGIS? ) o SQL o estadísticas ( https://gis.stackexchange.com/editing-help ) pero sólo busco una solución relacionada con Python.

5voto

Braiam Puntos 120

cuando lo hagas

flatssurface=layer.dataProvider().fieldNameIndex('FLATSURF')

efectivamente se obtiene el índice (número de columna) del campo Flatsurf . Para acceder a los datos, en su bucle, necesita obtener la característica, sus atributos y, por último, restringir a la columna adecuada utilizando el índice que ha encontrado. Así, el valor numérico que quieres usar en tu bucle es

f.attributes()[flatssurface]

Además de acceder al valor del campo, hay que sumarlo mediante la construcción. Usando tu código de ejemplo estás haciendo el producto cruzado de todos los edificios por todos los valores de los edificios.

buildingidx=layer.dataProvider().fieldNameIndex('BUILDING')
flatssurfaceidx=layer.dataProvider().fieldNameIndex('FLATSURF')

uniquevalues=layer.uniqueValues(buildingidx,limit=10000)
for uv in uniquevalues:
    #re-initialise the total area for each building
    tot = 0.0        

    #statement for selecting just the proper buildings
    exp = QgsExpression('BUILDING = ' + str(uv))
    request = QgsFeatureRequest(exp)
    #Select only the buildings having the specified value
    feat=layer.getFeatures(request)
    #Do the sum
    for f in feat:
      tot+=f.attributes()[flatssurfaceidx]
    #once done, print the building value and the corresponding total surface
    print("Building:",uv, "Total surface:", tot)

0 votos

Gracias @JGH pero no estoy seguro de haber entendido cómo insertarlo en el script. He probado esto: for uv in unval: feat=layer.getFeatures() attr=feat.attributes() for f in feat: tot=sum([attr[6]]) print tot

0 votos

Error tipográfico corregido en mi post. De tu código original, sólo tienes que sustituir la línea 'tot=suma([flatssurface])' por ' tot=suma(f.attributes()[flatssurface])' Los atributos son por característica, así que accedes a ellos dentro del bucle 'for f in feat:'

0 votos

Ahora parece que funciona pero no puedo comprobarlo porque el bucle no se detiene...

3voto

Mue Puntos 2469

Existe la Estadísticas por categorías algoritmo del Caja de herramientas de procesamiento que parece hacer lo que usted busca. Esto calcula varias estadísticas utilizando el Clase QgsStatisticalSummary como los valores máximos, mínimos y de suma. El script se puede encontrar en su directorio QGIS, por ejemplo

C:/Program Files/QGIS 2.18/apps/qgis/python/plugins/processing/algs/qgis/StatisticsByCategories.py

O encontrar el última versión del script en GitHub .

Pero podemos tomar el grueso del código, modificarlo ligeramente y utilizarlo en el Consola Python (recuerde seleccionar primero su capa antes de ejecutar el código):

layer = iface.activeLayer()
building = layer.fieldNameIndex('BUILDING')
flatssurface = layer.fieldNameIndex('FLATSURF')

features = layer.getFeatures()
values = {}
for current, feat in enumerate(features):
    attrs = feat.attributes()
    try:        
        cat = unicode(attrs[building])
        value = float(attrs[flatssurface])
        if cat not in values:
            values[cat] = []
        values[cat].append(value)
    except:
        pass

stat = QgsStatisticalSummary(QgsStatisticalSummary.Min | QgsStatisticalSummary.Max |
                            QgsStatisticalSummary.Mean | QgsStatisticalSummary.StDevSample |
                            QgsStatisticalSummary.Sum | QgsStatisticalSummary.Count)

for (cat, v) in values.items():
    stat.calculate(v)
    record = [cat, stat.min(), stat.max(), stat.mean(), stat.sampleStDev(), stat.sum(), stat.count()]
    print record

0 votos

@FedericaZ - De nada, espero que haya sido útil :)

0voto

201044 Puntos 106

Puedes hacerlo utilizando: Herramientas de análisis>Estadística>Estadística de resumen (si es que entendí su pregunta) Seleccione FLATSURF para "Campo(s) estadístico(s)" y cambie el "tipo de estadística" a SUM. Luego, BUILDING para el "Campo del caso". Te creará una tabla. Es muy fácil. ¿Verdad? no necesitas escribir todos esos scripts.

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