Skip to content

Commit 18756ea

Browse files
committed
Keep CSV row indices continuous across batches
Assign each exported DataFrame its logical dataset row offset when index output is requested. Preserve index=False behavior and cover single and multiple batches, multiprocessing, selected rows, and byte counts.
1 parent 9e7496a commit 18756ea

3 files changed

Lines changed: 23 additions & 1 deletion

File tree

‎src/datasets/arrow_dataset.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5355,6 +5355,8 @@ def to_csv(
53555355
53565356
</Changed>
53575357
5358+
With `index=True`, row indices are zero-based positions in the dataset and are continuous across batches.
5359+
53585360
Returns:
53595361
`int`: The number of characters or bytes written.
53605362

‎src/datasets/io/csv.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,10 @@ def _batch_csv(self, args):
105105
key=slice(offset, offset + self.batch_size),
106106
indices=self.dataset._indices,
107107
)
108-
csv_str = batch.to_pandas(integer_object_nulls=True).to_csv(
108+
batch_df = batch.to_pandas(integer_object_nulls=True)
109+
if index:
110+
batch_df.index = range(offset, offset + len(batch_df))
111+
csv_str = batch_df.to_csv(
109112
path_or_buf=None, header=header if (offset == 0) else False, index=index, **to_csv_kwargs
110113
)
111114
return csv_str.encode(self.encoding)

‎tests/io/test_csv.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,23 @@ def test_dataset_to_csv_multiproc(csv_path, tmp_path):
157157
assert row1 == row2
158158

159159

160+
@pytest.mark.parametrize("batch_size", [5, 20])
161+
@pytest.mark.parametrize("num_proc", [None, 2])
162+
@pytest.mark.parametrize("index", [False, True])
163+
@pytest.mark.parametrize("selection", [None, [11, 3, 8, 0, 10, 1, 9]])
164+
def test_dataset_to_csv_index_independent_of_batch_size(batch_size, num_proc, index, selection, tmp_path):
165+
dataset = Dataset.from_dict({"value": list(range(12))})
166+
if selection is not None:
167+
dataset = dataset.select(selection)
168+
expected = dataset.to_pandas().to_csv(index=index, index_label="row").encode("utf-8")
169+
output_csv = tmp_path / "out.csv"
170+
171+
written = dataset.to_csv(output_csv, batch_size=batch_size, num_proc=num_proc, index=index, index_label="row")
172+
173+
assert output_csv.read_bytes() == expected
174+
assert written == len(expected)
175+
176+
160177
def test_dataset_to_csv_invalidproc(csv_path, tmp_path):
161178
cache_dir = tmp_path / "cache"
162179
output_csv = os.path.join(cache_dir, "tmp.csv")

0 commit comments

Comments
 (0)