Skip to content

Commit 103336e

Browse files
author
maechler
committed
model.frame(~1, list(), ..) - PR#18977
git-svn-id: https://svn.r-project.org/R/trunk@89113 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 3b0cf6e commit 103336e

File tree

3 files changed

+54
-7
lines changed

3 files changed

+54
-7
lines changed

doc/NEWS.Rd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,10 @@
426426

427427
\item \code{str(x, give.attr=FALSE)} no longer shows attributes when
428428
\code{x} is a zero length \code{"Date"} or \code{"POSIXt"} object.
429+
430+
\item \code{model.frame(~1, list(), na.action=na.pass)} and similar
431+
\dQuote{border-line} uses no longer produce invalid data frames,
432+
fixing \PR{18977}, reported with patch by \I{Mikael Jagan}.
429433
}
430434
}
431435
}

src/library/stats/src/model.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,15 +169,17 @@ SEXP modelframe(SEXP call, SEXP op, SEXP args, SEXP rho)
169169
PROTECT(tmp = mkString("data.frame"));
170170
setAttrib(data, R_ClassSymbol, tmp);
171171
UNPROTECT(1);
172-
if (length(row_names) == nr) {
172+
if (length(row_names) == nr && row_names != R_NilValue) {
173173
setAttrib(data, R_RowNamesSymbol, row_names);
174174
} else {
175175
/*
176176
PROTECT(row_names = allocVector(INTSXP, nr));
177177
for (i = 0; i < nr; i++) INTEGER(row_names)[i] = i+1; */
178-
PROTECT(row_names = allocVector(INTSXP, 2));
179-
INTEGER(row_names)[0] = NA_INTEGER;
180-
INTEGER(row_names)[1] = nr;
178+
PROTECT(row_names = allocVector(INTSXP, (nr > 0) ? 2 : 0));
179+
if (nr > 0) {
180+
INTEGER(row_names)[0] = NA_INTEGER;
181+
INTEGER(row_names)[1] = nr;
182+
}
181183
setAttrib(data, R_RowNamesSymbol, row_names);
182184
UNPROTECT(1);
183185
}

src/library/stats/tests/glm-etc.R

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ stopifnot(names(which(!jj)) == "am1:mpg"
2121
)
2222

2323

24-
### predict.lm(<rank-deficient>, newdata = *) -- PR#15072, PR#16158 --------------
24+
###-- predict.lm(<rank-deficient>, newdata = *) -- PR#15072, PR#16158 --------------
2525

2626
## constructed "exactly" rank-deficient
2727
x1 <- -4:4
@@ -121,7 +121,7 @@ stopifnot(exprs = {
121121
})
122122

123123
## play with tol
124-
str(tls <- sort(outer(c(1,2,4), 10^-(9:5))))
124+
str(tls <- sort(outer(c(1,2,4), 10^-(9:5)))) # tolerances to try
125125
nT <- length(tls <- setNames(tls, formatC(tls)))
126126
pls <- t(sapply(tls, function(TL) predict(fm8. , newdata=nd, tol = TL, rankdeficient = "NA")))
127127
stopifnot(is.finite(plsLst <- pls[nT,])) # (no NA)
@@ -164,7 +164,7 @@ stopifnot(exprs = {
164164
## predict(*, ... type="terms" .. ) does *not* obey rankdeficient=".."
165165

166166

167-
##-------- dummy.coef() -- with "character"-factor ---------------------------------------
167+
###-------- dummy.coef() -- with "character"-factor ---------------------------------------
168168
## [Bug 18635] New: dummy.coef could not deal with character variable // 9 Dec 2023
169169
## --------- https://bugs.r-project.org/show_bug.cgi?id=18635
170170

@@ -243,3 +243,44 @@ stopifnot(exprs = {
243243
all.equal15(tail(dc2f, 7),
244244
c(`x:chA` = 0, tail(cf2f, 6)))
245245
})
246+
247+
248+
###-------- model.frame() empty - NULL row.names ========================
249+
## [Bug 18977] -- model.frame(~1, list()) constructed invalid data frame with
250+
## 'row.names' attribute NULL rather than empty integer|character
251+
chk <- function(x, rn) stopifnot(exprs = {
252+
is.data.frame(x)
253+
identical(.row_names_info(x, 0L), rn)
254+
identical(.row_names_info(x, 1L), 0L)
255+
identical(.row_names_info(x, 2L), 0L)
256+
identical(attr(x, "row.names"),
257+
if (is.character(rn)) character(0L) else integer(0L))
258+
identical(row.names(x), character(0L))
259+
})
260+
a0 <- .set_row_names(0L) # [a]utomatic
261+
i0 <- integer(0L)
262+
c0 <- character(0L)
263+
stopifnot(identical(a0, i0)) # currently, but not documented
264+
chk(da <- data.frame(row.names = ), a0)
265+
chk(di <- data.frame(row.names = i0), i0)
266+
chk(dc <- data.frame(row.names = c0), c0)
267+
ona <- options(na.action = "na.pass") # => testing 'model.frame' proper
268+
chk(mfa <- model.frame(~1, da), a0)
269+
chk(mfi <- model.frame(~1, di), i0)
270+
chk(mfc <- model.frame(~1, dc), c0)
271+
chk(mfl <- model.frame(~1, list()), a0) # failed
272+
## Error .... : identical(.row_names_info(x, 0L), rn) is not TRUE
273+
.row_names_info(mfl, 0L) # was NULL, not a0
274+
options(ona)
275+
L <- list(da, di, dc, mfa, mfi, mfc, mfl)
276+
stopifnot(identical(lapply(L, complete.cases),
277+
rep(list(logical(0L)), length(L)))) # failed for mfl
278+
## Error .... : no input has determined the number of cases
279+
## stats:::na.fail.default calls 'complete.cases', hence:
280+
(mf0 <- model.frame(~1, list(), na.action = na.fail)) # failed similarly
281+
282+
283+
### Local variables:
284+
### mode: R
285+
### page-delimiter: "^###[#-]"
286+
### End:

0 commit comments

Comments
 (0)