0
votes

I have the following dataframe

date1         date2           Date3        n_var
2017-02-01    2019-02-04      2018-04-01   2
2016-02-01    NA              2017-01-02   3
2017-02-01    2019-02-04      2020-04-01   7
2016-02-01    2019-02-04      2020-04-01   7

And i want this

date1         date2           Date3        price 
2017-02-01    2019-02-04      2018-04-01   2
2016-02-01    NA              2017-01-02   3
2017-02-01    2019-02-04      2020-04-01   NA
2016-02-01    2019-02-04      2020-04-01   NA

Rules :

date3 < date1 we pute na in column n_var
date2 is na and date2 < date3 --> we put na in column n_var
otherwise we want the value at each row for n_var

This is my code :

f_NA <- function(nvar)
    for(i in 1:nrow(df)) {
        df$nvar[i,] <- ifelse((date3<date1), NA,
                                 ifelse(((!is.na(date2)) & date3>date2), NA,df$nvar[i,]))
                          }         

but it does'nt walk?

5
ifelse is vectorized so no need for a loop. Check if your date[1:3] variables are set as.Date, If not convert them and try again - Sotos
yes it's date! I have already converted it - Naï
Also you should probably use df$nvar[i] or df[i,] instead of df$nvar[i,]. - niko
I am not sure if your rule is correct. If date2 is NA then the second condition does not matter. The result will always be NA because the conditional statement date2<date3 is then not possible. - Drj
column n_var date2 is na and ....? Your code is doing opposite of what the rule is stated here for the second condition. May be it is a typo. - Drj

5 Answers

2
votes

One way:

library(data.table)
setDT(DF)

f = function(DF, nvar) DF[!(date2 >= Date3 & Date3 >= date1), (nvar) := NA][]

f(DF, "n_var")

It works like DF[filter, edit columns]. You don't need to separately treat cases where date2 is NA, since they will be skipped during filtering anyways.

Note that this function modifies the input table, rather than just returning a new one with the column edits.

Data

DF = structure(list(date1 = structure(c(17198, 16832, 17198, 16832
), class = "Date"), date2 = structure(c(17931, NA, 17931, 17931
), class = "Date"), Date3 = structure(c(17622, 17168, 18353, 
18353), class = "Date"), n_var = c(2L, 3L, 7L, 7L)), .Names = c("date1", 
"date2", "Date3", "n_var"), row.names = c(NA, -4L), class = "data.frame")
1
votes

Here is one way to try it. ifelse construct should have worked as well but not sure what is happening there.

date1 <- c("2017-02-01", "2016-02-01", "2017-02-01", "2016-02-01")       
date2 <- c("2019-02-04", NA, "2019-02-04", "2019-02-04")    
date3 <- c("2018-04-01", "2017-01-02", "2020-04-01", "2020-04-01")
n_var <- c(2,3,7,7)

df <- cbind.data.frame(date1,date2, date3, n_var)
df$date1 <- as.Date(df$date1, format = "%Y-%m-%d")
df$date2 <- as.Date(df$date2, format = "%Y-%m-%d")
df$date3 <- as.Date(df$date3, format = "%Y-%m-%d")

idx1 <- df$date3<df$date1
idx2 <- !is.na(df$date2) & df$date2<df$date3

df$n_var[c(idx1 | idx2)] <- NA

Hope this helps.

1
votes

Try

f_NA <- function(nvar){
  condition1 <- which(df$date3 < df$date1)
  condition2 <- intersect(which(!is.na(df$date2)), which(df$date2 < df$date3))
  cc <- union(condition1, condition2)
  df$nvar[cc] <- NA
  return(df)
}
0
votes

ifelse works on vectors, so you don't need to use the [i,] index, or the loop for that matter. Instead, use directly: (This code works for me, thanks Drj for building the data)

date1 <- c("2017-02-01", "2016-02-01", "2017-02-01", "2016-02-01")       
date2 <- c("2019-02-04", NA, "2019-02-04", "2019-02-04")    
date3 <- c("2018-04-01", "2017-01-02", "2020-04-01", "2020-04-01")
n_var <- c(2,3,7,7)
df <- cbind.data.frame(date1,date2, date3, n_var)
df$date1 <- as.Date(df$date1, format = "%Y-%m-%d")
df$date2 <- as.Date(df$date2, format = "%Y-%m-%d")
df$date3 <- as.Date(df$date3, format = "%Y-%m-%d")
f_NA <- ifelse(df$date3<df$date1, NA,
               ifelse(((!is.na(df$date2)) & df$date3>df$date2), NA,df$n_var))
-2
votes

Have you tried using NA_character_ instead of NA in your function?