Published

April 3, 2026

作业完成情况检查

课程作业

课程目前布置过下面的 5 项作业。

判定标准:

作业 标准 数据来源
作业1 入学报到 在 Issue #1 下回复 members 仓库 Issue #1 评论
作业2 模型性能 在 Issue #2 下回复 members 仓库 Issue #2 评论
作业3 练习协作 发起过 PR(含 closed) members 仓库 Pull Requests
作业4 我的主页 在 Issue #99 下回复 members 仓库 Issue #99 评论
作业5 计划项目 在 projects 仓库发起 Issue projects 仓库 Issues

数据获取

学生名单

显示/隐藏代码
# 读取学生名单
students <- read.csv("data/students/student-list.csv", fileEncoding = "UTF-8-BOM")
colnames(students) <- c("学号", "姓名", "学院")
students$学号 <- as.character(students$学号)

cat("共有", nrow(students), "名学生\n")
共有 312 名学生

从 Issue #1 建立学号-GitHub 用户名映射

显示/隐藏代码
# 获取 Issue #1 所有评论
issue1_comments <- gh(
  "GET /repos/{owner}/{repo}/issues/{issue_number}/comments",
  owner = "D2RS-2026spring",
  repo = "members",
  issue_number = 1,
  per_page = 100,
  .limit = Inf
)

cat("Issue #1 共有", length(issue1_comments), "条评论\n")
Issue #1 共有 329 条评论
显示/隐藏代码
# 从评论中提取学号和 GitHub 用户名的对应关系
extract_student_id <- function(comment) {
  body <- comment$body
  user <- comment$user$login
  
  # 尝试提取学号(13位数字,以2025开头)
  student_id <- NA_character_
  
  # 格式: "学号:2025303110116" 或 "学号: 2025303110116"
  student_id <- str_extract(body, "\\d{13}")
  
  data.frame(
    github_user = user,
    学号 = student_id,
    stringsAsFactors = FALSE
  )
}

# 批量提取映射关系
id_mapping <- map_dfr(issue1_comments, extract_student_id)
显示/隐藏代码
# 去重:同一学号可能有多条评论,取第一条
id_mapping <- id_mapping |>
  filter(!is.na(学号)) |>
  distinct(学号, .keep_all = TRUE)

cat("成功建立", nrow(id_mapping), "个学号-GitHub用户名映射\n")
成功建立 315 个学号-GitHub用户名映射

目前还没有建立映射的同学。

显示/隐藏代码
students |> filter(!学号 %in% id_mapping[["学号"]])
           学号   姓名           学院
1 2025303110066 李健萍 资源与环境学院

获取各作业数据

显示/隐藏代码
# --- 作业1: Issue #1 回复者 ---
hw1_users <- map_chr(issue1_comments, ~ .x$user$login) |> unique()
cat("作业1(Issue #1)回复人数:", length(hw1_users), "\n")
作业1(Issue #1)回复人数: 313 
显示/隐藏代码
# --- 作业2: Issue #2 回复者 ---
issue2_comments <- gh(
  "GET /repos/{owner}/{repo}/issues/{issue_number}/comments",
  owner = "D2RS-2026spring",
  repo = "members",
  issue_number = 2,
  per_page = 100,
  .limit = Inf
)
hw2_users <- map_chr(issue2_comments, ~ .x$user$login) |> unique()
cat("作业2(Issue #2)回复人数:", length(hw2_users), "\n")
作业2(Issue #2)回复人数: 308 
显示/隐藏代码
# --- 作业3: PR 发起者(含 closed) ---
prs <- gh(
  "GET /repos/{owner}/{repo}/pulls",
  owner = "D2RS-2026spring",
  repo = "members",
  state = "all",
  per_page = 100,
  .limit = Inf
)
hw3_users <- map_chr(prs, ~ .x$user$login) |> unique()
cat("作业3(PR)发起人数:", length(hw3_users), "\n")
作业3(PR)发起人数: 307 
显示/隐藏代码
# --- 作业4: Issue #99 回复者 ---
issue99_comments <- gh(
  "GET /repos/{owner}/{repo}/issues/{issue_number}/comments",
  owner = "D2RS-2026spring",
  repo = "members",
  issue_number = 99,
  per_page = 100,
  .limit = Inf
)
hw4_users <- map_chr(issue99_comments, ~ .x$user$login) |> unique()
cat("作业4(Issue #99)回复人数:", length(hw4_users), "\n")
作业4(Issue #99)回复人数: 283 
显示/隐藏代码
# --- 作业5: projects 仓库的 Issues ---
project_issues <- gh(
  "GET /repos/{owner}/{repo}/issues",
  owner = "D2RS-2026spring",
  repo = "projects",
  state = "all",
  per_page = 100,
  .limit = Inf
)
cat("作业5(projects Issues)数量:", length(project_issues), "\n")
作业5(projects Issues)数量: 84 
显示/隐藏代码
# 从 project issues 的 body 中提取所有学号
hw5_student_ids <- character(0)
for (issue in project_issues) {
  body <- issue$body %||% ""
  # 提取所有13位学号
  ids <- str_extract_all(body, "\\d{13}")[[1]]
  hw5_student_ids <- c(hw5_student_ids, ids)
}
hw5_student_ids <- unique(hw5_student_ids)
cat("作业5 提取到学号数:", length(hw5_student_ids), "\n")
作业5 提取到学号数: 284 

作业完成情况

显示/隐藏代码
# 将学生名单与 GitHub 用户名映射合并
result <- students |>
  left_join(id_mapping, by = "学号")

# 判断各项作业完成情况
result <- result |>
  mutate(
    作业1_入学报到 = github_user %in% hw1_users,
    作业2_模型性能 = github_user %in% hw2_users,
    作业3_练习协作 = github_user %in% hw3_users,
    作业4_我的主页 = github_user %in% hw4_users,
    作业5_计划项目 = 学号 %in% hw5_student_ids
  )

# 没有 GitHub 用户名的学生,作业1-4 标记为 FALSE
result <- result |>
  mutate(
    across(starts_with("作业"), ~ ifelse(is.na(github_user) & cur_column() != "作业5_计划项目", FALSE, .x)),
    across(starts_with("作业"), ~ replace_na(.x, FALSE))
  )

# 统计完成数量
result <- result |>
  mutate(
    完成数 = 作业1_入学报到 + 作业2_模型性能 + 作业3_练习协作 + 作业4_我的主页 + 作业5_计划项目
  )

总体统计

显示/隐藏代码
# 各作业完成率
summary_df <- data.frame(
  作业 = c("作业1 入学报到", "作业2 模型性能", "作业3 练习协作", "作业4 我的主页", "作业5 计划项目"),
  完成人数 = c(
    sum(result$作业1_入学报到),
    sum(result$作业2_模型性能),
    sum(result$作业3_练习协作),
    sum(result$作业4_我的主页),
    sum(result$作业5_计划项目)
  ),
  总人数 = nrow(result)
)
summary_df$完成率 <- paste0(round(summary_df$完成人数 / summary_df$总人数 * 100, 1), "%")

kable(summary_df, caption = "各作业完成率统计")
各作业完成率统计
作业 完成人数 总人数 完成率
作业1 入学报到 311 312 99.7%
作业2 模型性能 307 312 98.4%
作业3 练习协作 303 312 97.1%
作业4 我的主页 281 312 90.1%
作业5 计划项目 277 312 88.8%

完成情况明细

显示/隐藏代码
# 将 TRUE/FALSE 转换为可视化符号
display <- result |>
  arrange(学院, 学号) |>
  mutate(
    作业1 = ifelse(作业1_入学报到, "✅", "❌"),
    作业2 = ifelse(作业2_模型性能, "✅", "❌"),
    作业3 = ifelse(作业3_练习协作, "✅", "❌"),
    作业4 = ifelse(作业4_我的主页, "✅", "❌"),
    作业5 = ifelse(作业5_计划项目, "✅", "❌"),
    GitHub = ifelse(is.na(github_user), "—",
                    paste0("[", github_user, "](https://github.com/", github_user, ")"))
  ) |>
  select(学号, GitHub, 作业1, 作业2, 作业3, 作业4, 作业5)

kable(display, caption = "学生作业完成情况明细表")
Table 1: 学生作业完成情况明细表
学号 GitHub 作业1 作业2 作业3 作业4 作业5
2025317120090 dadfr
2025317120097 1613208672lilei-dotcom
2025317120099 wangbin98765432100-pixel
2025305110001 Mayshn
2025305120260 hzau-wujing
2025301110128 AetaosRauKeres
2025303110001 APFSDS-HE
2025303110002 159368qwe
2025303110003 Lzy-NICE
2025303110004 Lvshu118
2025303110005 abcdefg123803
2025303110006 2025303110006
2025303110007 justleap-amdd
2025303110008 Linyunyun123
2025303110009 Andy-95277259
2025303110010 tianjiayu-6
2025303110011 Qhaiyu777
2025303110012 winter0120
2025303110013 ChenYu-7317
2025303110014 1712203708-a11y
2025303110015 MFWWW
2025303110016 Zhang-JunH
2025303110017 kzdpgy
2025303110018 duyankun
2025303110019 JWenJing
2025303110020 taro-2026
2025303110021 FangYuan-Miao
2025303110022 chen11810
2025303110023 Liujunruo
2025303110024 jiaoliu425
2025303110025 wumingzhou1216
2025303110026 zhangyuxiang04
2025303110027 qinghuaZhang-prog
2025303110028 XuZQ-come
2025303110029 yijiashun08
2025303110030 caoyao-03
2025303110031 liming030523
2025303110032 lym7755
2025303110033 6622339
2025303110034 hanyu-Yang
2025303110035 YangMiaoSi
2025303110036 shuyan-yang326
2025303110037 Mei0416
2025303110038 yu-jiangjinag
2025303110039 Niu0306419
2025303110040 dilikelei01
2025303110041 luoqiuqiu123
2025303110042 ymr10
2025303110043 den-160
2025303110044 Ljy-cell429
2025303110045 Downey888
2025303110046 JiangYee393
2025303110047 Qin1310
2025303110048 HIMENO873
2025303110049 Leo-hub123
2025303110050 Liuqian615
2025303110051 LZT56
2025303110052 20WPL
2025303110053 zzzzz0928
2025303110054 Jiang-yu-yang
2025303110055 Swb123-star
2025303110056 Shiwen-Yue
2025303110057 ZZY-423
2025303110058 Qinova02
2025303110059 Xushining1220
2025303110060 AO-wj
2025303110061 flovar
2025303110062 cyx-coco
2025303110063 zlznevergu
2025303110064 Ban-bit
2025303110065 zhuxinglin8
2025303110066
2025303110067 LiBoFei1129
2025303110068 Yunhhhsheng
2025303110069 Yangjiahao1234
2025303110070 LLLLLinin
2025303110071 Dear-meng
2025303110072 Fuguiera11y
2025303110073 Wangchenyang321
2025303110074 KeV1n03
2025303110075 Zhao2002jun
2025303110076 zy076
2025303110077 guoyouyan391-maker
2025303110078 herb1124
2025303110079 ChenZhuo-hz
2025303110080 cx20263333333
2025303110081 cyz20030901
2025303110082 Hackysaw
2025303110083 yeelike
2025303110084 huangcan-1
2025303110085 HY-hyyyy
2025303110086 RenYuan916
2025303110087 xiangcaigongzhu999
2025303110088 nilongaixuexi66
2025303110089 liuhui0411
2025303110090 yooyoo2
2025303110091 ddjspx
2025303110092 Kongruyuan
2025303110093 jijiahui02
2025303110094 xihongshi2021
2025303110095 l110095
2025303110096 Britney-128
2025303110097 xueli9g
2025303110098 longxi112
2025303110099 BINGWANYANG
2025303110100 logicyyh
2025303110101 Bijiayu-yyds
2025303110102 1122333666jjj
2025303110103 Zukoin
2025303110104 c-duoduo
2025303110105 doujiayi-2025
2025303110106 zh-ang-jing
2025303110107 lll4123
2025303110108 chenyuhaobio
2025303110109 Doloressss770
2025303110110 q234-coder
2025303110111 haochen-co
2025303110112 Q110112
2025303110113 SHUZHIQI
2025303110114 dinglsnow
2025303110115 Dhjsmart
2025303110116 nicek4267-max
2025303110117 Yu-yuyuy
2025303110118 fza20030825-star
2025303110119 very6jia1
2025303110120 CANGSU-mei
2025303110121 XMZ183
2025303110122 cyxxx101
2025303110123 Rrhly
2025303110124 YYT0511
2025303110125 WZH-303110125
2025303110126 shiwanting0204
2025303110127 Zhu-123-er
2025303110128 helloworld2060
2025303110129 Hu-liye
2025303110130 JiangYida666
2025303110131 yunyuntiantian
2025303110132 star0421
2025303110133 Hankexinn
2025303110134 hcy20030822
2025303110135 LLLJY-ljy
2025303110136 zpq2003
2025303110137 xinyuzhu-lang
2025303110138 oufangfang1209
2025303110139 huanyu8
2025303110140 meilin090
2025303110141 hirasauayui
2025303110142 liyanfeng123
2025303110143 RalphBaejeongWong
2025303110144 chenbingyu-HZAU
2025303120001 welljie12138
2025303120002 renpeng-rp916
2025303120003 hewen717478
2025303120004 LingerYU
2025303120005 yuyuyu93764
2025303120008 Fish-star-liu
2025303120009 18135600866
2025303120010 lvye-maker
2025303120011 qiaoling-X
2025303120012 zxy189
2025303120013 Firezyyy
2025303120014 BILLDOU
2025303120015 Iris-ty193
2025303120017 hxm0123
2025303120018 shiyikai666
2025303120022 zj0022
2025303120023 zhangpuxian
2025303120024 cgcgtfy
2025303120025 xluug
2025303120026 aixfang-two
2025303120027 19839671980
2025303120029 ARSEN-4321
2025303120030 Lihn20030201
2025303120031 619890876-lgtm
2025303120033 oyang666
2025303120034 SHELLY203
2025303120036 tujunyi124
2025303120037 WJJ200212
2025303120038 Olivia-yao710
2025303120039 Jyyy12138
2025303120041 Wang-source-boop
2025303120042 HulThe-shuai
2025303120043 cvvcI
2025303120044 kskbl-CXY
2025303120045 Tziyu125
2025303120047 CYY386
2025303120052 Gao-Jinhua
2025303120055 Chenht111
2025303120059 cjd-alt
2025303120060 weiwe0829-creator
2025303120061 mazhihui-star
2025303120062 mamingwei2026
2025303120063 boyfriend-svg
2025303120064 YI-1005
2025303120065 Janney-huang
2025303120066 Maikexin
2025303120067 YR-yyy
2025303120069 yuqi-1209
2025303120070 hongyu929
2025303120071 houkunjun
2025303120072 Fu-cole
2025303120073 ly9495
2025303120074 Liuxinrui926
2025303120075 solitude879
2025303120076 yolo0-0
2025303120077 Liuxinya0801
2025303120078 Bao-cell
2025303120079 luWheeler
2025303120080 gudashuai6
2025303120081 2025WL
2025303120082 CishuiMoon
2025303120083 pidan431
2025303120084 tang7928
2025303120085 JZHEN03625
2025303120086 Jiesun-star
2025303120087 Mingyi-SUN
2025303120088 Mengyuxin224
2025303120089 erwin214
2025303120090 Ahatm
2025303120091 Cuiys123
2025303120092 hzauShixin
2025303120093 niun8108-boop
2025303120094 KANGJINGWEN0803
2025303120095 Zhang-ym-ing
2025303120096 zhixuan-zhang767
2025303120097 zry0309
2025303120098 ningdanzhang
2025303120099 ZHGlory
2025303120100 111222333xxxx
2025303120101 20260305
2025303120102 wenyujia2003
2025303120103 DragonBron23
2025303120104 EIO-lyr
2025303120105 lijj2K
2025303120106 lirumeng-mary
2025303120107 haoqi159
2025303120108 LQY123-Sketch
2025303120109 zhiyuanli-beep
2025303120110 li20010229-eng
2025303120111 kajolliangeliki857-cpu
2025303120112 DUYongqi0116
2025303120113 yanggang-0304
2025303120114 LGQ559492
2025303120115 dlliang2026
2025303120116 shi-mlml
2025303120117 omo-rlaith
2025303120118 wovej
2025303120119 laopyoutiao
2025303120120 2160698686-ship-it
2025303120121 yuting-Mu
2025303120122 Tuyuhan
2025303120123 yb9966
2025303120124 tzy311
2025303120125 JIAOjiao0504
2025303120126 xyj666357
2025303120127 niuideal
2025303120128 30-niu
2025303120129 wblai
2025303120130 okbk130
2025303120131 WANGSpecial
2025303120132 wangxuan24
2025303120134 WYR1016
2025303120135 KINGWINM
2025303120136 shengxian9277
2025303120137 nie-3
2025303120138 Neflibata0627
2025303120139 geyuqing3-stack
2025303120140 dj4296
2025303120141 MHFDH
2025303120142 cuut123
2025303120143 Ccwwjia-032
2025303120144 yaya2026
2025303120145 wudan-06
2025303120146 yunokaaa
2025303120147 zcguksjv65
2025303120148 zhengdispecial
2025303120149 Abudula-Aizezi
2025303120150 GS-Liang
2025303120151 yftao0106-droid
2025303120152 Jneey-add
2025303120153 xiaozz-zl
2025303120154 GuXiang0730
2025303120155 unique520521
2025303120156 geiut
2025303120157 gaoxinling
2025303120158 Ray111-Arch
2025303120159 DYRRRRUI
2025303120160 Xczx1000
2025303120161 FYY0130
2025303120162 broucemonkey-stack
2025303120163 Xing0630
2025303120164 lll-liwen
2025303120165 zhoushige666-crypto
2025303120166 SuperXi-9
2025303120167 SCD1106
2025303120169 nanlingZXY
2025303120170 lsh1221
2025303120171 lcx920
2025303120172 Lc898
2025303120173 cito37
2025303120174 shenwenjun111
2025303120175 mustiheng
2025303120176 Gladsxzhou
2025303120177 dongshuai9331
2025303120178 yisar
2025303120179 zhengzhenghuhuhu
2025303120180 CXWYWG
2025303120181 winn-coder
2025303120182 JieHan369
2025303120183 hzs12
2025303121001 lyh-2025
2025303121002 Luxiaolu330

未完成任何作业的学生

显示/隐藏代码
no_hw <- result |>
  filter(完成数 == 0) |>
  select(学号, 姓名, 学院)

if (nrow(no_hw) > 0) {
  cat("共有", nrow(no_hw), "名学生未完成任何作业:\n")
  kable(no_hw, caption = "未完成任何作业的学生")
} else {
  cat("所有学生都至少完成了一项作业 🎉\n")
}
共有 1 名学生未完成任何作业:
未完成任何作业的学生
学号 姓名 学院
2025303110066 李健萍 资源与环境学院

按学院统计

显示/隐藏代码
college_stats <- result |>
  group_by(学院) |>
  summarise(
    学生数 = n(),
    作业1 = sum(作业1_入学报到),
    作业2 = sum(作业2_模型性能),
    作业3 = sum(作业3_练习协作),
    作业4 = sum(作业4_我的主页),
    作业5 = sum(作业5_计划项目),
    平均完成数 = round(mean(完成数), 1),
    .groups = "drop"
  ) |>
  arrange(desc(平均完成数))

kable(college_stats, caption = "按学院统计作业完成情况")
按学院统计作业完成情况
学院 学生数 作业1 作业2 作业3 作业4 作业5 平均完成数
信息学院 3 3 3 3 3 3 5.0
园艺林学学院 2 2 2 2 2 2 5.0
资源与环境学院 306 305 301 297 275 272 4.7
植物科学技术学院 1 1 1 1 1 0 4.0