code: def test_given_simple_gaussian_data_when_attribute_anomaly_scores_with_it_score_then_returns_qualitatively_correct_results():
      Z = np.random.normal(0, 1, 5000)
      X0 = Z + np.random.normal(0, 1, 5000)
      X1 = Z + np.random.normal(0, 1, 5000)
      X2 = Z + np.random.normal(0, 1, 5000)
      X3 = Z + np.random.normal(0, 1, 5000)
  
      original_observations = np.column_stack([X0, X1, X2, X3])
  
      # Defining an anomaly scorer that handles multidimensional inputs.
      density_estimator = GaussianMixtureDensityEstimator()
      anomaly_scorer = InverseDensityScorer(density_estimator)
      anomaly_scorer.fit(original_observations)
  
      # Seeing that the expectation of the noise in all nodes is 0, we introduce anomalies by setting some of them to 3.
      anomaly_samples = np.array(
          [
              [3, 0, 0, 0],
              [0, 3, 0, 0],
              [0, 0, 3, 0],
              [0, 3, 3, 0],
              [3, 0, 3, 3],
          ]
      )
  
      contributions = attribute_anomaly_scores(
          anomaly_samples,
          original_observations,
          anomaly_scorer.score,
          False,
      )
  
      # In the first sample, only the first variable is anomalous. Therefore, it should have the highest contribution
      # and it should be "significantly" higher than the contribution of the other ones (here, we just arbitrarily say
      # it should be 3x higher. Due to the confounding factor Z, the reconstructed noise variables are pairwise dependent,
      # which is a violation of our causal sufficiency assumption. However, a confounder is included here to demonstrate
      # some robustness. Note that due to this and stochastic behaviour of the density estimator, it is
      # not possible to analytically compute expected results. Therefore, we rather look at the relations here.
      assert np.argmax(contributions[0]) == 0
      assert np.all(contributions[0][0] > contributions[0][1:] * 3)
  
      # Same idea for the second sample, but here, it is the second variable that is anomalous.
      assert np.argmax(contributions[1]) == 1
      assert np.all(contributions[1][1] > contributions[1][0] * 3)
      assert np.all(contributions[1][1] > contributions[1][2:] * 3)
  
      assert np.argmax(contributions[2]) == 2
      assert np.all(contributions[2][2] > contributions[2][0:2] * 3)
      assert np.all(contributions[2][2] > contributions[2][3:] * 3)
  
      # In the fourth sample, there are 2 anomalous variables. Therefore, the contribution of these 2 variables should be
      # "significantly" higher than the contribution of the other variables. The contribution of both anomalous variables
      # should be equal (approximately).
      assert np.all(contributions[3][1] > contributions[3][0] * 3)
      assert np.all(contributions[3][2] > contributions[3][0] * 3)
      assert np.all(contributions[3][1] > contributions[3][3] * 3)
      assert np.all(contributions[3][2] > contributions[3][3] * 3)
      assert contributions[3][1] == approx(contributions[3][2], abs=0.5)
  
      assert np.all(contributions[4][0] > contributions[4][1] * 3)
      assert np.all(contributions[4][2] > contributions[4][1] * 3)
      assert np.all(contributions[4][3] > contributions[4][1] * 3)
      assert contributions[4][0] == approx(contributions[4][2], abs=0.5)
      assert contributions[4][2] == approx(contributions[4][3], abs=0.5)
  
file_path: dowhy/tests/gcm/test_anomaly_attribution.py
imports: import networkx
  import numpy
  import pandas
  from flaky import flaky
  from pytest import approx
  from dowhy.gcm import AdditiveNoiseModel, InverseDensityScorer, InvertibleStructuralCausalModel, MedianCDFQuantileScorer, attribute_anomalies, auto, fit
  from dowhy.gcm.anomaly import _relative_frequency, attribute_anomaly_scores
  from dowhy.gcm.density_estimators import GaussianMixtureDensityEstimator
  from dowhy.gcm.ml import PredictionModel
label_desc: Use image node_id 1 for calling a global function with example usage: test_given_simple_gaussian_data_when_attribute_anomaly_scores_with_it_score_then_returns_qualitatively_correct_results() without return types