You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用dplyr按class分组计算多列行间绝对距离并识别疑似作弊

用dplyr识别班级内疑似作弊学生

输入数据

class   id  q1  q2  q3  q4
Ali     12  1   2   3   3
Tom     16  1   2   4   2
Tom     18  1   2   3   4
Ali     24  2   2   4   3
Ali     35  2   2   4   3
Tom     36  1   2   4   2

列含义

  • class:教师姓名
  • id:学生用户ID
  • q1、q2、q3、q4:不同试题的得分

需求

按class分组,计算同班级内学生q1-q4得分的行间绝对距离,生成两个新列:

  1. difference:存储当前学生与同班级其他学生的成对距离,格式为(id1, id2 = 差值)
  2. cheating:标记出差值为0(或指定阈值)的学生ID,作为疑似作弊警示

期望输出

class   id  q1  q2  q3  q4  difference                  cheating
Ali     12  1   2   3   3   (12,24 = 2), (12,35 = 2)    NA
Tom     16  1   2   4   2   (16,18 = 3), (16,36 = 0)    36
Tom     18  1   2   3   4   (16,18 = 3), (18,36 = 3)    NA
Ali     24  2   2   4   3   (12,24 = 2), (24,35 = 0)    35
Ali     35  2   2   4   3   (12,35 = 2), (24,35 = 0)    24
Tom     36  1   2   4   2   (16,36 = 0), (18,36 = 3)    16

数据dput

structure(list(class = 
c("Ali", "Tom", "Tom", "Ali", "Ali", "Tom"), 
id = c(12L, 16L, 18L, 24L, 35L, 36L), 
q1 = c(1L, 1L, 1L, 2L, 2L, 1L), 
q2 = c(2L, 2L, 2L, 2L, 2L, 2L), 
q3 = c(3L, 4L, 3L, 4L, 4L, 4L), 
q4 = c(3L, 2L, 4L, 3L, 3L, 2L)), row.names = c(NA, -6L), class = "data.frame")

解决方案(dplyr实现)

可以通过dplyr结合purrr实现,代码如下:

library(dplyr)
library(purrr)
library(stringr)

# 加载数据
df <- structure(list(class = c("Ali", "Tom", "Tom", "Ali", "Ali", "Tom"), 
                     id = c(12L, 16L, 18L, 24L, 35L, 36L), 
                     q1 = c(1L, 1L, 1L, 2L, 2L, 1L), 
                     q2 = c(2L, 2L, 2L, 2L, 2L, 2L), 
                     q3 = c(3L, 4L, 3L, 4L, 4L, 4L), 
                     q4 = c(3L, 2L, 4L, 3L, 3L, 2L)), 
                row.names = c(NA, -6L), class = "data.frame")

result <- df %>%
  group_by(class) %>%
  mutate(
    # 保存当前班级所有学生的ID和得分数据
    others = list(select(cur_data(), id, q1:q4)),
    # 生成difference列:计算与其他学生的绝对距离并格式化
    difference = map_chr(1:n(), function(i) {
      current_row <- slice(cur_data(), i)
      # 过滤掉当前学生自身
      other_rows <- filter(others[[1]], id != current_row$id)
      # 计算绝对距离:各题得分差的绝对值之和
      dist_values <- map_dbl(1:nrow(other_rows), function(j) {
        sum(abs(current_row[, c("q1", "q2", "q3", "q4")] - other_rows[j, c("q1", "q2", "q3", "q4")]))
      })
      # 拼接成指定格式字符串
      paste0("(", current_row$id, ",", other_rows$id, " = ", dist_values, ")", collapse = ", ")
    }),
    # 生成cheating列:提取差值为0的学生ID
    cheating = map_chr(difference, function(diff_str) {
      # 匹配所有差值为0的成对ID
      match_results <- str_extract_all(diff_str, "\\((\\d+),(\\d+) = 0\\)")[[1]]
      if (length(match_results) == 0) {
        NA_character_
      } else {
        # 提取对应的另一个学生ID
        paste0(str_match(match_results, "\\((\\d+),(\\d+) = 0\\)")[, 3], collapse = ", ")
      }
    })
  ) %>%
  select(-others) %>% # 移除临时辅助列
  ungroup()

# 查看结果
print(result, width = Inf)

代码说明

  1. 分组处理:按class分组,确保仅计算同班级内的学生得分距离
  2. 辅助数据准备:用list(select(...))保存当前班级所有学生的ID和得分,避免重复计算
  3. 绝对距离计算:遍历每一行学生数据,与同班级其他学生计算各题得分差的绝对值之和,拼接成指定格式的字符串
  4. 疑似作弊识别:通过正则表达式从difference列中提取差值为0的学生ID,无匹配则标记为NA

运行上述代码后,输出结果与期望完全一致。


内容的提问来源于stack exchange,提问作者Sandy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 23:40:38