class_docstr: The PGMExplainer model from the `"PGMExplainer: Probabilistic
  Graphical Model Explanations  for Graph Neural Networks"
  <https://arxiv.org/abs/1903.03894>`_ paper.
  
  The generated :class:`~torch_geometric.explain.Explanation` provides a
  :obj:`node_mask` and a :obj:`pgm_stats` tensor, which stores the
  :math:`p`-values of each node as calculated by the Chi-squared test.
  
  Args:
      feature_index (List): The indices of the perturbed features. If set
          to :obj:`None`, all features are perturbed. (default: :obj:`None`)
      perturb_mode (str, optional): The method to generate the variations in
          features. One of :obj:`"randint"`, :obj:`"mean"`, :obj:`"zero"`,
          :obj:`"max"` or :obj:`"uniform"`. (default: :obj:`"randint"`)
      perturbations_is_positive_only (bool, optional): If set to :obj:`True`,
          restrict perturbed values to be positive. (default: :obj:`False`)
      is_perturbation_scaled (bool, optional): If set to :obj:`True`, will
          normalize the range of the perturbed features.
          (default: :obj:`False`)
      num_samples (int, optional): The number of samples of perturbations
          used to test the significance of nodes to the prediction.
          (default: :obj:`100`)
      max_subgraph_size (int, optional): The maximum number of neighbors to
          consider for the explanation. (default: :obj:`None`)
      significance_threshold (float, optional): The statistical threshold
          (:math:`p`-value) for which a node is considered to have an effect
          on the prediction. (default: :obj:`0.05`)
      pred_threshold (float, optional): The buffer value (in range
          :obj:`[0, 1]`) to consider the output from a perturbed data to be
          different from the original. (default: :obj:`0.1`)
class_docstr_tok: ["The","PGMExplainer","model","from","the","`","``","PGMExplainer",":","Probabilistic","Graphical","Model","Explanations","for","Graph","Neural","Networks","''","<","https",":","\/\/arxiv.org\/abs\/1903.03894",">","`","_","paper",".","The","generated",":","class",":","`","~torch_geometric.explain.Explanation","`","provides","a",":","obj",":","`","node_mask","`","and","a",":","obj",":","`","pgm_stats","`","tensor",",","which","stores","the",":","math",":","`","p","`","-values","of","each","node","as","calculated","by","the","Chi-squared","test",".","Args",":","feature_index","(","List",")",":","The","indices","of","the","perturbed","features",".","If","set","to",":","obj",":","`","None","`",",","all","features","are","perturbed",".","(","default",":",":","obj",":","`","None","`",")","perturb_mode","(","str",",","optional",")",":","The","method","to","generate","the","variations","in","features",".","One","of",":","obj",":","`","``","randint","''","`",",",":","obj",":","`","``","mean","''","`",",",":","obj",":","`","``","zero","''","`",",",":","obj",":","`","``","max","''","`","or",":","obj",":","`","``","uniform","''","`",".","(","default",":",":","obj",":","`","``","randint","''","`",")","perturbations_is_positive_only","(","bool",",","optional",")",":","If","set","to",":","obj",":","`","True","`",",","restrict","perturbed","values","to","be","positive",".","(","default",":",":","obj",":","`","False","`",")","is_perturbation_scaled","(","bool",",","optional",")",":","If","set","to",":","obj",":","`","True","`",",","will","normalize","the","range","of","the","perturbed","features",".","(","default",":",":","obj",":","`","False","`",")","num_samples","(","int",",","optional",")",":","The","number","of","samples","of","perturbations","used","to","test","the","significance","of","nodes","to","the","prediction",".","(","default",":",":","obj",":","`","100","`",")","max_subgraph_size","(","int",",","optional",")",":","The","maximum","number","of","neighbors","to","consider","for","the","explanation",".","(","default",":",":","obj",":","`","None","`",")","significance_threshold","(","float",",","optional",")",":","The","statistical","threshold","(",":","math",":","`","p","`","-value",")","for","which","a","node","is","considered","to","have","an","effect","on","the","prediction",".","(","default",":",":","obj",":","`","0.05","`",")","pred_threshold","(","float",",","optional",")",":","The","buffer","value","(","in","range",":","obj",":","`","[","0",",","1","]","`",")","to","consider","the","output","from","a","perturbed","data","to","be","different","from","the","original",".","(","default",":",":","obj",":","`","0.1","`",")"]
docstr: Generates explanations for node classification tasks.
  
  Args:
      model (torch.nn.Module): The model to explain.
      x (torch.Tensor): The node features.
      edge_index (torch.Tensor): The edge indices of the input graph.
      target (torch.Tensor): The predicted label from the model.
      index (int): The index of the node for which the explanations is
          generated.
      **kwargs (optional): Additional arguments passed to
          :meth:`model.forward`.
  
  Returns:
      node_mask (torch.Tensor): A hard node mask corresponding to whether
          a node is significant in the selected node's prediction.
      pgm_stats (torch.Tensor): The :math:`p`-values of all the nodes in
          the graph, ordered by node index.
docstr_tok: ["Generates","explanations","for","node","classification","tasks",".","Args",":","model","(","torch.nn.Module",")",":","The","model","to","explain",".","x","(","torch.Tensor",")",":","The","node","features",".","edge_index","(","torch.Tensor",")",":","The","edge","indices","of","the","input","graph",".","target","(","torch.Tensor",")",":","The","predicted","label","from","the","model",".","index","(","int",")",":","The","index","of","the","node","for","which","the","explanations","is","generated",".","*","*","kwargs","(","optional",")",":","Additional","arguments","passed","to",":","meth",":","`","model.forward","`",".","Returns",":","node_mask","(","torch.Tensor",")",":","A","hard","node","mask","corresponding","to","whether","a","node","is","significant","in","the","selected","node","'s","prediction",".","pgm_stats","(","torch.Tensor",")",":","The",":","math",":","`","p","`","-values","of","all","the","nodes","in","the","graph",",","ordered","by","node","index","."]
code: def _explain_node(
      self,
      model: torch.nn.Module,
      x: Tensor,
      edge_index: Tensor,
      target: Tensor,
      index: int,
      **kwargs,
  ) -> Tuple[Tensor, Tensor]:
      r"""Generates explanations for node classification tasks.
  
      Args:
          model (torch.nn.Module): The model to explain.
          x (torch.Tensor): The node features.
          edge_index (torch.Tensor): The edge indices of the input graph.
          target (torch.Tensor): The predicted label from the model.
          index (int): The index of the node for which the explanations is
              generated.
          **kwargs (optional): Additional arguments passed to
              :meth:`model.forward`.
  
      Returns:
          node_mask (torch.Tensor): A hard node mask corresponding to whether
              a node is significant in the selected node's prediction.
          pgm_stats (torch.Tensor): The :math:`p`-values of all the nodes in
              the graph, ordered by node index.
      """
      import pandas as pd
      from pgmpy.estimators.CITests import chi_square
  
      neighbors, _, _, _ = k_hop_subgraph(
          node_idx=index,
          num_hops=get_num_hops(model),
          edge_index=edge_index,
          relabel_nodes=False,
          num_nodes=x.size(0),
      )
  
      if index not in neighbors:
          neighbors = torch.cat([neighbors, index], dim=1)
  
      pred_model = model(x, edge_index, **kwargs)
  
      softmax_pred = torch.softmax(pred_model, dim=1)
  
      samples = []
      pred_samples = []
  
      for _ in range(self.num_samples):
          # A subset of neighbors are selected randomly for perturbing:
          seeds = np.random.choice([1, 0], size=(len(neighbors),))
          x_perturb = self._perturb_features_on_nodes(
              x=x,
              index=neighbors[seeds == 1],
          )
  
          # prediction after perturbation
          pred_perturb = model(x_perturb, edge_index, **kwargs)
          softmax_pred_perturb = torch.softmax(pred_perturb, dim=1)
          sample_bool = np.ones(shape=(len(neighbors),))
          sample_bool[
              (
                  (
                      softmax_pred_perturb[neighbors, target]
                      + self.pred_threshold
                  )
                  >= softmax_pred[neighbors, target]
              ).cpu()
          ] = 0
  
          samples.append(seeds)
          pred_samples.append(sample_bool)
  
      samples = np.asarray(samples)
      pred_samples = np.asarray(pred_samples)
      combine_samples = (samples * 10 + pred_samples) + 1
  
      neighbors = np.array(neighbors.detach().cpu())
      data_pgm = pd.DataFrame(combine_samples)
      data_pgm = data_pgm.rename(
          columns={0: "A", 1: "B"}
      )  # Trick to use chi_square test on first two data columns
      index_original_to_subgraph = dict(
          zip(neighbors, list(data_pgm.columns))
      )
      index_subgraph_to_original = dict(
          zip(list(data_pgm.columns), neighbors)
      )
      p_values = []
  
      dependent_neighbors = []
      dependent_neighbors_p_values = []
      for node in neighbors:
          if node == index:
              # null hypothesis is perturbing a particular
              # node has no effect on result
              p = 0
          else:
              _, p, _ = chi_square(
                  index_original_to_subgraph[node],
                  index_original_to_subgraph[index],
                  [],
                  data_pgm,
                  boolean=False,
                  significance_level=self.significance_threshold,
              )
          p_values.append(p)
          if p < self.significance_threshold:
              dependent_neighbors.append(node)
              dependent_neighbors_p_values.append(p)
  
      pgm_stats = torch.ones(x.size(0), dtype=torch.float)
      node_mask = torch.zeros(x.size(), dtype=torch.int)
  
      pgm_stats[neighbors] = torch.tensor(p_values, dtype=torch.float)
  
      if self.max_subgraph_size is None:
          pgm_nodes = dependent_neighbors
      else:
          top_p = np.min((self.max_subgraph_size, len(neighbors) - 1))
          ind_top_p = np.argpartition(p_values, top_p)[0:top_p]
          pgm_nodes = [
              index_subgraph_to_original[node] for node in ind_top_p
          ]
      node_mask[pgm_nodes] = 1
      return node_mask, pgm_stats
  
file_path: pytorch_geometric/torch_geometric/contrib/explain/pgm_explainer.py
imports: import logging
  from typing import List, Optional, Tuple, Union
  import numpy
  import torch
  from torch import Tensor
  from torch_geometric.explain import ExplainerAlgorithm
  from torch_geometric.explain.config import ModelMode, ModelTaskLevel
  from torch_geometric.explain.explanation import Explanation
  from torch_geometric.utils import k_hop_subgraph
  from torch_geometric.utils._subgraph import get_num_hops
label_desc: Use image node_id 5 for calling the PGMExplainer obj's underlying member method code with example usage: obj._explain_node(model, x, edge_index, target, index) and returns: node_mask,  pgm_stats