** 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:
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"))
CodePudding user response:
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)
.