Merge branch 'MDL-43369-26' of git://github.com/jamiepratt/moodle into MOODLE_26_STABLE

This commit is contained in:
Sam Hemelryk
2014-02-04 15:24:02 +13:00
4 changed files with 81 additions and 33 deletions
@@ -53,10 +53,10 @@ class testable_question_statistics extends \core_question\statistics\questions\c
/**
* @param $qubaids qubaid_condition is ignored in this test
* @return array with three items
* @return array with two items
* - $lateststeps array of latest step data for the question usages
* - $summarks array of total marks for each usage, indexed by usage id
* - $summarksavg the average of the total marks over all the usages */
*/
protected function get_latest_steps($qubaids) {
$summarks = array();
$fakeusageid = 0;
@@ -72,8 +72,7 @@ class testable_question_statistics extends \core_question\statistics\questions\c
$step->questionusageid = $fakeusageid;
}
$summarksavg = array_sum($summarks) / count($summarks);
return array($this->lateststeps, $summarks, $summarksavg);
return array($this->lateststeps, $summarks);
}
protected function cache_stats($qubaids) {
@@ -32,7 +32,6 @@ require_once($CFG->dirroot . '/mod/quiz/report/default.php');
require_once($CFG->dirroot . '/mod/quiz/report/statistics/report.php');
require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
/**
* Quiz attempt walk through using data from csv file.
*
@@ -42,7 +41,7 @@ require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
* @author Jamie Pratt <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class quiz_report_statistics_from_steps extends mod_quiz_attempt_walkthrough_from_csv_testcase {
class quiz_report_statistics_from_steps_testcase extends mod_quiz_attempt_walkthrough_from_csv_testcase {
/**
* @var quiz_statistics_report object to do stats calculations.
@@ -103,9 +102,11 @@ class quiz_report_statistics_from_steps extends mod_quiz_attempt_walkthrough_fro
$this->assertTimeCurrent($responesstats->get_last_analysed_time($qubaids));
}
// These quiz stats and the question stats found in qstats00.csv were calculated independently in spreadsheet which is
// These quiz stats and the question stats found in qstats00.csv were calculated independently in spreadsheets which are
// available in open document or excel format here :
// https://github.com/jamiepratt/moodle-quiz-tools/tree/master/statsspreadsheet
// These quiz stats and the position stats here are calculated in stats.xls and stats.ods available, see above github URL.
$quizstatsexpected = array(
'median' => 4.5,
'firstattemptsavg' => 4.617333332,
@@ -128,22 +129,62 @@ class quiz_report_statistics_from_steps extends mod_quiz_attempt_walkthrough_fro
$slotqstats = $csvdata['qstats']->getRow($rowno);
foreach ($slotqstats as $statname => $slotqstat) {
if ($statname !== 'slot') {
switch ($statname) {
case 'covariance' :
case 'discriminationindex' :
case 'discriminativeefficiency' :
case 'effectiveweight' :
$precision = 1e-5;
break;
default :
$precision = 1e-6;
}
$slot = $slotqstats['slot'];
$delta = abs($slotqstat) * $precision;
$actual = $questionstats[$slot]->{$statname};
$this->assertEquals(floatval($slotqstat), $actual, "$statname for slot $slot", $delta);
$this->assert_stat_equals($questionstats, $subquestionstats, $slotqstats['slot'],
null, null, $statname, (float)$slotqstat);
}
}
}
$itemstats = array('s' => 12,
'effectiveweight' => null,
'discriminationindex' => 35.803933,
'discriminativeefficiency' => 39.39393939,
'sd' => 0.514928651,
'facility' => 0.583333333,
'maxmark' => 1,
'positions' => '1',
'slot' => null,
'subquestion' => true);
foreach ($itemstats as $statname => $expected) {
$this->assert_stat_equals($questionstats, $subquestionstats, 1, null, 'numerical', $statname, $expected);
}
}
/**
* Check that the stat is as expected within a reasonable tolerance.
*
* @param \core_question\statistics\questions\calculated[] $questionstats
* @param \core_question\statistics\questions\calculated_for_subquestion[] $subquestionstats
* @param int $slot
* @param int|null $variant if null then not a variant stat.
* @param string|null $subqname if null then not an item stat.
* @param string $statname
* @param float $expected
*/
protected function assert_stat_equals($questionstats, $subquestionstats, $slot, $variant, $subqname, $statname, $expected) {
if ($variant === null && $subqname === null) {
$actual = $questionstats[$slot]->{$statname};
} else if ($subqname !== null) {
$actual = $subquestionstats[$this->randqids[$slot][$subqname]]->{$statname};
} else {
$actual = $questionstats[$slot]->variantstats[$variant]->{$statname};
}
if (is_bool($expected) || is_string($expected)) {
$this->assertEquals($expected, $actual, "$statname for slot $slot");
} else {
switch ($statname) {
case 'covariance' :
case 'discriminationindex' :
case 'discriminativeefficiency' :
case 'effectiveweight' :
$precision = 1e-5;
break;
default :
$precision = 1e-6;
}
$delta = abs($expected) * $precision;
$this->assertEquals(floatval($expected), $actual, "$statname for slot $slot", $delta);
}
}
}
@@ -99,6 +99,7 @@ class calculated {
*/
public $randomguessscore = null;
// End of fields in db.
protected $fieldsindb = array('questionid', 'slot', 'subquestion', 's', 'effectiveweight', 'negcovar', 'discriminationindex',
@@ -110,6 +111,11 @@ class calculated {
public $totalothermarks = 0;
/**
* @var float The total of marks achieved for all positions in all attempts where this item was seen.
*/
public $totalsummarks = 0;
public $markvariancesum = 0;
public $othermarkvariancesum = 0;
@@ -130,6 +136,11 @@ class calculated {
public $othermarkaverage;
/**
* @var float The average for all attempts, of the sum of the marks for all positions in which this item appeared.
*/
public $summarksaverage;
public $markvariance;
public $othermarkvariance;
public $covariance;
@@ -78,7 +78,7 @@ class calculator {
public function calculate($qubaids) {
set_time_limit(0);
list($lateststeps, $summarks, $summarksavg) = $this->get_latest_steps($qubaids);
list($lateststeps, $summarks) = $this->get_latest_steps($qubaids);
if ($lateststeps) {
@@ -169,10 +169,10 @@ class calculator {
// Go through the records one more time.
foreach ($lateststeps as $step) {
$this->secondary_steps_walker($step, $this->questionstats[$step->slot], $summarks, $summarksavg);
$this->secondary_steps_walker($step, $this->questionstats[$step->slot], $summarks);
if ($this->questionstats[$step->slot]->subquestions) {
$this->secondary_steps_walker($step, $this->subquestionstats[$step->questionid], $summarks, $summarksavg);
$this->secondary_steps_walker($step, $this->subquestionstats[$step->questionid], $summarks);
}
}
@@ -268,10 +268,9 @@ class calculator {
/**
* @param $qubaids \qubaid_condition
* @return array with three items
* @return array with two items
* - $lateststeps array of latest step data for the question usages
* - $summarks array of total marks for each usage, indexed by usage id
* - $summarksavg the average of the total marks over all the usages
*/
protected function get_latest_steps($qubaids) {
$dm = new \question_engine_data_mapper();
@@ -292,12 +291,9 @@ class calculator {
}
$summarks[$step->questionusageid] += $step->mark;
}
$summarksavg = array_sum($summarks) / count($summarks);
} else {
$summarksavg = null;
}
return array($lateststeps, $summarks, $summarksavg);
return array($lateststeps, $summarks);
}
/**
@@ -341,6 +337,8 @@ class calculator {
$stats->othermarkaverage = $stats->totalothermarks / $stats->s;
$stats->summarksaverage = $stats->totalsummarks / $stats->s;
sort($stats->markarray, SORT_NUMERIC);
sort($stats->othermarksarray, SORT_NUMERIC);
}
@@ -352,16 +350,15 @@ class calculator {
* @param object $step the state to add to the statistics.
* @param calculated $stats the question statistics we are accumulating.
* @param array $summarks of the sum of marks for each question usage, indexed by question usage id
* @param float $summarksavg the average sum of marks for all question usages
*/
protected function secondary_steps_walker($step, $stats, $summarks, $summarksavg) {
protected function secondary_steps_walker($step, $stats, $summarks) {
$markdifference = $step->mark - $stats->markaverage;
if ($stats->subquestion) {
$othermarkdifference = $summarks[$step->questionusageid] - $stats->othermarkaverage;
} else {
$othermarkdifference = $summarks[$step->questionusageid] - $step->mark - $stats->othermarkaverage;
}
$overallmarkdifference = $summarks[$step->questionusageid] - $summarksavg;
$overallmarkdifference = $summarks[$step->questionusageid] - $stats->summarksaverage;
$sortedmarkdifference = array_shift($stats->markarray) - $stats->markaverage;
$sortedothermarkdifference = array_shift($stats->othermarksarray) - $stats->othermarkaverage;