0

Im trying to make a large blank data.table with a header row in order to add values in specific places once it is set up. I have been able to duplicate the first row and then clear every other row or every row, but what I'd like to do is clear every row after the header row. Some columns are numeric input and some are character input.

[input3]:

headers: header1 header2 header3..... header 60+

Values:   NA      NA       NA   ...     NA

Duplicate row:

input3 <- input2[rep(1:nrow(input2), each = 2), ]

Clear every row:

input3[1:nrow(input3) %% 1 == 0, ] <- NA

But if I try to rewrite that as duplicating blank rows starting at row 2 (to preserve the header) I get this error:

input3[2:nrow(input3) %% 1 == 0, ] <- NA

"Error in [.data.table(x, i, which = TRUE) : i evaluates to a logical vector length 9 but there are 10 rows. Recycling of logical i is no longer allowed as it hides more bugs than is worth the rare convenience. Explicitly use rep(...,length=.N) if you really need to recycle."

I need to be able to dynamically add rows while keeping the header as this is going to be a gigantic table I will export to another program.

Edit: this is different from this link in that I'm adding additional rows not specified originally in the data. Not just wiping rows.

SqueakyBeak
  • 366
  • 4
  • 15
  • 1
    Instead use `input3[c(FALSE,2:nrow(input3) %% 1 == 0),] <- NA`. By using `2:nrow`, you were explicitly giving too few arguments. When that *thing* is a logical vector, it *must be* length 1 or the same as the number of rows. Period. – r2evans Jan 28 '19 at 16:56
  • 1
    I think we're missing a parenthesis – SqueakyBeak Jan 28 '19 at 16:59
  • Ok I got it to work with input3[c(FALSE,2:nrow(input3) %% 1 == 0),] <- NA. Thank you! – SqueakyBeak Jan 28 '19 at 17:00
  • Possible duplicate of [how to remove all rows from a data.frame in r](https://stackoverflow.com/questions/25588336/how-to-remove-all-rows-from-a-data-frame-in-r) – LocoGris Jan 28 '19 at 17:02
  • Caveat: when I say *"it must be"*, I mean doing otherwise (and relying on recycling) can easily be problematic. The worst case is that it succeeds silently when you intended something different than what it assumed. – r2evans Jan 28 '19 at 17:03

1 Answers1

1

Instead use

input3[c(FALSE,2:nrow(input3) %% 1 == 0,] <- NA

By using 2:nrow, you were explicitly giving a shortened vector. When that thing is a logical vector, it must be length 1 or the same as the number of rows. Period.

Though this has its problems and I discourage its use, perhaps you were expecting it to behave like this:

input3[which(2:nrow(input3) %% 1 == 0),] <- NA

The "good" of this is that the which(...) returns a vector of integer, so it does not need to be the same length as the number of rows in the frame/table.

From ?Extract (which includes [ and friends):

      For '['-indexing only: 'i', 'j', '...' can be logical
      vectors, indicating elements/slices to select.  Such vectors
      are recycled if necessary to match the corresponding extent.
      'i', 'j', '...' can also be negative integers, indicating
      elements/slices to leave out of the selection.

"Recycling" is why length 1 works: its logical value is used for all rows. If you use length 2 and there are an even number of rows (e.g., mtcars[c(T,F),]), then it will give every-other-row. On a similar vein, if you assume recycling and there are not an even multiple of rows (e.g., mtcars[c(T,F,F),]), then your assumptions start becoming less clear.

Add to that the behavior of data.table where it does not enforcing of this. Recycling can get you in trouble, so data.table doesn't encourage it.

library(data.table)
mt <- as.data.table(mtcars)
mt[c(T,F),] <- NA
# Error in `[.data.table`(x, i, which = TRUE) : 
#   i evaluates to a logical vector length 2 but there are 32 rows. Recycling of logical i is no longer allowed as it hides more bugs than is worth the rare convenience. Explicitly use rep(...,length=.N) if you really need to recycle.
mt[c(1,3),] <- NA
r2evans
  • 141,215
  • 6
  • 77
  • 149