MDL-65633 analytics: New interfaces for time-splitting methods
This commit is contained in:
@@ -96,17 +96,6 @@ class models_list implements \renderable, \templatable {
|
||||
$onlycli = 1;
|
||||
}
|
||||
|
||||
// Evaluation options.
|
||||
$timesplittingmethods = [
|
||||
['id' => 'all', 'text' => get_string('alltimesplittingmethods', 'tool_analytics')],
|
||||
];
|
||||
foreach (\core_analytics\manager::get_time_splitting_methods_for_evaluation(true) as $timesplitting) {
|
||||
$timesplittingmethods[] = [
|
||||
'id' => \tool_analytics\output\helper::class_to_option($timesplitting->get_id()),
|
||||
'text' => $timesplitting->get_name()->out(),
|
||||
];
|
||||
}
|
||||
|
||||
$data->models = array();
|
||||
foreach ($this->models as $model) {
|
||||
$modeldata = $model->export($output);
|
||||
@@ -216,7 +205,22 @@ class models_list implements \renderable, \templatable {
|
||||
|
||||
$actionid = 'evaluate-' . $model->get_id();
|
||||
|
||||
$modeltimesplittingmethods = $timesplittingmethods;
|
||||
// Evaluation options.
|
||||
$modeltimesplittingmethods = [
|
||||
['id' => 'all', 'text' => get_string('alltimesplittingmethods', 'tool_analytics')],
|
||||
];
|
||||
$potentialtimesplittingmethods = $model->get_potential_timesplittings();
|
||||
foreach (\core_analytics\manager::get_time_splitting_methods_for_evaluation(true) as $timesplitting) {
|
||||
if (empty($potentialtimesplittingmethods[$timesplitting->get_id()])) {
|
||||
// This time-splitting method can not be used for this model.
|
||||
continue;
|
||||
}
|
||||
$modeltimesplittingmethods[] = [
|
||||
'id' => \tool_analytics\output\helper::class_to_option($timesplitting->get_id()),
|
||||
'text' => $timesplitting->get_name()->out(),
|
||||
];
|
||||
}
|
||||
|
||||
// Include the current time-splitting method as the default selection method the model already have one.
|
||||
if ($model->get_model_obj()->timesplitting) {
|
||||
$currenttimesplitting = ['id' => 'current', 'text' => get_string('currenttimesplitting', 'tool_analytics')];
|
||||
|
||||
@@ -118,7 +118,7 @@ switch ($action) {
|
||||
'trainedmodel' => $model->is_trained(),
|
||||
'staticmodel' => $model->is_static(),
|
||||
'indicators' => $model->get_potential_indicators(),
|
||||
'timesplittings' => \core_analytics\manager::get_all_time_splittings(),
|
||||
'timesplittings' => $model->get_potential_timesplittings(),
|
||||
'predictionprocessors' => \core_analytics\manager::get_all_prediction_processors()
|
||||
);
|
||||
$mform = new \tool_analytics\output\form\edit_model(null, $customdata);
|
||||
|
||||
@@ -104,6 +104,18 @@ abstract class base extends \core_analytics\calculable {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the last analysis time on analysable processed or always.
|
||||
*
|
||||
|
||||
@@ -33,7 +33,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class accumulative_parts extends base {
|
||||
abstract class accumulative_parts extends base implements before_now {
|
||||
|
||||
/**
|
||||
* The number of parts to split the analysable duration in.
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Interface for time-splitting methods whose ranges' times are after time().
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2019 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_analytics\local\time_splitting;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Interface for time-splitting methods whose ranges' times are after time().
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2019 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
interface after_now {
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Interface for time-splitting methods whose ranges' times are before time().
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2019 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_analytics\local\time_splitting;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Interface for time-splitting methods whose ranges' times are before time().
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2019 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
interface before_now {
|
||||
}
|
||||
@@ -33,7 +33,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class equal_parts extends base {
|
||||
abstract class equal_parts extends base implements before_now {
|
||||
|
||||
/**
|
||||
* Returns the number of parts the analyser duration should be split in.
|
||||
|
||||
@@ -33,7 +33,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2019 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class upcoming_periodic extends periodic {
|
||||
abstract class upcoming_periodic extends periodic implements after_now {
|
||||
|
||||
/**
|
||||
* The next range indicator calculations should be based on upcoming dates.
|
||||
|
||||
@@ -238,7 +238,7 @@ class model {
|
||||
$indicators = \core_analytics\manager::get_all_indicators();
|
||||
|
||||
if (empty($this->analyser)) {
|
||||
$this->init_analyser(array('evaluation' => true));
|
||||
$this->init_analyser(array('notimesplitting' => true));
|
||||
}
|
||||
|
||||
foreach ($indicators as $classname => $indicator) {
|
||||
@@ -281,15 +281,24 @@ class model {
|
||||
throw new \moodle_exception('errornotarget', 'analytics');
|
||||
}
|
||||
|
||||
$potentialtimesplittings = $this->get_potential_timesplittings();
|
||||
|
||||
$timesplittings = array();
|
||||
if (empty($options['notimesplitting'])) {
|
||||
if (!empty($options['evaluation'])) {
|
||||
// The evaluation process will run using all available time splitting methods unless one is specified.
|
||||
if (!empty($options['timesplitting'])) {
|
||||
$timesplitting = \core_analytics\manager::get_time_splitting($options['timesplitting']);
|
||||
|
||||
if (empty($potentialtimesplittings[$timesplitting->get_id()])) {
|
||||
throw new \moodle_exception('errorcannotusetimesplitting', 'analytics');
|
||||
}
|
||||
$timesplittings = array($timesplitting->get_id() => $timesplitting);
|
||||
} else {
|
||||
$timesplittings = \core_analytics\manager::get_time_splitting_methods_for_evaluation();
|
||||
$timesplittingsforevaluation = \core_analytics\manager::get_time_splitting_methods_for_evaluation();
|
||||
|
||||
// They both have the same objects, using $potentialtimesplittings as its items are sorted.
|
||||
$timesplittings = array_intersect_key($potentialtimesplittings, $timesplittingsforevaluation);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -327,6 +336,27 @@ class model {
|
||||
return \core_analytics\manager::get_time_splitting($this->model->timesplitting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time-splitting methods that can be used by this model.
|
||||
*
|
||||
* @return \core_analytics\local\time_splitting\base[]
|
||||
*/
|
||||
public function get_potential_timesplittings() {
|
||||
|
||||
$timesplittings = \core_analytics\manager::get_all_time_splittings();
|
||||
uasort($timesplittings, function($a, $b) {
|
||||
return strcasecmp($a->get_name(), $b->get_name());
|
||||
});
|
||||
|
||||
foreach ($timesplittings as $key => $timesplitting) {
|
||||
if (!$this->get_target()->can_use_timesplitting($timesplitting)) {
|
||||
unset($timesplittings[$key]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return $timesplittings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new model. Enables it if $timesplittingid is specified.
|
||||
*
|
||||
|
||||
@@ -91,6 +91,16 @@ class test_target_shortname extends \core_analytics\local\target\binary {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only past stuff.
|
||||
*
|
||||
* @param \core_analytics\local\time_splitting\base $timesplitting
|
||||
* @return bool
|
||||
*/
|
||||
public function can_use_timesplitting(\core_analytics\local\time_splitting\base $timesplitting): bool {
|
||||
return ($timesplitting instanceof \core_analytics\local\time_splitting\before_now);
|
||||
}
|
||||
|
||||
/**
|
||||
* is_valid_analysable
|
||||
*
|
||||
|
||||
@@ -94,7 +94,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
$coursetrain1 = $this->getDataGenerator()->create_course(array('visible' => 1));
|
||||
$coursetrain2 = $this->getDataGenerator()->create_course(array('visible' => 1));
|
||||
|
||||
$this->model->enable('\core\analytics\time_splitting\no_splitting');
|
||||
$this->model->enable('\core\analytics\time_splitting\single_range');
|
||||
|
||||
$this->model->train();
|
||||
$this->model->predict();
|
||||
@@ -139,7 +139,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
$coursetrain1 = $this->getDataGenerator()->create_course(array('visible' => 1));
|
||||
$coursetrain2 = $this->getDataGenerator()->create_course(array('visible' => 1));
|
||||
|
||||
$this->model->enable('\core\analytics\time_splitting\no_splitting');
|
||||
$this->model->enable('\core\analytics\time_splitting\single_range');
|
||||
|
||||
$this->model->train();
|
||||
$this->model->predict();
|
||||
@@ -494,6 +494,17 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
$this->assertEquals($data->name['value'], '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests model::get_potential_timesplittings()
|
||||
*/
|
||||
public function test_potential_timesplittings() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->assertArrayNotHasKey('\core\analytics\time_splitting\no_splitting', $this->model->get_potential_timesplittings());
|
||||
$this->assertArrayHasKey('\core\analytics\time_splitting\single_range', $this->model->get_potential_timesplittings());
|
||||
$this->assertArrayHasKey('\core\analytics\time_splitting\quarters', $this->model->get_potential_timesplittings());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a model log record.
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,8 @@ information provided here is intended especially for developers.
|
||||
* "Time-splitting method" have been replaced by "Analysis interval" for the language strings that are
|
||||
displayed in the Moodle UI. The name of several time-splitting methods have been updated according
|
||||
to the new description of the field.
|
||||
* A new target::can_use_timesplitting method can be used to discard time-splitting methods that can not
|
||||
be used on a target.
|
||||
|
||||
=== 3.7 ===
|
||||
|
||||
|
||||
@@ -50,6 +50,16 @@ abstract class course_enrolments extends \core_analytics\local\target\binary {
|
||||
return '\core\analytics\analyser\student_enrolments';
|
||||
}
|
||||
|
||||
/**
|
||||
* Only past stuff.
|
||||
*
|
||||
* @param \core_analytics\local\time_splitting\base $timesplitting
|
||||
* @return bool
|
||||
*/
|
||||
public function can_use_timesplitting(\core_analytics\local\time_splitting\base $timesplitting): bool {
|
||||
return ($timesplitting instanceof \core_analytics\local\time_splitting\before_now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten to show a simpler language string.
|
||||
*
|
||||
|
||||
@@ -44,6 +44,16 @@ class no_teaching extends \core_analytics\local\target\binary {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* It requires a specific time-splitting method.
|
||||
*
|
||||
* @param \core_analytics\local\time_splitting\base $timesplitting
|
||||
* @return bool
|
||||
*/
|
||||
public function can_use_timesplitting(\core_analytics\local\time_splitting\base $timesplitting): bool {
|
||||
return (get_class($timesplitting) === \core\analytics\time_splitting\single_range::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name.
|
||||
*
|
||||
|
||||
@@ -37,6 +37,7 @@ $string['defaultpredictoroption'] = 'Default processor ({$a})';
|
||||
$string['disabledmodel'] = 'Disabled model';
|
||||
$string['erroralreadypredict'] = 'File {$a} has already been used to generate predictions.';
|
||||
$string['errorcannotreaddataset'] = 'Dataset file {$a} cannot be read.';
|
||||
$string['errorcannotusetimesplitting'] = 'The provided analysis interval can not be used on this model.';
|
||||
$string['errorcannotwritedataset'] = 'Dataset file {$a} cannot be written.';
|
||||
$string['errorexportmodelresult'] = 'The machine learning model cannot be exported.';
|
||||
$string['errorimport'] = 'Error importing the provided JSON file.';
|
||||
|
||||
@@ -33,7 +33,8 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class single_range extends \core_analytics\local\time_splitting\base {
|
||||
class single_range extends \core_analytics\local\time_splitting\base
|
||||
implements \core_analytics\local\time_splitting\before_now {
|
||||
|
||||
/**
|
||||
* Returns a lang_string object representing the name for the time spliting method.
|
||||
|
||||
@@ -54,6 +54,16 @@ class upcoming_activities_due extends \core_analytics\local\target\binary {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only upcoming stuff.
|
||||
*
|
||||
* @param \core_analytics\local\time_splitting\base $timesplitting
|
||||
* @return bool
|
||||
*/
|
||||
public function can_use_timesplitting(\core_analytics\local\time_splitting\base $timesplitting): bool {
|
||||
return ($timesplitting instanceof \core_analytics\local\time_splitting\after_now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user