下学期的排课选课表!

下学期的排课选课表!

每学期第二轮选课结束之后就要把教务处里面的排课选课表爬爬。再加上好久没有用Stata了,再练练手。

爬取

爬取代码简单、稳定耐用,可以参考这篇推文:暨南大学教务处排课选课表爬取

这里是我从教务处复制的待处理代码:

暨南大学2019年春排课选课表.html

Stata
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
clear all
copy 暨南大学2019年春排课选课表.html paikexuanke.csv, replace
utrans paikexuanke.csv
insheet using paikexuanke.csv, clear
tostring v8 v10 v11 v12 v14, replace
replace v1 = v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11 + v12 + v13 + v14 + v15
drop v2-v15
keep if index(v1, "<td>") | index(v1, "</span>")
drop in 1/10
replace v1 = subinstr(v1, " ", "", .)
split v1, parse(</td><td>)
drop v1
compress
drop if v11 == "....." & v12 == ""
drop v18
gen 上课地点 = ""
gen 上课时间 = ""
gen 排课班号 = ""
gen 招生对象 = ""
gen 考试日期 = ""
gen 考试时间 = ""
gen 备注 = ""
gen 方式 = ""
forval i = 1/`=_N'{
if index(v11[`i'], "<td>") & index(v11[`i'+4], "<td>"){
replace 上课地点 = v11[`i'+1] if _n == `i'
replace 上课时间 = v11[`i'+2] if _n == `i'
replace 排课班号 = v12[`i'+3] if _n == `i'
replace 招生对象 = v13[`i'+3] if _n == `i'
replace 考试日期 = v14[`i'+3] if _n == `i'
replace 备注 = v15[`i'+3] if _n == `i'
replace 方式 = v16[`i'+3] if _n == `i'
}
if index(v11[`i'], "<td>") & index(v11[`i'+5], "<td>"){
replace 上课地点 = v11[`i'+1] if _n == `i'
replace 上课时间 = v11[`i'+2] if _n == `i'
replace 排课班号 = v12[`i'+3] if _n == `i'
replace 招生对象 = v13[`i'+3] if _n == `i'
replace 考试日期 = v14[`i'+3] if _n == `i'
replace 考试时间 = v11[`i'+4] if _n == `i'
replace 备注 = v12[`i'+4] if _n == `i'
replace 方式 = v13[`i'+4] if _n == `i'
}
}
drop if v17 == ""
replace v11 = subinstr(v11, "<td>", "", .)
replace 上课地点 = ustrregexs(1) if ustrregexm(上课地点, ">(.*)<")
replace 上课时间 = ustrregexs(1) if ustrregexm(上课时间, ">(.*)<")
foreach i of varlist _all{
replace `i' = "" if `i' == "&nbsp;"
format `i' %15s
replace `i' = subinstr(`i', "<td>", "", .)
replace `i' = subinstr(`i', "</td>", "", .)
replace `i' = subinstr(`i', "南校区教学楼", "", .)
replace `i' = subinstr(`i', "南校区", "", .)
}
destring v13 v14 v17, replace
rename v11 课程编号
rename v12 课程名称
rename v13 排课限制
rename v14 选课人数
rename v15 主讲教师
rename v16 专业名称
rename v17 学分
format 学分 %2.1f
gen date = date(考试日期, "YMD")
format date %dCY-N-D
drop 考试日期
rename date 考试日期
replace 方式 = subinstr(方式, ".....", "", .)
format 考试时间 %15s
destring, replace
save 2019a排课选课表, replace

同样我把整理结果放在这里供大家下载:2019a排课选课表.dta

下面进行一些有意思的分析:

选课/排课比

Stata
1
2
3
4
5
6
7
8
use 2019a排课选课表, clear
gen ratio = 选课人数/排课限制 * 100
format ratio %6.0f
tw ///
hist ratio, xti("选课人数/排课限制") yti("频率") ///
bc(red * 0.6) ti("2019年春 暨大排课选课比率分布", size(*1.2)) ///
subti(排课选课比 = 选课人数 / 排课限制) ///
caption("数据来源:暨南大学教务处" "https://jwxt.jnu.edu.cn/")

可以看到,有七成的课都已经选满了,没选到课的同学基本可以死心了。

内外招开课数量

Stata
1
2
3
4
5
6
7
8
9
10
11
12
13
use 2019a排课选课表, clear
contract 招生对象
encode 招生对象, generate(cat) label(招生对象)
gr pie _freq, over(cat) missing ///
pie(1, color(red*0.6)) ///
pie(2, color(blue*0.6)) ///
pie(3, color(green*0.6)) ///
leg(order(1 "内招生" 2 "外招生" 3 "内外招") pos(6) row(1)) ///
ti("内外招开课数量对比", size(*1.2)) ///
subti("在我们学校,内招生不能选外招生的课,除非是内外招共同开的课。同样外招生也一样。", size(*0.8)) ///
caption("数据来源:暨南大学教务处" "https://jwxt.jnu.edu.cn/", size(*0.7) pos(5)) ///
plotr(margin(large)) ///
graphr(margin(large))

可以看到,虽然内招生的课程数量远远多于外招生。不过好像我们学校的外招生数量多于内招生的。

考试的方式对比

Stata
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use 2019a排课选课表, clear
encode 方式, gen(testway) label(方式)
colorscheme 8, palette(Set2) display
ret list
gr pie, over(testway) missing ///
pie(1, color(`r(color1)')) ///
pie(2, color(`r(color2)')) ///
pie(3, color(`r(color3)')) ///
pie(4, color(`r(color4)')) ///
pie(5, color(`r(color5)')) ///
leg(order(1 "开卷" 2 "笔试" 3 "论文" 4 "闭卷" 5 "未定") ///
pos(6) row(1)) ///
ti("考试方式的分布", size(*1.2)) ///
subti("笔试一般默认为闭卷", size(*0.8)) ///
caption("数据来源:暨南大学教务处" "https://jwxt.jnu.edu.cn/", size(*0.7) pos(5)) ///
plotr(margin(large)) ///
graphr(margin(medium))

colorscheme的配色方案也是来自于:ColorBrewer: Color Advice for Maps,是一个非常好的配色命令。具体使用可以参考这篇推文:colorscheme——调色选色命令

课程的星期分布

这个的处理就比较复杂了:

Stata
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use 2019a排课选课表, clear
keep 课程名称 选课人数 上课时间
split 上课时间, parse(; ② ③ ④)
ret list
foreach i in `r(varlist)'{
replace `i' = subinstr(`i', "单周", "", .)
replace `i' = subinstr(`i', "双周", "", .)
replace `i' = ustrregexs(0) if ustrregexm(`i', "周(.*)-")
replace `i' = subinstr(`i', "-", "", .)
replace `i' = subinstr(`i', "周周", "周", .)
}
drop 上课时间
compress

* 把几个上课时间合并起来
expand 6
gsort 课程名称
forval i = 1(6)`=_N'{
forval j = 1/6{
local n = `i' + `j' - 1
local m = `n' + 5
replace 上课时间`j' = "" if (_n != `n' & inrange(_n, `n', `m'))
}
}

gen 上课时间 = 上课时间1 + ///
上课时间2 + ///
上课时间3 + ///
上课时间4 + ///
上课时间5 + ///
上课时间6

drop if 上课时间 == ""
keep 课程名称 选课人数 上课时间
drop if 选课人数 == .

format 课程名称 %20s
format 上课时间 %10s
tab 上课时间
* 可以看到数据已经被整理好了。
gsort 上课时间
save 课程的星期分布, replace

use 课程的星期分布, clear
contract 上课时间
gen week = .
replace week = 1 if 上课时间 == "周一"
replace week = 3 if 上课时间 == "周三"
replace week = 2 if 上课时间 == "周二"
replace week = 3 if 上课时间 == "周五"
replace week = 6 if 上课时间 == "周六"
replace week = 4 if 上课时间 == "周四"
replace week = 7 if 上课时间 == "周日"
gsort week
encode 上课时间, gen(weekday) label(上课时间)

gr tw bar _freq weekday, ///
xlab(1(1)7, val) ///
xti("") yti("课程数") ///
ti("暨南大学2019年春课程的星期分布") ///
subti("程振兴") ///
caption("数据来源:暨南大学教务处" "https://jwxt.jnu.edu.cn/", size(*0.7) pos(5)) ///
plotr(margin(large)) ///
graphr(margin(medium))

由于上课时间很复杂,所以我是先分割,然后拓展数据集,再删除部分+合并,这样实际上是实现了宽数据->长数据的转换。

课程和人数的分布

最后再看课程和人数的分布:

Stata
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use 课程的星期分布, clear
* 使用expgen命令按照选课人数变量扩展数据集
* net install expgen.pkg, from("http://fmwww.bc.edu/RePEc/bocode/e/")
expgen nreps = 选课人数, copy(repseq) order
* 这么一来生成的就是上课的人数了:
contract 上课时间
gen week = .
replace week = 1 if 上课时间 == "周一"
replace week = 3 if 上课时间 == "周三"
replace week = 2 if 上课时间 == "周二"
replace week = 3 if 上课时间 == "周五"
replace week = 6 if 上课时间 == "周六"
replace week = 4 if 上课时间 == "周四"
replace week = 7 if 上课时间 == "周日"
gsort week
encode 上课时间, gen(weekday) label(上课时间)

gr tw bar _freq weekday, ///
xlab(1(1)7, val) ///
xti("") yti("上课人数") ///
ti("暨南大学2019年春上课人数的星期分布") ///
subti("程振兴") ///
caption("数据来源:暨南大学教务处" "https://jwxt.jnu.edu.cn/", size(*0.7) pos(5)) ///
plotr(margin(large)) ///
graphr(margin(medium))

这个数据的处理也极具技巧性,这里我是先把数据集按照选课人数变量进行拓展,然后再分组汇总,这样就得到了每天的上课人数。

周二上课的人数高达5万人呢!

其它

其实最有趣的分析要算统计每天每节课的上课人数了,不过比较麻烦,以前我是做的,现在懒得做了。具体可以参考这篇推文:暨南大学教务处排课选课表爬取

# Stata

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×