Thanks to visit codestin.com
Credit goes to github.com

Skip to content

BUG: read_csv dtype="category" now infers numeric categories - #7

Open
xirafa wants to merge 25 commits into
mainfrom
jbrockmendel/api-categorical-csv
Open

BUG: read_csv dtype="category" now infers numeric categories#7
xirafa wants to merge 25 commits into
mainfrom
jbrockmendel/api-categorical-csv

Conversation

@xirafa

@xirafa xirafa commented Jul 28, 2026

Copy link
Copy Markdown

Mirror of pandas-dev/pandas#64659. Runs the pandas test suite through dagz.

Summary by CodeRabbit

  • Bug Fixes

    • Improved dtype="category" inference for CSV, table, fixed-width, Feather, and Excel readers.
    • Numeric and boolean values now retain appropriate categorical types instead of being converted to strings.
    • Improved handling of missing values, ordered categories, duplicate values, chunked reads, and parser options.
    • Ensured more consistent behavior across supported parsing engines and dtype backends.
  • Documentation

    • Added guidance and examples covering categorical inference, formatting options, and fallback behavior.

jbrockmendel and others added 13 commits July 19, 2026 13:22
Previously, the c and python parsers produced string categories for
numeric columns (e.g., categories=['1', '2'] with object dtype),
while the pyarrow engine correctly inferred numeric types. Now all
engines consistently infer proper types for categories.

closes #56044

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Use explicit dtype mapping instead of accessing .numpy_dtype
on a union type that the type checkers can't narrow.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…type_backend is defined

The block referenced `dtype_backend` inside `_normalize_timezone_dtypes`,
which only takes `df`. Every pyarrow-backed IO path hit a NameError at
runtime, breaking Type Checking, Doctests, Doc Build, and pyarrow IO
tests. Moved the block into `_post_convert_dtypes` (after the astype),
where `dtype_backend` is already a parameter.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
…read_csv dtype="category"

- Merge categories when distinct strings convert to the same number
  (e.g. "1" and "1.0") instead of raising on duplicate categories
- Skip numeric inference when thousands/decimal are set, since
  to_numeric is unaware of those options
- Only downcast IntegerDtype categories that the pyarrow workaround
  introduced, not categories the user explicitly requested; restrict
  the downcast to read_csv (dtype is not None) and make it safe for
  duplicate column labels
- Add tests for the above plus large-integer behavior
- Move the whatsnew entry to the notable bug fixes section

Co-Authored-By: Claude Fable 5 <[email protected]>
The c and python engines produced string categories for boolean columns
under dtype="category" while the pyarrow engine inferred bool categories.
All engines now infer boolean categories, mirroring each engine's
non-categorical inference (numeric first, then boolean). GH#56044

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…ory"

- Defer category-dtype inference in low_memory mode until chunks are
  concatenated; per-chunk inference could produce differing category
  dtypes, breaking union_categoricals
- Keep string categories when to_numeric turns "" into NaN
  (na_filter=False / keep_default_na=False)
- Keep object dtype for empty inferred categories (all-NA columns)

Co-Authored-By: Claude Fable 5 <[email protected]>
… docs

- factor _from_converted_categories out of _from_inferred_categories so
  the low_memory deferred path runs to_numeric once on the unioned
  categories
- update stale io.rst note obsoleted by GH#56044 inference
- pin dtype_backend and QUOTE_NONNUMERIC category behavior in tests;
  scope the whatsnew claim to the default dtype_backend

Co-Authored-By: Claude Fable 5 <[email protected]>
…tegory"

With dtype_backend="pyarrow" the python engine's values arrive as
ArrowDtype strings, whose kind is "U" rather than "O", so the guard in
_maybe_convert_categories bailed and no inference was applied at all.
Categories now infer to int64[pyarrow], matching a non-categorical read.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
# Conflicts:
#	doc/source/whatsnew/v3.1.0.rst
#	pandas/_libs/parsers.pyx
…tegories unsorted

With the c and python engines, a CategoricalDtype specifying ordered=True but
not categories silently produced an unordered result, while the pyarrow engine
honored it. Separately, low_memory=True (the c engine default) left string
categories in the order the file's buffer chunks happened to produce them,
rather than sorted as every other path gives.

Also restore the pre-GH#56044 defaults of Categorical._from_inferred_categories
so callers other than the parsers are unaffected, and collapse
_from_converted_categories to a single recode pass.

Co-Authored-By: Claude Opus 5 <[email protected]>
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

Next included review available in 50 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 7e81173a-6c70-45d7-9654-0e7e3afc4f33

📥 Commits

Reviewing files that changed from the base of the PR and between 81e0576 and fc08241.

📒 Files selected for processing (13)
  • doc/source/user_guide/io.rst
  • doc/source/whatsnew/v3.1.0.rst
  • pandas/_libs/parsers.pyi
  • pandas/_libs/parsers.pyx
  • pandas/core/arrays/categorical.py
  • pandas/io/_util.py
  • pandas/io/parsers/arrow_parser_wrapper.py
  • pandas/io/parsers/c_parser_wrapper.py
  • pandas/io/parsers/python_parser.py
  • pandas/tests/io/excel/test_readers.py
  • pandas/tests/io/parser/dtypes/test_categorical.py
  • pandas/tests/io/parser/test_read_fwf.py
  • pandas/tests/io/test_feather.py

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d7ce0e18-8546-4514-9339-ffb7ce2659d4

📥 Commits

Reviewing files that changed from the base of the PR and between 5ea2fe9 and 1592944.

📒 Files selected for processing (7)
  • doc/source/user_guide/io.rst
  • doc/source/whatsnew/v3.1.0.rst
  • pandas/_libs/parsers.pyx
  • pandas/core/arrays/categorical.py
  • pandas/tests/io/excel/test_readers.py
  • pandas/tests/io/parser/dtypes/test_categorical.py
  • pandas/tests/io/test_feather.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • doc/source/user_guide/io.rst

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

dtype="category" now infers numeric and boolean categories across CSV, FWF, Excel, and related readers. Low-memory parsing defers category conversion until chunk concatenation. Category ordering, backends, missing values, parsing options, and explicit categorical dtypes receive updated handling and tests.

Changes

Categorical dtype inference

Layer / File(s) Summary
Category conversion helpers
pandas/core/arrays/categorical.py
Added numeric and boolean category conversion, duplicate merging, sorting controls, code recoding, and ordered-category preservation.
Parser categorical inference
pandas/_libs/parsers.pyx, pandas/_libs/parsers.pyi, pandas/io/parsers/python_parser.py
Parser paths apply numeric and boolean inference. Low-memory reads defer inferred category conversion until after chunk processing.
Chunk reconciliation and dtype normalization
pandas/io/parsers/c_parser_wrapper.py, pandas/io/_util.py
Categorical chunks are harmonized before union. Integer and string-backed category dtypes are normalized after conversion.
Reader and parser validation
pandas/tests/io/parser/dtypes/test_categorical.py, pandas/tests/io/parser/test_read_fwf.py, pandas/tests/io/excel/test_readers.py, pandas/tests/io/test_feather.py
Added coverage for numeric and boolean inference, parsing options, backends, missing values, chunking, ordering, and category dtype preservation.
Categorical inference documentation
doc/source/user_guide/io.rst, doc/source/whatsnew/v3.1.0.rst
Documented categorical inference, parser and backend differences, chunked reads, missing values, ordering, and related reader behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 15929

The change updates CSV categorical dtype inference and adds related coverage and documentation; no actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: jbrockmendel, alvaro-kothe

Sequence Diagram(s)

sequenceDiagram
  participant Reader
  participant TextReader
  participant CategoricalArray
  participant CParserWrapper
  Reader->>TextReader: parse data with dtype="category"
  TextReader->>CategoricalArray: infer numeric or boolean categories
  TextReader->>CParserWrapper: provide low-memory categorical chunks
  CParserWrapper->>CategoricalArray: reconcile categories after concatenation
  CategoricalArray-->>Reader: return categorical columns
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.70% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 46 functions across 4 files. (3 skipped: 3… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: fixing read_csv(dtype="category") so it infers numeric categories.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 8.70% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 46 functions across 4 files. (3 skipped: 3 unsupported.)

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jbrockmendel/api-categorical-csv

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@xirafa
xirafa force-pushed the main branch 14 times, most recently from c83b924 to 5ef188f Compare July 31, 2026 22:36
…ed categories

Follow-up fixes on top of the GH#56044 inference change:

- with quoting=QUOTE_NONNUMERIC the deferred low-memory path now gives
  float64 categories like the eager path, casting before de-duplication so
  that values colliding at float64 precision merge into one category
- an all-NA chunk no longer breaks union_categoricals when the other chunks
  inferred a non-object category dtype
- to_numeric raises OverflowError for integers too large to represent as
  float64; such columns keep string categories rather than propagating it
- under PANDAS_FUTURE_INFER_STRING=0 the pyarrow engine kept StringDtype
  categories for ordered categoricals, since CategoricalDtype.__eq__ ignores
  the categories' dtype when ordered and the astype was a no-op
- read_fwf and read_excel coverage for the shared inference

Co-Authored-By: Claude Opus 5 <[email protected]>
@xirafa
xirafa force-pushed the main branch 4 times, most recently from 0eb7bfa to f4391ca Compare August 8, 2026 17:40
# Conflicts:
#	pandas/_libs/parsers.pyx
@xirafa
xirafa force-pushed the main branch 14 times, most recently from abdaebc to 65097c2 Compare August 10, 2026 15:28
# Conflicts:
#	pandas/io/parsers/c_parser_wrapper.py
@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

jbrockmendel and others added 5 commits August 26, 2026 07:59
…gine

The c tokenizer matches the default True/False spellings with strncasecmp, so
a plain read infers bool for "tRuE" while dtype="category" kept string
categories. Fold those spellings for the c engine only, after consulting
true_values/false_values, which the tokenizer checks first.

Also keep the arrow backing for inferred boolean categories, document the
low_memory all-NA-chunk crash and the per-chunk inference that chunksize now
does, and cover the ordered-categorical fix that reaches every reader built on
an Arrow table.

Co-Authored-By: Claude Opus 5 <[email protected]>
The pyarrow engine parsed a categorical with no explicit categories as
large_string, so the categories were the raw text from the file instead of
the inferred values the other engines now give (GH#56044).

This reverses one branch of GH-62242, which aligned the pyarrow engine with
the c and python engines as they behaved before this PR changed them. Its
dtype=str and dtype=object handling, and every issue it cites, are
unaffected.

Co-Authored-By: Claude Opus 5 <[email protected]>
# Conflicts:
#	doc/source/whatsnew/v3.1.0.rst
#	pandas/io/parsers/c_parser_wrapper.py
#	pandas/tests/io/excel/test_readers.py
#	pandas/tests/io/parser/dtypes/test_categorical.py
#	pandas/tests/io/parser/test_read_fwf.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants