fix: keep empty crosstab rows and columns through the reshape - #9
Merged
Conversation
dcast only emits a row/column for each .ri/.ci value actually present in
the data, so a crosstab row or column with no observations at all fell
out of the wide table while the headers were still built from the full
rselect()/cselect(). Reported by PamGene as:
Error in setnames(x, value) :
Can't assign 5 names to a 4-column data.table
That is the benign failure. When the surviving row count divides evenly
into the expected one, cbind() recycles instead of erroring and the
export silently contains the wrong values - rows 3 and 4 carrying the
data of rows 1 and 2, with only a warning. The default crosstab-view
path (collapse_cols = FALSE) is affected the same way.
Pin the .ri/.ci factor levels to the full index range and dcast with
drop = FALSE, so the data block always lines up with the headers and
empty cells come through as NA.
Verified against the shipped test_1 fixture (output byte-identical) and
across empty-row/empty-column shapes for both collapse_cols modes, CSV,
TSV and XLSX.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EeoFKnewHFjCdPK45kWjDG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reported by PamGene (bionavigator) after upgrading to 1.1.1:
Cause
dcastonly emits a row/column for each.ri/.civalue that actually occurs in the data. A crosstab row or column with no observations at all therefore drops out of the wide table, while the headers are still built from the fullrselect()/cselect(). The two then disagree:The error is the good outcome
When the number of surviving rows divides evenly into the expected count,
cbind()recycles instead of erroring and the export silently contains the wrong values, with only a warning:The default crosstab-view path (
collapse_cols = FALSE) is affected the same way. So an unknown number of previously "successful" exports from tables with empty rows/columns may contain misaligned data.Fix
Pin the
.ri/.cifactor levels to the full index range and reshape withdrop = FALSE, so the data block always lines up with the headers and genuinely empty cells come through asNA.Verification
Ran the real
main.Ragainst a mock context, comparing every cell value against the expected grid.Before (as released in 1.1.1):
After: all 10 PASS.
Regression checks:
tests/test_1fixture reproduces its expected output byte-identicalcollapse_colsmodes, and withcollapse_rows = TRUE🤖 Generated with Claude Code
https://claude.ai/code/session_01EeoFKnewHFjCdPK45kWjDG