R Case语句同时使用和或在同一语句中-在日期之间,有些在多列中缺少值

时间:2019-06-06 16:47:09

标签: r

我试图查看每个月初的计划参与者是否活跃。

我有计划的开始和结束日期,但是其中一些参与者仍在参加该计划,因此结束日期为空。

我的表有前两列,但我希望用以下case语句填充其余的列:

case when Date > Admission and (Date < Discharge or Discharge is null) then 'Active' else 'Inactive'

日期为月份的第一天 (我已经为此日期预先填充了列,因此可以逐行完成等式)

Admission Discharge Jan-19   Feb-19   Mar-19
12/3/18   4/3/19    Active   Active   Active
01/7/19   NA        Inactive Active   Active
02/25/19  03/02/19  Inactive Inactive Active

我已经尝试过ifelse和if语句,但无法弄清楚如何同时执行多个条件。如果所有其他方法都失败了,我将使用sqldf程序包,但我希望在R中有一种方法可以通过循环执行此操作,因为随着时间的推移,最近几个月会增加这种情况。

我尝试运行此代码段,但不适用于缺少放电日期的情况

Dates$`Sep-2018` <- ifelse(Dates$`Sep-2018` > Dates$Admission_Date & Dates$`Sep-2018` < Dates$Discharge_Date, "Active",
       ifelse(Dates$`Sep-2018` > Dates$Admission_Date & is.na(Dates$Discharge_Date), "Active", "Inactive"))

有没有一种方法可以在多个列中使用case语句?

3 个答案:

答案 0 :(得分:1)

这有点笨拙,但是如果要执行for循环,则可以执行以下操作:

for(i in 1:nrow(df)){
  startDate<-df[i,1] #Puts the start date in assuming the admission column is column 1
  endDate<-df[i,2] #Puts the end date in assuming the discharge column is column 2
  for(z in 3:ncol(df)){ #Starts at the date column
    colValue<-colnames(df[z]) #Gives the value of the column name
    if(startDate>colValue){ #If the participant has not been enrolled yet
      df[i,z]<-"Inactive"
    }
    if(startDate<colValue){ #If the startdate is before the value of the column
      if(colValue<endDate | is.null(endDate)){
        df[i,z]<-"Active"
      }else{
        df[i,z]<="Inactive"
      }
    }
    }
  }

希望我能正确理解您的问题,并且可以正常工作。如果没有,则可能需要将日期转换为R中的POSIXct日期时间。

答案 1 :(得分:1)

或者,可以通过组合使用交叉连接非等距连接并随后从长格式更改为宽格式来解决此问题。

library(data.table)
months <- seq(as.Date("2019-01-01"), Sys.Date(), by = "month")
cbind(
  dates,
  setDT(dates)[, lapply(.SD, as.Date, format = "%m/%d/%y")][
    is.na(Discharge), Discharge := Sys.Date()][
      , rn := .I][
        .(months), on = .(Admission <= V1, Discharge >= V1)
        , allow.cartesian = TRUE, .(rn, V1, active = "Active")][
          , V1 := factor(V1, labels = format(months, "%b-%y"))][
          , dcast(.SD, rn ~ V1, value.var = "active", fill = "Inactive")][
            , rn := NULL]
)
   Admission Discharge   Jan-19   Feb-19 Mrz-19   Apr-19   Mai-19   Jun-19
1:   12/3/18    4/3/19   Active   Active Active   Active Inactive Inactive
2:   01/7/19      <NA> Inactive   Active Active   Active   Active   Active
3:  02/25/19  03/02/19 Inactive Inactive Active Inactive Inactive Inactive

说明

  1. months包含一个参考日期向量。在这里,使用每月的第一天。
  2. AdmissionDischarge日期从字符强制转换为Date类,以便进行日期计算。
  3. 所有丢失的Discharge日期都将被当前日期填满。
  4. 添加了行号以保持原始行顺序在随后的重塑中。
  5. 然后将其右连months。这是一个非公平交叉联接,它仅返回当月V1的第一天介于入场日期和出场日期之间的情况。 V1months.(months)向量转换为列表时创建的默认列名。 allow.cartesian = TRUE表示交叉连接。在联接中,将创建一个新列active,其默认值为"Active"
  6. V1变成了一个具有适当命名的月份的因子,例如"Jan-19""Feb-19"等。这确保了日期将以正确的顺序出现(而不是按字典顺序排序) ),然后进行重塑。
  7. dcast()将数据从长格式整形为宽格式,而丢失的条目用"Inactive"填充。
  8. 行号已删除。
  9. 最后,使用dates将结果与原始cbind()数据集合并。

更短版本

以上代码尝试尽可能接近地再现OP的预期结果。可以使用更简洁的代码来检索相同的信息(但外观不同):

setDT(dates)[, lapply(.SD, as.Date, format = "%m/%d/%y")][
  is.na(Discharge), Discharge := Sys.Date()][
    , rn := .I][
      .(months), on = .(Admission <= V1, Discharge >= V1), allow.cartesian = TRUE
      , .(rn, Admission = x.Admission, Disscharge = x.Discharge, V1)][
        , dcast(.SD, rn + ... ~ V1, length)]

返回

   rn  Admission Disscharge 2019-01-01 2019-02-01 2019-03-01 2019-04-01 2019-05-01 2019-06-01
1:  1 2018-12-03 2019-04-03          1          1          1          1          0          0
2:  2 2019-01-07 2019-06-07          0          1          1          1          1          1
3:  3 2019-02-25 2019-03-02          0          0          1          0          0          0

数据

library(data.table)
dates <- fread("Admission Discharge Jan-19   Feb-19   Mar-19
12/3/18   4/3/19    Active   Active   Active
01/7/19   NA        Inactive Active   Active
02/25/19  03/02/19  Inactive Inactive Active"
            , select = 1:2)

dates
   Admission Discharge
1:   12/3/18    4/3/19
2:   01/7/19      <NA>
3:  02/25/19  03/02/19

答案 2 :(得分:1)

使用dplyr的动态变量创建:

library(dplyr) # version 0.6 and above
library(lubridate)

df <- df %>% 
  select(Admission, Discharge) %>% 
  mutate_all(mdy) # convert the columns to date format

# Start dates of the months and respective month names
my_months <- ymd("2019-01-01", "2019-02-01", "2019-03-01", "2019-04-01")
month_names <- month(my_months, label=T) %>% as.character()


# Looping through the months and dynamic creation of month columns
for (i in seq(length(my_months))){
  df <- df %>%  
    mutate(!!month_names[i] := ifelse(my_months[i] > Admission &
                                        (my_months[i] < Discharge | is.na(Discharge)), 
                                        "Active", "NotActive"))
}