Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

R 1:nrow() that loops ok but ruturning NULL

** Problem Loop **

A loop that only returns [1] FALSE result, yet loops 1:nrow(dataset). This should set FALSE when year equals 1987 and month equals 3rd month.

souvenir_festival<- c(n)
for(i in 1:nrow(souvenirs)){
  if (as.numeric(year(yearmonth(souvenirs$Month))) == 1987) {
      souvenir_festival[i] <- FALSE
    }
    else if (!as.numeric(month(souvenirs$Month)) == 3) {
      souvenir_festival[i] <- TRUE
    }
}

Greg’s suggestion code:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

    souvenir_festival <- !(month(souvenirs$Month) == 3 & year(yearmonth(souvenirs$Month)) == 1987)

length(souvenir_festival)

I had the inner loop test month = 3 and still the sf is 1 row, e.g, length(souvenir_festival)

** DPUT data **


    structure(list(Month = structure(c(6209, 6240, 6268, 6299, 6329, 
    6360, 6390, 6421, 6452, 6482, 6513, 6543, 6574, 6605, 6634, 6665, 
    6695, 6726, 6756, 6787, 6818, 6848, 6879, 6909, 6940, 6971, 6999, 
    7030, 7060, 7091, 7121, 7152, 7183, 7213, 7244, 7274, 7305, 7336, 
    7364, 7395, 7425, 7456, 7486, 7517, 7548, 7578, 7609, 7639, 7670, 
    7701, 7729, 7760, 7790, 7821, 7851, 7882, 7913, 7943, 7974, 8004, 
    8035, 8066, 8095, 8126, 8156, 8187, 8217, 8248, 8279, 8309, 8340, 
    8370, 8401, 8432, 8460, 8491, 8521, 8552, 8582, 8613, 8644, 8674, 
    8705, 8735), class = c("yearmonth", "vctrs_vctr")), Sales = c(1664.81, 
    2397.53, 2840.71, 3547.29, 3752.96, 3714.74, 4349.61, 3566.34, 
    5021.82, 6423.48, 7600.6, 19756.21, 2499.81, 5198.24, 7225.14, 
    4806.03, 5900.88, 4951.34, 6179.12, 4752.15, 5496.43, 5835.1, 
    12600.08, 28541.72, 4717.02, 5702.63, 9957.58, 5304.78, 6492.43, 
    6630.8, 7349.62, 8176.62, 8573.17, 9690.5, 15151.84, 34061.01, 
    5921.1, 5814.58, 12421.25, 6369.77, 7609.12, 7224.75, 8121.22, 
    7979.25, 8093.06, 8476.7, 17914.66, 30114.41, 4826.64, 6470.23, 
    9638.77, 8821.17, 8722.37, 10209.48, 11276.55, 12552.22, 11637.39, 
    13606.89, 21822.11, 45060.69, 7615.03, 9849.69, 14558.4, 11587.33, 
    9332.56, 13082.09, 16732.78, 19888.61, 23933.38, 25391.35, 36024.8, 
    80721.71, 10243.24, 11266.88, 21826.84, 17357.33, 15997.79, 18601.53, 
    26155.15, 28586.52, 30505.41, 30821.33, 46634.38, 104660.67)), row.names = c(NA, 
    -84L), key = structure(list(.rows = structure(list(1:84), ptype = integer(0), class = c("vctrs_list_of", 
    "vctrs_vctr", "list"))), row.names = c(NA, -1L), class = c("tbl_df", 
    "tbl", "data.frame")), index = structure("Month", ordered = TRUE), index2 = "Month", interval = structure(list(
        year = 0, quarter = 0, month = 1, week = 0, day = 0, hour = 0, 
        minute = 0, second = 0, millisecond = 0, microsecond = 0, 
        nanosecond = 0, unit = 0), .regular = TRUE, class = c("interval", 
    "vctrs_rcrd", "vctrs_vctr")), class = c("tbl_ts", "tbl_df", "tbl", 
    "data.frame"))

>Solution :

Here’s a fixed version of your code:

sf <- logical(nrow(souvenirs))
for(i in 1:nrow(souvenirs)){
  if (year(souvenirs$Month[i]) == 1987 & month(souvenirs$Month[i]) == 3) {
      sf[i] <- FALSE
  } else {
    sf[i] <- TRUE
  }
}
sf
#  [1]  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
# [17]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
# [33]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
# [49]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
# [65]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
# [81]  TRUE  TRUE  TRUE  TRUE

A more concise and efficient version for the same result:

sf <- !(month(souvenirs$Month) == 3 & year(souvenirs$Month) == 1987)

Here’s a breakdown of problems:

sf <- c(n) 
## n is not defined. 
## If we assume n <- nrow(souvenirs), this is still bad because then we 
## have basically sf <- 84. The goal for `sf` should be for it to be 
## class logical and have length equal to the number of rows, hence
## sf <- logical(nrow(souvenirs))  # is good
for(i in 1:nrow(souvenirs)){
  # your `Month` column is already yearmonth class.
  # year(souvenirs$Month) returns a numeric year, the as.numeric()` and yearmonth()` are pointless
  # ditto below, month(souvenirs$Month) returns the numeric month - nothing more needed
  
  # If you have a loop over `i`, you should expect to use `i` in the loop.
  # You do use it for the ouptut, but not for the input. 
  # souvenirs$Month is the whole column. But in a loop you're trying to test
  # one value at a time, so you need to use `souvenirs$Month[i]`
  
  if (as.numeric(year(yearmonth(souvenirs$Month))) == 1987) {
   if (as.numeric(month(souvenirs$Month)) == 3) {
      sf[i] <- FALSE
    }
    else {
      sf[i] <- TRUE
    }
  }
  # Your nesting structure is messing you up here.
  # The else{} only pertains to the *inner* if(month == 3).
  # This inner if(month == 3) only is run if the outer if(year == 1987) is true.
  # So if the year isn't 1987, the inner if(){}else{} is never run, and 
  # the TRUE result is never assigned.
  # If you want to check two conditions simultaneously, the AND operator `&`
  # is better than two if statements.
  # You could fix the nesting, e.g. (pseudocode)
  # if(year == 1987) {
  #   if(month == 3) {
  #     sf[i] <- TRUE
  #   }
  # }  ## Note that we close both inner AND outer if(){} before the else{} 
  # else {
  #   sf[i] <- FALSE
  # }
  # But the `&` is much cleaner
}
nrow(sf)
## sf is a vector, it doesn't have rows. Use `length()`

More generally, if your code is if(X is TRUE) {TRUE} else {FALSE}, that’s a really long way to write X–you want something that is identical to X. Here, your code is if(X is TRUE) {FALSE} else {TRUE}, which can be written !X. Thanks to R’s vectorization, that’s how my version works: sf <- !(month(souvenirs$Month) == 3 & year(souvenirs$Month) == 1987).

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading