<p dir="auto">From statistics point of view standard deviation when all values are equal should be <code class="notranslate">0</code>. For <code class="notranslate">arr1</code> result is as expected: <code class="notranslate">0</code>, but for <code class="notranslate">arr2</code> is <code class="notranslate">1.3877787807814457e-17</code> - very small but not 0, which leads to issues with e.g. <code class="notranslate">zscore</code>.<br>
As discussed here: <a href="https://stackoverflow.com/questions/63772729/numpy-std-standard-deviation-function-weird-behavior" rel="nofollow">https://stackoverflow.com/questions/63772729/numpy-std-standard-deviation-function-weird-behavior</a> issue is caused by floating errors.<br>
I think the problem could be solved by checking for "equality" before calculating <code class="notranslate">std = sqrt(mean(abs(x - x.mean())**2))</code>; when all values are equal <code class="notranslate">std</code> should return <code class="notranslate">0.0</code><br>
Why this is important? For example <code class="notranslate">zscore</code> from <code class="notranslate">scipy.stats</code> is calculated as "(x-np.mean)/np.std ". Division by <code class="notranslate">0</code> return <code class="notranslate">np.nan</code> but division even by small number gives "proper number", but it also should be <code class="notranslate">nan</code>.</p>
<h3 dir="auto">Reproducing code example:</h3>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import numpy as np
arr1 = [20.0] * 3
#[20.0, 20.0, 20.0]

arr2 = [-0.087] * 3
#[-0.087, -0.087, -0.087]

np.std(arr1) #0.0
np.std(arr2) #1.3877787807814457e-17"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">numpy</span> <span class="pl-k">as</span> <span class="pl-s1">np</span>
<span class="pl-s1">arr1</span> <span class="pl-c1">=</span> [<span class="pl-c1">20.0</span>] <span class="pl-c1">*</span> <span class="pl-c1">3</span>
<span class="pl-c">#[20.0, 20.0, 20.0]</span>

<span class="pl-s1">arr2</span> <span class="pl-c1">=</span> [<span class="pl-c1">-</span><span class="pl-c1">0.087</span>] <span class="pl-c1">*</span> <span class="pl-c1">3</span>
<span class="pl-c">#[-0.087, -0.087, -0.087]</span>

<span class="pl-s1">np</span>.<span class="pl-en">std</span>(<span class="pl-s1">arr1</span>) <span class="pl-c">#0.0</span>
<span class="pl-s1">np</span>.<span class="pl-en">std</span>(<span class="pl-s1">arr2</span>) <span class="pl-c">#1.3877787807814457e-17</span></pre></div>
<h3 dir="auto">Numpy/Python version information:</h3>
<p dir="auto">1.19.1 3.6.9 (default, Jul 17 2020, 12:50:27) [GCC 8.4.0]</p>
<p dir="auto">NumPy may give a nonzero variance (and thus standard deviation) for a constant array.  This may be due to loss of numerical precision, but Pythons builtin variance routine gives the correct 0 answer, so clearly it's a preventable loss:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="In [45]: x = [6715266981.538051]*10

In [46]: statistics.variance(x)
Out[46]: 0.0

In [47]: numpy.array(x).var()
Out[47]: 9.0949470177292824e-13"><pre class="notranslate"><code class="notranslate">In [45]: x = [6715266981.538051]*10

In [46]: statistics.variance(x)
Out[46]: 0.0

In [47]: numpy.array(x).var()
Out[47]: 9.0949470177292824e-13
</code></pre></div>
<p dir="auto">I think it would be highly desirable if <code class="notranslate">x.std()</code> and <code class="notranslate">x.var()</code> for a constant array could be assumed to be exactly identical to zero.  I'm aware one should not compare floating point numbers but zero is a bit of a special case.</p>