mirrored from git://git.moodle.org/moodle.git
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MDL-58992 analytics: add multi-classification to predictors
Adds multi-class capabilities to prediction processors as well as multi-classification unit tests
- Loading branch information
Showing
5 changed files
with
422 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
<?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/>. | ||
|
||
/** | ||
* Multiclass test indicator. | ||
* | ||
* @package core_analytics | ||
* @copyright 2019 Vlad Apetrei | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
|
||
defined('MOODLE_INTERNAL') || die(); | ||
|
||
/** | ||
* Multiclass test indicator. | ||
* | ||
* @package core_analytics | ||
* @copyright 2019 Vlad Apetrei | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
class test_indicator_multiclass extends \core_analytics\local\indicator\linear { | ||
|
||
/** | ||
* Returns a lang_string object representing the name for the indicator. | ||
* | ||
* Used as column identificator. | ||
* | ||
* If there is a corresponding '_help' string this will be shown as well. | ||
* | ||
* @return \lang_string | ||
*/ | ||
public static function get_name() : \lang_string { | ||
// Using a string that exists and contains a corresponding '_help' string. | ||
return new \lang_string('allowstealthmodules'); | ||
} | ||
|
||
/** | ||
* include_averages | ||
* | ||
* @return bool | ||
*/ | ||
protected static function include_averages() { | ||
return false; | ||
} | ||
|
||
/** | ||
* required_sample_data | ||
* | ||
* @return string[] | ||
*/ | ||
public static function required_sample_data() { | ||
return array('course'); | ||
} | ||
|
||
/** | ||
* calculate_sample | ||
* | ||
* @param int $sampleid | ||
* @param string $samplesorigin | ||
* @param int $starttime | ||
* @param int $endtime | ||
* @return float | ||
*/ | ||
protected function calculate_sample($sampleid, $samplesorigin, $starttime, $endtime) { | ||
|
||
$course = $this->retrieve('course', $sampleid); | ||
|
||
$firstchar = substr($course->fullname, 0, 1); | ||
if ($firstchar === 'a') { | ||
return 1; | ||
} else if ($firstchar === 'b') { | ||
return -1; | ||
} else if ($firstchar === 'c') { | ||
return 1; | ||
} else { | ||
return self::MAX_VALUE; | ||
} | ||
} | ||
} |
211 changes: 211 additions & 0 deletions
211
analytics/tests/fixtures/test_target_shortname_multiclass.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
<?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/>. | ||
|
||
/** | ||
* Multi-class classifier target. | ||
* | ||
* @package core_analytics | ||
* @copyright 2019 Apetrei Vlad | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
|
||
defined('MOODLE_INTERNAL') || die(); | ||
|
||
/** | ||
* Multi-class classifier target. | ||
* | ||
* @package core_analytics | ||
* @copyright 2019 Apetrei Vlad | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
class test_target_shortname_multiclass extends \core_analytics\local\target\discrete { | ||
|
||
/** | ||
* Returns a lang_string object representing the name for the indicator. | ||
* | ||
* Used as column identificator. | ||
* | ||
* If there is a corresponding '_help' string this will be shown as well. | ||
* | ||
* @return \lang_string | ||
*/ | ||
public static function get_name() : \lang_string { | ||
// Using a string that exists and contains a corresponding '_help' string. | ||
return new \lang_string('allowstealthmodules'); | ||
} | ||
|
||
/** | ||
* predictions | ||
* | ||
* @var array | ||
*/ | ||
protected $predictions = array(); | ||
|
||
/** | ||
* is_linear | ||
* | ||
* @return bool | ||
*/ | ||
public function is_linear() { | ||
return false; | ||
} | ||
|
||
/** | ||
* Returns the target discrete values. | ||
* | ||
* Only useful for targets using discrete values, must be overwriten if it is the case. | ||
* | ||
* @return array | ||
*/ | ||
public static final function get_classes() { | ||
return array(0, 1, 2); | ||
} | ||
|
||
/** | ||
* Is the calculated value a positive outcome of this target? | ||
* | ||
* @param string $value | ||
* @param string $ignoredsubtype | ||
* @return int | ||
*/ | ||
public function get_calculation_outcome($value, $ignoredsubtype = false) { | ||
|
||
if (!self::is_a_class($value)) { | ||
throw new \moodle_exception('errorpredictionformat', 'analytics'); | ||
} | ||
|
||
if (in_array($value, $this->ignored_predicted_classes(), false)) { | ||
// Just in case, if it is ignored the prediction should not even be recorded but if it would, it is ignored now, | ||
// which should mean that is it nothing serious. | ||
return self::OUTCOME_VERY_POSITIVE; | ||
} | ||
|
||
// By default binaries are danger when prediction = 1. | ||
if ($value) { | ||
return self::OUTCOME_VERY_NEGATIVE; | ||
} | ||
return self::OUTCOME_VERY_POSITIVE; | ||
} | ||
|
||
/** | ||
* get_analyser_class | ||
* | ||
* @return string | ||
*/ | ||
public function get_analyser_class() { | ||
return '\core\analytics\analyser\site_courses'; | ||
} | ||
|
||
/** | ||
* We don't want to discard results. | ||
* @return float | ||
*/ | ||
protected function min_prediction_score() { | ||
return null; | ||
} | ||
|
||
/** | ||
* We don't want to discard results. | ||
* @return array | ||
*/ | ||
public function ignored_predicted_classes() { | ||
return array(); | ||
} | ||
|
||
/** | ||
* is_valid_analysable | ||
* | ||
* @param \core_analytics\analysable $analysable | ||
* @param bool $fortraining | ||
* @return bool | ||
*/ | ||
public function is_valid_analysable(\core_analytics\analysable $analysable, $fortraining = true) { | ||
// This is testing, let's make things easy. | ||
return true; | ||
} | ||
|
||
/** | ||
* is_valid_sample | ||
* | ||
* @param int $sampleid | ||
* @param \core_analytics\analysable $analysable | ||
* @param bool $fortraining | ||
* @return bool | ||
*/ | ||
public function is_valid_sample($sampleid, \core_analytics\analysable $analysable, $fortraining = true) { | ||
// We skip not-visible courses during training as a way to emulate the training data / prediction data difference. | ||
// In normal circumstances is_valid_sample will return false when they receive a sample that can not be | ||
// processed. | ||
if (!$fortraining) { | ||
return true; | ||
} | ||
|
||
$sample = $this->retrieve('course', $sampleid); | ||
if ($sample->visible == 0) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
/** | ||
* classes_description | ||
* | ||
* @return string[] | ||
*/ | ||
protected static function classes_description() { | ||
return array( | ||
get_string('first class'), | ||
get_string('second class'), | ||
get_string('third class') | ||
); | ||
} | ||
|
||
/** | ||
* calculate_sample | ||
* | ||
* @param int $sampleid | ||
* @param \core_analytics\analysable $analysable | ||
* @param int $starttime | ||
* @param int $endtime | ||
* @return float | ||
*/ | ||
protected function calculate_sample($sampleid, \core_analytics\analysable $analysable, $starttime = false, $endtime = false) { | ||
|
||
$sample = $this->retrieve('course', $sampleid); | ||
|
||
$firstchar = substr($sample->shortname, 0, 1); | ||
switch ($firstchar) { | ||
case 'a': | ||
return 0; | ||
case 'b': | ||
return 1; | ||
case 'c': | ||
return 2; | ||
} | ||
} | ||
|
||
/** | ||
* Can the provided time-splitting method be used on this target?. | ||
* | ||
* Time-splitting methods not matching the target requirements will not be selectable by models based on this target. | ||
* | ||
* @param \core_analytics\local\time_splitting\base $timesplitting | ||
* @return bool | ||
*/ | ||
public function can_use_timesplitting(\core_analytics\local\time_splitting\base $timesplitting):bool { | ||
return true; | ||
} | ||
} |
Oops, something went wrong.