0

I created a model that combines two vector layers and outputs a single layer with aggregated data. I have a Python script that calculates the Chi-square, and I would like it to be executed at the end of the model's execution.

How do I incorporate the Chi-square code into the modeler?

script Chi-square:

import numpy as np
from scipy.stats import chisquare, norm
from qgis.gui import QgsFieldComboBox, QgsDoubleSpinBox
from qgis.PyQt.QtWidgets import QInputDialog, QMessageBox

# Função para calcular os valores críticos com base no novo valor de alfa corrigido
def calcular_valores_criticos(alfa_corrigido):
    # Calcular os valores críticos da distribuição normal padrão
    limite_superior = norm.ppf(1 - alfa_corrigido / 2)
    limite_inferior = norm.ppf(alfa_corrigido / 2)
    return limite_superior, limite_inferior

# Função para realizar o teste qui-quadrado de aderência com correção de Bonferroni
def qui_quadrado_aderencia_qgis(camada, campo_esperado, campo_observado, alfa):
    # Verificar se a camada está carregada
    if not camada:
        print("Camada inválida. Verifique se uma camada está ativa.")
        return

    # Inicializar listas para valores esperados e observados
    valores_esperados = []
    valores_observados = []

    # Acessar os dados da camada e extrair os valores esperados e observados
    for feature in camada.getFeatures():
        valor_esperado = feature[campo_esperado]
        valor_observado = feature[campo_observado]
        if isinstance(valor_esperado, (int, float)) and isinstance(valor_observado, (int, float)):
            valores_esperados.append(float(valor_esperado))
            valores_observados.append(float(valor_observado))

    # Executar o teste qui-quadrado de aderência
    chi2, p_valor = chisquare(valores_observados, f_exp=valores_esperados)

    # Calcular os resíduos padronizados ajustados
    res_padronizados = (np.array(valores_observados) - np.array(valores_esperados)) / np.sqrt(valores_esperados)

    # Aplicar a correção de Bonferroni ao valor de alfa
    p_valor_corrigido = p_valor * len(valores_esperados)  # Número de testes multiplicado pelo p-valor original
    alfa_corrigido = alfa / len(valores_esperados)

    # Calcular os valores críticos com base no novo valor de alfa corrigido
    limite_superior, limite_inferior = calcular_valores_criticos(alfa_corrigido)

    # Imprimir os resultados
    print("Estatística qui-quadrado:", chi2)
    print("Valor-p:", p_valor)
    print("Valor-p corrigido (Bonferroni):", p_valor_corrigido)
    print("Resíduos Padronizados:")
    print(res_padronizados)
    print(f"Valores críticos para alfa corrigido ({alfa_corrigido}):")
    print(f"Limite Superior: {limite_superior}")
    print(f"Limite Inferior: {limite_inferior}")

    # Interpretar o resultado com a correção de Bonferroni
    if p_valor_corrigido < alfa_corrigido:
        print("Rejeitar a hipótese nula: A distribuição do fenômeno analisado não possui carácter aleatório (com correção de Bonferroni).")
    else:
        print("Falha em rejeitar a hipótese nula: A distribuição do fenômeno analisado possui carácter aleatório (com correção de Bonferroni).")

# Obter a camada ativa no QGIS
camada_ativa = iface.activeLayer()

# Usar QInputDialog para obter os campos de atributos e o valor de alfa
campo_esperado, ok = QInputDialog.getItem(None, "Campo de Valores Esperados", "Selecione o campo de valores esperados:",
                                          [field.name() for field in camada_ativa.fields()])
if not ok:
    QMessageBox.critical(None, "Erro", "Seleção de campo de valores esperados cancelada.")
else:
    campo_observado, ok = QInputDialog.getItem(None, "Campo de Valores Observados", "Selecione o campo de valores observados:",
                                               [field.name() for field in camada_ativa.fields()])
    if not ok:
        QMessageBox.critical(None, "Erro", "Seleção de campo de valores observados cancelada.")
    else:
        alfa, ok = QInputDialog.getDouble(None, "Valor de Alfa", "Digite o valor de alfa (nível de significância):", 0.05, 0, 1, 6)
        if ok:
            # Chamar a função qui_quadrado_aderencia_qgis
            qui_quadrado_aderencia_qgis(camada_ativa, campo_esperado, campo_observado, alfa)
2
  • I don't believe it is possible, but you could export your model, as it is with the merge of 2 vector layers), to a Python script algorithm (Model -> Export -> Export as Python Script...) and edit that script to include your Chi-square code.
    – Kalak
    Commented Jan 11 at 7:22
  • Or as the deleted answer proposed (sorry answerer, I misread it), you can turn your Chi-square code into a Processing Algorithm and insert it inside your model.
    – Kalak
    Commented Jan 11 at 8:53

1 Answer 1

-1

It is possible to include your script into a model. I would not export the whole model and include your script. An other way is, to make a seperate process and include the process in a model. You have to get rid of all QInputDialogs and integrate inputs into the processing script. It then looks like the following script. This will produce an Inputdialog for the algorithm. You have to put your logic then in the def processAlgorithm function.

from qgis.core import QgsProcessing
from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingMultiStepFeedback
from qgis.core import QgsProcessingParameterField
from qgis.core import QgsProcessingParameterVectorLayer
from qgis.core import QgsProcessingParameterFeatureSink
import processing
import numpy as np
from scipy.stats import chisquare, norm

#Função para calcular os valores críticos com base no novo valor de alfa corrigido
def calcular_valores_criticos(alfa_corrigido):
    # Calcular os valores críticos da distribuição normal padrão
    limite_superior = norm.ppf(1 - alfa_corrigido / 2)
    limite_inferior = norm.ppf(alfa_corrigido / 2)
    return limite_superior, limite_inferior

class p_chisquare(QgsProcessingAlgorithm):

    def initAlgorithm(self, config=None):
         self.addParameter(QgsProcessingParameterVectorLayer('camada_ativa', 'camada_ativa', types=[QgsProcessing.TypeVectorAnyGeometry], defaultValue=None))        
         self.addParameter(QgsProcessingParameterField('campo_observado', 'campo_observado', type=QgsProcessingParameterField.Any, parentLayerParameterName='camada_ativa', allowMultiple=False, defaultValue=None))
         self.addParameter(QgsProcessingParameterField('campo_esperado', 'campo_esperado', type=QgsProcessingParameterField.Any, parentLayerParameterName='camada_ativa', allowMultiple=False, defaultValue=None))
         self.addParameter(QgsProcessingParameterFeatureSink('Result', 'Result', type=QgsProcessing.TypeVectorPolygon, createByDefault=True, supportsAppend=True, defaultValue=None))

    def processAlgorithm(self, parameters, context, model_feedback):
    # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
    # overall progress through the model
        feedback = QgsProcessingMultiStepFeedback(1, model_feedback)
        results = {}
        outputs = {}
    
        #-->> Here comes your algorithm

        return results

    def name(self):
        return 'p_chisquare'

    def displayName(self):
        return 'chisquare'

    def group(self):
        return ''

    def groupId(self):
        return ''

    def createInstance(self):
        return p_chisquare()
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.