[Bug]: DetectionDataset.split loses a train item when len(images) * split_ratio is a whole number (90 images at 0.7 give 62/28, not 63/27)

Open
#2,968 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@avanish-garg is already working on this.

Since Nov 13, 2026.

  • #2969 by @avanish-garg — open

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
30/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
data

Research direction

Start with train_test_split in supervision/dataset/utils.py, where the train size is computed as int(len(data) * train_ratio) and floating-point error floors exact products such as 90 * 0.7. Reproduce with train_test_split(list(range(90)), train_ratio=0.7, shuffle=False), which should return 63 train and 27 test items. Done means the split matches exact decimal arithmetic for the listed cases while non-whole products still round down. Pull request #2969 is already open against this issue, so check it before starting.

Written by the indexing model from the issue text.

Description

bug
Search before asking
  • I have searched the issues and discussions and found no similar bug report.
Bug

train_test_split (used by DetectionDataset.split and ClassificationDataset.split) computes the train size as int(len(data) * train_ratio). When the exact product is a whole number, the floating-point product can land just below it and int() floors it, so one item moves from the train part to the test part. For example, 90 images at split_ratio=0.7 give 62 train / 28 test, but 0.7 * 90 is exactly 63.

Expected behavior:
A ratio typed as a decimal should split exactly as that decimal says: 63 train / 27 test for 90 images at 0.7 (rounding down, as now, whenever the product is not a whole number).

Actual behavior:

n=  90 ratio=0.7: len(train)=62 len(test)=28  expected train=63 test=27  WRONG
n= 100 ratio=0.57: len(train)=56 len(test)=44  expected train=57 test=43  WRONG
n= 100 ratio=0.29: len(train)=28 len(test)=72  expected train=29 test=71  WRONG
n= 180 ratio=0.35: len(train)=62 len(test)=118  expected train=63 test=117  WRONG
n= 100 ratio=0.58: len(train)=57 len(test)=43  expected train=58 test=42  WRONG
DetectionDataset(90 images).split(0.7): train=62 test=28 (expected 63 / 27)

Over every length 0 to 300 and every ratio k/1000, the current code differs from exact arithmetic in 20 cells, always by one item too few in the train part.

Environment
  • Supervision: 0.32.0.dev (develop at 5210466)
  • Python: 3.12.14
  • OS: macOS (Apple Silicon)
Minimal Reproducible Example
import supervision as sv
from supervision.dataset.utils import train_test_split

train, test = train_test_split(list(range(90)), train_ratio=0.7, shuffle=False)
print(len(train), len(test))  # 62 28, expected 63 27

paths = [f"img_{i}.jpg" for i in range(90)]
ds = sv.DetectionDataset(
    classes=["a"],
    images=paths,
    annotations={p: sv.Detections.empty() for p in paths},
)
train_ds, test_ds = ds.split(split_ratio=0.7, random_state=0)
print(len(train_ds), len(test_ds))  # 62 28, expected 63 27
Are you willing to submit a PR?
  • Yes I'd like to help by submitting a PR!
Dominant language
Python
Stars
51.6k
Forks
5k
Avg merge
1d 17h
Merged PRs (30d)
191

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from roboflow/supervision

All issues in roboflow/supervision

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.