KBinsDiscretizer creates wrong bins.

### Describe the bug

`KBinsDiscretizer` gives wrong bins and wrong transformed data, when the inputs contains only 2 distinct values, and `n_bins=3`. It only produces 1 bin, which is not expected.  The warning shows some bins are too small so they are merged.

Note that when setting `n_bins=2`, `KBinsDiscretizer` gives more reasonable bins and correct results. However, from the `bin_edges_`, it seems `n_bins=2` is handled separately.

### My guess about the cause
I think the root cause is inconsistent handling of `-inf` and `+inf` in fitting and transforming. 

In fitting, `-inf` and `+inf` are not considered when removing duplicated bin edges. But in transforming data, the first and last bin edges are replaces with `-inf` and `+inf`. Such differences obviously removes some necessary bins.

Taking the case I mentioned as a example, current implementation deduplicates bin edges from `[-1.0, -1.0, 0.0, 0.0]` to `[-1.0, 0.0]`.  Then in transforming, all real values are actually in one bin, since the bin edges are replaced with `-inf` and `+inf`.

A more reasonable conversion is replacing first and last bin edges with `-inf` and `+inf` in fitting, i.e., `[-inf, -1.0, 0.0, inf]`, then removing duplicated edges, which gives `[-inf, -1.0, 0.0, inf]`. This will give expected results.




### Steps/Code to Reproduce

```
from sklearn.preprocessing import KBinsDiscretizer
X = [[-1], [-1], [ 0], [ 0]]
discretizer = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='quantile')
discretizer.fit(X)

print(discretizer.bin_edges_)
Xt = discretizer.transform(X)
print(Xt)
```

### Expected Results

The last `print` should give 
```
[[0.]
 [0.]
 [1.]
 [1.]]
```
or 

```
[[1.]
 [1.]
 [2.]
 [2.]]
```
. It depends on how to implement it correctly.

### Actual Results

The last `print` gives
```
[[0.]
 [0.]
 [0.]
 [0.]]
```

### Versions

```shell
System:
    python: 3.8.16 (default, Jan 17 2023, 16:42:09)  [Clang 14.0.6 ]
executable: /opt/anaconda3/envs/sklearn/bin/python3
   machine: macOS-10.16-x86_64-i386-64bit

Python dependencies:
      sklearn: 1.2.1
          pip: 22.3.1
   setuptools: 65.6.3
        numpy: 1.24.2
        scipy: 1.10.0
       Cython: None
       pandas: None
   matplotlib: None
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: openmp
   internal_api: openmp
         prefix: libomp
       filepath: /opt/anaconda3/envs/sklearn/lib/python3.8/site-packages/sklearn/.dylibs/libomp.dylib
        version: None
    num_threads: 10

       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /opt/anaconda3/envs/sklearn/lib/python3.8/site-packages/numpy/.dylibs/libopenblas64_.0.dylib
        version: 0.3.21
threading_layer: pthreads
   architecture: Nehalem
    num_threads: 10

       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /opt/anaconda3/envs/sklearn/lib/python3.8/site-packages/scipy/.dylibs/libopenblas.0.dylib
        version: 0.3.18
threading_layer: pthreads
   architecture: Nehalem
    num_threads: 10
```
```

COMMENT:
I've run into this issue as well. But I would like to ask to confirm the intended behavior. Say we have a binary feature (values 0 and 1), my initial intuition is then that there should be 2 bins created for any n_bins >= 2. As stated above currently no bins are created.

Proposed above is that the edges are considered to stretch to infinity in the fitting stage, to be consistent with the transform stage. This could be accomplished by changing the mask from:
```python
# Remove bins whose width are too small (i.e., <= 1e-8)
mask = np.ediff1d(bin_edges[jj], to_begin=np.inf) > 1e-8
bin_edges[jj] = bin_edges[jj][mask]
```
to:
```python
# Remove bins whose width are too small (i.e., <= 1e-8)
mask = np.ediff1d(bin_edges[jj][1:-1], to_begin=[np.inf, np.inf], to_end=np.inf) > 1e-8
bin_edges[jj] = bin_edges[jj][mask]
```

However, this would create up to three buckets for a binary feature. E.g. when bin_edges before the mask is `0,0,0,1,1,1` ediff1d will be `inf,inf,0,1,0,inf` giving bin_edges `0,0,1,1` which when stretched to infinity will be `-inf,0,1,inf`.

Any thoughts on if this is OK? This could be fine, just a bit counterintuitive for me that running KBinsDiscretizer on a binary feature would result in three buckets. In any case to me it would be better than no features.

Labels: Bug, Needs Decision, module:preprocessing