R 如何检查事件序列是否有序?

R 如何检查事件序列是否有序?,r,date-comparison,R,Date Comparison,我有一个数据表,其中每列表示一个事件:如果事件发生了,则有一个日期值,如果没有发生,则为空。现在,所有事件都是可选的,但是如果它们发生,它们必须遵循一个顺序(A,然后B,C…) 在研究数据时,我发现至少存在两个数据质量问题:例如,事件a为空,事件B有一个日期:或者事件a的日期晚于事件B。我必须检查1000多行中的10列,因此我想知道是否有一种方法可以使用R自动执行此操作(我只需要标记序列是否正确,然后手动检查错误的情况)…我唯一能想到的是执行大量似乎根本不合适的ifelse嵌套语句 有人知道更好

我有一个数据表,其中每列表示一个事件:如果事件发生了,则有一个日期值,如果没有发生,则为空。现在,所有事件都是可选的,但是如果它们发生,它们必须遵循一个顺序(A,然后B,C…)

在研究数据时,我发现至少存在两个数据质量问题:例如,事件a为空,事件B有一个日期:或者事件a的日期晚于事件B。我必须检查1000多行中的10列,因此我想知道是否有一种方法可以使用R自动执行此操作(我只需要标记序列是否正确,然后手动检查错误的情况)…我唯一能想到的是执行大量似乎根本不合适的ifelse嵌套语句

有人知道更好的功能/方法吗?提前感谢,这里有一些虚拟数据:(以下事件可以有相同的日期)

因此,在本例中,应标记第2、10和14行

提前感谢

您可以使用
apply()
依次检查每一行,并且(在其中)
sapply()
检查行中的每个元素

假设您的数据框名为
test\u data
,我们将添加一个新列,显示根据您指定的规则,每行中的日期列是否有意义

test_data$valid <- apply(test_data[2:ncol(test_data)], 1, function (x) {

  # sapply iterates over each element in the row after the first one, checking 
  # all the previous elements
  valid <- sapply(2:length(x), function (y) {
    ifelse(
      !is.na(x[y]) # we can only check an element if it is a date
      & (
        # if any of the elements before the current one are NA, this is a 
        # problem
        sum(is.na(x[1:y-1]) > 0) | 
          # if any of the dates before the current one are greater than the 
          # current one, this is also a problem
          max(x[1:y-1]) > x[y]
      ), 
      FALSE, TRUE)
  })

  # if any of the elements in `valid` are false, this says there is a problem in
  # the data (note `valid` is shorter than `x` by one element because the first
  # element isn't checked against itself)
  ifelse(sum(valid) == length(x) - 1, TRUE, FALSE)

})

test_data[test_data$valid == FALSE,]
test_数据$valid x[y]
), 
(假,真)
})
#如果'valid'中的任何一个元素为false,则表示
#数据(注意'valid'比'x'短一个元素,因为第一个
#元素未对照自身进行检查)
ifelse(总和(有效)=长度(x)-1,真,假)
})
测试数据[测试数据$valid==FALSE,]
您可以使用
apply()
依次检查每一行,并(在其中)
sapply()
检查行中的每个元素

假设您的数据框名为
test\u data
,我们将添加一个新列,显示根据您指定的规则,每行中的日期列是否有意义

test_data$valid <- apply(test_data[2:ncol(test_data)], 1, function (x) {

  # sapply iterates over each element in the row after the first one, checking 
  # all the previous elements
  valid <- sapply(2:length(x), function (y) {
    ifelse(
      !is.na(x[y]) # we can only check an element if it is a date
      & (
        # if any of the elements before the current one are NA, this is a 
        # problem
        sum(is.na(x[1:y-1]) > 0) | 
          # if any of the dates before the current one are greater than the 
          # current one, this is also a problem
          max(x[1:y-1]) > x[y]
      ), 
      FALSE, TRUE)
  })

  # if any of the elements in `valid` are false, this says there is a problem in
  # the data (note `valid` is shorter than `x` by one element because the first
  # element isn't checked against itself)
  ifelse(sum(valid) == length(x) - 1, TRUE, FALSE)

})

test_data[test_data$valid == FALSE,]
test_数据$valid x[y]
), 
(假,真)
})
#如果'valid'中的任何一个元素为false,则表示
#数据(注意'valid'比'x'短一个元素,因为第一个
#元素未对照自身进行检查)
ifelse(总和(有效)=长度(x)-1,真,假)
})
测试数据[测试数据$valid==FALSE,]

我会在
数据表中执行此操作,但我确信
dplyr
版本类似:

library(data.table)
setDT(DF) # <- convert to data.table
DF[DF[ , melt(.SD, id.vars = 'ID')
       ][ , {
         non_na_idx = which(!is.na(value))
         any(diff(value) < 0, na.rm = TRUE) || 
           (length(non_na_idx) && 
              max(non_na_idx) != length(non_na_idx))
       }, keyby = ID],
   flag := i.V1, on = 'ID'][]
#     ID          A          B          C          D          E  flag
#  1:  1 2018-01-01 2018-02-05       <NA>       <NA>       <NA> FALSE
#  2:  2       <NA> 2018-07-04       <NA>       <NA>       <NA>  TRUE
#  3:  3       <NA>       <NA>       <NA>       <NA>       <NA> FALSE
#  4:  4 2017-03-01 2017-04-03 2017-04-04 2017-08-29 2018-03-16 FALSE
#  5:  5 2017-11-28 2018-01-31       <NA>       <NA>       <NA> FALSE
#  6:  6 2017-02-07       <NA>       <NA>       <NA>       <NA> FALSE
#  7:  7 2018-04-25 2018-04-30       <NA>       <NA>       <NA> FALSE
#  8:  8 2018-02-05 2018-03-16       <NA>       <NA>       <NA> FALSE
#  9:  9 2018-03-19 2018-03-22 2018-03-24 2018-04-04       <NA> FALSE
# 10: 10 2017-04-03 2017-03-01       <NA>       <NA>       <NA>  TRUE
# 11: 11 2018-03-16       <NA>       <NA>       <NA>       <NA> FALSE
# 12: 12 2018-03-16 2018-05-30 2018-06-05       <NA>       <NA> FALSE
# 13: 13 2018-02-05       <NA>       <NA>       <NA>       <NA> FALSE
# 14: 14 2018-03-22       <NA> 2018-06-05       <NA>       <NA>  TRUE
# 15: 15 2018-03-22       <NA>       <NA>       <NA>       <NA> FALSE
# 16: 16 2018-03-22       <NA>       <NA>       <NA>       <NA> FALSE
# 17: 17 2017-08-17 2017-08-29       <NA>       <NA>       <NA> FALSE
# 18: 18 2018-06-05 2018-06-05       <NA>       <NA>       <NA> FALSE
# 19: 19 2018-03-22       <NA>       <NA>       <NA>       <NA> FALSE
# 20: 20 2018-06-05 2018-07-04 2018-07-04       <NA>       <NA> FALSE
你需要两个条件--

在任何一行中,较高列的日期(按字母排序)都不应在较低列的日期之前。在数据的长形式中,这意味着每个
ID
中的连续差异应该是单调递增的,或者等价地,
diff(value)
始终是非负的。因此,如果
有任何差异(diff(value)<0,na.rm=TRUE)
,则我们的
标志为
TRUE
,这意味着对于该
ID
,至少有一个这样的差异为负值:

DF[ , melt(.SD, id.vars = 'ID')
    ][ , any(diff(na.omit(value)) < 0, na.rm = TRUE), 
       keyby = ID]
#     ID    V1
#  1:  1 FALSE
# < omitted; all FALSE >
#  9:  9 FALSE
# 10: 10  TRUE # <- column B comes before column A
# 11: 11 FALSE
# < omitted; all FALSE >
# 20: 20 FALSE
结合这两个条件可以获得所有三行的标志

最后,我们将新创建的标志连接回原始表,并创建一个名为
flag
的列。这可以分为两个步骤——创建带有标志列的表,然后连接:

DF_with_flag = 
  DF[ , melt(.SD, id.vars = 'ID')
      ][ , {
        non_na_idx = which(!is.na(value))
        any(diff(na.omit(value)) < 0, na.rm = TRUE) || 
          (length(non_na_idx) && 
             max(non_na_idx) != length(non_na_idx))
      }, keyby = ID]
DF[DF_with_flag, flag := i.V1, on = 'ID']
DF_带_标志=
DF[,melt(.SD,id.vars='id')
][ , {
non_na_idx=哪个(!是.na(值))
any(diff(na.omit(value))<0,na.rm=TRUE)|
(长度(非na_idx)和
最大值(非na_idx)!=长度(非na_idx))
},keyby=ID]
DF[DF_with_flag,flag:=i.V1,on='ID']

我会在
数据表中执行此操作,但我确信
dplyr
版本类似:

library(data.table)
setDT(DF) # <- convert to data.table
DF[DF[ , melt(.SD, id.vars = 'ID')
       ][ , {
         non_na_idx = which(!is.na(value))
         any(diff(value) < 0, na.rm = TRUE) || 
           (length(non_na_idx) && 
              max(non_na_idx) != length(non_na_idx))
       }, keyby = ID],
   flag := i.V1, on = 'ID'][]
#     ID          A          B          C          D          E  flag
#  1:  1 2018-01-01 2018-02-05       <NA>       <NA>       <NA> FALSE
#  2:  2       <NA> 2018-07-04       <NA>       <NA>       <NA>  TRUE
#  3:  3       <NA>       <NA>       <NA>       <NA>       <NA> FALSE
#  4:  4 2017-03-01 2017-04-03 2017-04-04 2017-08-29 2018-03-16 FALSE
#  5:  5 2017-11-28 2018-01-31       <NA>       <NA>       <NA> FALSE
#  6:  6 2017-02-07       <NA>       <NA>       <NA>       <NA> FALSE
#  7:  7 2018-04-25 2018-04-30       <NA>       <NA>       <NA> FALSE
#  8:  8 2018-02-05 2018-03-16       <NA>       <NA>       <NA> FALSE
#  9:  9 2018-03-19 2018-03-22 2018-03-24 2018-04-04       <NA> FALSE
# 10: 10 2017-04-03 2017-03-01       <NA>       <NA>       <NA>  TRUE
# 11: 11 2018-03-16       <NA>       <NA>       <NA>       <NA> FALSE
# 12: 12 2018-03-16 2018-05-30 2018-06-05       <NA>       <NA> FALSE
# 13: 13 2018-02-05       <NA>       <NA>       <NA>       <NA> FALSE
# 14: 14 2018-03-22       <NA> 2018-06-05       <NA>       <NA>  TRUE
# 15: 15 2018-03-22       <NA>       <NA>       <NA>       <NA> FALSE
# 16: 16 2018-03-22       <NA>       <NA>       <NA>       <NA> FALSE
# 17: 17 2017-08-17 2017-08-29       <NA>       <NA>       <NA> FALSE
# 18: 18 2018-06-05 2018-06-05       <NA>       <NA>       <NA> FALSE
# 19: 19 2018-03-22       <NA>       <NA>       <NA>       <NA> FALSE
# 20: 20 2018-06-05 2018-07-04 2018-07-04       <NA>       <NA> FALSE
你需要两个条件--

在任何一行中,较高列的日期(按字母排序)都不应在较低列的日期之前。在数据的长形式中,这意味着每个
ID
中的连续差异应该是单调递增的,或者等价地,
diff(value)
始终是非负的。因此,如果
有任何差异(diff(value)<0,na.rm=TRUE)
,则我们的
标志为
TRUE
,这意味着对于该
ID
,至少有一个这样的差异为负值:

DF[ , melt(.SD, id.vars = 'ID')
    ][ , any(diff(na.omit(value)) < 0, na.rm = TRUE), 
       keyby = ID]
#     ID    V1
#  1:  1 FALSE
# < omitted; all FALSE >
#  9:  9 FALSE
# 10: 10  TRUE # <- column B comes before column A
# 11: 11 FALSE
# < omitted; all FALSE >
# 20: 20 FALSE
结合这两个条件可以获得所有三行的标志

最后,我们将新创建的标志连接回原始表,并创建一个名为
flag
的列。这可以分为两个步骤——创建带有标志列的表,然后连接:

DF_with_flag = 
  DF[ , melt(.SD, id.vars = 'ID')
      ][ , {
        non_na_idx = which(!is.na(value))
        any(diff(na.omit(value)) < 0, na.rm = TRUE) || 
          (length(non_na_idx) && 
             max(non_na_idx) != length(non_na_idx))
      }, keyby = ID]
DF[DF_with_flag, flag := i.V1, on = 'ID']
DF_带_标志=
DF[,melt(.SD,id.vars='id')
][ , {
non_na_idx=哪个(!是.na(值))
any(diff(na.omit(value))<0,na.rm=TRUE)|
(长度(非na_idx)和
最大值(非na_idx)!=长度(非na_idx))
},keyby=ID]
DF[DF_with_flag,flag:=i.V1,on='ID']

第14行的问题是存在“间隙”?是的,没错。顺序必须遵循顺序,连续步骤之间不得有间隙。下面的步骤的日期不能早于上一步。第14行的问题是存在“间隙”?是的,没错。顺序必须遵循顺序,连续步骤之间不得有间隙。以下步骤的日期不能早于上一步。谢谢!我喜欢data.table的使用,您的评论有助于理解代码,非常感谢!谢谢我喜欢data.table的使用,您的评论有助于理解代码,非常感谢!谢谢我检查了这段代码,它也工作得很好。非常直观!谢谢我检查了这段代码,它也工作得很好。非常直观!