-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathPassRate.jl
146 lines (128 loc) · 5.32 KB
/
PassRate.jl
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# Predicts whether a student will pass a course using the course's passrate
# as a probability.
module PassRate
# Train the model
function train(degree_plan)
for course in degree_plan.curriculum.courses
model = Dict()
model[:passrate] = course.passrate
course.metadata["model"]= model
end
degree_plan.metadata["stopout_model"][:rates] = [0.0838, 0.1334, 0.0465, 0.0631, 0.0368, 0.0189, 0.0165] * 100
end
# Predict grade
function predict_grade(course, student)
roll = rand()
if roll <= course.metadata["model"][:passrate]
return 4.0
else
return 0.0
end
end
# Predict stopout
function predict_stopout(student, current_term, model)
if current_term > 7
return false
else
roll = rand(1:100)
return roll <= model[:rates][current_term]
end
end
end
# Sets all course model passrates to given value
function set_passrates(courses, passrate)
for course in courses
course.passrate = passrate
end
end
# Read from a CSV file that contains all courses taken by all students of a certain academic period
# Compute and set the pass rates for given courses based on the student performance in the file
# If a course is not found, set its pass rate to a preset value
# If a course is presented as a requirement (a set of courses), use the average pass rate of the set
# Note: Only support Tier I General Education for now
function set_passrates_from_csv(courses, csv_path, pass_rate)
university_course_table = CSV.File(csv_path, delim = ',', silencewarnings = true) |> DataFrame
passing_grades = ["A", "B", "C", "D", "P"]
all_grades = ["A", "B", "C", "D", "P", "W", "F", "E", "S", "WS"]
for course in courses
prefix = string(strip(course.prefix))
num = string(strip(course.num))
# Compute the number of student passed the course, and number of student took the course
num_passes = nrow(filter(row -> passrate_filter(row, prefix, num, passing_grades), university_course_table))
num_students_taken = nrow(filter(row -> passrate_filter(row, prefix, num, all_grades), university_course_table))
# The course is not found in the course table
if (num_students_taken == 0)
# The course is in a Tier I General Education, then use the average pass rate of them
if (prefix == "" && num == "" && occursin("Tier I", course.name))
course_passrate, num_passes, num_students_taken = get_gen_tier_I_passrate(university_course_table, ["150", "160"], passing_grades, all_grades, pass_rate)
course.passrate = course_passrate
else
course.passrate = pass_rate # Hard code the rest of the course to a preset value for now
end
else
course.passrate = num_passes / num_students_taken # Computer the course pass rate
end
course.metadata["num_students_taken"] = num_students_taken
course.metadata["num_students_passes"] = num_passes
end
end
# Compute the average pass rate of Tier I General Education of given numbers
function get_gen_tier_I_passrate(university_course_table, nums, passing_grades, all_grades, pass_rate)
# Compute the number of student passed the course, and number of student took the course
num_passes = nrow(filter(row -> passrate_filter(row, nums, passing_grades), university_course_table))
num_students_taken = nrow(filter(row -> passrate_filter(row, nums, all_grades), university_course_table))
if (num_students_taken == 0)
return pass_rate, 0, 0
else
return num_passes / num_students_taken, num_passes, num_students_taken
end
end
# A course prefix, course number based filter.
# The function returns true if the course taken by the student has the given prefix, number, and is in the grade range
function passrate_filter(row, prefix, num, grades)
if row[:course_prefix] == prefix && row[:course_num] == num
for grade in grades
if row[:grade] == grade
return true
end
end
end
return false
end
# A course number based filter.
# The function returns true if the number of course taken by the student contains the given number, and is in the grade range
function passrate_filter(row, nums, grades)
if start_with_nums(row[:course_num], nums)
for grade in grades
if row[:grade] == grade
return true
end
end
end
return false
end
# Help function
function start_with_nums(str, nums)
for num in nums
if startswith(str, num)
return true
end
end
return false
end
# Set passrate for a given course
function set_passrate_for_course(course::Course, passrate::Float64)
course.passrate = passrate
end
# set passrate based on given course prefix and number
function set_passrate_for_course(degree_plan::DegreePlan, course_prefix::AbstractString, course_num::AbstractString, passrate::Float64)
courses = degree_plan.curriculum.courses
course_found = false
for course in courses
if course.prefix == course_prefix && course.num == course_num
course.passrate = passrate
course_found = true
end
end
return course_found
end