Repository: understandable-machine-intelligence-lab/Quantus
Issue: Sensitivity-n seems to average over features and correlate samples rather than correlate features and average over samples
Root cause: Algorithmic Error

Hello @annahedstroem,
It is possible that I am confusing something or calling the function incorrectly but if not, then I think there might be a mistake in how Sensitivity-n is calculated.
### Description
In custom_postprocess, the similarity_func (pearson correlation) is calculated [for each n](https://github.com/understandable-machine-intelligence-lab/Quantus/blob/0088a7fb24d880ea57df4feedf834f7d4458e1f5/quantus/metrics/faithfulness/sensitivity_n.py#L407), between the different samples in the batch rather than for every sample, between all n. In the [readme](https://github.com/understandable-machine-intelligence-lab/Quantus/blob/0088a7fb24d880ea57df4feedf834f7d4458e1f5/README.md?plain=1#L91) and the original paper, this does seem to be the other way around if I am not mistaken.

For example, when a batch size of 1 is used, the pearson coefficient cannot be calculated anymore and it will fail.

### Steps to reproduce the behavior (batch size 1 case)
```
import numpy as np
from quantus.helpers.model.models import LeNet
import quantus

quantus.SensitivityN()(
            model=LeNet(),
            x_batch=np.zeros((1, 1, 28, 28)),
            y_batch=np.zeros((1,), dtype=np.int64),
            device="cuda",
            explain_func=quantus.explain,
            explain_func_kwargs={"method": "Saliency"}
        )
```
Output:
```
File "...\quantus\metrics\faithfulness\sensitivity_n.py", line 408, in custom_postprocess
    self.evaluation_scores = [
                             ^
  File "...\quantus\metrics\faithfulness\sensitivity_n.py", line 409, in <listcomp>
    self.similarity_func(
  File "...\quantus\functions\similarity_func.py", line 56, in correlation_pearson
    return scipy.stats.pearsonr(a, b)[0]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "...\scipy\stats\_stats_py.py", line 4816, in pearsonr
    raise ValueError('`x` and `y` must have length at least 2.')
ValueError: `x` and `y` must have length at least 2.
```

Expected: a single output representing the Sensitivity-N score of a single sample

Hi @arnon-1 thanks for notifying this. We'll look into this and get back to you!

After I had confirmed that the implementation did not completely match the documentation, I had quickly skimmed through the paper and it seems that what I mentioned last time did not fully match the original implementation (my apologies for that).
Now that I actually read the paper: the original implementation sampled 100 different subsets of features for a single value of n to estimate the correlation, so the correlation is not calculated over the number of samples nor over different n values but over different subsets of the same number of features using the same input sample. After that, the correlation was averaged across 1000 samples.
However, that would mean that it is not possible to use the top n features as subset.


Hi @arnon-1  thanks for following back here. Can you please refer to the specific line of code that you're unsure about? So that we can better address and target the potential implementation fixes.

Hello @annahedstroem,
In the current implementation, for a single instance, [the top-n features are used](https://github.com/understandable-machine-intelligence-lab/Quantus/blob/0088a7fb24d880ea57df4feedf834f7d4458e1f5/quantus/metrics/faithfulness/sensitivity_n.py#L401) [and perturbed](https://github.com/understandable-machine-intelligence-lab/Quantus/blob/0088a7fb24d880ea57df4feedf834f7d4458e1f5/quantus/metrics/faithfulness/sensitivity_n.py#L308). 

The correlation is calculated [between samples in the same batch](https://github.com/understandable-machine-intelligence-lab/Quantus/blob/0088a7fb24d880ea57df4feedf834f7d4458e1f5/quantus/metrics/faithfulness/sensitivity_n.py#L407).

The resulting correlation is then optionally averaged over the different n-values.



The implementation in the original paper is given by the following paragraph if I am not mistaken:

![image](https://github.com/user-attachments/assets/d18568a4-8eb2-4ca6-a508-17cac92dd95d)