MDL-32188 question CBM: alter score handling.

We now change so that minfraction is -6 and maxfraction is 3, so getting
the question right a low certainty gives maxmark marks, and you get a
bonus for being more confident (rather than being penalised for being
unconfident). Mathematically it is the same, but the difference is
importnat psychologically.

We also change how partially correct scores are handled.
It is too harsh to penalise a partially correct score with full
certainty by doing a linear interpolation between -6 and +3. Instead,
any partially correct score (e.g. 0.5) becomes that fraction of the
correct score (e.g. 0.5 * 3 = 1.5). Also, any incorrect score is treated
as 0, so if you have a multiple choice question that normally gives a
negative score for a wrong choice, this will now never give a score of
less than -6.

Finally we change how this is displayed to students beside the question.
Rather than saying "Marked out of 1.00", we say "Base mark 1.00", and
then later we say "CBM mark 3.00" (or whatever it is).
This commit is contained in:
Tim Hunt 2013-10-02 17:33:14 +01:00
parent 7ab9ce3a3c
commit fb74929e97
9 changed files with 167 additions and 87 deletions

View File

@ -643,16 +643,16 @@ abstract class question_cbm {
/** @var array list of all the certainty levels. */
public static $certainties = array(self::LOW, self::MED, self::HIGH);
/**#@+ @var array coefficients used to adjust the fraction based on certainty.. */
protected static $factor = array(
self::LOW => 0.333333333333333,
self::MED => 1.333333333333333,
/**#@+ @var array coefficients used to adjust the fraction based on certainty. */
protected static $rightscore = array(
self::LOW => 1,
self::MED => 2,
self::HIGH => 3,
);
protected static $offset = array(
self::LOW => 0,
self::MED => -0.666666666666667,
self::HIGH => -2,
protected static $wrongscore = array(
self::LOW => 0,
self::MED => -2,
self::HIGH => -6,
);
/**#@-*/
@ -671,7 +671,11 @@ abstract class question_cbm {
* @return number the adjusted fraction taking the certainty into account.
*/
public static function adjust_fraction($fraction, $certainty) {
return self::$offset[$certainty] + self::$factor[$certainty] * $fraction;
if ($fraction <= 0.00000005) {
return self::$wrongscore[$certainty];
} else {
return self::$rightscore[$certainty] * $fraction;
}
}
/**

View File

@ -46,11 +46,11 @@ class qbehaviour_deferredcbm extends qbehaviour_deferredfeedback {
const IS_ARCHETYPAL = true;
public function get_min_fraction() {
return question_cbm::adjust_fraction(parent::get_min_fraction(), question_cbm::HIGH);
return question_cbm::adjust_fraction(0, question_cbm::HIGH);
}
public function get_max_fraction() {
return question_cbm::adjust_fraction(parent::get_max_fraction(), question_cbm::HIGH);
return question_cbm::adjust_fraction(1, question_cbm::HIGH);
}
public function get_expected_data() {

View File

@ -24,9 +24,10 @@
*/
$string['assumingcertainty'] = 'You did not select a certainty. Assuming: {$a}.';
$string['basemark'] = 'Base mark {$a}';
$string['cbmmark'] = 'CBM mark {$a}';
$string['certainty1'] = 'Not very (less than 67%)';
$string['certainty2'] = 'Fairly (more than 67%)';
$string['certainty3'] = 'Very (more than 80%)';
$string['howcertainareyou'] = 'How certain are you? {$a}';
$string['markadjustment'] = 'Based on the certainty you expressed, your base mark of {$a->rawmark} was adjusted to {$a->mark}.';
$string['pluginname'] = 'Deferred feedback with CBM';

View File

@ -87,15 +87,18 @@ class qbehaviour_deferredcbm_renderer extends qbehaviour_renderer {
question_cbm::get_string($qa->get_last_behaviour_var('_assumedcertainty'))));
}
if ($options->marks >= question_display_options::MARK_AND_MAX) {
$a = new stdClass();
$a->rawmark = format_float($qa->get_last_behaviour_var('_rawfraction') *
$qa->get_max_mark(), $options->markdp);
$a->mark = $qa->format_mark($options->markdp);
$feedback .= html_writer::tag('p',
get_string('markadjustment', 'qbehaviour_deferredcbm', $a));
}
return $feedback;
}
public function marked_out_of_max(question_attempt $qa, core_question_renderer $qoutput,
question_display_options $options) {
return get_string('basemark', 'qbehaviour_deferredcbm', $qa->format_fraction_as_mark(
question_cbm::adjust_fraction(1, question_cbm::default_certainty()),
$options->markdp));
}
public function mark_out_of_max(question_attempt $qa, core_question_renderer $qoutput,
question_display_options $options) {
return get_string('cbmmark', 'qbehaviour_deferredcbm', $qa->format_mark($options->markdp));
}
}

View File

@ -0,0 +1,64 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains tests that walks a question through the deferred feedback
* with certainty base marking behaviour.
*
* @package qbehaviour
* @subpackage deferredcbm
* @copyright 2009 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once(dirname(__FILE__) . '/../../../engine/lib.php');
require_once(dirname(__FILE__) . '/../../../engine/tests/helpers.php');
/**
* Unit tests for the deferred feedback with certainty base marking behaviour.
*
* @copyright 2009 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_deferredcbm_type_test extends qbehaviour_walkthrough_test_base {
/** @var qbehaviour_deferredcbm_type */
protected $behaviourtype;
public function setUp() {
parent::setUp();
$this->behaviourtype = question_engine::get_behaviour_type('deferredcbm');
}
public function test_is_archetypal() {
$this->assertTrue($this->behaviourtype->is_archetypal());
}
public function test_get_unused_display_options() {
$this->assertEquals(array('correctness', 'marks', 'specificfeedback', 'generalfeedback', 'rightanswer'),
$this->behaviourtype->get_unused_display_options());
}
public function test_adjust_random_guess_score() {
$this->assertEquals(0, $this->behaviourtype->adjust_random_guess_score(0));
$this->assertEquals(1, $this->behaviourtype->adjust_random_guess_score(1));
}
}

View File

@ -0,0 +1,56 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains tests that walks a question through the deferred feedback
* with certainty base marking behaviour.
*
* @package qbehaviour
* @subpackage deferredcbm
* @copyright 2009 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once(dirname(__FILE__) . '/../../../engine/lib.php');
/**
* Unit tests for the deferred feedback with certainty base marking behaviour.
*
* @copyright 2009 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_deferredcbm_cbm_test extends basic_testcase {
public function test_adjust_fraction() {
$this->assertEquals( 1, question_cbm::adjust_fraction( 1, question_cbm::LOW), '', 0.0000001);
$this->assertEquals( 2, question_cbm::adjust_fraction( 1, question_cbm::MED), '', 0.0000001);
$this->assertEquals( 3, question_cbm::adjust_fraction( 1, question_cbm::HIGH), '', 0.0000001);
$this->assertEquals( 0, question_cbm::adjust_fraction( 0, question_cbm::LOW), '', 0.0000001);
$this->assertEquals(-2, question_cbm::adjust_fraction( 0, question_cbm::MED), '', 0.0000001);
$this->assertEquals(-6, question_cbm::adjust_fraction( 0, question_cbm::HIGH), '', 0.0000001);
$this->assertEquals( 0.5, question_cbm::adjust_fraction( 0.5, question_cbm::LOW), '', 0.0000001);
$this->assertEquals( 1, question_cbm::adjust_fraction( 0.5, question_cbm::MED), '', 0.0000001);
$this->assertEquals( 1.5, question_cbm::adjust_fraction( 0.5, question_cbm::HIGH), '', 0.0000001);
$this->assertEquals( 0, question_cbm::adjust_fraction(-0.25, question_cbm::LOW), '', 0.0000001);
$this->assertEquals(-2, question_cbm::adjust_fraction(-0.25, question_cbm::MED), '', 0.0000001);
$this->assertEquals(-6, question_cbm::adjust_fraction(-0.25, question_cbm::HIGH), '', 0.0000001);
}
}

View File

@ -90,18 +90,18 @@ class qbehaviour_deferredcbm_walkthrough_test extends qbehaviour_walkthrough_tes
// Verify.
$this->check_current_state(question_state::$gradedright);
$this->check_current_mark(2);
$this->check_current_mark(6);
$this->check_current_output(
$this->get_contains_tf_true_radio_expectation(false, true),
$this->get_contains_cbm_radio_expectation(3, false, true),
$this->get_contains_correct_expectation());
// Process a manual comment.
$this->manual_grade('Not good enough!', 1, FORMAT_HTML);
$this->manual_grade('Not good enough!', 5, FORMAT_HTML);
// Verify.
$this->check_current_state(question_state::$mangrpartial);
$this->check_current_mark(1);
$this->check_current_state(question_state::$mangrright);
$this->check_current_mark(5);
$this->check_current_output(new question_pattern_expectation('/' .
preg_quote('Not good enough!', '/') . '/'));
@ -110,10 +110,10 @@ class qbehaviour_deferredcbm_walkthrough_test extends qbehaviour_walkthrough_tes
$this->quba->regrade_all_questions();
// Verify.
$this->check_current_state(question_state::$mangrpartial);
$this->check_current_mark(1);
$this->check_current_state(question_state::$mangrright);
$this->check_current_mark(5);
$autogradedstep = $this->get_step($this->get_step_count() - 2);
$this->assertEquals($autogradedstep->get_fraction(), -2, '', 0.0000001);
$this->assertEquals(-6, $autogradedstep->get_fraction(), '', 0.0000001);
}
public function test_deferred_cbm_truefalse_low_certainty() {
@ -147,7 +147,7 @@ class qbehaviour_deferredcbm_walkthrough_test extends qbehaviour_walkthrough_tes
// Verify.
$this->check_current_state(question_state::$gradedright);
$this->check_current_mark(0.6666667);
$this->check_current_mark(2);
$this->check_current_output($this->get_contains_correct_expectation(),
$this->get_contains_cbm_radio_expectation(1, false, true));
$this->assertEquals(get_string('true', 'qtype_truefalse') . ' [' .
@ -177,7 +177,7 @@ class qbehaviour_deferredcbm_walkthrough_test extends qbehaviour_walkthrough_tes
// Verify.
$qa = $this->quba->get_question_attempt($this->slot);
$this->check_current_state(question_state::$gradedright);
$this->check_current_mark(0.6666667);
$this->check_current_mark(2);
$this->check_current_output($this->get_contains_correct_expectation(),
$this->get_contains_cbm_radio_expectation(1, false, false),
new question_pattern_expectation('/' . preg_quote(
@ -194,7 +194,7 @@ class qbehaviour_deferredcbm_walkthrough_test extends qbehaviour_walkthrough_tes
$mc = test_question_maker::make_a_multichoice_single_question();
// Attempt it getting it wrong.
$this->start_attempt_at_question($mc, 'deferredcbm', 3);
$this->start_attempt_at_question($mc, 'deferredcbm', 1);
$rightindex = $this->get_mc_right_answer_index($mc);
$wrongindex = ($rightindex + 1) % 3;
$this->process_submission(array('answer' => $wrongindex, '-certainty' => 2));
@ -202,7 +202,7 @@ class qbehaviour_deferredcbm_walkthrough_test extends qbehaviour_walkthrough_tes
// Verify.
$this->check_current_state(question_state::$gradedwrong);
$this->check_current_mark(-3.3333333);
$this->check_current_mark(-2);
$this->check_current_output(
$this->get_contains_mc_radio_expectation($wrongindex, false, true),
$this->get_contains_cbm_radio_expectation(2, false, true),
@ -220,7 +220,7 @@ class qbehaviour_deferredcbm_walkthrough_test extends qbehaviour_walkthrough_tes
// Reinitialise.
$this->setUp();
$this->quba->set_preferred_behaviour('deferredcbm');
$this->slot = $this->quba->add_question($mc, 3);
$this->slot = $this->quba->add_question($mc, 1);
$this->quba->start_question_based_on($this->slot, $oldqa);
// Verify.

View File

@ -84,7 +84,7 @@ class qbehaviour_immediatecbm_walkthrough_test extends qbehaviour_walkthrough_te
// Verify.
$this->check_current_state(question_state::$gradedright);
$this->check_current_mark(2/3);
$this->check_current_mark(2);
$this->check_current_output(
$this->get_contains_mc_radio_expectation($rightindex, false, true),
$this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, false, false),
@ -101,7 +101,7 @@ class qbehaviour_immediatecbm_walkthrough_test extends qbehaviour_walkthrough_te
// Verify.
$this->assertEquals($numsteps, $this->get_step_count());
$this->check_current_state(question_state::$gradedright);
$this->check_current_mark(2/3);
$this->check_current_mark(2);
$this->check_current_output(
$this->get_contains_mc_radio_expectation($rightindex, false, true),
$this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, false, false),
@ -130,7 +130,7 @@ class qbehaviour_immediatecbm_walkthrough_test extends qbehaviour_walkthrough_te
$this->get_contains_partcorrect_expectation());
$autogradedstep = $this->get_step($this->get_step_count() - 2);
$this->assertEquals($autogradedstep->get_fraction(), -10/9, '', 0.0000001);
$this->assertEquals($autogradedstep->get_fraction(), -2, '', 0.0000001);
}
public function test_immediatecbm_feedback_multichoice_try_to_submit_blank() {
@ -215,7 +215,7 @@ class qbehaviour_immediatecbm_walkthrough_test extends qbehaviour_walkthrough_te
// Verify.
$this->check_current_state(question_state::$gradedright);
$this->check_current_mark(1);
$this->check_current_mark(3);
$this->check_current_output(
$this->get_does_not_contain_validation_error_expectation());
}
@ -258,7 +258,7 @@ class qbehaviour_immediatecbm_walkthrough_test extends qbehaviour_walkthrough_te
// Verify.
$this->check_current_state(question_state::$gradedwrong);
$this->check_current_mark(-3);
$this->check_current_mark(-6);
$this->check_current_output(
$this->get_contains_mc_radio_expectation($wrongindex, false, true),
$this->get_contains_mc_radio_expectation(($wrongindex + 1) % 3, false, false),
@ -270,7 +270,7 @@ class qbehaviour_immediatecbm_walkthrough_test extends qbehaviour_walkthrough_te
// Create a true-false question with correct answer true.
$tf = test_question_maker::make_question('truefalse', 'true');
$this->start_attempt_at_question($tf, 'deferredcbm', 2);
$this->start_attempt_at_question($tf, 'immediatecbm', 2);
// Verify.
$this->check_current_state(question_state::$todo);

View File

@ -1,48 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains tests for the question_cbm class.
*
* @package moodlecore
* @subpackage questionengine
* @copyright 2009 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once(dirname(__FILE__) . '/../lib.php');
/**
* Unit tests for the question_cbm class.
*
* @copyright 2009 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class question_cbm_test extends advanced_testcase {
public function test_adjust_fraction() {
$this->assertEquals(0, question_cbm::adjust_fraction(0, question_cbm::LOW), '', 0.0000001);
$this->assertEquals(-2/3, question_cbm::adjust_fraction(0, question_cbm::MED), '', 0.0000001);
$this->assertEquals(-2, question_cbm::adjust_fraction(0, question_cbm::HIGH), '', 0.0000001);
$this->assertEquals(1/3, question_cbm::adjust_fraction(1, question_cbm::LOW), '', 0.0000001);
$this->assertEquals(2/3, question_cbm::adjust_fraction(1, question_cbm::MED), '', 0.0000001);
$this->assertEquals(1, question_cbm::adjust_fraction(1, question_cbm::HIGH), '', 0.0000001);
}
}