Modify score calculations. Ignore any survey item scores of 0.

Never include zero when performing calculations for scores.
pull/1/head
Nelson Jovel 4 years ago
parent 0e85370b90
commit c475744939

@ -50,20 +50,17 @@ class Measure < ActiveRecord::Base
meets_student_threshold = sufficient_student_data?(school:, academic_year:) meets_student_threshold = sufficient_student_data?(school:, academic_year:)
meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:) meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:)
meets_admin_data_threshold = all_admin_data_collected?(school:, academic_year:) meets_admin_data_threshold = all_admin_data_collected?(school:, academic_year:)
lacks_sufficient_data = !meets_student_threshold && !meets_teacher_threshold && !includes_admin_data_items? lacks_sufficient_survey_data = !meets_student_threshold && !meets_teacher_threshold
incalculable_score = lacks_sufficient_survey_data && !includes_admin_data_items?
next Score.new(nil, false, false, false) if lacks_sufficient_data next Score.new(nil, false, false, false) if incalculable_score
scores = [] scores = []
scores << teacher_scales.map { |scale| scale.score(school:, academic_year:) }.average if meets_teacher_threshold scores << collect_survey_scale_average(teacher_scales, school, academic_year) if meets_teacher_threshold
scores << student_scales.map { |scale| scale.score(school:, academic_year:) }.average if meets_student_threshold scores << collect_survey_scale_average(student_scales, school, academic_year) if meets_student_threshold
if includes_admin_data_items? scores << collect_admin_scale_average(admin_data_items, school, academic_year) if includes_admin_data_items?
scores << admin_data_items.map do |admin_data_item|
admin_value = admin_data_item.admin_data_values.where(school:, academic_year:).first average = scores.flatten.compact.remove_zeros.average
admin_value.likert_score if admin_value.present?
end
end
average = scores.flatten.compact.average
next Score.new(nil, false, false, false) if average.nan? next Score.new(nil, false, false, false) if average.nan?
@ -122,6 +119,17 @@ class Measure < ActiveRecord::Base
private private
def collect_survey_scale_average(scales, school, academic_year)
scales.map { |scale| scale.score(school:, academic_year:) }.average
end
def collect_admin_scale_average(scales, school, academic_year)
scales.map do |admin_data_item|
admin_value = admin_data_item.admin_data_values.where(school:, academic_year:).first
admin_value.likert_score if admin_value.present?
end
end
def benchmark(name) def benchmark(name)
averages = [] averages = []
averages << student_survey_items.first.send(name) if includes_student_survey_items? averages << student_survey_items.first.send(name) if includes_student_survey_items?

@ -8,12 +8,10 @@ class Scale < ApplicationRecord
@score ||= Hash.new do |memo| @score ||= Hash.new do |memo|
memo[[school, academic_year]] = begin memo[[school, academic_year]] = begin
items = [] items = []
items << student_survey_items(school:, academic_year:) items << collect_survey_item_average(student_survey_items(school:, academic_year:), school, academic_year)
items << teacher_survey_items items << collect_survey_item_average(teacher_survey_items, school, academic_year)
items.flatten.map do |survey_item| items.remove_zeros.average
survey_item.score(school:, academic_year:)
end.average
end end
end end
@score[[school, academic_year]] @score[[school, academic_year]]
@ -28,6 +26,12 @@ class Scale < ApplicationRecord
private private
def collect_survey_item_average(survey_items, school, academic_year)
survey_items.map do |survey_item|
survey_item.score(school:, academic_year:)
end.remove_zeros.average
end
def teacher_survey_items def teacher_survey_items
survey_items.teacher_survey_items survey_items.teacher_survey_items
end end

@ -2,6 +2,10 @@ module ArrayMonkeyPatches
def average def average
sum.to_f / size sum.to_f / size
end end
def remove_zeros
reject { |item| item == 0 || item.to_f.nan? }
end
end end
Array.include ArrayMonkeyPatches Array.include ArrayMonkeyPatches

@ -0,0 +1,19 @@
# Decision record 9
# Modify score calculations so that a survey item score of 0 is never included in the average
## Status
Completed
## Context
Some scores were artificially low because survey items that lacked survey item responses returned a score of 0. 0 did not represent the average likert_scores of survey item responses, only the lack of responses. 0 was incorrectly being averaged with other survey items and artificially dragging down the score.
## Decision
Survey item scores of 0 should be ignored and filtered out when performing score calculations.
## Consequences
Some average scores have increased.

@ -12,32 +12,64 @@ RSpec.describe Scale, type: :model do
let(:teacher_survey_item_1) { create(:teacher_survey_item, scale:) } let(:teacher_survey_item_1) { create(:teacher_survey_item, scale:) }
let(:teacher_survey_item_2) { create(:teacher_survey_item, scale:) } let(:teacher_survey_item_2) { create(:teacher_survey_item, scale:) }
let(:teacher_survey_item_3) { create(:teacher_survey_item, scale:) } let(:teacher_survey_item_3) { create(:teacher_survey_item, scale:) }
let(:student_survey_item_1) { create(:student_survey_item, scale:) }
before :each do context 'when only teacher survey items exist' do
before :each do
create(:survey_item_response,
survey_item: teacher_survey_item_1, academic_year:, school:, likert_score: 3)
create(:survey_item_response,
survey_item: teacher_survey_item_2, academic_year:, school:, likert_score: 4)
create(:survey_item_response,
survey_item: teacher_survey_item_3, academic_year:, school:, likert_score: 5)
end
it 'returns the average of the likert scores of the survey items' do
expect(scale.score(school:, academic_year:)).to eq 4
end
context 'when other scales exist' do
before :each do
create(:survey_item_response,
academic_year:, school:, likert_score: 1)
create(:survey_item_response,
academic_year:, school:, likert_score: 1)
create(:survey_item_response,
academic_year:, school:, likert_score: 1)
end
it 'does not affect the score for the original scale' do
expect(scale.score(school:, academic_year:)).to eq 4
end
end
end
context 'when both teacher and student survey items exist' do
before :each do
create(:survey_item_response, create(:survey_item_response,
survey_item: teacher_survey_item_1, academic_year:, school:, likert_score: 3) survey_item: teacher_survey_item_1, academic_year:, school:, likert_score: 3)
create(:survey_item_response, create(:survey_item_response,
survey_item: teacher_survey_item_2, academic_year:, school:, likert_score: 4) survey_item: teacher_survey_item_2, academic_year:, school:, likert_score: 4)
create(:survey_item_response, create(:survey_item_response,
survey_item: teacher_survey_item_3, academic_year:, school:, likert_score: 5) survey_item: teacher_survey_item_3, academic_year:, school:, likert_score: 5)
end end
context 'but no survey item responses are linked to student survey items' do
it 'returns the average of the likert scores of the survey items' do before :each do
expect(scale.score(school:, academic_year:)).to eq 4 student_survey_item_1
end end
context 'when other scales exist' do it 'returns a score that only averages teacher survey items' do
before :each do expect(scale.score(school:, academic_year:)).to eq 4
create(:survey_item_response, end
academic_year:, school:, likert_score: 1)
create(:survey_item_response,
academic_year:, school:, likert_score: 1)
create(:survey_item_response,
academic_year:, school:, likert_score: 1)
end end
it 'does not affect the score for the original scale' do context 'and some survey item responses exist for a student survey item' do
expect(scale.score(school:, academic_year:)).to eq 4 before :each do
create(:survey_item_response,
survey_item: student_survey_item_1, academic_year:, school:, likert_score: 2)
end
it 'returns a score that gives equal weight to student and teacher survey items' do
expect(scale.score(school:, academic_year:)).to eq 3
end
end end
end end
end end

Loading…
Cancel
Save