<p dir="auto">Hi,<br>
Thank you for your awesome work which I regularly use!<br>
Unfortunately after a <a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.kruskal.html" rel="nofollow">Kruskal-Wallis H-test</a> for independent samples I need to perform a Dunn test which is not already present and does not exist at all in Python (I only managed to found an R implementation <a href="https://cran.r-project.org/web/packages/dunn.test/index.html" rel="nofollow">cf this link</a>).</p>
<p dir="auto">When using <code class="notranslate">scipy.interpolate.interp1d</code> and specifying the same x-value multiple times the result is undefined, i.e., it depends on the interpolation method used (<code class="notranslate">kind</code>), but not in a very predictable way. The result ranges from <code class="notranslate">np.nan</code>, through any of the y-values that correspond to the duplicate x-values, to exceptions in the case of quadric and cubic splines.</p>
<p dir="auto">I guess this is a weird edge case, so maybe it is okay to be inconsistent and not support it at all. This would make a lot of sense to me. In this case, I would like to suggest updating the documentation to something like <code class="notranslate">x-values must be unique</code>, potentially paired with an exception if non-unique values are encountered.</p>
<p dir="auto">Alternatively, one could sanitize the input by merging duplicates, e.g., by computing their mean. That said, I didn't spend a lot of time thinking this option through so it might be unexpected for some interpolation methods.</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&gt;&gt;&gt; from scipy.interpolate import interp1d
&gt;&gt;&gt; kinds = ['linear', 'nearest', 'nearest-up', 'zero', 'slinear', 'previous', 'next']
&gt;&gt;&gt; for kind in kinds:
...     print(f&quot;Output for Kind: {kind} \n {interp1d([0, 0, 1], [0, 0.5, 1], kind=kind)(0)}\n----&quot;)
... 
Output for Kind: linear 
 nan  # also creates warnings when called outside of f-string
----
Output for Kind: nearest 
 0.0
----
Output for Kind: nearest-up 
 0.5
----
Output for Kind: zero 
 0.5
----
Output for Kind: slinear 
 0.5
----
Output for Kind: previous 
 0.5  # should this not be 0.0 since the previous value should be 0
----
Output for Kind: next 
 0.0 # should this not be 0.5 since the next value is 0.5
----
&gt;&gt;&gt; interp1d([0, 0, 1], [0, 0.5, 1], kind=&quot;quadric&quot;)(0)
Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
  File &quot;/home/sebastian/.local/lib/python3.8/site-packages/scipy/interpolate/interpolate.py&quot;, line 443, in __init__
    raise NotImplementedError(&quot;%s is unsupported: Use fitpack &quot;
NotImplementedError: quadric is unsupported: Use fitpack routines for other types.
&gt;&gt;&gt; interp1d([0, 0, 1], [0, 0.5, 1], kind=&quot;cubic&quot;)(0)
Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
  File &quot;/home/sebastian/.local/lib/python3.8/site-packages/scipy/interpolate/interpolate.py&quot;, line 546, in __init__
    self._spline = make_interp_spline(xx, yy, k=order,
  File &quot;/home/sebastian/.local/lib/python3.8/site-packages/scipy/interpolate/_bsplines.py&quot;, line 788, in make_interp_spline
    raise ValueError(&quot;Expect x to not have duplicates&quot;)
ValueError: Expect x to not have duplicates"><pre class="notranslate"><span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-k">from</span> <span class="pl-s1">scipy</span>.<span class="pl-s1">interpolate</span> <span class="pl-k">import</span> <span class="pl-s1">interp1d</span>
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">kinds</span> <span class="pl-c1">=</span> [<span class="pl-s">'linear'</span>, <span class="pl-s">'nearest'</span>, <span class="pl-s">'nearest-up'</span>, <span class="pl-s">'zero'</span>, <span class="pl-s">'slinear'</span>, <span class="pl-s">'previous'</span>, <span class="pl-s">'next'</span>]
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-k">for</span> <span class="pl-s1">kind</span> <span class="pl-c1">in</span> <span class="pl-s1">kinds</span>:
...     <span class="pl-s1">print</span>(<span class="pl-s">f"Output for Kind: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">kind</span><span class="pl-kos">}</span></span> <span class="pl-cce">\n</span> <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-en">interp1d</span>([<span class="pl-c1">0</span>, <span class="pl-c1">0</span>, <span class="pl-c1">1</span>], [<span class="pl-c1">0</span>, <span class="pl-c1">0.5</span>, <span class="pl-c1">1</span>], <span class="pl-s1">kind</span><span class="pl-c1">=</span><span class="pl-s1">kind</span>)(<span class="pl-c1">0</span>)<span class="pl-kos">}</span></span><span class="pl-cce">\n</span>----"</span>)
... 
<span class="pl-v">Output</span> <span class="pl-s1">for</span> <span class="pl-v">Kind</span>: <span class="pl-s1">linear</span> 
 <span class="pl-s1">nan</span>  <span class="pl-c"># also creates warnings when called outside of f-string</span>
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span>
<span class="pl-v">Output</span> <span class="pl-s1">for</span> <span class="pl-v">Kind</span>: <span class="pl-s1">nearest</span> 
 <span class="pl-c1">0.0</span>
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span>
<span class="pl-v">Output</span> <span class="pl-s1">for</span> <span class="pl-v">Kind</span>: <span class="pl-s1">nearest</span><span class="pl-c1">-</span><span class="pl-s1">up</span> 
 <span class="pl-c1">0.5</span>
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span>
<span class="pl-v">Output</span> <span class="pl-s1">for</span> <span class="pl-v">Kind</span>: <span class="pl-s1">zero</span> 
 <span class="pl-c1">0.5</span>
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span>
<span class="pl-v">Output</span> <span class="pl-s1">for</span> <span class="pl-v">Kind</span>: <span class="pl-s1">slinear</span> 
 <span class="pl-c1">0.5</span>
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span>
<span class="pl-v">Output</span> <span class="pl-s1">for</span> <span class="pl-v">Kind</span>: <span class="pl-s1">previous</span> 
 <span class="pl-c1">0.5</span>  <span class="pl-c"># should this not be 0.0 since the previous value should be 0</span>
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span>
<span class="pl-v">Output</span> <span class="pl-s1">for</span> <span class="pl-v">Kind</span>: <span class="pl-s1">next</span> 
 <span class="pl-c1">0.0</span> <span class="pl-c"># should this not be 0.5 since the next value is 0.5</span>
<span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span><span class="pl-c1">-</span>
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-en">interp1d</span>([<span class="pl-c1">0</span>, <span class="pl-c1">0</span>, <span class="pl-c1">1</span>], [<span class="pl-c1">0</span>, <span class="pl-c1">0.5</span>, <span class="pl-c1">1</span>], <span class="pl-s1">kind</span><span class="pl-c1">=</span><span class="pl-s">"quadric"</span>)(<span class="pl-c1">0</span>)
<span class="pl-v">Traceback</span> (<span class="pl-s1">most</span> <span class="pl-s1">recent</span> <span class="pl-s1">call</span> <span class="pl-s1">last</span>):
  <span class="pl-v">File</span> <span class="pl-s">"&lt;stdin&gt;"</span>, <span class="pl-s1">line</span> <span class="pl-c1">1</span>, <span class="pl-s1">in</span> <span class="pl-c1">&lt;</span><span class="pl-s1">module</span><span class="pl-c1">&gt;</span>
  <span class="pl-v">File</span> <span class="pl-s">"/home/sebastian/.local/lib/python3.8/site-packages/scipy/interpolate/interpolate.py"</span>, <span class="pl-s1">line</span> <span class="pl-c1">443</span>, <span class="pl-s1">in</span> <span class="pl-s1">__init__</span>
    <span class="pl-k">raise</span> <span class="pl-v">NotImplementedError</span>(<span class="pl-s">"%s is unsupported: Use fitpack "</span>
<span class="pl-v">NotImplementedError</span>: <span class="pl-s1">quadric</span> <span class="pl-c1">is</span> <span class="pl-s1">unsupported</span>: <span class="pl-v">Use</span> <span class="pl-s1">fitpack</span> <span class="pl-s1">routines</span> <span class="pl-k">for</span> <span class="pl-s1">other</span> <span class="pl-s1">types</span>.
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-en">interp1d</span>([<span class="pl-c1">0</span>, <span class="pl-c1">0</span>, <span class="pl-c1">1</span>], [<span class="pl-c1">0</span>, <span class="pl-c1">0.5</span>, <span class="pl-c1">1</span>], <span class="pl-s1">kind</span><span class="pl-c1">=</span><span class="pl-s">"cubic"</span>)(<span class="pl-c1">0</span>)
<span class="pl-v">Traceback</span> (<span class="pl-s1">most</span> <span class="pl-s1">recent</span> <span class="pl-s1">call</span> <span class="pl-s1">last</span>):
  <span class="pl-v">File</span> <span class="pl-s">"&lt;stdin&gt;"</span>, <span class="pl-s1">line</span> <span class="pl-c1">1</span>, <span class="pl-c1">in</span> <span class="pl-c1">&lt;</span><span class="pl-s1">module</span><span class="pl-c1">&gt;</span>
  <span class="pl-v">File</span> <span class="pl-s">"/home/sebastian/.local/lib/python3.8/site-packages/scipy/interpolate/interpolate.py"</span>, <span class="pl-s1">line</span> <span class="pl-c1">546</span>, <span class="pl-s1">in</span> <span class="pl-s1">__init__</span>
    <span class="pl-s1">self</span>.<span class="pl-s1">_spline</span> <span class="pl-c1">=</span> <span class="pl-s1">make_interp_spline</span>(<span class="pl-s1">xx</span>, <span class="pl-s1">yy</span>, <span class="pl-s1">k</span><span class="pl-c1">=</span><span class="pl-s1">order</span>,
  <span class="pl-v">File</span> <span class="pl-s">"/home/sebastian/.local/lib/python3.8/site-packages/scipy/interpolate/_bsplines.py"</span>, <span class="pl-s1">line</span> <span class="pl-c1">788</span>, <span class="pl-s1">in</span> <span class="pl-s1">make_interp_spline</span>
    <span class="pl-s1">raise</span> <span class="pl-v">ValueError</span>(<span class="pl-s">"Expect x to not have duplicates"</span>)
<span class="pl-v">ValueError</span>: <span class="pl-v">Expect</span> <span class="pl-s1">x</span> <span class="pl-s1">to</span> <span class="pl-c1">not</span> <span class="pl-s1">have</span> <span class="pl-s1">duplicates</span></pre></div>