Issue 1:
Description

Incorrect clustering results when using dbscan clustering with brute algorithm and large values.

See the below code snippet - when the data type is changed to float64 or the algorithm is changed to ball_tree the correct clustering results are obtained.

For context, the large values are geographic coordinates.

I suspect this is because of the use of squared euclidean distance in the brute algorithm, which is outside the range where float32 can provide adequate precision:

scikit-learn/sklearn/neighbors/base.py

Line 699
in
7b136e9

# for efficiency, use squared euclidean distances

Perhaps it would be appropriate to warn if epsilon is so small compared to the values being clustered that it will cause issues with precision.

Steps/Code to Reproduce

import numpy as np
from sklearn.cluster import DBSCAN
from scipy.spatial import distance_matrix

import platform; print(platform.platform())
import sys; print("Python", sys.version)
import numpy; print("NumPy", numpy.__version__)
import scipy; print("SciPy", scipy.__version__)
import sklearn; print("Scikit-Learn", sklearn.__version__)

xy = np.array([[400000, 400000],
[400000, 400000+1],
[400000, 400000+5]
], dtype=np.float32)

print(distance_matrix(xy, xy))

print('incorrect', DBSCAN(eps=2, min_samples=1, algorithm='brute'
).fit(xy.astype(np.float32)).labels_)
print('correct ', DBSCAN(eps=2, min_samples=1, algorithm='brute'
).fit(xy.astype(np.float64)).labels_)
print('correct ', DBSCAN(eps=2, min_samples=1, algorithm='ball_tree'
).fit(xy.astype(np.float32)).labels_)

Results

Windows-10-10.0.17134-SP0
Python 3.7.2 (default, Feb 21 2019, 17:35:59) [MSC v.1915 64 bit (AMD64)]
NumPy 1.16.1
SciPy 1.2.1
Scikit-Learn 0.20.3
[[0. 1. 5.]
[1. 0. 4.]
[5. 4. 0.]]
incorrect [0 1 0]
correct [0 0 1]
correct [0 0 1]

Issue 2:
Description

I noticed that sklearn.metrics.pairwise.pairwise_distances function agrees with np.linalg.norm when using np.float64 arrays, but disagrees when using np.float32 arrays. See the code snippet below.

Steps/Code to Reproduce

import numpy as np
import scipy
import sklearn.metrics.pairwise

# create 64-bit vectors a and b that are very similar to each other
a_64 = np.array([61.221637725830078125, 71.60662841796875, -65.7512664794921875], dtype=np.float64)
b_64 = np.array([61.221637725830078125, 71.60894012451171875, -65.72847747802734375], dtype=np.float64)

# create 32-bit versions of a and b
a_32 = a_64.astype(np.float32)
b_32 = b_64.astype(np.float32)

# compute the distance from a to b using numpy, for both 64-bit and 32-bit
dist_64_np = np.array([np.linalg.norm(a_64 - b_64)], dtype=np.float64)
dist_32_np = np.array([np.linalg.norm(a_32 - b_32)], dtype=np.float32)

# compute the distance from a to b using sklearn, for both 64-bit and 32-bit
dist_64_sklearn = sklearn.metrics.pairwise.pairwise_distances([a_64], [b_64])
dist_32_sklearn = sklearn.metrics.pairwise.pairwise_distances([a_32], [b_32])

# note that the 64-bit sklearn results agree exactly with numpy, but the 32-bit results disagree
np.set_printoptions(precision=200)

print(dist_64_np)
print(dist_32_np)
print(dist_64_sklearn)
print(dist_32_sklearn)

Expected Results

I expect that the results from sklearn.metrics.pairwise.pairwise_distances would agree with np.linalg.norm for both 64-bit and 32-bit. In other words, I expect the following output:

[ 0.0229059506440019884643266578905240749008953571319580078125]
[ 0.02290595136582851409912109375]
[[ 0.0229059506440019884643266578905240749008953571319580078125]]
[[ 0.02290595136582851409912109375]]

Actual Results

The code snippet above produces the following output for me:

[ 0.0229059506440019884643266578905240749008953571319580078125]
[ 0.02290595136582851409912109375]
[[ 0.0229059506440019884643266578905240749008953571319580078125]]
[[ 0.03125]]

Versions

Darwin-16.6.0-x86_64-i386-64bit
('Python', '2.7.11 | 64-bit | (default, Jun 11 2016, 03:41:56) \n[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)]')
('NumPy', '1.11.3')
('SciPy', '0.19.0')
('Scikit-Learn', '0.18.1')