识别数据序列根据其他列 UserID 发生变化的情况

Identify cases where data sequence changes based on other column UserIDs

我正在处理一个数据框 df,如下所示:

输入:
TUserId  SUID   mid_sum final_sum
 115      201   2       7     
 115      309   1       8     
 115      404   1       9           
 209      245   2       10    
 209      398   2       10          
 209      510   2       10
 209      602   1       10
 371      111   2       11
 371      115   1       11
 371      123   3       11
 371      124   2       11

1- 我的数据以 wide 格式排列,其中每一行都有一个唯一的学生 ID,显示为 SUID

2- 多个学生可以有相同的老师,因此多行的公共老师 ID 显示为 TUserId

3- 数据包括学生期中成绩和期末成绩。

4- 我很想知道是否存在任何情况,如 mid_sum 所示,在期中考试中给学生相似分数的老师在期末考试中给出的分数不一致,如final_sum。如果在数据中发现这种不一致,我想添加一列Status来记录这个inconsistency

要求:

a- 为此,我的规则是如果 mid_sumfinal_sum 按升序排序,就像我在这个示例数据框 df 中所做的那样。我想确定在 mid_sumfinal_sum.

这些列中的任何一个中升序中断的情况

b- 如果数据没有排序,能做到吗?

示例 1:

例如,对于SUID = 309mid_sum是从前面的mid_sum减去的。所以它应该被标记为inconsistent。它应该只发生在被同一个老师 TUserId 打分的学生身上,在这种情况下是 115.

示例 2:

同样,对于SUID = 602mid_sum是从前面的mid_sum减去的。所以它应该被标记为inconsistent。同样,这是给同一个老师的TUserId = 209

为了进一步详细说明,我想要这样的输出:

输出:
TUserId  SUID   mid_sum final_sum   Status
 115      201   2       7           consistent
 115      309   1       8           inconsistent
 115      404   1       9           consistent
 209      245   2       10          consistent
 209      398   2       10          consistent
 209      510   2       10          consistent
 209      602   1       10          inconsistent
 371      111   2       11          consistent
 371      115   1       11          inconsistent
 371      123   3       11          consistent
 371      124   2       11          inconsistent
 

数据导入dput()

数据框的dput()如下:

dput(df)

structure(list(
TUserId = c(115L, 115L, 115L, 209L, 209L, 209L, 209L, 371L, 371L, 371L, 371L), 
SUID = c(201L, 309L, 404L, 245L, 398L, 510L, 602L, 111L, 115L, 123L, 124L), 
mid_sum = c(2L, 1L, 1L, 2L, 2L, 2L, 1L, 2L, 1L, 3L, 2L), 
final_sum = c(7L, 8L, 9L, 10L, 10L, 10L, 10L, 11L, 11L, 11L, 11L)), 
class = "data.frame", row.names = c(NA, -11L))

我在 SO 上查找了类似的问题并找到了这个 但它似乎无法帮助我解决我的问题。 另一个相关的 post 是 Determine when a sequence of numbers has been broken in R 但同样,它对我的​​情况没有帮助。

任何有关如何解决此问题的建议将不胜感激。

谢谢!

这是我们测试滞后差异符号的一种相当简单的方法。如果 mid_sum 差号与 final_sum 差号相同,则它们是“一致的”。

library(dplyr)
df %>%
  arrange(TUserId, final_sum) %>%
  group_by(TUserId) %>%
  mutate(
    Status = if_else(
      sign(final_sum + 0.1 - lag(final_sum, default = 0)) == sign(mid_sum + 0.1 - lag(mid_sum, default = 0)),
      "consisent", "inconsistent"
    )
  )
# # A tibble: 11 x 5
# # Groups:   TUserId [3]
#    TUserId  SUID mid_sum final_sum Status      
#      <int> <int>   <int>     <int> <chr>       
#  1     115   201       2         7 consisent   
#  2     115   309       1         8 inconsistent
#  3     115   404       1         9 consisent   
#  4     209   245       2        10 consisent   
#  5     209   398       2        10 consisent   
#  6     209   510       2        10 consisent   
#  7     209   602       1        10 inconsistent
#  8     371   111       2        11 consisent   
#  9     371   115       1        11 inconsistent
# 10     371   123       3        11 consisent   
# 11     371   124       2        11 inconsistent

+ .1 用于使分数保持相同的行计为正号。

也许 accumulate 函数族是为这些情况设计的。这里使用 accumulate2 -

  • 作为第一个参数,我要通过 mid_sum
  • 第二个参数是滞后值,即 lag(mid_sum),默认为除 NA 之外的任何值和它可能采用的实际值。我认为 0 是安全的
  • .init 提供任何值。我只选了c
  • 如果第一个参数 (..2) [..1 是累加值而不是第一个参数] 小于 ..3 即第二个参数,return inconsistent 否则 consistent.
  • 现在由于提供了 .init,结果将比提供的值大一个值,因此删除了它的第一个值 [-1]
df <- structure(list(
  TUserId = c(115L, 115L, 115L, 209L, 209L, 209L, 209L, 371L, 371L, 371L, 371L), 
  SUID = c(201L, 309L, 404L, 245L, 398L, 510L, 602L, 111L, 115L, 123L, 124L), 
  mid_sum = c(2L, 1L, 1L, 2L, 2L, 2L, 1L, 2L, 1L, 3L, 2L), 
  final_sum = c(7L, 8L, 9L, 10L, 10L, 10L, 10L, 11L, 11L, 11L, 11L)), 
  class = "data.frame", row.names = c(NA, -11L))

library(tidyverse)

df %>%
  arrange(TUserId, final_sum) %>%
  group_by(TUserId) %>%
  mutate(status = unlist(accumulate2(mid_sum, lag(mid_sum, default = 0), .init = 'c', 
                              ~ if(..2 < ..3) 'inconsistent' else 'consistent')[-1]))
#> # A tibble: 11 x 5
#> # Groups:   TUserId [3]
#>    TUserId  SUID mid_sum final_sum status      
#>      <int> <int>   <int>     <int> <chr>       
#>  1     115   201       2         7 consistent  
#>  2     115   309       1         8 inconsistent
#>  3     115   404       1         9 consistent  
#>  4     209   245       2        10 consistent  
#>  5     209   398       2        10 consistent  
#>  6     209   510       2        10 consistent  
#>  7     209   602       1        10 inconsistent
#>  8     371   111       2        11 consistent  
#>  9     371   115       1        11 inconsistent
#> 10     371   123       3        11 consistent  
#> 11     371   124       2        11 inconsistent

reprex package (v2.0.0)

于 2021-06-15 创建