Skip to content

fix: remove.na.rows() ignored the cols subset and crashed on single column - #64

Merged
vertesy merged 3 commits into
devfrom
fix/remove-na-rows-ncol-bug
Aug 31, 2026
Merged

fix: remove.na.rows() ignored the cols subset and crashed on single column#64
vertesy merged 3 commits into
devfrom
fix/remove-na-rows-ncol-bug

Conversation

@vertesy

@vertesy vertesy commented Aug 30, 2026

Copy link
Copy Markdown
Owner

What was the bug?

Two bugs in one function:

  1. Wrong completeness check. The check compared the per-row non-NA count in the selected cols subset against NCOL(mat) — the full matrix's column count:

    idxOK <- which(rowSums(!apply(mat2, 2, is.na)) == NCOL(mat))

    Whenever cols was a proper subset of all columns (exactly what the cols parameter is documented for: "Cols to check for NAs"), a row's per-checked-column non-NA count can never reach the full matrix's column count unless cols happens to be every column. Net effect: passing any cols narrower than the whole matrix silently dropped rows based on NAs outside the columns the caller asked to check — or dropped every row entirely.

  2. Crash on a single-column subset. mat[, cols] used the default drop = TRUE, so cols = 2 (a single column) collapsed to a plain vector, and apply(mat2, 2, is.na) on a vector throws dim(X) must have a positive length.

The fix

  • Added drop = FALSE to the subsetting.
  • Compare against NCOL(mat2) (the actual subset size) instead of NCOL(mat).

Testing

4x3 matrix, one NA in column a (row r3), one NA in column b (row r2):

remove.na.rows(mat)                # default, all columns
remove.na.rows(mat, cols = c(1,3)) # columns a,c only
remove.na.rows(mat, cols = 1)      # column a only
remove.na.rows(mat, cols = 2)      # column b only
  • Default: drops r2, r3, keeps r1/r4 — unchanged.

  • cols = c(1,3): now correctly keeps r2 (its only NA is in column b, not checked) — previously this dropped every row, including ones with zero NAs anywhere in the checked columns.

  • cols = 1: previously crashed; now correctly drops only r3.

  • cols = 2: previously crashed; now correctly drops only r2.

  • R CMD build + R CMD check: no new NOTEs/WARNINGs/ERRORs vs. the current dev branch (the one remaining ERROR, a missing @export on pU(), is pre-existing and already tracked separately).

  • No .Rd/NAMESPACE change needed (roxygen block unchanged).

  • No testthat/automated tests added, per repo convention.


Generated by Claude Code

…olumn

Two bugs in one function:

1. The completeness check compared against NCOL(mat) (the full
   matrix's column count), not the size of the requested cols subset:
     idxOK <- which(rowSums(!apply(mat2, 2, is.na)) == NCOL(mat))
   Whenever cols was a proper subset of all columns -- exactly what
   the cols parameter exists for, per its own doc "Cols to check for
   NAs" -- a row could have zero NAs in the checked columns and still
   never satisfy rowSums(...) == NCOL(mat), because that per-row count
   can never reach the *full* matrix's column count unless cols
   happens to be all of them. Net effect: passing any cols narrower
   than the whole matrix silently dropped every row that had an NA
   anywhere outside the checked columns too -- rows the caller
   explicitly asked not to check.

2. mat[, cols] used the default drop = TRUE, so a single-column cols
   (e.g. cols = 2) collapsed to a plain vector, and
   apply(mat2, 2, is.na) on a vector errors ("dim(X) must have a
   positive length").

Fixed both: added drop = FALSE to the subsetting, and compare against
NCOL(mat2) (the actual subset size) instead of NCOL(mat).

Verified on a 4x3 matrix with one NA in column "a" (row r3) and one
NA in column "b" (row r2):
- Default (all columns): drops r2 and r3, keeps r1/r4 -- unchanged.
- cols = c(1,3) (columns a,c, neither has NA in the surviving rows'
  intersection... actually columns a and c only, ignoring column b):
  now correctly keeps r2 (its only NA is in column b, not checked) --
  previously this configuration dropped every row, including ones
  with zero NAs anywhere.
- cols = 1 (single column, a): previously crashed; now correctly
  drops only r3 (the row with an NA in column a).
- cols = 2 (single column, b): previously crashed; now correctly
  drops only r2 (the row with an NA in column b).

Also bumps Development/config.R/DESCRIPTION to 2.8.14 per repo
convention.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6b676f1401

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Development/config.R Outdated
Comment thread R/CodeAndRoll2.R Outdated
claude and others added 2 commits August 30, 2026 13:35
rowSums(!apply(mat2, 2, is.na)) crashed when mat2 had exactly one row,
since apply() simplifies its result to a plain logical vector (no
dimensions) in that case, so rowSums() has nothing to sum over. This
included the single-column subset case this branch already fixes.

Replace with rowSums(!is.na(mat2)), which never depends on apply()'s
simplification behavior and gives the same result for all other cases.

Verified: default all-cols, 2-col subset, single-col subset, one-row
all-cols, one-row with NA, and one-row single-col subset (the exact
crash Codex flagged) all now return correct results with no error.
@vertesy
vertesy merged commit 5a62819 into dev Aug 31, 2026
@vertesy
vertesy deleted the fix/remove-na-rows-ncol-bug branch August 31, 2026 15:19
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