scikit-learn: BisectingKMeans floating point exception fatal error on OSX

Describe the bug

Hi, thanks for this fantastic library 🚀 🎉

I believe I found a bug. In the BisectingKMeans clustering, the predict function cannot be used when the to-be-predicted-data is on a different numerical scale than the fitted data. Other clustering methods like e.g., KMeans dont have this problem.

In the example below, I fitted the BisectingKMeans on random data and then multiplied the data that should be predicted by 50. It causes a floating point exception error which is pretty bad because python silently exits.

Steps/Code to Reproduce

from sklearn.cluster import BisectingKMeans, KMeans
import numpy as np
x = np.random.rand(3000, 10)

bisect_means = BisectingKMeans(n_clusters=10).fit(x)

labels = bisect_means.predict(50*np.random.rand(100, 10))
print(labels)

Expected Results

A list of predicted class labels

Actual Results

Python silently exits with:

[1]    45074 floating point exception  python foo.py

In Jupyter/ipython the kernel simply dies.

Versions

System:
    python: 3.9.16 (main, Mar  8 2023, 04:29:44)  [Clang 14.0.6 ]
executable: /Users/jab/miniconda3/envs/qondot/bin/python
   machine: macOS-10.16-x86_64-i386-64bit

Python dependencies:
      sklearn: 1.3.0
          pip: 23.0.1
   setuptools: 67.8.0
        numpy: 1.21.6
        scipy: 1.10.1
       Cython: 0.29.35
       pandas: 1.5.3
   matplotlib: 3.7.1
       joblib: 1.2.0
threadpoolctl: 3.1.0

Built with OpenMP: True

threadpoolctl info:
       user_api: openmp
   internal_api: openmp
         prefix: libomp
       filepath: /Users/jab/miniconda3/envs/qondot/lib/python3.9/site-packages/sklearn/.dylibs/libomp.dylib
        version: None
    num_threads: 8

       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /Users/jab/miniconda3/envs/qondot/lib/python3.9/site-packages/numpy/.dylibs/libopenblas.0.dylib
        version: 0.3.17
threading_layer: pthreads
   architecture: Haswell
    num_threads: 4

       user_api: blas
   internal_api: openblas
         prefix: libopenblas
       filepath: /Users/jab/miniconda3/envs/qondot/lib/python3.9/site-packages/scipy/.dylibs/libopenblas.0.dylib
        version: 0.3.18
threading_layer: pthreads
   architecture: SkylakeX
    num_threads: 4

About this issue

  • Original URL
  • State: closed
  • Created 10 months ago
  • Comments: 21 (13 by maintainers)

Most upvoted comments

Thanks for all the effort @ogrisel.

  1. The issue persists even if I install everything from the forge channel as suggested in your edit
  2. I also tested an ubuntu machine, no issues observed, everything works fine.
  3. I debugged with lldb, here is the output:
lldb -- python debug_bkmeans.py
(lldb) target create "python"
Current executable set to '/Users/jab/miniconda3/envs/debug-env/bin/python' (x86_64).
(lldb) settings set -- target.run-args  "debug_bkmeans.py"
(lldb) run
Process 62887 launched: '/Users/jab/miniconda3/envs/debug-env/bin/python' (x86_64)
Process 62887 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_ARITHMETIC (code=EXC_I386_DIV, subcode=0x0)
    frame #0: 0x000000012b11ca6b _k_means_lloyd.cpython-311-darwin.so`__pyx_fuse_1__pyx_pw_7sklearn_7cluster_14_k_means_lloyd_7lloyd_iter_chunked_dense + 3739
_k_means_lloyd.cpython-311-darwin.so`:
->  0x12b11ca6b <+3739>: idivl  %ebx
    0x12b11ca6d <+3741>: movl   %eax, -0x108c(%rbp)
    0x12b11ca73 <+3747>: movl   %edx, -0x1090(%rbp)
    0x12b11ca79 <+3753>: movq   0x18148(%rip), %rax       ; __pyx_pf_7sklearn_7cluster_14_k_means_lloyd_6lloyd_iter_chunked_dense.__pyx_dict_version.312
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_ARITHMETIC (code=EXC_I386_DIV, subcode=0x0)
  * frame #0: 0x000000012b11ca6b _k_means_lloyd.cpython-311-darwin.so`__pyx_fuse_1__pyx_pw_7sklearn_7cluster_14_k_means_lloyd_7lloyd_iter_chunked_dense + 3739
    frame #1: 0x000000012a57a55f _isfinite.cpython-311-darwin.so`__pyx_FusedFunction_call + 783
    frame #2: 0x00000001001c9d09 python`_PyEval_EvalFrameDefault + 232441
    frame #3: 0x000000010018ea5b python`_PyEval_Vector + 1275
    frame #4: 0x000000010018e4ea python`PyEval_EvalCode + 250
    frame #5: 0x000000010023d787 python`run_mod + 167
    frame #6: 0x000000010023d595 python`pyrun_file + 133
    frame #7: 0x000000010023d073 python`_PyRun_SimpleFileObject + 275
    frame #8: 0x000000010023ca1f python`_PyRun_AnyFileObject + 143
    frame #9: 0x0000000100261a6b python`pymain_run_file_obj + 267
    frame #10: 0x0000000100261485 python`pymain_run_file + 85
    frame #11: 0x0000000100260dfd python`Py_RunMain + 1965
    frame #12: 0x00000001000018a8 python`main + 56
    frame #13: 0x00007ff80b34241f dyld`start + 1903
(lldb)

The error code (EXC_ARITHMETIC (code=EXC_I386_DIV, subcode=0x0)) seems to suggest a division-by-zero error inside _k_means_lloyd.cpython-311-darwin.so