<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dmonllao</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dmonllao"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Dmonllao"/>
	<updated>2026-04-11T06:18:29Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=56740</id>
		<title>Machine learning backends</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=56740"/>
		<updated>2019-12-16T08:58:48Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Predictor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learning training, prediction and models evaluation. May be good that you also read [https://docs.moodle.org/dev/Analytics_API Analytics API] to read some concept definitions, how these concepts are implemented in Moodle and how machine learning backend plugins fit into the analytics API.&lt;br /&gt;
&lt;br /&gt;
The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
Machine learning backend is a new Moodle plugin type. They are stored in lib/mlbackend, where you can add your own plugins.&lt;br /&gt;
&lt;br /&gt;
== Backends included in Moodle core ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PHP backend&#039;&#039;&#039; is the default predictions processor as it is written in PHP and do not have any external dependencies. It is using logistic regression.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Python backend&#039;&#039;&#039; requires &#039;&#039;python&#039;&#039; binary (either python 2 or python 3) and [https://pypi.python.org/pypi?name=moodlemlbackend&amp;amp;version=0.0.5&amp;amp;:action=display moodlemlbackend python package] which is maintained by Moodle HQ. It is based on [https://www.tensorflow.org/ Google&#039;s tensorflow library] and it is using a feed-forward neural network with 1 single hidden layer. &#039;&#039;moodlemlbackend&#039;&#039; package does store model performance information that can be visualised using [https://www.tensorflow.org/get_started/summaries_and_tensorboard tensorboard]. Information generated during models evaluation is available through the models management page, under each model &#039;&#039;Actions &amp;gt; Log&#039;&#039; menu. &#039;&#039;moodlemlbackend&#039;&#039; source code is available in https://github.com/moodlehq/moodle-mlbackend-python.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Python backend is recommended over the PHP&#039;&#039;&#039; as it is able to predict more accurately than the PHP backend and it is faster.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
A summary of these interfaces purpose:&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train machine learning algorithms with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
This is the basic interface to be implemented by machine learning backends. Two main types are, &#039;&#039;classifiers&#039;&#039; and &#039;&#039;regressors&#039;&#039;. We provide the &#039;&#039;Regressor&#039;&#039; interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;is_ready&#039;&#039;&#039; to check that the backend is available.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is it ready to predict?&lt;br /&gt;
     *&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_ready();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clear_model&#039;&#039;&#039; and &#039;&#039;&#039;delete_output_dir&#039;&#039;&#039; purpose is to clean up stuff created by the machine learning backend.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete all stored information of the current model id.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when there are important changes to a model,&lt;br /&gt;
     * all previous training algorithms using that version of the model&lt;br /&gt;
     * should be deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid The site model unique id string&lt;br /&gt;
     * @param string $modelversionoutputdir The output dir of this model version&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function clear_model($uniqueid, $modelversionoutputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete the output directory.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when a model is completely deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $modeloutputdir The model directory id (parent of all model versions subdirectories).&lt;br /&gt;
     * @param string $uniqueid The site model unique id string&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function delete_output_dir($modeloutputdir, $uniqueid);&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Statistical_classification classifier] sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
Both these methods and &#039;&#039;Predictor&#039;&#039; methods should be implemented.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Train this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function train_classification($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Classifies the provided dataset samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function classify($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Evaluates this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param float $maxdeviation&lt;br /&gt;
     * @param int $niterations&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @param  string $trainedmodeldir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function evaluate_classification($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Regression_analysis regressor] predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
Both these methods and &#039;&#039;Predictor&#039;&#039; methods should be implemented.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Train this processor regression model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function train_regression($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Estimates linear values for the provided dataset samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param mixed $outputdir&lt;br /&gt;
     * @return void&lt;br /&gt;
     */&lt;br /&gt;
    public function estimate($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Evaluates this processor regression model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param float $maxdeviation&lt;br /&gt;
     * @param int $niterations&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @param  string $trainedmodeldir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function evaluate_regression($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=GSOC/2019&amp;diff=56383</id>
		<title>GSOC/2019</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=GSOC/2019&amp;diff=56383"/>
		<updated>2019-09-05T01:45:05Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Adding multi-class classification to machine learning backend */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Projects ==&lt;br /&gt;
&lt;br /&gt;
=== Attendance password rotation/expiry ===&lt;br /&gt;
&lt;br /&gt;
[https://moodle.org/plugins/mod_attendance The attendance plugin] provides the ability for teachers to display a QR code to allow students to take their own attendance, the QR code is currently static for the current session and does not change. This project aims to increase the security of the feature by implementing a process that frequently changes the displayed QR code and expires the old QR code, making it difficult for the QR code to be shared outside the session.&lt;br /&gt;
&lt;br /&gt;
* Student: [https://moodle.org/user/profile.php?id=2628543 Mohammed Rahman]&lt;br /&gt;
* Mentor: Dan Marsden&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/images_dev/d/de/gsoc2019attendanceqr.ogg video showing the work in progress (2019-06-02)]&lt;br /&gt;
&lt;br /&gt;
=== Adding multi-class classification to machine learning backend ===&lt;br /&gt;
&lt;br /&gt;
Adding multi-class classification to the Moodle machine learning backend by exposing functionality to the core which is derived from python Tensorflow and the phpml library.&lt;br /&gt;
&lt;br /&gt;
* Student: [https://moodle.org/user/profile.php?id=2404150 Vlad Apetrei]&lt;br /&gt;
* Mentor: David Monllaó&lt;br /&gt;
* Project outcomes https://gist.github.com/valadhi/992b808005a2cf7b7988276aa1533c92&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Recommender_system_specification&amp;diff=56021</id>
		<title>Recommender system specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Recommender_system_specification&amp;diff=56021"/>
		<updated>2019-05-07T16:19:11Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Recommender system */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a proposal for a [https://en.wikipedia.org/wiki/Recommender_system recommender system] in Moodle. A recommender system &#039;&#039;&amp;quot;seeks to predict the &amp;quot;rating&amp;quot; or &amp;quot;preference&amp;quot; a user would give to an item.&amp;quot;&#039;&#039;, in other words, it tries to identify items that would be interesting for a user.&lt;br /&gt;
&lt;br /&gt;
== Proposal info ==&lt;br /&gt;
This proposal is based on some assumptions:&lt;br /&gt;
# Recommender systems will be limited to specific contexts in most cases (e.g. a course, an activity).&lt;br /&gt;
## In cases where they will not be limited to a specific context (e.g. recommend a course) the number of items will not reach millions of records. The reason is that a two-dimensional array with scalar values is loaded in PHP memory.&lt;br /&gt;
# Recommendations can be generated on-demand, that is: we don&#039;t need to train the recommender systems in CLI tasks in the background before being able to use them. We can do it because of #1 above.&lt;br /&gt;
# The training data changes too often to spend resources on a complex caching system.&lt;br /&gt;
## Every time we have a new user in a course or a new activity (using the example recommender system described below) the dimensions of the training data change and the recommender system needs to be re-trained.&lt;br /&gt;
## Every time there is a new user rating (using the example recommender system below) the training data should be refreshed.  &lt;br /&gt;
# We want the filtering to be applied before generating the training data as it modifies the dimensions of the dataset which is critical for the recommender system.&lt;br /&gt;
&lt;br /&gt;
== Classes diagram ==&lt;br /&gt;
This is an overview of the classes involved.&lt;br /&gt;
&lt;br /&gt;
[[File:Recommender_system_class_diagram.png]]&lt;br /&gt;
&lt;br /&gt;
== API specs ==&lt;br /&gt;
&lt;br /&gt;
=== Public API === &lt;br /&gt;
This code snippet below is an example using the proposed public API. This generates two recommended activities of type &#039;&#039;&#039;page&#039;&#039;&#039; for the user with id &#039;&#039;&#039;111&#039;&#039;&#039; in the course with id &#039;&#039;&#039;222&#039;&#039;&#039; based on the values in an hypothetical &#039;&#039;&#039;user_activity_rates&#039;&#039;&#039; table. The recommender system should only consider users whose &#039;&#039;&#039;city&#039;&#039;&#039; is &#039;&#039;&#039;Barcelona&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// The &#039;contexts&#039; filter is used to restrict the recommender system to a specific set of contexts. It can be used to restrict a recommender&lt;br /&gt;
// system to the activities of a single course or to restrict a recommender system to the entries of a single glossary activity.&lt;br /&gt;
// The filters in &#039;dimensions&#039; are applied to each of the dimensions used by the recommender system.&lt;br /&gt;
$coursecontext = \context_course::instance(222);&lt;br /&gt;
$filters = [&lt;br /&gt;
    &#039;contexts&#039; =&amp;gt; [$coursecontext-&amp;gt;id],&lt;br /&gt;
    &#039;dimensions&#039; =&amp;gt; [&lt;br /&gt;
        &#039;user&#039; =&amp;gt; [&#039;city&#039; =&amp;gt; &#039;Barcelona&#039;],&lt;br /&gt;
        &#039;activity&#039; =&amp;gt; [&#039;modulename&#039; =&amp;gt; &#039;page&#039;]&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
$dataset = new \core_course\analytics\recommender\dataset\activities($filters);&lt;br /&gt;
&lt;br /&gt;
$recommender = \core_analytics\recommender($dataset);&lt;br /&gt;
$recommendations = $recommender-&amp;gt;recommend(111, 2);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Training dataset ===&lt;br /&gt;
The training data for a recommender system is usually a grid of values in a two-dimensional matrix, where one of the axis usually represent the user. The classes extending the base &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class are responsible of instantiating their dimensions and to fill the two-dimensional matrix.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;We could replace &#039;&#039;&#039;x&#039;&#039;&#039; and &#039;&#039;&#039;y&#039;&#039;&#039; for &#039;&#039;&#039;items&#039;&#039;&#039; and &#039;&#039;&#039;users&#039;&#039;&#039; if we can not find use cases that do not directly involve users.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example of a &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace \core_course\analytics\recommender\dataset;&lt;br /&gt;
class activities implements \core_analytics\recommender_dataset {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(array $filters) {&lt;br /&gt;
        $this-&amp;gt;filters = $filters;&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;x = new \core_course\analytics\recommender\dimension\activity();&lt;br /&gt;
        $this-&amp;gt;y = new \core_user\analytics\recommender\dimension\user();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_training_data() {&lt;br /&gt;
        $courseids = $this-&amp;gt;get_course_ids_from_context_filter();&lt;br /&gt;
        $activityrates = $DB-&amp;gt;get_records(&amp;quot;SELECT * FROM {user_activity_rates} where courseid IN $courseids&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        $xitems = $this-&amp;gt;x-&amp;gt;get_items($this-&amp;gt;filters);&lt;br /&gt;
        $yitems = $this-&amp;gt;y-&amp;gt;get_items($this-&amp;gt;filters);&lt;br /&gt;
        // Iterate through both $xitems and $yitems filling $trainingdata two-dimensional array with $activityrates values.&lt;br /&gt;
&lt;br /&gt;
        return $trainingdata;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dimensions ===&lt;br /&gt;
Classes like &#039;&#039;&#039;user&#039;&#039;&#039; or &#039;&#039;&#039;activity&#039;&#039;&#039; (shown below) that extend the base class &#039;&#039;&#039;recommender_dimension&#039;&#039;&#039; represent each of dimensions in the two-dimensional matrix. They basically return the list of records used by the implementation of the &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class. They are separated from the &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class for re-usability in different recommender systems.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;We can remove this &#039;&#039;&#039;recommender_dataset recommender_dimension&#039;&#039;&#039; separation if we don&#039;t find enough use cases that justify the separation.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These implementations serve as example of &#039;&#039;&#039;recommender_dimension&#039;&#039;&#039; classes.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace \core_course\analytics\recommender\dimension;&lt;br /&gt;
class activity extends \core_analytics\recommender_dimension {&lt;br /&gt;
&lt;br /&gt;
    private $acceptedfilters = [&#039;modulename&#039;, &#039;coursecategory&#039;];&lt;br /&gt;
&lt;br /&gt;
    public function get_items(array $filters) {&lt;br /&gt;
        // The context filtering would not make sense applied to context module if what we want is a list of activities.&lt;br /&gt;
        return $DB-&amp;gt;get_recordset_sql(&amp;quot;SELECT cm.*, c.* FROM {course_modules} cm&lt;br /&gt;
                                         JOIN {course} c on cm.course = c.id&lt;br /&gt;
                                         JOIN {context} ctx ON ctx.contextlevel = CONTEXT_COURSE AND ctx.instanceid = c.id&lt;br /&gt;
                                        WHERE ctx.id IN $contexts AND modulename = $filters[&#039;modulename&#039;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
namespace \core_user\analytics\recommender\dimension;&lt;br /&gt;
class user extends \core_analytics\recommender_dimension {&lt;br /&gt;
&lt;br /&gt;
    public function get_items(array $filters) {&lt;br /&gt;
       // $contexts is ignored as users depend on the system context.&lt;br /&gt;
        return $DB-&amp;gt;get_recordset_sql(&amp;quot;SELECT * FROM {user}&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Recommender system ===&lt;br /&gt;
&lt;br /&gt;
The recommender class is the key element of the whole system and can be shared across all recommender systems built using this API. Extra methods to evaluate the accuracy of the recommender system should be added.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Recommender systems can also be used for things like predicting student grades. We need to rename or add some methods and parameters if we want this sort of usages to feel natural. For example, a &#039;&#039;&#039;predict($yid, $xid)&#039;&#039;&#039; method would be more appropriate for predicting student grades based on previous grades.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is the recommender class skeleton.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace \core_analytics;&lt;br /&gt;
class recommender {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(\core_analytics\recommender_dataset $dataset) {&lt;br /&gt;
        $this-&amp;gt;dataset = $dataset;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function recommend($yid, $nrecommendations = 1) {&lt;br /&gt;
        $trainingdata = $dataset-&amp;gt;get_training_data();&lt;br /&gt;
&lt;br /&gt;
        // Collaborative filtering or any other alternative. This is just an example.&lt;br /&gt;
        $model = $this-&amp;gt;get_embeddings($trainingdata);&lt;br /&gt;
&lt;br /&gt;
        $y = $trainingdata[$yid];&lt;br /&gt;
        return $model-&amp;gt;recommend($y, $nrecommendations);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Recommender_system_specification&amp;diff=56020</id>
		<title>Recommender system specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Recommender_system_specification&amp;diff=56020"/>
		<updated>2019-05-07T15:58:56Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a proposal for a [https://en.wikipedia.org/wiki/Recommender_system recommender system] in Moodle. A recommender system &#039;&#039;&amp;quot;seeks to predict the &amp;quot;rating&amp;quot; or &amp;quot;preference&amp;quot; a user would give to an item.&amp;quot;&#039;&#039;, in other words, it tries to identify items that would be interesting for a user.&lt;br /&gt;
&lt;br /&gt;
== Proposal info ==&lt;br /&gt;
This proposal is based on some assumptions:&lt;br /&gt;
# Recommender systems will be limited to specific contexts in most cases (e.g. a course, an activity).&lt;br /&gt;
## In cases where they will not be limited to a specific context (e.g. recommend a course) the number of items will not reach millions of records. The reason is that a two-dimensional array with scalar values is loaded in PHP memory.&lt;br /&gt;
# Recommendations can be generated on-demand, that is: we don&#039;t need to train the recommender systems in CLI tasks in the background before being able to use them. We can do it because of #1 above.&lt;br /&gt;
# The training data changes too often to spend resources on a complex caching system.&lt;br /&gt;
## Every time we have a new user in a course or a new activity (using the example recommender system described below) the dimensions of the training data change and the recommender system needs to be re-trained.&lt;br /&gt;
## Every time there is a new user rating (using the example recommender system below) the training data should be refreshed.  &lt;br /&gt;
# We want the filtering to be applied before generating the training data as it modifies the dimensions of the dataset which is critical for the recommender system.&lt;br /&gt;
&lt;br /&gt;
== Classes diagram ==&lt;br /&gt;
This is an overview of the classes involved.&lt;br /&gt;
&lt;br /&gt;
[[File:Recommender_system_class_diagram.png]]&lt;br /&gt;
&lt;br /&gt;
== API specs ==&lt;br /&gt;
&lt;br /&gt;
=== Public API === &lt;br /&gt;
This code snippet below is an example using the proposed public API. This generates two recommended activities of type &#039;&#039;&#039;page&#039;&#039;&#039; for the user with id &#039;&#039;&#039;111&#039;&#039;&#039; in the course with id &#039;&#039;&#039;222&#039;&#039;&#039; based on the values in an hypothetical &#039;&#039;&#039;user_activity_rates&#039;&#039;&#039; table. The recommender system should only consider users whose &#039;&#039;&#039;city&#039;&#039;&#039; is &#039;&#039;&#039;Barcelona&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// The &#039;contexts&#039; filter is used to restrict the recommender system to a specific set of contexts. It can be used to restrict a recommender&lt;br /&gt;
// system to the activities of a single course or to restrict a recommender system to the entries of a single glossary activity.&lt;br /&gt;
// The filters in &#039;dimensions&#039; are applied to each of the dimensions used by the recommender system.&lt;br /&gt;
$coursecontext = \context_course::instance(222);&lt;br /&gt;
$filters = [&lt;br /&gt;
    &#039;contexts&#039; =&amp;gt; [$coursecontext-&amp;gt;id],&lt;br /&gt;
    &#039;dimensions&#039; =&amp;gt; [&lt;br /&gt;
        &#039;user&#039; =&amp;gt; [&#039;city&#039; =&amp;gt; &#039;Barcelona&#039;],&lt;br /&gt;
        &#039;activity&#039; =&amp;gt; [&#039;modulename&#039; =&amp;gt; &#039;page&#039;]&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
$dataset = new \core_course\analytics\recommender\dataset\activities($filters);&lt;br /&gt;
&lt;br /&gt;
$recommender = \core_analytics\recommender($dataset);&lt;br /&gt;
$recommendations = $recommender-&amp;gt;recommend(111, 2);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Training dataset ===&lt;br /&gt;
The training data for a recommender system is usually a grid of values in a two-dimensional matrix, where one of the axis usually represent the user. The classes extending the base &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class are responsible of instantiating their dimensions and to fill the two-dimensional matrix.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;We could replace &#039;&#039;&#039;x&#039;&#039;&#039; and &#039;&#039;&#039;y&#039;&#039;&#039; for &#039;&#039;&#039;items&#039;&#039;&#039; and &#039;&#039;&#039;users&#039;&#039;&#039; if we can not find use cases that do not directly involve users.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example of a &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace \core_course\analytics\recommender\dataset;&lt;br /&gt;
class activities implements \core_analytics\recommender_dataset {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(array $filters) {&lt;br /&gt;
        $this-&amp;gt;filters = $filters;&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;x = new \core_course\analytics\recommender\dimension\activity();&lt;br /&gt;
        $this-&amp;gt;y = new \core_user\analytics\recommender\dimension\user();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_training_data() {&lt;br /&gt;
        $courseids = $this-&amp;gt;get_course_ids_from_context_filter();&lt;br /&gt;
        $activityrates = $DB-&amp;gt;get_records(&amp;quot;SELECT * FROM {user_activity_rates} where courseid IN $courseids&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        $xitems = $this-&amp;gt;x-&amp;gt;get_items($this-&amp;gt;filters);&lt;br /&gt;
        $yitems = $this-&amp;gt;y-&amp;gt;get_items($this-&amp;gt;filters);&lt;br /&gt;
        // Iterate through both $xitems and $yitems filling $trainingdata two-dimensional array with $activityrates values.&lt;br /&gt;
&lt;br /&gt;
        return $trainingdata;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dimensions ===&lt;br /&gt;
Classes like &#039;&#039;&#039;user&#039;&#039;&#039; or &#039;&#039;&#039;activity&#039;&#039;&#039; (shown below) that extend the base class &#039;&#039;&#039;recommender_dimension&#039;&#039;&#039; represent each of dimensions in the two-dimensional matrix. They basically return the list of records used by the implementation of the &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class. They are separated from the &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class for re-usability in different recommender systems.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;We can remove this &#039;&#039;&#039;recommender_dataset recommender_dimension&#039;&#039;&#039; separation if we don&#039;t find enough use cases that justify the separation.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These implementations serve as example of &#039;&#039;&#039;recommender_dimension&#039;&#039;&#039; classes.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace \core_course\analytics\recommender\dimension;&lt;br /&gt;
class activity extends \core_analytics\recommender_dimension {&lt;br /&gt;
&lt;br /&gt;
    private $acceptedfilters = [&#039;modulename&#039;, &#039;coursecategory&#039;];&lt;br /&gt;
&lt;br /&gt;
    public function get_items(array $filters) {&lt;br /&gt;
        // The context filtering would not make sense applied to context module if what we want is a list of activities.&lt;br /&gt;
        return $DB-&amp;gt;get_recordset_sql(&amp;quot;SELECT cm.*, c.* FROM {course_modules} cm&lt;br /&gt;
                                         JOIN {course} c on cm.course = c.id&lt;br /&gt;
                                         JOIN {context} ctx ON ctx.contextlevel = CONTEXT_COURSE AND ctx.instanceid = c.id&lt;br /&gt;
                                        WHERE ctx.id IN $contexts AND modulename = $filters[&#039;modulename&#039;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
namespace \core_user\analytics\recommender\dimension;&lt;br /&gt;
class user extends \core_analytics\recommender_dimension {&lt;br /&gt;
&lt;br /&gt;
    public function get_items(array $filters) {&lt;br /&gt;
       // $contexts is ignored as users depend on the system context.&lt;br /&gt;
        return $DB-&amp;gt;get_recordset_sql(&amp;quot;SELECT * FROM {user}&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Recommender system ===&lt;br /&gt;
This is the recommender class skeleton.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Recommender systems can also be used for things like predicting student grades. We need to rename or add some methods and parameters if we want this sort of usages to feel natural. For example, a &#039;&#039;&#039;predict($yid, $xid)&#039;&#039;&#039; method would be more appropriate for predicting student grades based on previous grades.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace \core_analytics;&lt;br /&gt;
class recommender {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(\core_analytics\recommender_dataset $dataset) {&lt;br /&gt;
        $this-&amp;gt;dataset = $dataset;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function recommend($yid, $nrecommendations = 1) {&lt;br /&gt;
        $trainingdata = $dataset-&amp;gt;get_training_data();&lt;br /&gt;
&lt;br /&gt;
        // Collaborative filtering or any other alternative. This is just an example.&lt;br /&gt;
        $model = $this-&amp;gt;get_embeddings($trainingdata);&lt;br /&gt;
&lt;br /&gt;
        $y = $trainingdata[$yid];&lt;br /&gt;
        return $model-&amp;gt;recommend($y, $nrecommendations);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Recommender_system_specification&amp;diff=56019</id>
		<title>Recommender system specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Recommender_system_specification&amp;diff=56019"/>
		<updated>2019-05-07T15:55:13Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a proposal for a [https://en.wikipedia.org/wiki/Recommender_system recommender system] in Moodle. A recommender system &#039;&#039;&amp;quot;seeks to predict the &amp;quot;rating&amp;quot; or &amp;quot;preference&amp;quot; a user would give to an item.&amp;quot;&#039;&#039;, in other words, it tries to identify items that would be interesting for a user.&lt;br /&gt;
&lt;br /&gt;
== Proposal info ==&lt;br /&gt;
This proposal is based on some assumptions:&lt;br /&gt;
# Recommender systems will be limited to specific contexts in most cases (e.g. a course, an activity).&lt;br /&gt;
## In cases where they will not be limited to a specific context (e.g. recommend a course) the number of items will not reach millions of records. The reason is that a two-dimensional array with scalar values is loaded in PHP memory.&lt;br /&gt;
# Recommendations can be generated on-demand, that is: we don&#039;t need to train the recommender systems in CLI tasks in the background before being able to use them. We can do it because #1 above.&lt;br /&gt;
# The training data changes too often to spend resources on a complex caching system.&lt;br /&gt;
## Every time we have a new user in a course or a new activity (using the example recommender system described below) the dimensions of the training data change and the recommender system needs to be re-trained.&lt;br /&gt;
## Every time there is a new user rating (using the example recommender system below) the training data should be refreshed.  &lt;br /&gt;
# We want the filtering to be applied before generating the training data as it modifies the dimensions of the dataset which is critical for the recommender system.&lt;br /&gt;
&lt;br /&gt;
== Classes diagram ==&lt;br /&gt;
This is an overview of the classes involved.&lt;br /&gt;
&lt;br /&gt;
[[File:Recommender_system_class_diagram.png]]&lt;br /&gt;
&lt;br /&gt;
== API specs ==&lt;br /&gt;
&lt;br /&gt;
=== Public API === &lt;br /&gt;
This code snippet below is an example using the proposed public API. This generates two recommended activities of type &#039;&#039;page&#039;&#039; for the user with id 111 in the course with id 222 based on the values in an hypothetical &#039;&#039;user_activity_rates&#039;&#039; table. The recommender system should only consider users whose &#039;&#039;city&#039;&#039; is &#039;&#039;Barcelona&#039;&#039;.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// The &#039;contexts&#039; filter is used to restrict the recommender system to a specific set of contexts. It can be used to restrict a recommender&lt;br /&gt;
// system to the activities of a single course or to restrict a recommender system to the entries of a single glossary activity.&lt;br /&gt;
// The filters in &#039;dimensions&#039; are applied to each of the dimensions used by the recommender system.&lt;br /&gt;
$coursecontext = \context_course::instance(222);&lt;br /&gt;
$filters = [&lt;br /&gt;
    &#039;contexts&#039; =&amp;gt; [$coursecontext-&amp;gt;id],&lt;br /&gt;
    &#039;dimensions&#039; =&amp;gt; [&lt;br /&gt;
        &#039;user&#039; =&amp;gt; [&#039;city&#039; =&amp;gt; &#039;Barcelona&#039;],&lt;br /&gt;
        &#039;activity&#039; =&amp;gt; [&#039;modulename&#039; =&amp;gt; &#039;page&#039;]&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
$dataset = new \core_course\analytics\recommender\dataset\activities($filters);&lt;br /&gt;
&lt;br /&gt;
$recommender = \core_analytics\recommender($dataset);&lt;br /&gt;
$recommendations = $recommender-&amp;gt;recommend(111, 2);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Training dataset ===&lt;br /&gt;
The training data for a recommender system is usually a grid of values in a two-dimensional matrix, where one of the axis usually represent the user. The classes extending the base &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class are responsible of instantiating their dimensions and to fill the two-dimensional matrix.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;We could replace &#039;&#039;&#039;x&#039;&#039;&#039; and &#039;&#039;&#039;y&#039;&#039;&#039; for &#039;&#039;&#039;items&#039;&#039;&#039; and &#039;&#039;&#039;users&#039;&#039;&#039; if we can not find use cases that do not directly involve users.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example of a &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace \core_course\analytics\recommender\dataset;&lt;br /&gt;
class activities implements \core_analytics\recommender_dataset {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(array $filters) {&lt;br /&gt;
        $this-&amp;gt;filters = $filters;&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;x = new \core_course\analytics\recommender\dimension\activity();&lt;br /&gt;
        $this-&amp;gt;y = new \core_user\analytics\recommender\dimension\user();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_training_data() {&lt;br /&gt;
        $courseids = $this-&amp;gt;get_course_ids_from_context_filter();&lt;br /&gt;
        $activityrates = $DB-&amp;gt;get_records(&amp;quot;SELECT * FROM {user_activity_rates} where courseid IN $courseids&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        $xitems = $this-&amp;gt;x-&amp;gt;get_items($this-&amp;gt;filters);&lt;br /&gt;
        $yitems = $this-&amp;gt;y-&amp;gt;get_items($this-&amp;gt;filters);&lt;br /&gt;
        // Iterate through both $xitems and $yitems filling $trainingdata two-dimensional array with $activityrates values.&lt;br /&gt;
&lt;br /&gt;
        return $trainingdata;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dimensions ===&lt;br /&gt;
Classes like &#039;&#039;&#039;user&#039;&#039;&#039; or &#039;&#039;&#039;activity&#039;&#039;&#039; that extend the base class &#039;&#039;&#039;recommender_dimension&#039;&#039;&#039; represent each of dimensions in the two-dimensional matrix. They basically return the list of records used by the implementation of the &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class. They are separated from the &#039;&#039;&#039;recommender_dataset&#039;&#039; class for re-usability in different recommender systems.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;We can remove this &#039;&#039;&#039;recommender_dataset - recommender_dimension&#039;&#039;&#039; separation if we don&#039;t find enough use cases that justify the separation.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These implementations serve as example of &#039;&#039;&#039;recommender_dimension&#039;&#039;&#039; classes.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace \core_course\analytics\recommender\dimension;&lt;br /&gt;
class activity extends \core_analytics\recommender_dimension {&lt;br /&gt;
&lt;br /&gt;
    private $acceptedfilters = [&#039;modulename&#039;, &#039;coursecategory&#039;];&lt;br /&gt;
&lt;br /&gt;
    public function get_items(array $filters) {&lt;br /&gt;
        // The context filtering would not make sense applied to context module if what we want is a list of activities.&lt;br /&gt;
        return $DB-&amp;gt;get_recordset_sql(&amp;quot;SELECT cm.*, c.* FROM {course_modules} cm&lt;br /&gt;
                                         JOIN {course} c on cm.course = c.id&lt;br /&gt;
                                         JOIN {context} ctx ON ctx.contextlevel = CONTEXT_COURSE AND ctx.instanceid = c.id&lt;br /&gt;
                                        WHERE ctx.id IN $contexts AND modulename = $filters[&#039;modulename&#039;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
namespace \core_user\analytics\recommender\dimension;&lt;br /&gt;
class user extends \core_analytics\recommender_dimension {&lt;br /&gt;
&lt;br /&gt;
    public function get_items(array $filters) {&lt;br /&gt;
       // $contexts is ignored as users depend on the system context.&lt;br /&gt;
        return $DB-&amp;gt;get_recordset_sql(&amp;quot;SELECT * FROM {user}&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Recommender system ===&lt;br /&gt;
This is the recommender class skeleton.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Recommender systems can also be used for things like predicting student grades. We need to rename or add some methods and parameters if we want this sort of usages to feel natural. For example, a &#039;&#039;&#039;predict($yid, $xid)&#039;&#039;&#039; method would be more appropriate for predicting student grades based on previous grades.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace \core_analytics;&lt;br /&gt;
class recommender {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(\core_analytics\recommender_dataset $dataset) {&lt;br /&gt;
        $this-&amp;gt;dataset = $dataset;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function recommend($yid, $nrecommendations = 1) {&lt;br /&gt;
        $trainingdata = $dataset-&amp;gt;get_training_data();&lt;br /&gt;
&lt;br /&gt;
        // Collaborative filtering or any other alternative. This is just an example.&lt;br /&gt;
        $model = $this-&amp;gt;get_embeddings($trainingdata);&lt;br /&gt;
&lt;br /&gt;
        $y = $trainingdata[$yid];&lt;br /&gt;
        return $model-&amp;gt;recommend($y, $nrecommendations);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=File:Recommender_system_class_diagram.png&amp;diff=56018</id>
		<title>File:Recommender system class diagram.png</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=File:Recommender_system_class_diagram.png&amp;diff=56018"/>
		<updated>2019-05-07T15:28:18Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Recommender_system_specification&amp;diff=56017</id>
		<title>Recommender system specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Recommender_system_specification&amp;diff=56017"/>
		<updated>2019-05-07T15:27:54Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a proposal for a [https://en.wikipedia.org/wiki/Recommender_system recommender system] in Moodle. A recommender system &#039;&#039;&amp;quot;seeks to predict the &amp;quot;rating&amp;quot; or &amp;quot;preference&amp;quot; a user would give to an item.&amp;quot;&#039;&#039;, in other words, it tries to identify items that would be interesting for a user.&lt;br /&gt;
&lt;br /&gt;
This code snippet below is an example using the proposed public API. This generates two recommended activities of type &#039;&#039;page&#039;&#039; for the user with id 111 in the course with id 222 based on the values in an hypothetical &#039;&#039;user_activity_rates&#039;&#039; table. The recommender system should only consider users whose &#039;&#039;city&#039;&#039; is &#039;&#039;Barcelona&#039;&#039;.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// The &#039;contexts&#039; filter is used to restrict the recommender system to a specific set of contexts. It can be used to restrict a recommender&lt;br /&gt;
// system to the activities of a single course or to restrict a recommender system to the entries of a single glossary activity.&lt;br /&gt;
// The filters in &#039;dimensions&#039; are applied to each of the dimensions used by the recommender system.&lt;br /&gt;
$coursecontext = \context_course::instance(222);&lt;br /&gt;
$filters = [&lt;br /&gt;
    &#039;contexts&#039; =&amp;gt; [$coursecontext-&amp;gt;id],&lt;br /&gt;
    &#039;dimensions&#039; =&amp;gt; [&lt;br /&gt;
        &#039;user&#039; =&amp;gt; [&#039;city&#039; =&amp;gt; &#039;Barcelona&#039;],&lt;br /&gt;
        &#039;activity&#039; =&amp;gt; [&#039;modulename&#039; =&amp;gt; &#039;page&#039;]&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
$dataset = new \core_course\analytics\recommender\dataset\activities($filters);&lt;br /&gt;
&lt;br /&gt;
$recommender = \core_analytics\recommender($dataset);&lt;br /&gt;
$recommendations = $recommender-&amp;gt;recommend(111, 2);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is an overview of the classes involved.&lt;br /&gt;
&lt;br /&gt;
The training data for a recommender system is usually a grid of values in a two-dimensional matrix, where one of the axis usually represent the user. The classes extending the base &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class are responsible of instantiating their dimensions and to fill the two-dimensional matrix.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;We could replace &#039;&#039;&#039;x&#039;&#039;&#039; and &#039;&#039;&#039;y&#039;&#039;&#039; for &#039;&#039;&#039;items&#039;&#039;&#039; and &#039;&#039;&#039;users&#039;&#039;&#039; if we can not find use cases that do not directly involve users.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example of a &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace \core_course\analytics\recommender\dataset;&lt;br /&gt;
class activities implements \core_analytics\recommender_dataset {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(array $filters) {&lt;br /&gt;
        $this-&amp;gt;filters = $filters;&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;x = new \core_course\analytics\recommender\dimension\activity();&lt;br /&gt;
        $this-&amp;gt;y = new \core_user\analytics\recommender\dimension\user();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_training_data() {&lt;br /&gt;
        $courseids = $this-&amp;gt;get_course_ids_from_context_filter();&lt;br /&gt;
        $activityrates = $DB-&amp;gt;get_records(&amp;quot;SELECT * FROM {user_activity_rates} where courseid IN $courseids&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        $xitems = $this-&amp;gt;x-&amp;gt;get_items($this-&amp;gt;filters);&lt;br /&gt;
        $yitems = $this-&amp;gt;y-&amp;gt;get_items($this-&amp;gt;filters);&lt;br /&gt;
        // Iterate through both $xitems and $yitems filling $trainingdata two-dimensional array with $activityrates values.&lt;br /&gt;
&lt;br /&gt;
        return $trainingdata;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Classes like &#039;&#039;&#039;user&#039;&#039;&#039; or &#039;&#039;&#039;activity&#039;&#039;&#039; that extend the base class &#039;&#039;&#039;recommender_dimension&#039;&#039;&#039; represent each of dimensions in the two-dimensional matrix. They basically return the list of records used by the implementation of the &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class. They are separated from the &#039;&#039;&#039;recommender_dataset&#039;&#039; class for re-usability in different recommender systems.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;We can remove this &#039;&#039;&#039;recommender_dataset - recommender_dimension&#039;&#039;&#039; separation if we don&#039;t find enough use cases that justify the separation.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These implementations serve as example of &#039;&#039;&#039;recommender_dimension&#039;&#039;&#039; classes.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace \core_course\analytics\recommender;&lt;br /&gt;
class activity extends \core_analytics\recommender_dimension {&lt;br /&gt;
&lt;br /&gt;
    private $acceptedfilters = [&#039;modulename&#039;, &#039;coursecategory&#039;];&lt;br /&gt;
&lt;br /&gt;
    public function get_items(array $filters) {&lt;br /&gt;
        // The context filtering would not make sense applied to context module if what we want is a list of activities.&lt;br /&gt;
        return $DB-&amp;gt;get_recordset_sql(&amp;quot;SELECT cm.*, c.* FROM {course_modules} cm&lt;br /&gt;
                                         JOIN {course} c on cm.course = c.id&lt;br /&gt;
                                         JOIN {context} ctx ON ctx.contextlevel = CONTEXT_COURSE AND ctx.instanceid = c.id&lt;br /&gt;
                                        WHERE ctx.id IN $contexts AND modulename = $filters[&#039;modulename&#039;]&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
namespace \core_user\analytics\recommender;&lt;br /&gt;
class user extends \core_analytics\recommender_dimension {&lt;br /&gt;
&lt;br /&gt;
    public function get_items(array $filters) {&lt;br /&gt;
       // $contexts is ignored as users depend on the system context.&lt;br /&gt;
        return $DB-&amp;gt;get_recordset_sql(&amp;quot;SELECT * FROM {user}&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the recommender class skeleton. &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace \core_analytics;&lt;br /&gt;
class recommender {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(\core_analytics\recommender_dataset $dataset) {&lt;br /&gt;
        $this-&amp;gt;dataset = $dataset;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function recommend($yid, $nrecommendations = 1) {&lt;br /&gt;
        $trainingdata = $dataset-&amp;gt;get_training_data();&lt;br /&gt;
&lt;br /&gt;
        // Collaborative filtering or any other alternative. This is just an example.&lt;br /&gt;
        $model = $this-&amp;gt;get_embeddings($trainingdata);&lt;br /&gt;
&lt;br /&gt;
        $y = $trainingdata[$yid];&lt;br /&gt;
        return $model-&amp;gt;recommend($y, $nrecommendations);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Recommender_system_specification&amp;diff=56011</id>
		<title>Recommender system specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Recommender_system_specification&amp;diff=56011"/>
		<updated>2019-05-07T07:53:53Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: Created page with &amp;quot;This is a proposal for a [https://en.wikipedia.org/wiki/Recommender_system recommender system] in Moodle. A recommender system &amp;#039;&amp;#039;&amp;quot;seeks to predict the &amp;quot;rating&amp;quot; or &amp;quot;preference&amp;quot;...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a proposal for a [https://en.wikipedia.org/wiki/Recommender_system recommender system] in Moodle. A recommender system &#039;&#039;&amp;quot;seeks to predict the &amp;quot;rating&amp;quot; or &amp;quot;preference&amp;quot; a user would give to an item.&amp;quot;&#039;&#039;, in other words, it tries to identify items that would be interesting for a user.&lt;br /&gt;
&lt;br /&gt;
This code snippet below is an example using the proposed public API. This generates two recommended activities of type &#039;&#039;page&#039;&#039; for the user with id 111 in the course with id 222 based on the values in an hypothetical &#039;&#039;user_activity_rates&#039;&#039; table. The recommender system should only consider users whose &#039;&#039;city&#039;&#039; is &#039;&#039;Barcelona&#039;&#039;.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// The &#039;contexts&#039; filter is used to restrict the recommender system to a specific set of contexts. It can be used to restrict a recommender&lt;br /&gt;
// system to the activities of a single course or to restrict a recommender system to the entries of a single glossary activity.&lt;br /&gt;
// The filters in &#039;dimensions&#039; are applied to each of the dimensions used by the recommender system.&lt;br /&gt;
$coursecontext = \context_course::instance(222);&lt;br /&gt;
$filters = [&lt;br /&gt;
    &#039;contexts&#039; =&amp;gt; [$coursecontext-&amp;gt;id],&lt;br /&gt;
    &#039;dimensions&#039; =&amp;gt; [&lt;br /&gt;
        &#039;user&#039; =&amp;gt; [&#039;city&#039; =&amp;gt; &#039;Barcelona&#039;],&lt;br /&gt;
        &#039;activity&#039; =&amp;gt; [&#039;modulename&#039; =&amp;gt; &#039;page&#039;]&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
$dataset = new \core_course\analytics\recommender\dataset\activities($filters);&lt;br /&gt;
&lt;br /&gt;
$recommender = \core_analytics\recommender($dataset);&lt;br /&gt;
$recommendations = $recommender-&amp;gt;recommend(111, 2);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is an overview of the classes involved.&lt;br /&gt;
&lt;br /&gt;
The training data for a recommender system is usually a grid of values in a two-dimensional matrix, where one of the axis usually represent the user. The classes extending the base &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class are responsible of instantiating their dimensions and to fill the two-dimensional matrix.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;We could replace &#039;&#039;&#039;x&#039;&#039;&#039; and &#039;&#039;&#039;y&#039;&#039;&#039; for &#039;&#039;&#039;items&#039;&#039;&#039; and &#039;&#039;&#039;users&#039;&#039;&#039; if we can not find use cases that do not directly involve users.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example of a &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace \core_course\analytics\recommender\dataset;&lt;br /&gt;
class activities implements \core_analytics\recommender_dataset {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(array $filters) {&lt;br /&gt;
        $this-&amp;gt;filters = $filters;&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;x = new \core_course\analytics\recommender\dimension\activity();&lt;br /&gt;
        $this-&amp;gt;y = new \core_user\analytics\recommender\dimension\user();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_training_data() {&lt;br /&gt;
        $courseids = $this-&amp;gt;get_course_ids_from_context_filter();&lt;br /&gt;
        $activityrates = $DB-&amp;gt;get_records(&amp;quot;SELECT * FROM {user_activity_rates} where courseid IN $courseids&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        $xitems = $this-&amp;gt;x-&amp;gt;get_items($this-&amp;gt;filters);&lt;br /&gt;
        $yitems = $this-&amp;gt;y-&amp;gt;get_items($this-&amp;gt;filters);&lt;br /&gt;
        // Iterate through both $xitems and $yitems filling $trainingdata two-dimensional array with $activityrates values.&lt;br /&gt;
&lt;br /&gt;
        return $trainingdata;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Classes like &#039;&#039;&#039;user&#039;&#039;&#039; or &#039;&#039;&#039;activity&#039;&#039;&#039; that extend the base class &#039;&#039;&#039;recommender_dimension&#039;&#039;&#039; represent each of dimensions in the two-dimensional matrix. They basically return the list of records used by the implementation of the &#039;&#039;&#039;recommender_dataset&#039;&#039;&#039; class. They are separated from the &#039;&#039;&#039;recommender_dataset&#039;&#039; class for re-usability in different recommender systems.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;We can remove this &#039;&#039;&#039;recommender_dataset - recommender_dimension&#039;&#039;&#039; separation if we don&#039;t find enough use cases that justify the separation.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These implementations serve as example of &#039;&#039;&#039;recommender_dimension&#039;&#039;&#039; classes.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace \core_course\analytics\recommender;&lt;br /&gt;
class activity extends \core_analytics\recommender_dimension {&lt;br /&gt;
&lt;br /&gt;
    public function get_items(array $filters) {&lt;br /&gt;
        // This is not real code, it is just to get the idea.&lt;br /&gt;
        // The context filtering would not make sense applied to context module if&lt;br /&gt;
        // what we want is a list of activities.&lt;br /&gt;
        return $DB-&amp;gt;get_recordset_sql(&amp;quot;SELECT cm.*, c.* FROM {course_modules} cm&lt;br /&gt;
                                         JOIN {course} c on cm.course = c.id&lt;br /&gt;
                                         JOIN {context} ctx ON ctx.contextlevel = CONTEXT_COURSE AND ctx.instanceid = c.id&lt;br /&gt;
                                        WHERE ctx.id IN $contexts&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
namespace \core_user\analytics\recommender;&lt;br /&gt;
class user extends \core_analytics\recommender_dimension {&lt;br /&gt;
&lt;br /&gt;
    public function get_items(array $contexts) {&lt;br /&gt;
       // $contexts is ignored as users depend on the system context.&lt;br /&gt;
        return $DB-&amp;gt;get_recordset_sql(&amp;quot;SELECT * FROM {user}&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the recommender class skeleton. &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace \core_analytics;&lt;br /&gt;
class recommender {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(\core_analytics\recommender_dataset $dataset) {&lt;br /&gt;
        $this-&amp;gt;dataset = $dataset;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function recommend($yitem, $nrecommendations = 1) {&lt;br /&gt;
        // Collaborative filtering or any other alternative.&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=File:Inspire_data_flow.png&amp;diff=55991</id>
		<title>File:Inspire data flow.png</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=File:Inspire_data_flow.png&amp;diff=55991"/>
		<updated>2019-04-29T15:48:06Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: Dmonllao uploaded a new version of File:Inspire data flow.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=55826</id>
		<title>Machine learning backends</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=55826"/>
		<updated>2019-03-27T10:49:05Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learning training, prediction and models evaluation. May be good that you also read [https://docs.moodle.org/dev/Analytics_API Analytics API] to read some concept definitions, how these concepts are implemented in Moodle and how machine learning backend plugins fit into the analytics API.&lt;br /&gt;
&lt;br /&gt;
The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
Machine learning backend is a new Moodle plugin type. They are stored in lib/mlbackend, where you can add your own plugins.&lt;br /&gt;
&lt;br /&gt;
== Backends included in Moodle core ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PHP backend&#039;&#039;&#039; is the default predictions processor as it is written in PHP and do not have any external dependencies. It is using logistic regression.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Python backend&#039;&#039;&#039; requires &#039;&#039;python&#039;&#039; binary (either python 2 or python 3) and [https://pypi.python.org/pypi?name=moodlemlbackend&amp;amp;version=0.0.5&amp;amp;:action=display moodlemlbackend python package] which is maintained by Moodle HQ. It is based on [https://www.tensorflow.org/ Google&#039;s tensorflow library] and it is using a feed-forward neural network with 1 single hidden layer. &#039;&#039;moodlemlbackend&#039;&#039; package does store model performance information that can be visualised using [https://www.tensorflow.org/get_started/summaries_and_tensorboard tensorboard]. Information generated during models evaluation is available through the models management page, under each model &#039;&#039;Actions &amp;gt; Log&#039;&#039; menu. &#039;&#039;moodlemlbackend&#039;&#039; source code is available in https://github.com/moodlehq/moodle-mlbackend-python.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Python backend is recommended over the PHP&#039;&#039;&#039; as it is able to predict more accurately than the PHP backend and it is faster.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
A summary of these interfaces purpose:&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train machine learning algorithms with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
This is the basic interface to be implemented by machine learning backends. Two main types are, &#039;&#039;classifiers&#039;&#039; and &#039;&#039;regressors&#039;&#039;. We provide the &#039;&#039;Regressor&#039;&#039; interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;is_ready&#039;&#039;&#039; to check that the backend is available.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is it ready to predict?&lt;br /&gt;
     *&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_ready();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clear_model&#039;&#039;&#039; and &#039;&#039;&#039;delete_output_dir&#039;&#039;&#039; purpose is to clean up stuff created by the machine learning backend.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete all stored information of the current model id.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when there are important changes to a model,&lt;br /&gt;
     * all previous training algorithms using that version of the model&lt;br /&gt;
     * should be deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid The site model unique id string&lt;br /&gt;
     * @param string $modelversionoutputdir The output dir of this model version&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function clear_model($uniqueid, $modelversionoutputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete the output directory.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when a model is completely deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $modeloutputdir The model directory id (parent of all model versions subdirectories).&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function delete_output_dir($modeloutputdir);&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Statistical_classification classifier] sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
Both these methods and &#039;&#039;Predictor&#039;&#039; methods should be implemented.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Train this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function train_classification($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Classifies the provided dataset samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function classify($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Evaluates this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param float $maxdeviation&lt;br /&gt;
     * @param int $niterations&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function evaluate_classification($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Regression_analysis regressor] predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
Both these methods and &#039;&#039;Predictor&#039;&#039; methods should be implemented.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Train this processor regression model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function train_regression($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Estimates linear values for the provided dataset samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param mixed $outputdir&lt;br /&gt;
     * @return void&lt;br /&gt;
     */&lt;br /&gt;
    public function estimate($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Evaluates this processor regression model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param float $maxdeviation&lt;br /&gt;
     * @param int $niterations&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function evaluate_regression($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=55560</id>
		<title>Projects for new developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=55560"/>
		<updated>2019-02-08T12:04:19Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{GSOC}}&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
* Moodle uses PHP, JavaScript, SQL and a number of other Web languages, so learning those is a good place to start.&lt;br /&gt;
* When you have some basic PHP programming skills, you may wish to start learning about how the Moodle code is organised. It is recommended that you go through the [[Tutorial]].&lt;br /&gt;
* If you are looking for projects suggested in the tracker, look for issues with the [https://tracker.moodle.org/issues/?jql=labels%20in%20%28addon_candidate%29 &#039;addon_candidate&#039; label].&lt;br /&gt;
* If you are looking to make a quick contribution, look for tracker issues with marked as [https://tracker.moodle.org/issues/?jql=Difficulty%20%3D%20Easy easy].&lt;br /&gt;
* As you become more involved in Moodle development, you might like to learn more about the [[Coding|coding conventions]] used and how changes to Moodle core code are [[Process|processed]]. Once you become confident enough, please consider adopting a [https://moodle.org/plugins/browse.php?list=set&amp;amp;id=61 plugin seeking a new maintainer].&lt;br /&gt;
&lt;br /&gt;
==Potential projects==&lt;br /&gt;
&lt;br /&gt;
This evolving page lists possible Moodle projects for new developers derived from community suggestions and lists projects together with experienced core developers willing to mentor new developers.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you have any ideas for new features in Moodle which might be suitable as projects for new developers, please see [[New feature ideas]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Improve SCORM plugin ===&lt;br /&gt;
There are a number of areas of SCORM that could be improved as part of a GSOC project, some of these are bigger projects and others could be combined to form a single project.&lt;br /&gt;
&lt;br /&gt;
These are just some examples, take a look at the open SCORM issues in the Moodle tracker for a list of other issues.&lt;br /&gt;
* Improve Grading (MDL-51086, MDL-52871, MDL-37421)&lt;br /&gt;
* Improve validation of SCORM packages (MDL-38060, MDL-24057)&lt;br /&gt;
* Convert YUI Treeview to use Jquery (Moodle is moving away from YUI and the existing Treeview has a few issues)&lt;br /&gt;
* Choose where to send users after completing SCORM (MDL-61677)&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Acceptance tests for the Moodle app ===&lt;br /&gt;
&lt;br /&gt;
Since Moodle 3.7 it will be possible to write and run acceptance tests for the Moodle app.&lt;br /&gt;
&lt;br /&gt;
Tasks:&lt;br /&gt;
* Write new acceptance tests for the Moodle app&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
&lt;br /&gt;
* We require prospective students to set-up and run in a local environment the existing tests following this documentation: [[Acceptance testing for the mobile app]], students must record a video of the tests running on a local machine.&lt;br /&gt;
* We also require students to create an additional simple test (detailed instructions for writing tests are available in the previous link)&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; Behat (PHP)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level:&#039;&#039;&#039; Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor:&#039;&#039;&#039; [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Front-end editor for the plugin skeleton generator ===&lt;br /&gt;
&lt;br /&gt;
This is a follow-up project for a [[GSOC/2016#Plugin skeleton generator|successful GSOC 2016 project]] that resulted in a new tool allowing developers to quickly generate a skeleton (scaffolding, template) for a new Moodle plugin. The tool proved to be a helpful helper with significant impact on the quality of Moodle plugins code. This follow-up project aims at further improvements of the skeleton generator. The primary goal is to implement a developer-friendly user interface / front-end editor allowing to configure the plugin&#039;s properties (recipe file) easily. The UI should guide the developer through the process of designing and defining the plugin properties and facilitate the whole process.&lt;br /&gt;
&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP + JS&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=1601&amp;amp;course=5 David Mudrák]&lt;br /&gt;
&lt;br /&gt;
=== Add multi-class capabilities to Moodle&#039;s machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Moodle includes an analytics API that uses machine learning for binary classification. This is enough for classification problems like &amp;quot;student at risk&amp;quot; vs &amp;quot;student not at risk&amp;quot;. We want to expand this API capabilities by supporting multi-class classification, so we could write models like &amp;quot;very low grade&amp;quot;, &amp;quot;low grade&amp;quot;, &amp;quot;pass&amp;quot;, &amp;quot;best student ever&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Tasks:&lt;br /&gt;
* Modify the two machine learning backends included in Moodle core to support multi-class classification problems. This includes the PHP ML backend (based on php-ml library) and the Python ML backend (Tensorflow).&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Tracker issue:&#039;&#039;&#039; https://tracker.moodle.org/browse/MDL-58992&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP + Python + basic understanding of machine learning algorithms and TensorFlow&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level:&#039;&#039;&#039; Medium/High&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor:&#039;&#039;&#039; [https://moodle.org/user/profile.php?id=122326 David Monllaó]&lt;br /&gt;
&lt;br /&gt;
=== Add regressors to core machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Moodle includes an analytics API that uses machine learning for binary classification. This is enough for classification problems like &amp;quot;student at risk&amp;quot; vs &amp;quot;student not at risk&amp;quot;. We want to expand this API capabilities to support regression, so we can write models that estimate linear values instead of classes.&lt;br /&gt;
&lt;br /&gt;
Tasks:&lt;br /&gt;
* Modify the two machine learning backends included in Moodle core to support regression. This includes the PHP ML backend (based on php-ml library) and the Python ML backend (Tensorflow).&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Tracker issue:&#039;&#039;&#039; https://tracker.moodle.org/browse/MDL-60523&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP + Python + basic understanding of machine learning algorithms and TensorFlow&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level:&#039;&#039;&#039; Medium/High&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor:&#039;&#039;&#039; [https://moodle.org/user/profile.php?id=122326 David Monllaó]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program&lt;br /&gt;
* [https://tracker.moodle.org/issues/?jql=type%20in%20%28%22New%20Feature%22%2C%20Improvement%29%20AND%20resolution%20%3D%20unresolved%20and%20labels%20in%20%28addon_candidate%29%20ORDER%20BY%20votes%20DESC Popular new feature and improvement requests in Tracker that can be implemented as plugins]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=55559</id>
		<title>Projects for new developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=55559"/>
		<updated>2019-02-08T12:03:29Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Add multi-class capabilities to Moodle&amp;#039;s machine learning backends */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{GSOC}}&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
* Moodle uses PHP, JavaScript, SQL and a number of other Web languages, so learning those is a good place to start.&lt;br /&gt;
* When you have some basic PHP programming skills, you may wish to start learning about how the Moodle code is organised. It is recommended that you go through the [[Tutorial]].&lt;br /&gt;
* If you are looking for projects suggested in the tracker, look for issues with the [https://tracker.moodle.org/issues/?jql=labels%20in%20%28addon_candidate%29 &#039;addon_candidate&#039; label].&lt;br /&gt;
* If you are looking to make a quick contribution, look for tracker issues with marked as [https://tracker.moodle.org/issues/?jql=Difficulty%20%3D%20Easy easy].&lt;br /&gt;
* As you become more involved in Moodle development, you might like to learn more about the [[Coding|coding conventions]] used and how changes to Moodle core code are [[Process|processed]]. Once you become confident enough, please consider adopting a [https://moodle.org/plugins/browse.php?list=set&amp;amp;id=61 plugin seeking a new maintainer].&lt;br /&gt;
&lt;br /&gt;
==Potential projects==&lt;br /&gt;
&lt;br /&gt;
This evolving page lists possible Moodle projects for new developers derived from community suggestions and lists projects together with experienced core developers willing to mentor new developers.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you have any ideas for new features in Moodle which might be suitable as projects for new developers, please see [[New feature ideas]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Improve SCORM plugin ===&lt;br /&gt;
There are a number of areas of SCORM that could be improved as part of a GSOC project, some of these are bigger projects and others could be combined to form a single project.&lt;br /&gt;
&lt;br /&gt;
These are just some examples, take a look at the open SCORM issues in the Moodle tracker for a list of other issues.&lt;br /&gt;
* Improve Grading (MDL-51086, MDL-52871, MDL-37421)&lt;br /&gt;
* Improve validation of SCORM packages (MDL-38060, MDL-24057)&lt;br /&gt;
* Convert YUI Treeview to use Jquery (Moodle is moving away from YUI and the existing Treeview has a few issues)&lt;br /&gt;
* Choose where to send users after completing SCORM (MDL-61677)&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Acceptance tests for the Moodle app ===&lt;br /&gt;
&lt;br /&gt;
Since Moodle 3.7 it will be possible to write and run acceptance tests for the Moodle app.&lt;br /&gt;
&lt;br /&gt;
Tasks:&lt;br /&gt;
* Write new acceptance tests for the Moodle app&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
&lt;br /&gt;
* We require prospective students to set-up and run in a local environment the existing tests following this documentation: [[Acceptance testing for the mobile app]], students must record a video of the tests running on a local machine.&lt;br /&gt;
* We also require students to create an additional simple test (detailed instructions for writing tests are available in the previous link)&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; Behat (PHP)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level:&#039;&#039;&#039; Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor:&#039;&#039;&#039; [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Front-end editor for the plugin skeleton generator ===&lt;br /&gt;
&lt;br /&gt;
This is a follow-up project for a [[GSOC/2016#Plugin skeleton generator|successful GSOC 2016 project]] that resulted in a new tool allowing developers to quickly generate a skeleton (scaffolding, template) for a new Moodle plugin. The tool proved to be a helpful helper with significant impact on the quality of Moodle plugins code. This follow-up project aims at further improvements of the skeleton generator. The primary goal is to implement a developer-friendly user interface / front-end editor allowing to configure the plugin&#039;s properties (recipe file) easily. The UI should guide the developer through the process of designing and defining the plugin properties and facilitate the whole process.&lt;br /&gt;
&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP + JS&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=1601&amp;amp;course=5 David Mudrák]&lt;br /&gt;
&lt;br /&gt;
=== Add multi-class capabilities to Moodle&#039;s machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Moodle includes an analytics API that uses machine learning for binary classification. This is enough for classification problems like &amp;quot;student at risk&amp;quot; vs &amp;quot;student not at risk&amp;quot;. We want to expand this API capabilities by supporting multi-class classification, so we could write models like &amp;quot;very low grade&amp;quot;, &amp;quot;low grade&amp;quot;, &amp;quot;pass&amp;quot;, &amp;quot;best student ever&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Tasks:&lt;br /&gt;
* Modify the two machine learning backends included in Moodle core to support multi-class classification problems. This includes the PHP ML backend (based on php-ml library) and the Python ML backend (Tensorflow).&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Tracker issue:&#039;&#039;&#039; https://tracker.moodle.org/browse/MDL-58992&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP + Python + basic understanding of machine learning algorithms and TensorFlow&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level:&#039;&#039;&#039; Medium/High&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor:&#039;&#039;&#039; [https://moodle.org/user/profile.php?id=122326 David Monllaó]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program&lt;br /&gt;
* [https://tracker.moodle.org/issues/?jql=type%20in%20%28%22New%20Feature%22%2C%20Improvement%29%20AND%20resolution%20%3D%20unresolved%20and%20labels%20in%20%28addon_candidate%29%20ORDER%20BY%20votes%20DESC Popular new feature and improvement requests in Tracker that can be implemented as plugins]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=55558</id>
		<title>Projects for new developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=55558"/>
		<updated>2019-02-08T11:58:50Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Add multi-class capabilities to Moodle&amp;#039;s machine learning backends */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{GSOC}}&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
* Moodle uses PHP, JavaScript, SQL and a number of other Web languages, so learning those is a good place to start.&lt;br /&gt;
* When you have some basic PHP programming skills, you may wish to start learning about how the Moodle code is organised. It is recommended that you go through the [[Tutorial]].&lt;br /&gt;
* If you are looking for projects suggested in the tracker, look for issues with the [https://tracker.moodle.org/issues/?jql=labels%20in%20%28addon_candidate%29 &#039;addon_candidate&#039; label].&lt;br /&gt;
* If you are looking to make a quick contribution, look for tracker issues with marked as [https://tracker.moodle.org/issues/?jql=Difficulty%20%3D%20Easy easy].&lt;br /&gt;
* As you become more involved in Moodle development, you might like to learn more about the [[Coding|coding conventions]] used and how changes to Moodle core code are [[Process|processed]]. Once you become confident enough, please consider adopting a [https://moodle.org/plugins/browse.php?list=set&amp;amp;id=61 plugin seeking a new maintainer].&lt;br /&gt;
&lt;br /&gt;
==Potential projects==&lt;br /&gt;
&lt;br /&gt;
This evolving page lists possible Moodle projects for new developers derived from community suggestions and lists projects together with experienced core developers willing to mentor new developers.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you have any ideas for new features in Moodle which might be suitable as projects for new developers, please see [[New feature ideas]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Improve SCORM plugin ===&lt;br /&gt;
There are a number of areas of SCORM that could be improved as part of a GSOC project, some of these are bigger projects and others could be combined to form a single project.&lt;br /&gt;
&lt;br /&gt;
These are just some examples, take a look at the open SCORM issues in the Moodle tracker for a list of other issues.&lt;br /&gt;
* Improve Grading (MDL-51086, MDL-52871, MDL-37421)&lt;br /&gt;
* Improve validation of SCORM packages (MDL-38060, MDL-24057)&lt;br /&gt;
* Convert YUI Treeview to use Jquery (Moodle is moving away from YUI and the existing Treeview has a few issues)&lt;br /&gt;
* Choose where to send users after completing SCORM (MDL-61677)&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Acceptance tests for the Moodle app ===&lt;br /&gt;
&lt;br /&gt;
Since Moodle 3.7 it will be possible to write and run acceptance tests for the Moodle app.&lt;br /&gt;
&lt;br /&gt;
Tasks:&lt;br /&gt;
* Write new acceptance tests for the Moodle app&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
&lt;br /&gt;
* We require prospective students to set-up and run in a local environment the existing tests following this documentation: [[Acceptance testing for the mobile app]], students must record a video of the tests running on a local machine.&lt;br /&gt;
* We also require students to create an additional simple test (detailed instructions for writing tests are available in the previous link)&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; Behat (PHP)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level:&#039;&#039;&#039; Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor:&#039;&#039;&#039; [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Front-end editor for the plugin skeleton generator ===&lt;br /&gt;
&lt;br /&gt;
This is a follow-up project for a [[GSOC/2016#Plugin skeleton generator|successful GSOC 2016 project]] that resulted in a new tool allowing developers to quickly generate a skeleton (scaffolding, template) for a new Moodle plugin. The tool proved to be a helpful helper with significant impact on the quality of Moodle plugins code. This follow-up project aims at further improvements of the skeleton generator. The primary goal is to implement a developer-friendly user interface / front-end editor allowing to configure the plugin&#039;s properties (recipe file) easily. The UI should guide the developer through the process of designing and defining the plugin properties and facilitate the whole process.&lt;br /&gt;
&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP + JS&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=1601&amp;amp;course=5 David Mudrák]&lt;br /&gt;
&lt;br /&gt;
=== Add multi-class capabilities to Moodle&#039;s machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Moodle includes an analytics API that uses machine learning for binary classification. This is enough for classification problems like &amp;quot;student at risk&amp;quot; vs &amp;quot;student not at risk&amp;quot;. We want to expand this API capabilities by supporting multi-class classification, so we could write models like &amp;quot;very low grade&amp;quot;, &amp;quot;low grade&amp;quot;, &amp;quot;pass&amp;quot;, &amp;quot;best student ever&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Tasks:&lt;br /&gt;
* Modify the two machine learning backends included in Moodle core to support multi-class classification problems. This includes the PHP ML backend (based on php-ml library) and the Python ML backend (Tensorflow)&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Tracker issue:&#039;&#039;&#039; https://tracker.moodle.org/browse/MDL-58992&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP + Python + basic understanding of machine learning algorithms and TensorFlow&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level:&#039;&#039;&#039; Medium/High&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor:&#039;&#039;&#039; [https://moodle.org/user/profile.php?id=122326 David Monllaó]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program&lt;br /&gt;
* [https://tracker.moodle.org/issues/?jql=type%20in%20%28%22New%20Feature%22%2C%20Improvement%29%20AND%20resolution%20%3D%20unresolved%20and%20labels%20in%20%28addon_candidate%29%20ORDER%20BY%20votes%20DESC Popular new feature and improvement requests in Tracker that can be implemented as plugins]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=55557</id>
		<title>Projects for new developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=55557"/>
		<updated>2019-02-08T11:57:51Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{GSOC}}&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
* Moodle uses PHP, JavaScript, SQL and a number of other Web languages, so learning those is a good place to start.&lt;br /&gt;
* When you have some basic PHP programming skills, you may wish to start learning about how the Moodle code is organised. It is recommended that you go through the [[Tutorial]].&lt;br /&gt;
* If you are looking for projects suggested in the tracker, look for issues with the [https://tracker.moodle.org/issues/?jql=labels%20in%20%28addon_candidate%29 &#039;addon_candidate&#039; label].&lt;br /&gt;
* If you are looking to make a quick contribution, look for tracker issues with marked as [https://tracker.moodle.org/issues/?jql=Difficulty%20%3D%20Easy easy].&lt;br /&gt;
* As you become more involved in Moodle development, you might like to learn more about the [[Coding|coding conventions]] used and how changes to Moodle core code are [[Process|processed]]. Once you become confident enough, please consider adopting a [https://moodle.org/plugins/browse.php?list=set&amp;amp;id=61 plugin seeking a new maintainer].&lt;br /&gt;
&lt;br /&gt;
==Potential projects==&lt;br /&gt;
&lt;br /&gt;
This evolving page lists possible Moodle projects for new developers derived from community suggestions and lists projects together with experienced core developers willing to mentor new developers.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you have any ideas for new features in Moodle which might be suitable as projects for new developers, please see [[New feature ideas]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Improve SCORM plugin ===&lt;br /&gt;
There are a number of areas of SCORM that could be improved as part of a GSOC project, some of these are bigger projects and others could be combined to form a single project.&lt;br /&gt;
&lt;br /&gt;
These are just some examples, take a look at the open SCORM issues in the Moodle tracker for a list of other issues.&lt;br /&gt;
* Improve Grading (MDL-51086, MDL-52871, MDL-37421)&lt;br /&gt;
* Improve validation of SCORM packages (MDL-38060, MDL-24057)&lt;br /&gt;
* Convert YUI Treeview to use Jquery (Moodle is moving away from YUI and the existing Treeview has a few issues)&lt;br /&gt;
* Choose where to send users after completing SCORM (MDL-61677)&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Acceptance tests for the Moodle app ===&lt;br /&gt;
&lt;br /&gt;
Since Moodle 3.7 it will be possible to write and run acceptance tests for the Moodle app.&lt;br /&gt;
&lt;br /&gt;
Tasks:&lt;br /&gt;
* Write new acceptance tests for the Moodle app&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
&lt;br /&gt;
* We require prospective students to set-up and run in a local environment the existing tests following this documentation: [[Acceptance testing for the mobile app]], students must record a video of the tests running on a local machine.&lt;br /&gt;
* We also require students to create an additional simple test (detailed instructions for writing tests are available in the previous link)&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; Behat (PHP)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level:&#039;&#039;&#039; Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor:&#039;&#039;&#039; [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Front-end editor for the plugin skeleton generator ===&lt;br /&gt;
&lt;br /&gt;
This is a follow-up project for a [[GSOC/2016#Plugin skeleton generator|successful GSOC 2016 project]] that resulted in a new tool allowing developers to quickly generate a skeleton (scaffolding, template) for a new Moodle plugin. The tool proved to be a helpful helper with significant impact on the quality of Moodle plugins code. This follow-up project aims at further improvements of the skeleton generator. The primary goal is to implement a developer-friendly user interface / front-end editor allowing to configure the plugin&#039;s properties (recipe file) easily. The UI should guide the developer through the process of designing and defining the plugin properties and facilitate the whole process.&lt;br /&gt;
&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP + JS&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=1601&amp;amp;course=5 David Mudrák]&lt;br /&gt;
&lt;br /&gt;
=== Add multi-class capabilities to Moodle&#039;s machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Moodle includes an analytics API that uses machine learning for binary classification. This is enough for classification problems like &amp;quot;student at risk&amp;quot; vs &amp;quot;student not at risk&amp;quot;. We want to expand this API capabilities by supporting multi-class classification, so we could write models like &amp;quot;very low grade&amp;quot;, &amp;quot;low grade&amp;quot;, &amp;quot;pass&amp;quot;, &amp;quot;best student ever&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Tasks:&lt;br /&gt;
* Modify the two machine learning backends included in Moodle core to support multi-class classification problems. This includes the PHP ML backend (based on php-ml library) and the Python ML backend (Tensorflow)&lt;br /&gt;
&lt;br /&gt;
Requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered. This MUST be completed before your application can be considered valid.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Tracker issue:&#039;&#039;&#039; https://tracker.moodle.org/browse/MDL-60523&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP + Python + basic understanding of machine learning algorithms and TensorFlow&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level:&#039;&#039;&#039; Medium/High&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor:&#039;&#039;&#039; [https://moodle.org/user/profile.php?id=122326 David Monllaó]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program&lt;br /&gt;
* [https://tracker.moodle.org/issues/?jql=type%20in%20%28%22New%20Feature%22%2C%20Improvement%29%20AND%20resolution%20%3D%20unresolved%20and%20labels%20in%20%28addon_candidate%29%20ORDER%20BY%20votes%20DESC Popular new feature and improvement requests in Tracker that can be implemented as plugins]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=55209</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=55209"/>
		<updated>2018-12-04T15:42:19Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Create the model */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4+ provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Documentation available in [https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends].&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends] is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors. Analytics API will be able to find them as long as they follow the namespace conventions described below. &lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this section do not include Machine learning backend interfaces, they are available in https://docs.moodle.org/dev/Machine_learning_backends#Interfaces.&lt;br /&gt;
&lt;br /&gt;
==== Analysable (core_analytics\analysable) ====&lt;br /&gt;
&lt;br /&gt;
Analysables are those elements in Moodle that contain samples. In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity. Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
They list of methods that need to be implemented is quite simple and does not require much explanation.&lt;br /&gt;
&lt;br /&gt;
It is also important to mention that analysable elements should be lazy loaded, otherwise you may have PHP memory issues. The reason is that analysers load all analysable elements in the site to calculate which ones are going to be calculated next (skipping the ones processed recently and stuff like that) You can take core_analytics\course as an example.&lt;br /&gt;
&lt;br /&gt;
Methods to implement:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable unique identifier in the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_id();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable human readable name&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function get_name();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable context.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    public function get_context();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_start&#039;&#039;&#039; and &#039;&#039;&#039;get_end&#039;&#039;&#039; define the start and end times that indicators will use for their calculations.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The start of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_start();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The end of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_end();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Analyser (core_analytics\local\analyser\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_analysables&#039;&#039;&#039; returns the whole list of analysable elements in the site. Each model will later be able to discard analysables that do not match their expectations. &#039;&#039;e.g. if your model is only interested in quizzes with a time close the analyser will return all quizzes, your model will exclude the ones without a time close. This approach is supposed to make analysers more reusable.&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the list of analysable elements available on the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \core_analytics\analysable[] Array of analysable elements using the analysable id as array key.&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analysables();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_all_samples&#039;&#039;&#039; and &#039;&#039;&#039;get_samples&#039;&#039;&#039; should return data associated with the sample ids they provide. This is important for 2 reasons:&lt;br /&gt;
* The data they provide alongside the sample origin is used to filter out indicators that are not related to what this analyser analyses. &#039;&#039;e.g. courses analysers do provide courses and information about courses, but not information about users, a &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator will require the user object to be available. A model using a courses analyser will not be able to use the &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator.&lt;br /&gt;
* The data included here is cached in PHP static vars; on one hand this reduces the amount of db queries indicators need to perform. On the other hand, if not well balanced, it can lead to PHP memory issues.  &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns this analysable list of samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function get_all_samples(\core_analytics\analysable $analysable);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns the samples data from a list of sample ids.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int[] $sampleids&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples($sampleids);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_sample_analysable&#039;&#039;&#039; method is executing during prediction:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analysable of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \core_analytics\analysable&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_sample_analysable($sampleid);&lt;br /&gt;
&lt;br /&gt;
The sample origin is the moodle database table that uses the sample id as primary key.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the sample&#039;s origin in moodle database.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples_origin();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_access_context&#039;&#039;&#039; associates a context to a sampleid. This is important because this sample predictions will only be available for users with &#039;&#039;moodle/analytics:listinsights&#039;&#039; capability in that context.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the context of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_access_context($sampleid);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_description&#039;&#039;&#039; is used to display samples in &#039;&#039;Insights&#039;&#039; report:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Describes a sample with a description summary and a \renderable (an image for example)&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param int $contextid&lt;br /&gt;
     * @param array $sampledata&lt;br /&gt;
     * @return array array(string, \renderable)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_description($sampleid, $contextid, $sampledata);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;processes_user_data&#039;&#039;&#039; and &#039;&#039;&#039;join_sample_user&#039;&#039;&#039; methods are used by the analytics implementation of the privacy API. You only need to overwrite them if your analyser deals with user data. They are used to export and delete user data that is stored in analytics database tables:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Whether the plugin needs user data clearing or not.&lt;br /&gt;
     *&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function processes_user_data();&lt;br /&gt;
    /**&lt;br /&gt;
     * SQL JOIN from a sample to users table.&lt;br /&gt;
     *&lt;br /&gt;
     * More info in [https://github.com/moodle/moodle/blob/master/analytics/classes/local/analyser/base.php core_analytics\local\analyser\base]::join_sample_user&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $sampletablealias The alias of the table with a sampleid field that will join with this SQL string&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function join_sample_user($sampletablealias);&lt;br /&gt;
&lt;br /&gt;
==== Indicator (core_analytics\local\indicator\base) ====&lt;br /&gt;
&lt;br /&gt;
Indicators should generally extend one of these 3 classes, depending on the values they can return: &#039;&#039;core_analytics\local\indicator\binary&#039;&#039; for &#039;&#039;&#039;yes/no&#039;&#039;&#039; indicators, &#039;&#039;core_analytics\local\indicator\linear&#039;&#039; for indicators that return linear values and &#039;&#039;core_analytics\local\indicator\discrete&#039;&#039; for categorised indicators. In case you want your activity module to implement a [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out#Indicators community of inquiry] indicator you can extend &#039;&#039;core_analytics\local\indicator\community_of_inquiry_indicator&#039;&#039; look for examples in Moodle core.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;required_sample_data&#039;&#039;&#039; to specify what your indicator needs to be calculated; you may need a &#039;&#039;user&#039;&#039; object, a &#039;&#039;course&#039;&#039;, a &#039;&#039;grade item&#039;&#039;... The default implementation does not require anything. Models which analysers do not return the required data will not be able to use your indicator so only list here what you really need. e.g. if you need a grade_grades record mark it as required, but there is no need to require the &#039;&#039;user&#039;&#039; object and the &#039;&#039;course&#039;&#039; as well because you can obtain them from the grade_grades item. It is very likely that the analyser will provide them as well because the principle they follow is to include as much related data as possible but do not flag related objects as required because an analyser may, for example, chose to not include the &#039;&#039;user&#039;&#039; object because it is too big and sites can have memory problems.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows indicators to specify data they need.&lt;br /&gt;
     *&lt;br /&gt;
     * e.g. A model using courses as samples will not provide users data, but an indicator like&lt;br /&gt;
     * &amp;quot;user is hungry&amp;quot; needs user data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return null|string[] Name of the required elements (use the database tablename)&lt;br /&gt;
     */&lt;br /&gt;
    public static function required_sample_data() {&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A single method must be implemented, &#039;&#039;&#039;calculate_sample&#039;&#039;&#039;. Most indicators make use of $starttime and $endtime to restrict the time period they consider for their calculations (e.g. read actions during $starttime - $endtime period) but some indicators may not need to apply any restriction (e.g. does this user have a user picture and profile description?) &#039;&#039;self::MIN_VALUE&#039;&#039; is -1 and &#039;&#039;self::MAX_VALUE&#039;&#039; is 1. We do not recommend changing these values.&lt;br /&gt;
 &lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates the sample.&lt;br /&gt;
     *&lt;br /&gt;
     * Return a value from self::MIN_VALUE to self::MAX_VALUE or null if the indicator can not be calculated for this sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param string $sampleorigin&lt;br /&gt;
     * @param integer $starttime Limit the calculation to this timestart&lt;br /&gt;
     * @param integer $endtime Limit the calculation to this timeend&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function calculate_sample($sampleid, $sampleorigin, $starttime, $endtime);&lt;br /&gt;
&lt;br /&gt;
Note that performance here is critical as it runs once for each sample and for each range in the time-splitting method; some tips:  &lt;br /&gt;
* To avoid performance issues or repeated db queries analyser classes provide information about the samples that you can use for your calculations to save some database queries. You can retrieve information about a sample with &#039;&#039;&#039;$user = $this-&amp;gt;retrieve(&#039;user&#039;, $sampleid)&#039;&#039;&#039;. &#039;&#039;retrieve()&#039;&#039; will return false if the requested data is not available.&lt;br /&gt;
* You can also overwrite &#039;&#039;fill_per_analysable_caches&#039;&#039; method if necessary (keep in mind though that PHP memory is not unlimited).&lt;br /&gt;
* Indicator instances are reset for each analysable and time range that is processed. This helps keeping the memory usage acceptably low and prevents hard-to-trace caching bugs.&lt;br /&gt;
&lt;br /&gt;
==== Target (core_analytics\local\target\base) ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
The first thing a target must define is the analyser class that it will use. The analyser class is specified in &#039;&#039;&#039;get_analyser_class&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analyser class that should be used along with this target.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string The full class name as a string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analyser_class();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;is_valid_analysable&#039;&#039;&#039; and &#039;&#039;&#039;is_valid_sample&#039;&#039;&#039; are used to discard elements that are not valid for your target.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows the target to verify that the analysable is a good candidate.&lt;br /&gt;
     *&lt;br /&gt;
     * This method can be used as a quick way to discard invalid analysables.&lt;br /&gt;
     * e.g. Imagine that your analysable don&#039;t have students and you need them.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param bool $fortraining&lt;br /&gt;
     * @return true|string&lt;br /&gt;
     */&lt;br /&gt;
    public function is_valid_analysable(\core_analytics\analysable $analysable, $fortraining = true);&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is this sample from the $analysable valid?&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param bool $fortraining&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_valid_sample($sampleid, \core_analytics\analysable $analysable, $fortraining = true);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;calculate_sample&#039;&#039;&#039; is the method that calculates the target value.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates this target for the provided samples.&lt;br /&gt;
     *&lt;br /&gt;
     * In case there are no values to return or the provided sample is not applicable just return null.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param int|false $starttime Limit calculations to start time&lt;br /&gt;
     * @param int|false $endtime Limit calculations to end time&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    protected function calculate_sample($sampleid, \core_analytics\analysable $analysable, $starttime = false, $endtime = false);&lt;br /&gt;
&lt;br /&gt;
==== Time-splitting method (core_analytics\local\time_splitting\base) ====&lt;br /&gt;
&lt;br /&gt;
Time-splitting methods are useful to define when the analytics API will train the predictions processor and when it will generate predictions. As explained above in [[Analytics_API#Time_splitting_methods]], they define time ranges based on analysable elements start and end timestamps.&lt;br /&gt;
&lt;br /&gt;
The base class is &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;; if what you are after is to split the analysable duration in equal parts or in cumulative parts you can extend &#039;&#039;&#039;\core_analytics\local\time_splitting\equal_parts&#039;&#039;&#039; or &#039;&#039;&#039;\core_analytics\local\time_splitting\accumulative_parts&#039;&#039;&#039; instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;define_ranges&#039;&#039;&#039; is the main method to implement and its values mostly depend on the current analysable element (available in &#039;&#039;&#039;$this-&amp;gt;analysable&#039;&#039;&#039;). An array of time ranges should be returned, each of these ranges should contain 3 attributes: A start time (&#039;start&#039;) and an end time (&#039;end&#039;) that will be passed to indicators so they can limit the amount of activity logs they read; the 3rd attribute is &#039;time&#039;, which value will determine when the range will be executed.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define the time splitting methods ranges.&lt;br /&gt;
     *&lt;br /&gt;
     * &#039;time&#039; value defines when predictions are executed, their values will be compared with&lt;br /&gt;
     * the current time in ready_to_predict&lt;br /&gt;
     *&lt;br /&gt;
     * @return array(&#039;start&#039; =&amp;gt; time(), &#039;end&#039; =&amp;gt; time(), &#039;time&#039; =&amp;gt; time())&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_ranges();&lt;br /&gt;
&lt;br /&gt;
A name and description should also be specified:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns a lang_string object representing the name for the time splitting method.&lt;br /&gt;
     *&lt;br /&gt;
     * Used as column identificator.&lt;br /&gt;
     *&lt;br /&gt;
     * If there is a corresponding &#039;_help&#039; string this will be shown as well.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \lang_string&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_name() : \lang_string;&lt;br /&gt;
&lt;br /&gt;
==== Calculable (core_analytics\calculable) ====&lt;br /&gt;
&lt;br /&gt;
Leaving this interface for the end because it is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
New models can be created and implemented in php, and can be packaged as a Moodle local plugin for distribution. Sample model components and models are provided at https://github.com/dmonllao/moodle-local_testanalytics.&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
As specified in https://docs.moodle.org/dev/Analytics_API#Target_.28core_analytics.5Clocal.5Ctarget.5Cbase.29.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
To add a new model to the system, it must be defined in a PHP file. Normally this is done as part of  install.php or upgrade.php for a plugin that contains the new model and components. However, it is also possible to execute the necessary commands in a standalone PHP file that references the Moodle config.php.&lt;br /&gt;
&lt;br /&gt;
To create the model, specify at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    // Note that the 3rd and 4rd arguments (the time splitting method and the predictions processor) are optional. The 4th argument is available from Moodle 3.6 onwards.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;, &#039;\mlbackend_python\processor&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=54528</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=54528"/>
		<updated>2018-07-17T07:10:16Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Maintaining good security */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with [[PHP FAQ|PHP]] in general and that you are able to [[:en:Installing AMP|install a database and web server]] on your local machine. &lt;br /&gt;
&lt;br /&gt;
If you need to learn PHP, you can see one PHP tutorial at http://www.w3schools.com/php/default.asp, another at http://php.net/manual/en/tutorial.php and several videos in YouTube at https://www.youtube.com/results?search_query=learn+php. &lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===What&#039;s in the box===&lt;br /&gt;
If you [http://download.moodle.org/ download] Moodle source code or clone it from [https://github.com/moodle/moodle git], you will see a bunch of files and folders. This code consists of [[Core_APIs|Moodle core]] (that consists of the Very core and Core components), [[Moodle_libraries_credits|third party libraries]] and [[Plugin_types|plugins]]. Their mixed locations can be quite confusing at first but as you start working with it it will become more clear. Moodle developers should avoid modifications of the third party libraries (unless required) and core can never call methods defined in plugins. See also [[Communication Between Components]]&lt;br /&gt;
&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
* Moodle uses Git for developement. View the link below for basic information about Git and Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Git for developers]]&lt;br /&gt;
&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
* Moodle has lots of different types of plugins.&lt;br /&gt;
* There are 24 different categories of plugin listed on the moodle plugin database. Before starting check here to see if someone else has not already created what you are looking for. Perhaps you could contribute to their plugin instead of creating a new one.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* https://moodle.org/plugins/&lt;br /&gt;
* [[Plugin types]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
&lt;br /&gt;
The code of a plugin is organised into multiple different files and directories within a single root directory. All plugins follow the same directory and file structure.&lt;br /&gt;
&lt;br /&gt;
Links&lt;br /&gt;
&lt;br /&gt;
* [[Plugin files]] - Provides a list of required and common plugins files along with their location and purpose.&lt;br /&gt;
&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
&lt;br /&gt;
The link below explains how to create and display a simple page in Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
&lt;br /&gt;
===Multiple languages support===&lt;br /&gt;
Moodle has a mechanism for displaying given text string in multiple languages, depending on the user&#039;s preferred language and the site configuration. Plugin authors must define all the text strings used by the plugin in the default English language. That is then used as a reference for translations to other languages.&lt;br /&gt;
&lt;br /&gt;
* [[String API]]&lt;br /&gt;
&lt;br /&gt;
===Moodle file structure===&lt;br /&gt;
==== Automatic Class Loading ====&lt;br /&gt;
Automatic class loading helps us to automatically include class files as and when they are required instead of manually including them everytime. Moodle supports automatic class loading. See the link below for the explanation of rules associated with it - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Automatic class loading]]&lt;br /&gt;
&lt;br /&gt;
==== Callbacks ====&lt;br /&gt;
You can add a lot of features to your plugin by providing certain callbacks that Moodle expects to be present in your plugin&#039;s lib.php file. A detailed list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Callbacks ]]&lt;br /&gt;
&lt;br /&gt;
==== Plugin types ====&lt;br /&gt;
Moodle supports a wide range of plugin types. The complete list and location to place these plugins can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Plugin types ]]&lt;br /&gt;
&lt;br /&gt;
==== Core APIs ====&lt;br /&gt;
Moodle provides apis for a plugin to interact with core and other external systems. For example you don&#039;t have to manually do any SQL queries, Moodle provides it&#039;s own DDL and DML layers. The link below lists all major core apis in Moodle - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Core APIs ]]&lt;br /&gt;
&lt;br /&gt;
==== Browser accessible pages ====&lt;br /&gt;
Any php file in your plugin will either be browser accessible or be an internal file. &lt;br /&gt;
&lt;br /&gt;
For browser accessible pages you must include config.php with code something similar to this - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(&#039;../../config.php&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For internal files the code should use the following - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add basic content to your page===&lt;br /&gt;
* Content for a page is added through renderers.&lt;br /&gt;
* Renderers are typically stored in the &amp;quot;classes/output&amp;quot; directory.&lt;br /&gt;
* Putting content in renderers allows themers to override the visual display of the content.&lt;br /&gt;
* Very basic information is presented using the html_writer class.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Renderer]]&lt;br /&gt;
&lt;br /&gt;
=== Content with templates ===&lt;br /&gt;
* In most cases when displaying content, templates should be used.&lt;br /&gt;
* templates are stored in the &amp;quot;templates&amp;quot; directory. The templates use mustache files.&lt;br /&gt;
* Mustache files allow for more generic html with placeholders inserted, that inserts the data (context) at run time.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
* The moodle navigation system has hooks which allows plugins to add links to the navigation menu.&lt;br /&gt;
* Hooks are located in lib.php. Try to keep lib.php as small as possible as this file is included on every page. Put classes and functions elsewhere.&lt;br /&gt;
* Course navigation extension example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function tool_devcourse_extend_navigation_course($navigation, $course, $coursecontext) {&lt;br /&gt;
    $url = new moodle_url(&#039;/admin/tool/devcourse/index.php&#039;);&lt;br /&gt;
    $devcoursenode = navigation_node::create(&#039;Development course&#039;, $url, navigation_node::TYPE_CUSTOM, &#039;Dev course&#039;, &#039;devcourse&#039;);&lt;br /&gt;
    $navigation-&amp;gt;add_node($devcoursenode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[:en:Navigation]]&lt;br /&gt;
&lt;br /&gt;
===Database queries===&lt;br /&gt;
* Moodle has a generic database query library. Behind this library are additional libraries which allow Moodle to work with MySQL, PostgreSQL, Oracle, SQL Server, and Maria DB.&lt;br /&gt;
* Where possible it is advisable to use the predefined functions rather than write out SQL. Writing SQL has a greater chance of not working with one of the supported databases.&lt;br /&gt;
* The return of the select functions tends to be an object or an array of objects.&lt;br /&gt;
&lt;br /&gt;
Example call to retrieve data from the course table.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$courses = $DB-&amp;gt;get_records(&#039;course&#039;, null, &#039;&#039;, &#039;id, category, fullname, shortname&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example of data returned from the above code.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [43] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 43&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX -Test 5&lt;br /&gt;
            [shortname] =&amp;gt; xxt5&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [5] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 5&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; With the glossary&lt;br /&gt;
            [shortname] =&amp;gt; wtg&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [39] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 39&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX - Test 1&lt;br /&gt;
            [shortname] =&amp;gt; xxt1&lt;br /&gt;
        )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
* We create our database tables in Moodle using the  XMLDB editor. This is located in the administration block &amp;quot;Site administration | Development | XMLDB editor&amp;quot;.&lt;br /&gt;
* The {plugin}\db directory needs to have write access for the XMLDB editor to be most effective.&lt;br /&gt;
* XMLDB editor creates an install.xml file in the db directory. This file will be loaded during the install to create your tables.&lt;br /&gt;
* XMLDB editor will produce php update code for adding and updating moodle database tables.&lt;br /&gt;
&lt;br /&gt;
The XMLDB main page.&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-main.png]]&lt;br /&gt;
&lt;br /&gt;
Upgrade code generated by the XMLDB&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-upgrade-code.png]]&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[XMLDB editor]]&lt;br /&gt;
* [[Using XMLDB]]&lt;br /&gt;
* [[XMLDB Documentation]]&lt;br /&gt;
* [[Upgrade API]]&lt;br /&gt;
* [[XMLDB introduction]]&lt;br /&gt;
&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
* Capabilities are controlled in &amp;quot;access.php&amp;quot; under the &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* This file has an array of capabilities with the following:&lt;br /&gt;
** name&lt;br /&gt;
** possible security risks behind giving this capability.&lt;br /&gt;
** The context that this capability works in.&lt;br /&gt;
** The default roles (teacher, manager, student, etc) that have this capability.&lt;br /&gt;
** Various other information.&lt;br /&gt;
* These capabilities are checked in code to allow access to pages, sections, and abilities (saving, deleting, etc).&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles#Context]]&lt;br /&gt;
* [[:en:Category:Capabilities]]&lt;br /&gt;
* [[:en:Roles and permissions]]&lt;br /&gt;
&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
* Moodle has it&#039;s own forms library.&lt;br /&gt;
* The forms lib includes a lot of accessibility code, and error checking, by default.&lt;br /&gt;
* Moodle forms can be displayed in JavaScript using &#039;fragments&#039;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[lib/formslib.php Form Definition]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
* Use the sesskey when directing to pages to do actions.&lt;br /&gt;
* Use the appropriate filters when retrieving parameters&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Security]]&lt;br /&gt;
* [[lib/formslib.php Form Definition#Most Commonly Used PARAM .2A Types]]&lt;br /&gt;
* [[Output functions#p.28.29 and s.28.29]]&lt;br /&gt;
&lt;br /&gt;
===Handling files===&lt;br /&gt;
* Files are conceptually stored in file areas.&lt;br /&gt;
* Plugins can only access files from it&#039;s own component.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[File API internals]]&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
* Moodle is currently using jquery and AMD (Asynchronous Module Definition).&lt;br /&gt;
* JavaScript files are located in the &amp;quot;amd/src&amp;quot; directory.&lt;br /&gt;
* Use grunt to build your JavaScript.&lt;br /&gt;
* Include your JavaScript in php files as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;{JScriptfilename}&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Can also be included in mustache templates.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[jQuery]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[JavaScript guidelines]]&lt;br /&gt;
* [[Grunt]]&lt;br /&gt;
&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
* All logging in moodle is done through the events system.&lt;br /&gt;
* New events should be located in the &amp;quot;classes/event&amp;quot; directory.&lt;br /&gt;
* It is possible to create observers and subscribe to events.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
===Accessibility===&lt;br /&gt;
&lt;br /&gt;
Accessibility is an important consideration while developing a plugin to make sure your plugin is accessible to all users and doesn&#039;t discriminate against users with disablities. This often is a mandated requirement in many countries. The links below explain common practices that we follow at Moodle to make the interface more accessible.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Accessibility]]&lt;br /&gt;
* [[Usability]]&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
* Moodle web services uses the external functions API.&lt;br /&gt;
* The recommended way to make AJAX requests is to use the ajax AMD file which uses the external functions API.&lt;br /&gt;
* External functions should be located in the &amp;quot;classes/external.php&amp;quot; file.&lt;br /&gt;
* A list of services should be included in &amp;quot;db/services.php&amp;quot;. This file is required to register the web services with Moodle.&lt;br /&gt;
* The services list is an array which contains:&lt;br /&gt;
** &#039;&#039;&#039;classname&#039;&#039;&#039; Name of the external class.&lt;br /&gt;
** &#039;&#039;&#039;methodname&#039;&#039;&#039; The name of the external function.&lt;br /&gt;
** &#039;&#039;&#039;classpath&#039;&#039;&#039; system path to the external function file.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; Description of the function&lt;br /&gt;
** &#039;&#039;&#039;type&#039;&#039;&#039; Create, read, update, delete&lt;br /&gt;
** &#039;&#039;&#039;ajax&#039;&#039;&#039; Can this function be used with ajax?&lt;br /&gt;
** &#039;&#039;&#039;capabilities&#039;&#039;&#039; Capabilities required to use this function.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[External functions API]]&lt;br /&gt;
* [[Adding a web service to a plugin]]&lt;br /&gt;
* [[Web services API]]&lt;br /&gt;
&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
* The main cache used by moodle is the Moodle Universal Cache (MUC).&lt;br /&gt;
* The MUC has several cache definitions - &lt;br /&gt;
** Request cache&lt;br /&gt;
** Session cache&lt;br /&gt;
** Application&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[The Moodle Universal Cache (MUC)]]&lt;br /&gt;
* [[:en:MUC FAQ]]&lt;br /&gt;
* [[:en:Caching]]&lt;br /&gt;
&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
* Supporting backup and restore requires creating several files in the &#039;backup/moodle2&#039; directory.&lt;br /&gt;
* Back requires a class to extend the backup_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* Restore requires a class to extend the restore_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* The restore steps lib defines the structure of the plugin to be restored.&lt;br /&gt;
* The backup steps lib defines steps, settings, attributes, etc.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Backup 2.0 for developers]] - provides an example of step-by-step implementation of backup support to your plugin&lt;br /&gt;
* [[:en:Backup and restore FAQ]]&lt;br /&gt;
&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
* Moodle has two types of automated testing: php unit tests, and behat tests.&lt;br /&gt;
* Unit tests are for testing functions.&lt;br /&gt;
* Behat tests runs through scenarios.&lt;br /&gt;
** Behat tests follows a script and navigates through moodle pages.&lt;br /&gt;
* unit tests should be located in the &amp;quot;tests&amp;quot; directory.&lt;br /&gt;
* behat tests should be located in the &amp;quot;tests/behat&amp;quot; directory.&lt;br /&gt;
* Tests located in these directories will be run through when a full test run is initiated.&lt;br /&gt;
* behat tests are actually feature files and end with the extension &amp;quot;.feature&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Writing PHPUnit tests]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
* publish your plugins at https://moodle.org/plugins/&lt;br /&gt;
* Publishing plugins on the moodle site leads you through a bunch of steps that need to be completed in order for the plugin to be approved and published.&lt;br /&gt;
* Plugins will be run through a pre-checker to give suggestions about possible issues with the code.&lt;br /&gt;
&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==TODO==&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=355789 this (july 2017) forum thread ] about Getting Started with Moodle Development.&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=352360 this (may 2017) forum thread] about Getting Started with Moodle Development.&lt;br /&gt;
&lt;br /&gt;
See also these older tutorials:&lt;br /&gt;
&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
==Any questions?==&lt;br /&gt;
&lt;br /&gt;
If you have any questions, you&#039;re welcome to post in the [https://moodle.org/mod/forum/view.php?id=55 General developer forum] on moodle.org&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=54527</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=54527"/>
		<updated>2018-07-17T07:09:49Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Maintaining good security */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with [[PHP FAQ|PHP]] in general and that you are able to [[:en:Installing AMP|install a database and web server]] on your local machine. &lt;br /&gt;
&lt;br /&gt;
If you need to learn PHP, you can see one PHP tutorial at http://www.w3schools.com/php/default.asp, another at http://php.net/manual/en/tutorial.php and several videos in YouTube at https://www.youtube.com/results?search_query=learn+php. &lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===What&#039;s in the box===&lt;br /&gt;
If you [http://download.moodle.org/ download] Moodle source code or clone it from [https://github.com/moodle/moodle git], you will see a bunch of files and folders. This code consists of [[Core_APIs|Moodle core]] (that consists of the Very core and Core components), [[Moodle_libraries_credits|third party libraries]] and [[Plugin_types|plugins]]. Their mixed locations can be quite confusing at first but as you start working with it it will become more clear. Moodle developers should avoid modifications of the third party libraries (unless required) and core can never call methods defined in plugins. See also [[Communication Between Components]]&lt;br /&gt;
&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
* Moodle uses Git for developement. View the link below for basic information about Git and Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Git for developers]]&lt;br /&gt;
&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
* Moodle has lots of different types of plugins.&lt;br /&gt;
* There are 24 different categories of plugin listed on the moodle plugin database. Before starting check here to see if someone else has not already created what you are looking for. Perhaps you could contribute to their plugin instead of creating a new one.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* https://moodle.org/plugins/&lt;br /&gt;
* [[Plugin types]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
&lt;br /&gt;
The code of a plugin is organised into multiple different files and directories within a single root directory. All plugins follow the same directory and file structure.&lt;br /&gt;
&lt;br /&gt;
Links&lt;br /&gt;
&lt;br /&gt;
* [[Plugin files]] - Provides a list of required and common plugins files along with their location and purpose.&lt;br /&gt;
&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
&lt;br /&gt;
The link below explains how to create and display a simple page in Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
&lt;br /&gt;
===Multiple languages support===&lt;br /&gt;
Moodle has a mechanism for displaying given text string in multiple languages, depending on the user&#039;s preferred language and the site configuration. Plugin authors must define all the text strings used by the plugin in the default English language. That is then used as a reference for translations to other languages.&lt;br /&gt;
&lt;br /&gt;
* [[String API]]&lt;br /&gt;
&lt;br /&gt;
===Moodle file structure===&lt;br /&gt;
==== Automatic Class Loading ====&lt;br /&gt;
Automatic class loading helps us to automatically include class files as and when they are required instead of manually including them everytime. Moodle supports automatic class loading. See the link below for the explanation of rules associated with it - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Automatic class loading]]&lt;br /&gt;
&lt;br /&gt;
==== Callbacks ====&lt;br /&gt;
You can add a lot of features to your plugin by providing certain callbacks that Moodle expects to be present in your plugin&#039;s lib.php file. A detailed list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Callbacks ]]&lt;br /&gt;
&lt;br /&gt;
==== Plugin types ====&lt;br /&gt;
Moodle supports a wide range of plugin types. The complete list and location to place these plugins can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Plugin types ]]&lt;br /&gt;
&lt;br /&gt;
==== Core APIs ====&lt;br /&gt;
Moodle provides apis for a plugin to interact with core and other external systems. For example you don&#039;t have to manually do any SQL queries, Moodle provides it&#039;s own DDL and DML layers. The link below lists all major core apis in Moodle - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Core APIs ]]&lt;br /&gt;
&lt;br /&gt;
==== Browser accessible pages ====&lt;br /&gt;
Any php file in your plugin will either be browser accessible or be an internal file. &lt;br /&gt;
&lt;br /&gt;
For browser accessible pages you must include config.php with code something similar to this - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(&#039;../../config.php&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For internal files the code should use the following - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add basic content to your page===&lt;br /&gt;
* Content for a page is added through renderers.&lt;br /&gt;
* Renderers are typically stored in the &amp;quot;classes/output&amp;quot; directory.&lt;br /&gt;
* Putting content in renderers allows themers to override the visual display of the content.&lt;br /&gt;
* Very basic information is presented using the html_writer class.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Renderer]]&lt;br /&gt;
&lt;br /&gt;
=== Content with templates ===&lt;br /&gt;
* In most cases when displaying content, templates should be used.&lt;br /&gt;
* templates are stored in the &amp;quot;templates&amp;quot; directory. The templates use mustache files.&lt;br /&gt;
* Mustache files allow for more generic html with placeholders inserted, that inserts the data (context) at run time.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
* The moodle navigation system has hooks which allows plugins to add links to the navigation menu.&lt;br /&gt;
* Hooks are located in lib.php. Try to keep lib.php as small as possible as this file is included on every page. Put classes and functions elsewhere.&lt;br /&gt;
* Course navigation extension example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function tool_devcourse_extend_navigation_course($navigation, $course, $coursecontext) {&lt;br /&gt;
    $url = new moodle_url(&#039;/admin/tool/devcourse/index.php&#039;);&lt;br /&gt;
    $devcoursenode = navigation_node::create(&#039;Development course&#039;, $url, navigation_node::TYPE_CUSTOM, &#039;Dev course&#039;, &#039;devcourse&#039;);&lt;br /&gt;
    $navigation-&amp;gt;add_node($devcoursenode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[:en:Navigation]]&lt;br /&gt;
&lt;br /&gt;
===Database queries===&lt;br /&gt;
* Moodle has a generic database query library. Behind this library are additional libraries which allow Moodle to work with MySQL, PostgreSQL, Oracle, SQL Server, and Maria DB.&lt;br /&gt;
* Where possible it is advisable to use the predefined functions rather than write out SQL. Writing SQL has a greater chance of not working with one of the supported databases.&lt;br /&gt;
* The return of the select functions tends to be an object or an array of objects.&lt;br /&gt;
&lt;br /&gt;
Example call to retrieve data from the course table.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$courses = $DB-&amp;gt;get_records(&#039;course&#039;, null, &#039;&#039;, &#039;id, category, fullname, shortname&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example of data returned from the above code.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [43] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 43&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX -Test 5&lt;br /&gt;
            [shortname] =&amp;gt; xxt5&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [5] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 5&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; With the glossary&lt;br /&gt;
            [shortname] =&amp;gt; wtg&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [39] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 39&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX - Test 1&lt;br /&gt;
            [shortname] =&amp;gt; xxt1&lt;br /&gt;
        )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
* We create our database tables in Moodle using the  XMLDB editor. This is located in the administration block &amp;quot;Site administration | Development | XMLDB editor&amp;quot;.&lt;br /&gt;
* The {plugin}\db directory needs to have write access for the XMLDB editor to be most effective.&lt;br /&gt;
* XMLDB editor creates an install.xml file in the db directory. This file will be loaded during the install to create your tables.&lt;br /&gt;
* XMLDB editor will produce php update code for adding and updating moodle database tables.&lt;br /&gt;
&lt;br /&gt;
The XMLDB main page.&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-main.png]]&lt;br /&gt;
&lt;br /&gt;
Upgrade code generated by the XMLDB&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-upgrade-code.png]]&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[XMLDB editor]]&lt;br /&gt;
* [[Using XMLDB]]&lt;br /&gt;
* [[XMLDB Documentation]]&lt;br /&gt;
* [[Upgrade API]]&lt;br /&gt;
* [[XMLDB introduction]]&lt;br /&gt;
&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
* Capabilities are controlled in &amp;quot;access.php&amp;quot; under the &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* This file has an array of capabilities with the following:&lt;br /&gt;
** name&lt;br /&gt;
** possible security risks behind giving this capability.&lt;br /&gt;
** The context that this capability works in.&lt;br /&gt;
** The default roles (teacher, manager, student, etc) that have this capability.&lt;br /&gt;
** Various other information.&lt;br /&gt;
* These capabilities are checked in code to allow access to pages, sections, and abilities (saving, deleting, etc).&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles#Context]]&lt;br /&gt;
* [[:en:Category:Capabilities]]&lt;br /&gt;
* [[:en:Roles and permissions]]&lt;br /&gt;
&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
* Moodle has it&#039;s own forms library.&lt;br /&gt;
* The forms lib includes a lot of accessibility code, and error checking, by default.&lt;br /&gt;
* Moodle forms can be displayed in JavaScript using &#039;fragments&#039;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[lib/formslib.php Form Definition]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
* Use the sesskey when directing to pages to do actions.&lt;br /&gt;
* Use the appropriate filters when retrieving parameters&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/Security Security docs]&lt;br /&gt;
* [[lib/formslib.php Form Definition#Most Commonly Used PARAM .2A Types]]&lt;br /&gt;
* [[Output functions#p.28.29 and s.28.29]]&lt;br /&gt;
&lt;br /&gt;
===Handling files===&lt;br /&gt;
* Files are conceptually stored in file areas.&lt;br /&gt;
* Plugins can only access files from it&#039;s own component.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[File API internals]]&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
* Moodle is currently using jquery and AMD (Asynchronous Module Definition).&lt;br /&gt;
* JavaScript files are located in the &amp;quot;amd/src&amp;quot; directory.&lt;br /&gt;
* Use grunt to build your JavaScript.&lt;br /&gt;
* Include your JavaScript in php files as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;{JScriptfilename}&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Can also be included in mustache templates.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[jQuery]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[JavaScript guidelines]]&lt;br /&gt;
* [[Grunt]]&lt;br /&gt;
&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
* All logging in moodle is done through the events system.&lt;br /&gt;
* New events should be located in the &amp;quot;classes/event&amp;quot; directory.&lt;br /&gt;
* It is possible to create observers and subscribe to events.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
===Accessibility===&lt;br /&gt;
&lt;br /&gt;
Accessibility is an important consideration while developing a plugin to make sure your plugin is accessible to all users and doesn&#039;t discriminate against users with disablities. This often is a mandated requirement in many countries. The links below explain common practices that we follow at Moodle to make the interface more accessible.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Accessibility]]&lt;br /&gt;
* [[Usability]]&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
* Moodle web services uses the external functions API.&lt;br /&gt;
* The recommended way to make AJAX requests is to use the ajax AMD file which uses the external functions API.&lt;br /&gt;
* External functions should be located in the &amp;quot;classes/external.php&amp;quot; file.&lt;br /&gt;
* A list of services should be included in &amp;quot;db/services.php&amp;quot;. This file is required to register the web services with Moodle.&lt;br /&gt;
* The services list is an array which contains:&lt;br /&gt;
** &#039;&#039;&#039;classname&#039;&#039;&#039; Name of the external class.&lt;br /&gt;
** &#039;&#039;&#039;methodname&#039;&#039;&#039; The name of the external function.&lt;br /&gt;
** &#039;&#039;&#039;classpath&#039;&#039;&#039; system path to the external function file.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; Description of the function&lt;br /&gt;
** &#039;&#039;&#039;type&#039;&#039;&#039; Create, read, update, delete&lt;br /&gt;
** &#039;&#039;&#039;ajax&#039;&#039;&#039; Can this function be used with ajax?&lt;br /&gt;
** &#039;&#039;&#039;capabilities&#039;&#039;&#039; Capabilities required to use this function.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[External functions API]]&lt;br /&gt;
* [[Adding a web service to a plugin]]&lt;br /&gt;
* [[Web services API]]&lt;br /&gt;
&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
* The main cache used by moodle is the Moodle Universal Cache (MUC).&lt;br /&gt;
* The MUC has several cache definitions - &lt;br /&gt;
** Request cache&lt;br /&gt;
** Session cache&lt;br /&gt;
** Application&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[The Moodle Universal Cache (MUC)]]&lt;br /&gt;
* [[:en:MUC FAQ]]&lt;br /&gt;
* [[:en:Caching]]&lt;br /&gt;
&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
* Supporting backup and restore requires creating several files in the &#039;backup/moodle2&#039; directory.&lt;br /&gt;
* Back requires a class to extend the backup_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* Restore requires a class to extend the restore_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* The restore steps lib defines the structure of the plugin to be restored.&lt;br /&gt;
* The backup steps lib defines steps, settings, attributes, etc.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Backup 2.0 for developers]] - provides an example of step-by-step implementation of backup support to your plugin&lt;br /&gt;
* [[:en:Backup and restore FAQ]]&lt;br /&gt;
&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
* Moodle has two types of automated testing: php unit tests, and behat tests.&lt;br /&gt;
* Unit tests are for testing functions.&lt;br /&gt;
* Behat tests runs through scenarios.&lt;br /&gt;
** Behat tests follows a script and navigates through moodle pages.&lt;br /&gt;
* unit tests should be located in the &amp;quot;tests&amp;quot; directory.&lt;br /&gt;
* behat tests should be located in the &amp;quot;tests/behat&amp;quot; directory.&lt;br /&gt;
* Tests located in these directories will be run through when a full test run is initiated.&lt;br /&gt;
* behat tests are actually feature files and end with the extension &amp;quot;.feature&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Writing PHPUnit tests]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
* publish your plugins at https://moodle.org/plugins/&lt;br /&gt;
* Publishing plugins on the moodle site leads you through a bunch of steps that need to be completed in order for the plugin to be approved and published.&lt;br /&gt;
* Plugins will be run through a pre-checker to give suggestions about possible issues with the code.&lt;br /&gt;
&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==TODO==&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=355789 this (july 2017) forum thread ] about Getting Started with Moodle Development.&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=352360 this (may 2017) forum thread] about Getting Started with Moodle Development.&lt;br /&gt;
&lt;br /&gt;
See also these older tutorials:&lt;br /&gt;
&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
==Any questions?==&lt;br /&gt;
&lt;br /&gt;
If you have any questions, you&#039;re welcome to post in the [https://moodle.org/mod/forum/view.php?id=55 General developer forum] on moodle.org&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=54262</id>
		<title>Javascript Modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=54262"/>
		<updated>2018-05-21T10:00:43Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Install grunt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
= Javascript Modules =&lt;br /&gt;
&lt;br /&gt;
== What is a Javascript module and why do I care? ==&lt;br /&gt;
&lt;br /&gt;
A Javascript module is nothing more than a collection of Javascript code that can be used (reliably) from other pieces of Javascript. &lt;br /&gt;
&lt;br /&gt;
== Why should I package my code as a module? ==&lt;br /&gt;
&lt;br /&gt;
By packaging your code as a module you break your code up into smaller reusable pieces. This is good because:&lt;br /&gt;
&lt;br /&gt;
a) Each smaller piece is simpler to understand / debug&lt;br /&gt;
&lt;br /&gt;
b) Each smaller piece is simpler to test&lt;br /&gt;
&lt;br /&gt;
c) You can re-use common code instead of duplicating it&lt;br /&gt;
&lt;br /&gt;
= How do I write a Javascript module in Moodle? =&lt;br /&gt;
&lt;br /&gt;
Since version 2.9, Moodle supports Javascript modules written using the Asynchronous Module Definition ([https://github.com/amdjs/amdjs-api/wiki/AMD AMD]) API. This is a standard API for creating Javascript modules and you will find many useful third party libraries that are already using this format. &lt;br /&gt;
&lt;br /&gt;
To edit or create an AMD module in Moodle you need to do a couple of things. &lt;br /&gt;
&lt;br /&gt;
== Install grunt ==&lt;br /&gt;
&lt;br /&gt;
The AMD modules in Moodle must be processed by some build tools before they will be visible to your web browser. We use &amp;quot;[[grunt]]&amp;quot; as a build tool to wrap our different processes. Grunt is a build tool written in Javascript that runs in the &amp;quot;[http://nodejs.org/ nodejs]&amp;quot; environment.&lt;br /&gt;
&lt;br /&gt;
This means you first have to &#039;&#039;&#039;install nodejs&#039;&#039;&#039; - and its package manager [https://www.npmjs.com/ npm]. The details of how to install those packages will vary by operating system, but on Linux it&#039;s probably similar to &amp;quot;sudo apt-get install nodejs npm&amp;quot;. There are downloadable packages for other operating systems here: http://nodejs.org/download/. Moodle currently requires node &amp;quot;lts/carbon&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Once this is done, you can &#039;&#039;&#039;run the command&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
 npm install&lt;br /&gt;
 npm install -g grunt-cli&lt;br /&gt;
&lt;br /&gt;
from the top of the Moodle directory to install all of the required tools. (You may need extra permissions to use the -g option.)&lt;br /&gt;
&lt;br /&gt;
== Development mode ==&lt;br /&gt;
&lt;br /&gt;
To avoid having to constantly run grunt, make sure you set the following in your config.php&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moodle will now run your module from the amd/src module. Don&#039;t forget to switch this off and run &#039;grunt&#039; before deploying the new version!&lt;br /&gt;
&lt;br /&gt;
In this mode - if you get a strange message in your javascript console like &amp;quot;No define call for core/first&amp;quot; it means you have a syntax error in the javascript you are developing. &lt;br /&gt;
Or, &amp;quot;No define call for theme_XXX/loader&amp;quot; as you are probably missing the &#039;src&#039; folder with relevant JS files. which might happen when you turn debugging ON on a theme that was bought, without &#039;src&#039; folder :-(&lt;br /&gt;
&lt;br /&gt;
== Running grunt ==&lt;br /&gt;
&lt;br /&gt;
You can run grunt in your plugin&#039;s &#039;amd&#039; directory and it will only operate on your modules. If you&#039;re having problems or just want to check your work it is worth running for the &#039;lint&#039; feature. This can find basic problems. This sub-directory support wont work on Windows unfortunately but there is an alternative: Run grunt from the top directory with the --root=path/to/dir to limit execution to a sub-directory.&lt;br /&gt;
&lt;br /&gt;
See [[Grunt#Running_grunt]] for more details of specific grunt commands which can be used.&lt;br /&gt;
&lt;br /&gt;
If you get the error message&lt;br /&gt;
&lt;br /&gt;
 /usr/bin/env: node: No such file or directory&lt;br /&gt;
&lt;br /&gt;
Then see the thread https://github.com/nodejs/node-v0.x-archive/issues/3911&lt;br /&gt;
&lt;br /&gt;
On Ubuntu 14.04 this fixed it for me:&lt;br /&gt;
&lt;br /&gt;
 sudo ln -fs /usr/bin/nodejs /usr/local/bin/node&lt;br /&gt;
&lt;br /&gt;
Note: Once you have run grunt and built your code, you will then need to purge Moodle caches otherwise the changes made to your minified files may not be picked up by Moodle.&lt;br /&gt;
&lt;br /&gt;
== Minimum (getting started) module for plugins ==&lt;br /&gt;
&lt;br /&gt;
This shows the absolute minimum module you need to get started adding modules to your plugins. It&#039;s actually quite simple...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Put this file in path/to/plugin/amd/src&lt;br /&gt;
// You can call it anything you like&lt;br /&gt;
&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
&lt;br /&gt;
            // Put whatever you like here. $ is available&lt;br /&gt;
            // to you as normal.&lt;br /&gt;
            $(&amp;quot;.someclass&amp;quot;).change(function() {&lt;br /&gt;
                alert(&amp;quot;It changed!!&amp;quot;);&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code passes the jquery module into our function (parameter $). There are a number of other useful modules available in Moodle, some of which you&#039;ll probably need in a practical application. See [[Useful_core_Javascript_modules]]. Simply list them in both the define() first parameter and the function callback. E.g.,&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    define([&#039;jquery&#039;, &#039;core/str&#039;, &#039;core/ajax&#039;], function($, str, ajax) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The idea here is that we will run the &#039;init&#039; function from our (PHP) code to set things up. This is called from PHP like this...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;frankenstyle_path/your_js_filename&#039;, &#039;init&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to supply the complete &#039;[[Frankenstyle]]&#039; path. The .js is not needed. &lt;br /&gt;
&lt;br /&gt;
js_call_amd takes a third parameter which is an &#039;&#039;array&#039;&#039; of parameters. These will translate to individual parameters in the &#039;init&#039; function call. For example...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;block_iomad_company_admin/department_select&#039;, &#039;init&#039;, array($first, $last));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...calls&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    return {&lt;br /&gt;
        init: function(first, last) {&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A more comprehensive explanation follows...&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Hello World&amp;quot; I am a Javascript Module ==&lt;br /&gt;
Lets now create a simple Javascript module so we can see how to lay things out. &lt;br /&gt;
&lt;br /&gt;
Each Javascript module is contained in a single source file in the &amp;lt;componentdir&amp;gt;/amd/src folder. The final name of the module is taken from the file name and the component name. E.g. block_overview/amd/src/helloworld.js would be a module named &amp;quot;block_overview/helloworld&amp;quot;. the name of the module is important when you want to call it from somewhere else in the code. &lt;br /&gt;
&lt;br /&gt;
After running grunt - the minified Javascript files are stored in the &amp;lt;componentdir&amp;gt;/amd/build folder. The javascript files are renamed to show that they are minified (helloworld.js becomes helloworld.min.js). &lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to add the built files (the ones in amd/build) to your git commits, or in production no-one will see your changes. &lt;br /&gt;
&lt;br /&gt;
Lets create a simple module now:&lt;br /&gt;
&lt;br /&gt;
blocks/overview/amd/src/helloworld.js&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Standard license block omitted.&lt;br /&gt;
/*&lt;br /&gt;
 * @package    block_overview&lt;br /&gt;
 * @copyright  2015 Someone cool&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * @module block_overview/helloworld&lt;br /&gt;
  */&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&lt;br /&gt;
     /** &lt;br /&gt;
      * Give me blue.&lt;br /&gt;
      * @access private&lt;br /&gt;
      * @return {string}&lt;br /&gt;
      */&lt;br /&gt;
     var makeItBlue = function() {&lt;br /&gt;
          // We can use our jquery dependency here.&lt;br /&gt;
          return $(&#039;.blue&#039;).show();&lt;br /&gt;
     };&lt;br /&gt;
      &lt;br /&gt;
    /**&lt;br /&gt;
     * @constructor&lt;br /&gt;
     * @alias module:block_overview/helloworld&lt;br /&gt;
     */&lt;br /&gt;
    var greeting = function() {&lt;br /&gt;
        /** @access private */&lt;br /&gt;
        var privateThoughts = &#039;I like the colour blue&#039;;&lt;br /&gt;
        &lt;br /&gt;
        /** @access public */&lt;br /&gt;
        this.publicThoughts = &#039;I like the colour orange&#039;;&lt;br /&gt;
&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * A formal greeting.&lt;br /&gt;
     * @access public&lt;br /&gt;
     * @return {string}&lt;br /&gt;
     */&lt;br /&gt;
    greeting.prototype.formal = function() {&lt;br /&gt;
        return &#039;How do you do?&#039;;&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * An informal greeting.&lt;br /&gt;
     * @access public&lt;br /&gt;
     * @return {string}&lt;br /&gt;
     */&lt;br /&gt;
    greeting.prototype.informal = function() {&lt;br /&gt;
        return &#039;Wassup!&#039;;&lt;br /&gt;
    };&lt;br /&gt;
    return greeting;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The most interesting line above is:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All AMD modules must call &amp;quot;define()&amp;quot; as the first and only global scoped piece of code. This ensures the javascript code contains no global variables and will not conflict with any other loaded module. The name of the module does not need to be specified because it is determined from the filename and component (but it can be listed in a comment for JSDoc as shown here). &lt;br /&gt;
&lt;br /&gt;
The first argument to &amp;quot;define&amp;quot; is the list of dependencies for the module. This argument must be passed as an array, even if there is only one. In this example &amp;quot;jquery&amp;quot; is a dependency. &amp;quot;jquery&amp;quot; is shipped as a core module is available to all AMD modules. &lt;br /&gt;
&lt;br /&gt;
The second argument to &amp;quot;define&amp;quot; is the function that defines the module. This function will receive as arguments, each of the requested dependencies in the same order they were requested. In this example we receive JQuery as an argument and we name the variable &amp;quot;$&amp;quot; (it&#039;s a JQuery thing). We can then access JQuery normally through the $ variable which is in scope for any code in our module. &lt;br /&gt;
&lt;br /&gt;
The rest of the code in this example is a standard way to define a Javascript module with public/private variables and methods. There are many ways to do this, this is only one.&lt;br /&gt;
&lt;br /&gt;
It is important that we are returning &#039;greeting&#039;. If there is no return then your module will be declared as undefined.&lt;br /&gt;
&lt;br /&gt;
== Loading modules dynamically ==&lt;br /&gt;
What do you do if you don&#039;t know in advance which modules will be required? Stuffing all possible required modules in the define call is one solution, but it&#039;s ugly and it only works for code that is in an AMD module (what about inline code in the page?). AMD lets you load a dependency any time you like. &lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Load a new dependency.&lt;br /&gt;
require([&#039;mod_wiki/timer&#039;], function(timer) {&lt;br /&gt;
   // timer is available to do my bidding.&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Including an external javascript/jquery library ==&lt;br /&gt;
If you want to include a javascript / jquery library downloaded from the internet you can do so as follows:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning: if the library you download, supports AMD but is already &amp;quot;named&amp;quot; you will not be able to include it directly&#039;&#039;&#039;&lt;br /&gt;
e.g. &lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
        define(&amp;quot;typeahead.js&amp;quot;, *[ &amp;quot;jquery&amp;quot; ], function(a0) {&lt;br /&gt;
            return factory(a0);&lt;br /&gt;
        });&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
will not work, as moodle injects it&#039;s own define name when loading the library.&lt;br /&gt;
&lt;br /&gt;
If the library is in AMD format and has a define:&lt;br /&gt;
e.g. i want to include the jquery final countdown timer on my page ( hilios.github.io/jQuery.countdown/ )&lt;br /&gt;
* download the module in both normal and minified versions&lt;br /&gt;
* place the modules in your moodle install e.g. your custom theme dir, or plugin dir&lt;br /&gt;
* /theme/mytheme/amd/src/jquery.countdown.js&lt;br /&gt;
&lt;br /&gt;
you can now include the module and initialise it (there are multiple ways to do this)&lt;br /&gt;
php:&lt;br /&gt;
&lt;br /&gt;
1. Create your own AMD module and initialise it:&lt;br /&gt;
&lt;br /&gt;
In your PHP file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;theme_mytheme/countdowntimer&#039;, &#039;initialise&#039;, $params);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Javascript module:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// /theme/mytheme/amd/src/countdowntimer.js&lt;br /&gt;
define([&#039;jquery&#039;, &#039;theme_mytheme/jquery.countdown&#039;], function($, c) {&lt;br /&gt;
    return {&lt;br /&gt;
        initialise: function ($params) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Put the javascript into a mustache template:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// /theme/mytheme/templates/countdowntimer.mustache&lt;br /&gt;
&amp;lt;span id=&amp;quot;clock&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require([&#039;jquery&#039;, &#039;theme_mytheme/jquery.countdown&#039;], function($) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Call the javascript directly from php (although who would want to put javascript into php? ergh):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_amd_inline(&#039;&lt;br /&gt;
require([&#039;theme_mytheme/jquery.countdown&#039;], function(min) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
});&lt;br /&gt;
&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Embedding AMD code in a page ==&lt;br /&gt;
So you have created lots of cool Javascript modules. Great. How do we actually call them? Any javascript code that calls an AMD module must execute AFTER the requirejs module loader has finished loading. We have provided a function &amp;quot;js_call_amd&amp;quot; that will call a single function from an AMD module with parameters.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd($modulename, $functionname, $params);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
that will &amp;quot;do the right thing&amp;quot; with your block of AMD code and execute it at the end of the page, after our AMD module loader has loaded. &lt;br /&gt;
Notes:&lt;br /&gt;
* the $modulename is the &#039;componentname/modulename&#039; discussed above&lt;br /&gt;
* the $functionname is the name of a public function exposed by the amd module. &lt;br /&gt;
* the $params is an array of params passed as arguments to the function. These should be simple types that can be handled by json_encode (no recursive arrays, or complex classes please). &lt;br /&gt;
* if the size of the params array is too large (&amp;gt; 1Kb), this will produce a developer warning. Do not attempt to pass large amounts of data through this function, it will pollute the page size. A preferred approach is to pass css selectors for DOM elements that contain data-attributes for any required data, or fetch data via ajax in the background.&lt;br /&gt;
&lt;br /&gt;
AMD / JS code can also be embedded on a page via mustache templates&lt;br /&gt;
see here: https://docs.moodle.org/dev/Templates#What_if_a_template_contains_javascript.3F&lt;br /&gt;
&lt;br /&gt;
== But I have a mega JS file I don&#039;t want loaded on every page? ==&lt;br /&gt;
Loading all JS files at once and stuffing them in the browser cache is the right choice for MOST js files, there are probably some exceptions. For these files, you can rename the javascript file to end with the suffix &amp;quot;-lazy.js&amp;quot; which indicates that the module will not be loaded by default, it will be requested the first time it is used. There is no difference in usage for lazy loaded modules, the require() call looks exactly the same, it&#039;s just that the module name will also have the &amp;quot;-lazy&amp;quot; suffix.&lt;br /&gt;
&lt;br /&gt;
== Useful links ==&lt;br /&gt;
* [https://assets.moodlemoot.org/sites/15/20171004085436/JavaScript-AMD-with-RequireJS-presented-by-Daniel-Roperto-Catalyst.pdf JavaScript AMD with RequireJS] presented by Daniel Roperto, Catalyst. (MoodleMOOT AU 2017)&lt;br /&gt;
* [[Useful_core_Javascript_modules]]&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=54214</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=54214"/>
		<updated>2018-05-17T07:27:33Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Indicator (core_analytics\local\indicator\base) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4 provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/34/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Documentation available in [https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends].&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends] is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors. Analytics API will be able to find them as long as they follow the namespace conventions described below. &lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this section do not include Machine learning backend interfaces, they are available in https://docs.moodle.org/dev/Machine_learning_backends#Interfaces.&lt;br /&gt;
&lt;br /&gt;
==== Analysable (core_analytics\analysable) ====&lt;br /&gt;
&lt;br /&gt;
Analysables are those elements in Moodle that contain samples. In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity. Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
They list of methods that need to be implemented is quite simple and does not require much explanation.&lt;br /&gt;
&lt;br /&gt;
It is also important to mention that analysable elements should be lazy loaded, otherwise you may have PHP memory issues. The reason is that analysers load all analysable elements in the site to calculate which ones are going to be calculated next (skipping the ones processed recently and stuff like that) You can take core_analytics\course as an example.&lt;br /&gt;
&lt;br /&gt;
Methods to implement:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable unique identifier in the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_id();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable human readable name&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function get_name();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable context.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    public function get_context();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_start&#039;&#039;&#039; and &#039;&#039;&#039;get_end&#039;&#039;&#039; define the start and end times that indicators will use for their calculations.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The start of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_start();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The end of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_end();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Analyser (core_analytics\local\analyser\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_analysables&#039;&#039;&#039; returns the whole list of analysable elements in the site. Each model will later be able to discard analysables that do not match their expectations. &#039;&#039;e.g. if your model is only interested in quizzes with a time close the analyser will return all quizzes, your model will exclude the ones without a time close. This approach is supposed to make analysers more reusable.&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the list of analysable elements available on the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \core_analytics\analysable[] Array of analysable elements using the analysable id as array key.&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analysables();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_all_samples&#039;&#039;&#039; and &#039;&#039;&#039;get_samples&#039;&#039;&#039; should return data associated with the sample ids they provide. This is important for 2 reasons:&lt;br /&gt;
* The data they provide alongside the sample origin is used to filter out indicators that are not related to what this analyser analyses. &#039;&#039;e.g. courses analysers do provide courses and information about courses, but not information about users, a &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator will require the user object to be available. A model using a courses analyser will not be able to use the &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator.&lt;br /&gt;
* The data included here is cached in PHP static vars; on one hand this reduces the amount of db queries indicators need to perform. On the other hand, if not well balanced, it can lead to PHP memory issues.  &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns this analysable list of samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function get_all_samples(\core_analytics\analysable $analysable);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns the samples data from a list of sample ids.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int[] $sampleids&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples($sampleids);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_sample_analysable&#039;&#039;&#039; method is executing during prediction:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analysable of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \core_analytics\analysable&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_sample_analysable($sampleid);&lt;br /&gt;
&lt;br /&gt;
The sample origin is the moodle database table that uses the sample id as primary key.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the sample&#039;s origin in moodle database.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples_origin();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_access_context&#039;&#039;&#039; associates a context to a sampleid. This is important because this sample predictions will only be available for users with &#039;&#039;moodle/analytics:listinsights&#039;&#039; capability in that context.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the context of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_access_context($sampleid);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_description&#039;&#039;&#039; is used to display samples in &#039;&#039;Insights&#039;&#039; report:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Describes a sample with a description summary and a \renderable (an image for example)&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param int $contextid&lt;br /&gt;
     * @param array $sampledata&lt;br /&gt;
     * @return array array(string, \renderable)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_description($sampleid, $contextid, $sampledata);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;processes_user_data&#039;&#039;&#039; and &#039;&#039;&#039;join_sample_user&#039;&#039;&#039; methods are used by the analytics implementation of the privacy API. You only need to overwrite them if your analyser deals with user data. They are used to export and delete user data that is stored in analytics database tables:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Whether the plugin needs user data clearing or not.&lt;br /&gt;
     *&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function processes_user_data();&lt;br /&gt;
    /**&lt;br /&gt;
     * SQL JOIN from a sample to users table.&lt;br /&gt;
     *&lt;br /&gt;
     * More info in [https://github.com/moodle/moodle/blob/master/analytics/classes/local/analyser/base.php core_analytics\local\analyser\base]::join_sample_user&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $sampletablealias The alias of the table with a sampleid field that will join with this SQL string&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function join_sample_user($sampletablealias);&lt;br /&gt;
&lt;br /&gt;
==== Indicator (core_analytics\local\indicator\base) ====&lt;br /&gt;
&lt;br /&gt;
Indicators should generally extend one of these 3 classes, depending on the values they can return: &#039;&#039;core_analytics\local\indicator\binary&#039;&#039; for &#039;&#039;&#039;yes/no&#039;&#039;&#039; indicators, &#039;&#039;core_analytics\local\indicator\linear&#039;&#039; for indicators that return linear values and &#039;&#039;core_analytics\local\indicator\discrete&#039;&#039; for categorised indicators. In case you want your activity module to implement a [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out#Indicators community of inquiry] indicator you can extend &#039;&#039;core_analytics\local\indicator\community_of_inquiry_indicator&#039;&#039; look for examples in Moodle core.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;required_sample_data&#039;&#039;&#039; to specify what your indicator needs to be calculated; you may need a &#039;&#039;user&#039;&#039; object, a &#039;&#039;course&#039;&#039;, a &#039;&#039;grade item&#039;&#039;... The default implementation does not require anything. Models which analysers do not return the required data will not be able to use your indicator so only list here what you really need. e.g. if you need a grade_grades record mark it as required, but there is no need to require the &#039;&#039;user&#039;&#039; object and the &#039;&#039;course&#039;&#039; as well because you can obtain them from the grade_grades item. It is very likely that the analyser will provide them as well because the principle they follow is to include as much related data as possible but do not flag related objects as required because an analyser may, for example, chose to not include the &#039;&#039;user&#039;&#039; object because it is too big and sites can have memory problems.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows indicators to specify data they need.&lt;br /&gt;
     *&lt;br /&gt;
     * e.g. A model using courses as samples will not provide users data, but an indicator like&lt;br /&gt;
     * &amp;quot;user is hungry&amp;quot; needs user data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return null|string[] Name of the required elements (use the database tablename)&lt;br /&gt;
     */&lt;br /&gt;
    public static function required_sample_data() {&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A single method must be implemented, &#039;&#039;&#039;calculate_sample&#039;&#039;&#039;. Most indicators make use of $starttime and $endtime to restrict the time period they consider for their calculations (e.g. read actions during $starttime - $endtime period) but some indicators may not need to apply any restriction (e.g. does this user have a user picture and profile description?) &#039;&#039;self::MIN_VALUE&#039;&#039; is -1 and &#039;&#039;self::MAX_VALUE&#039;&#039; is 1. We do not recommend changing these values.&lt;br /&gt;
 &lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates the sample.&lt;br /&gt;
     *&lt;br /&gt;
     * Return a value from self::MIN_VALUE to self::MAX_VALUE or null if the indicator can not be calculated for this sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param string $sampleorigin&lt;br /&gt;
     * @param integer $starttime Limit the calculation to this timestart&lt;br /&gt;
     * @param integer $endtime Limit the calculation to this timeend&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function calculate_sample($sampleid, $sampleorigin, $starttime, $endtime);&lt;br /&gt;
&lt;br /&gt;
Note that performance here is critical as it runs once for each sample and for each range in the time-splitting method; some tips:  &lt;br /&gt;
* To avoid performance issues or repeated db queries analyser classes provide information about the samples that you can use for your calculations to save some database queries. You can retrieve information about a sample with &#039;&#039;&#039;$user = $this-&amp;gt;retrieve(&#039;user&#039;, $sampleid)&#039;&#039;&#039;. &#039;&#039;retrieve()&#039;&#039; will return false if the requested data is not available.&lt;br /&gt;
* You can also overwrite &#039;&#039;fill_per_analysable_caches&#039;&#039; method if necessary (keep in mind though that PHP memory is not unlimited).&lt;br /&gt;
* Indicator instances are reset for each analysable and time range that is processed. This helps keeping the memory usage acceptably low and prevents hard-to-trace caching bugs.&lt;br /&gt;
&lt;br /&gt;
==== Target (core_analytics\local\target\base) ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
The first thing a target must define is the analyser class that it will use. The analyser class is specified in &#039;&#039;&#039;get_analyser_class&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analyser class that should be used along with this target.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string The full class name as a string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analyser_class();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;is_valid_analysable&#039;&#039;&#039; and &#039;&#039;&#039;is_valid_sample&#039;&#039;&#039; are used to discard elements that are not valid for your target.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows the target to verify that the analysable is a good candidate.&lt;br /&gt;
     *&lt;br /&gt;
     * This method can be used as a quick way to discard invalid analysables.&lt;br /&gt;
     * e.g. Imagine that your analysable don&#039;t have students and you need them.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param bool $fortraining&lt;br /&gt;
     * @return true|string&lt;br /&gt;
     */&lt;br /&gt;
    public function is_valid_analysable(\core_analytics\analysable $analysable, $fortraining = true);&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is this sample from the $analysable valid?&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param bool $fortraining&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_valid_sample($sampleid, \core_analytics\analysable $analysable, $fortraining = true);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;calculate_sample&#039;&#039;&#039; is the method that calculates the target value.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates this target for the provided samples.&lt;br /&gt;
     *&lt;br /&gt;
     * In case there are no values to return or the provided sample is not applicable just return null.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param int|false $starttime Limit calculations to start time&lt;br /&gt;
     * @param int|false $endtime Limit calculations to end time&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    protected function calculate_sample($sampleid, \core_analytics\analysable $analysable, $starttime = false, $endtime = false);&lt;br /&gt;
&lt;br /&gt;
==== Time-splitting method (core_analytics\local\time_splitting\base) ====&lt;br /&gt;
&lt;br /&gt;
Time-splitting methods are useful to define when the analytics API will train the predictions processor and when it will generate predictions. As explained above in [[Analytics_API#Time_splitting_methods]], they define time ranges based on analysable elements start and end timestamps.&lt;br /&gt;
&lt;br /&gt;
The base class is &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;; if what you are after is to split the analysable duration in equal parts or in cumulative parts you can extend &#039;&#039;&#039;\core_analytics\local\time_splitting\equal_parts&#039;&#039;&#039; or &#039;&#039;&#039;\core_analytics\local\time_splitting\accumulative_parts&#039;&#039;&#039; instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;define_ranges&#039;&#039;&#039; is the main method to implement and its values mostly depend on the current analysable element (available in &#039;&#039;&#039;$this-&amp;gt;analysable&#039;&#039;&#039;). An array of time ranges should be returned, each of these ranges should contain 3 attributes: A start time (&#039;start&#039;) and an end time (&#039;end&#039;) that will be passed to indicators so they can limit the amount of activity logs they read; the 3rd attribute is &#039;time&#039;, which value will determine when the range will be executed.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define the time splitting methods ranges.&lt;br /&gt;
     *&lt;br /&gt;
     * &#039;time&#039; value defines when predictions are executed, their values will be compared with&lt;br /&gt;
     * the current time in ready_to_predict&lt;br /&gt;
     *&lt;br /&gt;
     * @return array(&#039;start&#039; =&amp;gt; time(), &#039;end&#039; =&amp;gt; time(), &#039;time&#039; =&amp;gt; time())&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_ranges();&lt;br /&gt;
&lt;br /&gt;
A name and description should also be specified:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns a lang_string object representing the name for the time splitting method.&lt;br /&gt;
     *&lt;br /&gt;
     * Used as column identificator.&lt;br /&gt;
     *&lt;br /&gt;
     * If there is a corresponding &#039;_help&#039; string this will be shown as well.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \lang_string&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_name() : \lang_string;&lt;br /&gt;
&lt;br /&gt;
==== Calculable (core_analytics\calculable) ====&lt;br /&gt;
&lt;br /&gt;
Leaving this interface for the end because it is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
New models can be created and implemented in php, and can be packaged as a Moodle local plugin for distribution. Sample model components and models are provided at https://github.com/dmonllao/moodle-local_testanalytics.&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
As specified in https://docs.moodle.org/dev/Analytics_API#Target_.28core_analytics.5Clocal.5Ctarget.5Cbase.29.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
To add a new model to the system, it must be defined in a PHP file. Normally this is done as part of  install.php or upgrade.php for a plugin that contains the new model and components. However, it is also possible to execute the necessary commands in a standalone PHP file that references the Moodle config.php.&lt;br /&gt;
&lt;br /&gt;
To create the model, specify at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=54212</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=54212"/>
		<updated>2018-05-17T06:57:44Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Analyser (core_analytics\local\analyser\base) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4 provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/34/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Documentation available in [https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends].&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends] is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors. Analytics API will be able to find them as long as they follow the namespace conventions described below. &lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this section do not include Machine learning backend interfaces, they are available in https://docs.moodle.org/dev/Machine_learning_backends#Interfaces.&lt;br /&gt;
&lt;br /&gt;
==== Analysable (core_analytics\analysable) ====&lt;br /&gt;
&lt;br /&gt;
Analysables are those elements in Moodle that contain samples. In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity. Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
They list of methods that need to be implemented is quite simple and does not require much explanation.&lt;br /&gt;
&lt;br /&gt;
It is also important to mention that analysable elements should be lazy loaded, otherwise you may have PHP memory issues. The reason is that analysers load all analysable elements in the site to calculate which ones are going to be calculated next (skipping the ones processed recently and stuff like that) You can take core_analytics\course as an example.&lt;br /&gt;
&lt;br /&gt;
Methods to implement:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable unique identifier in the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_id();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable human readable name&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function get_name();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable context.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    public function get_context();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_start&#039;&#039;&#039; and &#039;&#039;&#039;get_end&#039;&#039;&#039; define the start and end times that indicators will use for their calculations.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The start of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_start();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The end of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_end();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Analyser (core_analytics\local\analyser\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_analysables&#039;&#039;&#039; returns the whole list of analysable elements in the site. Each model will later be able to discard analysables that do not match their expectations. &#039;&#039;e.g. if your model is only interested in quizzes with a time close the analyser will return all quizzes, your model will exclude the ones without a time close. This approach is supposed to make analysers more reusable.&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the list of analysable elements available on the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \core_analytics\analysable[] Array of analysable elements using the analysable id as array key.&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analysables();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_all_samples&#039;&#039;&#039; and &#039;&#039;&#039;get_samples&#039;&#039;&#039; should return data associated with the sample ids they provide. This is important for 2 reasons:&lt;br /&gt;
* The data they provide alongside the sample origin is used to filter out indicators that are not related to what this analyser analyses. &#039;&#039;e.g. courses analysers do provide courses and information about courses, but not information about users, a &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator will require the user object to be available. A model using a courses analyser will not be able to use the &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator.&lt;br /&gt;
* The data included here is cached in PHP static vars; on one hand this reduces the amount of db queries indicators need to perform. On the other hand, if not well balanced, it can lead to PHP memory issues.  &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns this analysable list of samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function get_all_samples(\core_analytics\analysable $analysable);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns the samples data from a list of sample ids.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int[] $sampleids&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples($sampleids);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_sample_analysable&#039;&#039;&#039; method is executing during prediction:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analysable of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \core_analytics\analysable&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_sample_analysable($sampleid);&lt;br /&gt;
&lt;br /&gt;
The sample origin is the moodle database table that uses the sample id as primary key.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the sample&#039;s origin in moodle database.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples_origin();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_access_context&#039;&#039;&#039; associates a context to a sampleid. This is important because this sample predictions will only be available for users with &#039;&#039;moodle/analytics:listinsights&#039;&#039; capability in that context.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the context of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_access_context($sampleid);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_description&#039;&#039;&#039; is used to display samples in &#039;&#039;Insights&#039;&#039; report:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Describes a sample with a description summary and a \renderable (an image for example)&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param int $contextid&lt;br /&gt;
     * @param array $sampledata&lt;br /&gt;
     * @return array array(string, \renderable)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_description($sampleid, $contextid, $sampledata);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;processes_user_data&#039;&#039;&#039; and &#039;&#039;&#039;join_sample_user&#039;&#039;&#039; methods are used by the analytics implementation of the privacy API. You only need to overwrite them if your analyser deals with user data. They are used to export and delete user data that is stored in analytics database tables:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Whether the plugin needs user data clearing or not.&lt;br /&gt;
     *&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function processes_user_data();&lt;br /&gt;
    /**&lt;br /&gt;
     * SQL JOIN from a sample to users table.&lt;br /&gt;
     *&lt;br /&gt;
     * More info in [https://github.com/moodle/moodle/blob/master/analytics/classes/local/analyser/base.php core_analytics\local\analyser\base]::join_sample_user&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $sampletablealias The alias of the table with a sampleid field that will join with this SQL string&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function join_sample_user($sampletablealias);&lt;br /&gt;
&lt;br /&gt;
==== Indicator (core_analytics\local\indicator\base) ====&lt;br /&gt;
&lt;br /&gt;
Indicators should generally extend one of these 3 classes, depending on the values they can return: &#039;&#039;core_analytics\local\indicator\binary&#039;&#039; for &#039;&#039;&#039;yes/no&#039;&#039;&#039; indicators, &#039;&#039;core_analytics\local\indicator\linear&#039;&#039; for indicators that return linear values and &#039;&#039;core_analytics\local\indicator\discrete&#039;&#039; for categorised indicators.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;required_sample_data&#039;&#039;&#039; to specify what your indicator needs to be calculated; you may need a &#039;&#039;user&#039;&#039; object, a &#039;&#039;course&#039;&#039;, a &#039;&#039;grade item&#039;&#039;... The default implementation does not require anything. Models which analysers do not return the required data will not be able to use your indicator so only list here what you really need. e.g. if you need a grade_grades record mark it as required, but there is no need to require the &#039;&#039;user&#039;&#039; object and the &#039;&#039;course&#039;&#039; as well because you can obtain them from the grade_grades item. It is very likely that the analyser will provide them as well because the principle they follow is to include as much related data as possible but do not flag related objects as required because an analyser may, for example, chose to not include the &#039;&#039;user&#039;&#039; object because it is too big and sites can have memory problems.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows indicators to specify data they need.&lt;br /&gt;
     *&lt;br /&gt;
     * e.g. A model using courses as samples will not provide users data, but an indicator like&lt;br /&gt;
     * &amp;quot;user is hungry&amp;quot; needs user data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return null|string[] Name of the required elements (use the database tablename)&lt;br /&gt;
     */&lt;br /&gt;
    public static function required_sample_data() {&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A single method must be implemented, &#039;&#039;&#039;calculate_sample&#039;&#039;&#039;. Most indicators make use of $starttime and $endtime to restrict the time period they consider for their calculations (e.g. read actions during $starttime - $endtime period) but some indicators may not need to apply any restriction (e.g. does this user have a user picture and profile description?) &#039;&#039;self::MIN_VALUE&#039;&#039; is -1 and &#039;&#039;self::MAX_VALUE&#039;&#039; is 1. We do not recommend changing these values.&lt;br /&gt;
 &lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates the sample.&lt;br /&gt;
     *&lt;br /&gt;
     * Return a value from self::MIN_VALUE to self::MAX_VALUE or null if the indicator can not be calculated for this sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param string $sampleorigin&lt;br /&gt;
     * @param integer $starttime Limit the calculation to this timestart&lt;br /&gt;
     * @param integer $endtime Limit the calculation to this timeend&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function calculate_sample($sampleid, $sampleorigin, $starttime, $endtime);&lt;br /&gt;
&lt;br /&gt;
Note that performance here is critical as it runs once for each sample and for each range in the time-splitting method; some tips:  &lt;br /&gt;
* To avoid performance issues or repeated db queries analyser classes provide information about the samples that you can use for your calculations to save some database queries. You can retrieve information about a sample with &#039;&#039;&#039;$user = $this-&amp;gt;retrieve(&#039;user&#039;, $sampleid)&#039;&#039;&#039;. &#039;&#039;retrieve()&#039;&#039; will return false if the requested data is not available.&lt;br /&gt;
* You can also overwrite &#039;&#039;fill_per_analysable_caches&#039;&#039; method if necessary (keep in mind though that PHP memory is not unlimited).&lt;br /&gt;
* Indicator instances are reset for each analysable and time range that is processed. This helps keeping the memory usage acceptably low and prevents hard-to-trace caching bugs.&lt;br /&gt;
&lt;br /&gt;
==== Target (core_analytics\local\target\base) ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
The first thing a target must define is the analyser class that it will use. The analyser class is specified in &#039;&#039;&#039;get_analyser_class&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analyser class that should be used along with this target.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string The full class name as a string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analyser_class();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;is_valid_analysable&#039;&#039;&#039; and &#039;&#039;&#039;is_valid_sample&#039;&#039;&#039; are used to discard elements that are not valid for your target.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows the target to verify that the analysable is a good candidate.&lt;br /&gt;
     *&lt;br /&gt;
     * This method can be used as a quick way to discard invalid analysables.&lt;br /&gt;
     * e.g. Imagine that your analysable don&#039;t have students and you need them.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param bool $fortraining&lt;br /&gt;
     * @return true|string&lt;br /&gt;
     */&lt;br /&gt;
    public function is_valid_analysable(\core_analytics\analysable $analysable, $fortraining = true);&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is this sample from the $analysable valid?&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param bool $fortraining&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_valid_sample($sampleid, \core_analytics\analysable $analysable, $fortraining = true);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;calculate_sample&#039;&#039;&#039; is the method that calculates the target value.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates this target for the provided samples.&lt;br /&gt;
     *&lt;br /&gt;
     * In case there are no values to return or the provided sample is not applicable just return null.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param int|false $starttime Limit calculations to start time&lt;br /&gt;
     * @param int|false $endtime Limit calculations to end time&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    protected function calculate_sample($sampleid, \core_analytics\analysable $analysable, $starttime = false, $endtime = false);&lt;br /&gt;
&lt;br /&gt;
==== Time-splitting method (core_analytics\local\time_splitting\base) ====&lt;br /&gt;
&lt;br /&gt;
Time-splitting methods are useful to define when the analytics API will train the predictions processor and when it will generate predictions. As explained above in [[Analytics_API#Time_splitting_methods]], they define time ranges based on analysable elements start and end timestamps.&lt;br /&gt;
&lt;br /&gt;
The base class is &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;; if what you are after is to split the analysable duration in equal parts or in cumulative parts you can extend &#039;&#039;&#039;\core_analytics\local\time_splitting\equal_parts&#039;&#039;&#039; or &#039;&#039;&#039;\core_analytics\local\time_splitting\accumulative_parts&#039;&#039;&#039; instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;define_ranges&#039;&#039;&#039; is the main method to implement and its values mostly depend on the current analysable element (available in &#039;&#039;&#039;$this-&amp;gt;analysable&#039;&#039;&#039;). An array of time ranges should be returned, each of these ranges should contain 3 attributes: A start time (&#039;start&#039;) and an end time (&#039;end&#039;) that will be passed to indicators so they can limit the amount of activity logs they read; the 3rd attribute is &#039;time&#039;, which value will determine when the range will be executed.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define the time splitting methods ranges.&lt;br /&gt;
     *&lt;br /&gt;
     * &#039;time&#039; value defines when predictions are executed, their values will be compared with&lt;br /&gt;
     * the current time in ready_to_predict&lt;br /&gt;
     *&lt;br /&gt;
     * @return array(&#039;start&#039; =&amp;gt; time(), &#039;end&#039; =&amp;gt; time(), &#039;time&#039; =&amp;gt; time())&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_ranges();&lt;br /&gt;
&lt;br /&gt;
A name and description should also be specified:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns a lang_string object representing the name for the time splitting method.&lt;br /&gt;
     *&lt;br /&gt;
     * Used as column identificator.&lt;br /&gt;
     *&lt;br /&gt;
     * If there is a corresponding &#039;_help&#039; string this will be shown as well.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \lang_string&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_name() : \lang_string;&lt;br /&gt;
&lt;br /&gt;
==== Calculable (core_analytics\calculable) ====&lt;br /&gt;
&lt;br /&gt;
Leaving this interface for the end because it is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
New models can be created and implemented in php, and can be packaged as a Moodle local plugin for distribution. Sample model components and models are provided at https://github.com/dmonllao/moodle-local_testanalytics.&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
As specified in https://docs.moodle.org/dev/Analytics_API#Target_.28core_analytics.5Clocal.5Ctarget.5Cbase.29.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
To add a new model to the system, it must be defined in a PHP file. Normally this is done as part of  install.php or upgrade.php for a plugin that contains the new model and components. However, it is also possible to execute the necessary commands in a standalone PHP file that references the Moodle config.php.&lt;br /&gt;
&lt;br /&gt;
To create the model, specify at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Privacy_API&amp;diff=54077</id>
		<title>Privacy API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Privacy_API&amp;diff=54077"/>
		<updated>2018-04-24T08:34:00Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Delete for a context */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The [https://en.wikipedia.org/wiki/General_Data_Protection_Regulation General Data Protection Regulation] (GDPR) is an EU directive that looks at providing users with more control over their data and how it is processed. This regulation will come into effect on 25th of May 2018 and covers any citizen or permanent resident of the European Union. The directive will be respected by a number of other countries outside of the European Union.&lt;br /&gt;
&lt;br /&gt;
To help institutions become compliant with this new regulation we are adding functionality to Moodle. This includes a number of components, amongst others these include a user’s right to:&lt;br /&gt;
&lt;br /&gt;
* request information on the types of personal data held, the instances of that data, and the deletion policy for each;&lt;br /&gt;
* access all of their data; and&lt;br /&gt;
* be forgotten.&lt;br /&gt;
&lt;br /&gt;
The compliance requirements also extend to installed plugins (including third party plugins). These need to also be able to report what information they store or process regarding users, and have the ability to provide and delete data for a user request.&lt;br /&gt;
&lt;br /&gt;
This document describes the proposed API changes required for plugins which will allow a Moodle installation to become GDPR compliant.&lt;br /&gt;
&lt;br /&gt;
Target Audience: The intended audience for this document is Moodle plugin developers, who are aiming to ensure their plugins are updated to comply with GDPR requirements coming into effect in the EU in May, 2018.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Personal data in Moodle==&lt;br /&gt;
&lt;br /&gt;
From the GDPR Spec, Article 4:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;‘personal data’ means any information relating to an identified or identifiable natural person (‘data subject’); an identifiable natural person is one who can be identified, directly or indirectly, in particular by reference to an identifier such as a name, an identification number, location data, an online identifier or to one or more factors specific to the physical, physiological, genetic, mental, economic, cultural or social identity of that natural person;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In Moodle, we need to consider two main types of personal data; information entered by the user and information stored about the user. The key difference being that information stored about the user will have come from a source other than the user themselves. Both types of data can be used to form a profile of the individual.&lt;br /&gt;
&lt;br /&gt;
The most obvious clue to finding personal data entered by the user is the presence of a userid on a database field. Any data on the record (or linked records) pertaining to that user may be deemed personal data for that user, including things like timestamps and record identification numbers. Additionally, any free text field which allows the user to enter information must also be considered to be the personal data of that user.&lt;br /&gt;
&lt;br /&gt;
Data stored about the user includes things like ratings and comments made on a student submission. These may have been made by an assessor or teacher, but are considered the personal data of the student, as they are considered a reflection of the user’s competency in the subject matter and can be used to form a profile of that individual. &lt;br /&gt;
&lt;br /&gt;
The sections that follow outline what you need to do as a plugin developer to ensure any personal data is advertised and can be accessed and deleted according to the GDPR requirements.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
===Architecture overview===&lt;br /&gt;
&lt;br /&gt;
[[File:MoodlePrivacyMetadataUML.png|thumb|UML diagram of the metadata part of the privacy subsystem]]&lt;br /&gt;
[[File:MoodlePrivacyRequestUML.png|thumb|UML diagram of the request providers part of the privacy subsystem]]&lt;br /&gt;
&lt;br /&gt;
A new system for Privacy has been created within Moodle. This is broken down into several main parts and forms the &#039;&#039;core_privacy&#039;&#039; subsystem:&lt;br /&gt;
&lt;br /&gt;
* Some metadata providers - a set of PHP interfaces to be implemented by components for that component to describe the kind of data that it stores, and the purpose for its storage;&lt;br /&gt;
* Some request providers - a set of PHP interfaces to be implemented by components to allow that component to act upon user requests such as the Right to be Forgotten, and a Subject Access Request; and&lt;br /&gt;
* A manager - a concrete class used to bridge components which implement the providers with tools which request their data.&lt;br /&gt;
&lt;br /&gt;
All plugins will implement one metadata provider, and zero, one or two request providers.&lt;br /&gt;
&lt;br /&gt;
The fetching of data is broken into two separate steps:&lt;br /&gt;
&lt;br /&gt;
# Detecting in which Moodle contexts the user has any data; and&lt;br /&gt;
# Exporting all data from each of those contexts.&lt;br /&gt;
&lt;br /&gt;
This has been broken into two steps to later allow administrators to exclude certain contexts from an export - e.g. for courses currently in progress.&lt;br /&gt;
&lt;br /&gt;
A third component will later be added to facilitate the deletion of data within these contexts which will help to satisfy the Right to be Forgotten. This will also use the first step.&lt;br /&gt;
&lt;br /&gt;
===Implementing a provider===&lt;br /&gt;
&lt;br /&gt;
All plugins will need to create a concrete class which implements the relevant metadata and request providers. The exact providers you need to implement will depend on what data you store, and the type of plugin. This is covered in more detail in the following sections of the document.&lt;br /&gt;
&lt;br /&gt;
In order to do so:&lt;br /&gt;
&lt;br /&gt;
# You must create a class called &#039;&#039;provider&#039;&#039; within the namespace &#039;&#039;\your_pluginname\privacy&#039;&#039;.&lt;br /&gt;
# This class must be created at &#039;&#039;path/to/your/plugin/classes/privacy/provider.php&#039;&#039;.&lt;br /&gt;
# You must have your class implement the relevant metadata and request interfaces.&lt;br /&gt;
&lt;br /&gt;
==Plugins which do not store personal data==&lt;br /&gt;
&lt;br /&gt;
Many Moodle plugins do not store any personal data. This is usually the case for plugins which just add functionality, or which display the data already stored elsewhere in Moodle.&lt;br /&gt;
&lt;br /&gt;
Some examples of plugin types which might fit this criteria include themes, blocks, filters, editor plugins, etc.&lt;br /&gt;
&lt;br /&gt;
Plugins which cause data to be stored elsewhere in Moodle (e.g. via a subsystem call) are considered to store data.&lt;br /&gt;
&lt;br /&gt;
One examples of a plugin which does not store any data would be the Calendar month block which just displays a view of the user’s calendar. It does not store any data itself.&lt;br /&gt;
&lt;br /&gt;
An example of a plugin which must not use the null provider is the Comments block. The comments block is responsible for data subsequently being stored within Moodle. Although the block doesn’t store anything itself, it interacts with the comments subsystem and is the only component which knows how that data maps to a user.&lt;br /&gt;
&lt;br /&gt;
===Implementation requirements===&lt;br /&gt;
&lt;br /&gt;
In order to let Moodle know that you have audited your plugin, and that you do not store any personal user data, you must implement the &#039;&#039;\core_privacy\local\metadata\null_provider&#039;&#039; interface in your plugin’s provider.&lt;br /&gt;
&lt;br /&gt;
These null providers can only be implemented where a plugin has:&lt;br /&gt;
&lt;br /&gt;
* no external links (e.g. sends data to an external service like an LTI provider, repository plugin which you can search on)&lt;br /&gt;
* no database tables which store user data (including IP addresses)&lt;br /&gt;
* no user preferences&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;null_provider&#039;&#039; requires you to define one function &#039;&#039;get_reason()&#039;&#039; which returns the language string identifier within your component.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;blocks/calendar_month/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
&lt;br /&gt;
namespace block_calendar_month\privacy;&lt;br /&gt;
&lt;br /&gt;
class provider implements &lt;br /&gt;
    // This plugin does not store any personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\null_provider {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the language string identifier with the component&#039;s language&lt;br /&gt;
     * file to explain why this plugin stores no data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return  string&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_reason() : string {&lt;br /&gt;
        return &#039;privacy:metadata&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;blocks/calendar_month/lang/en/block_calendar_month.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
$string[&#039;privacy:metadata&#039;] = &#039;The Calendar block only displays existing calendar data.&#039;;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That’s it. Congratulations, your plugin now implements the Privacy API.&lt;br /&gt;
&lt;br /&gt;
==Plugins which store personal data==&lt;br /&gt;
&lt;br /&gt;
Many Moodle plugins do store some form of personal data.&lt;br /&gt;
&lt;br /&gt;
In some cases this will be stored within database tables in your plugin, and in other cases this will be in one of Moodle’s core subsystems - for example your plugin may store files, ratings, comments, or tags.&lt;br /&gt;
&lt;br /&gt;
Plugins which do store data will need to:&lt;br /&gt;
&lt;br /&gt;
* Describe the type of data that they store; &lt;br /&gt;
* Provide a way to export that data; and&lt;br /&gt;
* Provide a way to delete that data.&lt;br /&gt;
&lt;br /&gt;
Data is described via a &#039;&#039;metadata&#039;&#039; provider, and it is both exported and deleted via an implementation of a &#039;&#039;request&#039;&#039; provider.&lt;br /&gt;
&lt;br /&gt;
These are both explained in the sections below.&lt;br /&gt;
&lt;br /&gt;
===Describing the type of data you store===&lt;br /&gt;
&lt;br /&gt;
In order to describe the type of data that you store, you must implement the &#039;&#039;\core_privacy\local\metadata\provider&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
This interfaces requires that you define one function: &#039;&#039;get_metadata&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
There are several types of item to describe the data that you store. These are for:&lt;br /&gt;
&lt;br /&gt;
* Items in the Moodle database;&lt;br /&gt;
* Items stored by you in a Moodle subsystem - for example files, and ratings; and&lt;br /&gt;
* User preferences stored site-wide within Moodle for your plugin&lt;br /&gt;
&lt;br /&gt;
Note: All fields should include a description from a language string within your plugin.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
&lt;br /&gt;
namespace mod_forum\privacy;&lt;br /&gt;
use core_privacy\local\metadata\collection;&lt;br /&gt;
&lt;br /&gt;
class provider implements &lt;br /&gt;
        // This plugin does store personal user data.&lt;br /&gt;
        \core_privacy\local\metadata\provider {&lt;br /&gt;
&lt;br /&gt;
    public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
        // Here you will add more items into the collection.&lt;br /&gt;
&lt;br /&gt;
        return $collection;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you store content in a Moodle subsystem====&lt;br /&gt;
&lt;br /&gt;
Many plugins will use one of the core Moodle subsystems to store data.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer we do not expect you to describe those subsystems in detail, but we do need to know that you use them and to know what you use them for.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;add_subsystem_link()&#039;&#039; method on the &#039;&#039;collection&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;add_subsystem_link(&lt;br /&gt;
        &#039;core_files&#039;,&lt;br /&gt;
        [],&lt;br /&gt;
        &#039;privacy:metadata:core_files&#039;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/lang/en/forum.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:core_files&#039;] = &#039;The forum stores files which have been uploaded by the user to form part of a forum post.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Describing data stored in database tables====&lt;br /&gt;
&lt;br /&gt;
Most Moodle plugins will store some form of user data in their own database tables.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer you will need to describe each database table, and each field which includes user data.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;add_database_table(&lt;br /&gt;
        &#039;forum_discussion_subs&#039;,&lt;br /&gt;
         [&lt;br /&gt;
            &#039;userid&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:userid&#039;,&lt;br /&gt;
            &#039;discussionid&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:discussionid&#039;,&lt;br /&gt;
            &#039;preference&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:preference&#039;,&lt;br /&gt;
&lt;br /&gt;
         ],&lt;br /&gt;
        &#039;privacy:metadata:forum_discussion_subs&#039;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/lang/en/forum.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs&#039;] = &#039;Information about the subscriptions to individual forum discussions. This includes when a user has chosen to subscribe to a discussion, or to unsubscribe from one where they would otherwise be subscribed.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:userid&#039;] = &#039;The ID of the user with this subscription preference.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:discussionid&#039;] = &#039;The ID of the discussion that was subscribed to.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:preference&#039;] = &#039;The start time of the subscription.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you store site-wide user preferences====&lt;br /&gt;
&lt;br /&gt;
Many plugins will include one or more user preferences. Unfortunately this is one of Moodle’s older components and many of the values stored are not pure user preferences. Each plugin should be aware of how it handles its own preferences and is best placed to determine whether they are site-wide preferences, or per-instance preferences.&lt;br /&gt;
&lt;br /&gt;
Whilst most of these will have a fixed name (e.g. &#039;&#039;filepicker_recentrepository&#039;&#039;), some will include a variable of some kind (e.g. &#039;&#039;tool_usertours_tour_completion_time_2&#039;&#039;). Only the general name needs to be indicated rather than one copy for each preference.&lt;br /&gt;
&lt;br /&gt;
Also, these should only be &#039;&#039;site-wide&#039;&#039; user preferences which do not belong to a specific Moodle context.&lt;br /&gt;
&lt;br /&gt;
In the above examples:&lt;br /&gt;
&lt;br /&gt;
* Preference &#039;&#039;filepicker_recentrepository&#039;&#039; belongs to the file subsystem, and is a site-wide preference affecting the user anywhere that they view the filepicker.&lt;br /&gt;
* Preference &#039;&#039;tool_usertours_tour_completion_time_2&#039;&#039; belongs to user tours. User tours are a site-wide feature which can affect many parts of Moodle and cross multiple contexts.&lt;br /&gt;
&lt;br /&gt;
In some cases a value may be stored in the preferences table but is known to belong to a specific context within Moodle. In these cases they should be stored as metadata against that context rather than as a site-wide user preference.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;add_user_preference()&#039;&#039; method on the &#039;&#039;collection&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Any plugin providing user preferences must also implement the &#039;&#039;\core_privacy\local\request\preference_provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/tool/usertours/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;add_user_preference(&#039;tool_usertours_tour_completion_time,&lt;br /&gt;
        &#039;privacy:metadata:preference:tool_usertours_tour_completion_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/tool/usertours/lang/en/tool_usertours.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:tool_usertours_tour_completion_time&#039;] = &#039;The time that a specific user tour was last completed by a user.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you export data to an external location====&lt;br /&gt;
&lt;br /&gt;
Many plugins will interact with external systems - for example cloud-based services. Often this external location is configurable within the plugin either at the site or the instance level.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer you will need to describe each &#039;&#039;type&#039;&#039; of target destination, alongside a list of each exported field which includes user data.&lt;br /&gt;
The &#039;&#039;actual&#039;&#039; destination does not need to be described as this can change based on configuration.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;add_external_location_link()&#039;&#039; method on the collection.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/lti/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;add_external_location_link(&#039;lti_client&#039;, [&lt;br /&gt;
            &#039;userid&#039; =&amp;gt; &#039;privacy:metadata:lti_client:userid&#039;,&lt;br /&gt;
            &#039;fullname&#039; =&amp;gt; &#039;privacy:metadata:lti_client:fullname&#039;,&lt;br /&gt;
        ], &#039;privacy:metadata:lti_client&#039;);&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/lti/lang/en/lti.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:lti_client&#039;] = &#039;In order to integrate with a remote LTI service, user data needs to be exchanged with that service.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:lti_client:userid&#039;] = &#039;The userid is sent from Moodle to allow you to access your data on the remote system.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:lti_client:fullname&#039;] = &#039;Your full name is sent to the remote system to allow a better user experience.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Providing a way to export user data===&lt;br /&gt;
&lt;br /&gt;
In order to export the user data that you store, you must implement the relevant request provider.&lt;br /&gt;
&lt;br /&gt;
We have named these request providers because they are called in response to a specific request from a user to access their information.&lt;br /&gt;
&lt;br /&gt;
There are several different types of request provider, and you may need to implement several of these, depending on the type and nature of your plugin.&lt;br /&gt;
&lt;br /&gt;
Broadly speaking plugins will fit into one of the following categories:&lt;br /&gt;
&lt;br /&gt;
* Plugins which are a subplugin of another plugin. Examples include &#039;&#039;assignsubmission&#039;&#039;, &#039;&#039;atto&#039;&#039;, and &#039;&#039;datafield&#039;&#039;;&lt;br /&gt;
* Plugins which are typically called by a Moodle subsystem. Examples include &#039;&#039;qtype&#039;&#039;, and &#039;&#039;profilefield&#039;&#039;;&lt;br /&gt;
* All other plugins which store data.&lt;br /&gt;
&lt;br /&gt;
Most plugins will fit into this final category, whilst other plugins may fall into several categories.&lt;br /&gt;
Plugins which &#039;&#039;define&#039;&#039; a subplugin will also be responsible for  collecting this data from their subplugins.&lt;br /&gt;
&lt;br /&gt;
A final category exists - plugins which store user preferences. In some cases this may be the &#039;&#039;only&#039;&#039; provider implemented.&lt;br /&gt;
&lt;br /&gt;
====Standard plugins which store data====&lt;br /&gt;
&lt;br /&gt;
A majority of Moodle plugins will fit into this category and will be required to implement the &#039;&#039;\core_privacy\local\request\plugin\provider&#039;&#039; interface. This interface requires that you define two functions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;get_contexts_for_userid&#039;&#039; - to explain where data is held within Moodle for your plugin; and&lt;br /&gt;
* &#039;&#039;export_user_data&#039;&#039; - to export a user’s personal data from your plugin.&lt;br /&gt;
&lt;br /&gt;
These APIs make use of the Moodle &#039;&#039;context&#039;&#039; system to hierarchically store this data.&lt;br /&gt;
&lt;br /&gt;
====Retrieving the list of contexts====&lt;br /&gt;
&lt;br /&gt;
Contexts are retrieved using the &#039;&#039;get_contexts_for_userid&#039;&#039; function which takes the ID of the user being fetched, and returns a list of contexts in which the user has any data.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_contexts_for_userid(int $userid) : contextlist {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The function returns a &#039;&#039;\core_privacy\local\request\contextlist&#039;&#039; which is used to keep a set of contexts together in a fixed fashion.&lt;br /&gt;
&lt;br /&gt;
Because a Subject Access Request covers &#039;&#039;every&#039;&#039; piece of data that is held for a user within Moodle, efficiency and performance is highly important. As a result, contexts are added to the &#039;&#039;contextlist&#039;&#039; by defining one or more SQL queries which return just the contextid. Multiple SQL queries can be added as required.&lt;br /&gt;
&lt;br /&gt;
Many plugins will interact with specific subsystems and store data within them.&lt;br /&gt;
These subsystems will also provide a way in which to link the data that you have stored with your own database tables.&lt;br /&gt;
At present these are still a work in progress and only the &#039;&#039;core_ratings&#039;&#039; subsystem includes this.&lt;br /&gt;
&lt;br /&gt;
=====Basic example=====&lt;br /&gt;
&lt;br /&gt;
The following example simply fetches the contextid for all forums where a user has a single discussion (note: this is an incomplete example):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_contexts_for_userid(int $userid) : contextlist {&lt;br /&gt;
        $contextlist = new \core_privacy\local\request\contextlist();&lt;br /&gt;
&lt;br /&gt;
        $sql = &amp;quot;SELECT c.id&lt;br /&gt;
                 FROM {context} c&lt;br /&gt;
           INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel&lt;br /&gt;
           INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname&lt;br /&gt;
           INNER JOIN {forum} f ON f.id = cm.instance&lt;br /&gt;
            LEFT JOIN {forum_discussions} d ON d.forum = f.id&lt;br /&gt;
                WHERE (&lt;br /&gt;
                d.userid        = :discussionuserid&lt;br /&gt;
                )&lt;br /&gt;
        &amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        $params = [&lt;br /&gt;
            &#039;modname&#039;           =&amp;gt; &#039;forum&#039;,&lt;br /&gt;
            &#039;contextlevel&#039;      =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
            &#039;discussionuserid&#039;  =&amp;gt; $userid,&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        $contextlist-&amp;gt;add_from_sql($sql, $params);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====More complete example=====&lt;br /&gt;
&lt;br /&gt;
The following example includes a link to core_rating. &lt;br /&gt;
It will find any forum, forum discussion, or forum post where the user has any data, including:&lt;br /&gt;
&lt;br /&gt;
* Per-forum digest preferences;&lt;br /&gt;
* Per-forum subscription preferences;&lt;br /&gt;
* Per-forum read tracking preferences;&lt;br /&gt;
* Per-discussion subscription preferences;&lt;br /&gt;
* Per-post read data (if a user has read a post or not); and&lt;br /&gt;
* Per-post rating data.&lt;br /&gt;
&lt;br /&gt;
In the case of the rating data, this will include any post where the user has rated the post of another user.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   int           $userid       The user to search.&lt;br /&gt;
 * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
 */&lt;br /&gt;
public static function get_contexts_for_userid(int $userid) : contextlist {&lt;br /&gt;
    $ratingsql = \core_rating\privacy\provider::get_sql_join(&#039;rat&#039;, &#039;mod_forum&#039;, &#039;post&#039;, &#039;p.id&#039;, $userid);&lt;br /&gt;
    // Fetch all forum discussions, and forum posts.&lt;br /&gt;
    $sql = &amp;quot;SELECT c.id&lt;br /&gt;
                FROM {context} c&lt;br /&gt;
        INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel&lt;br /&gt;
        INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname&lt;br /&gt;
        INNER JOIN {forum} f ON f.id = cm.instance&lt;br /&gt;
            LEFT JOIN {forum_discussions} d ON d.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_posts} p ON p.discussion = d.id&lt;br /&gt;
            LEFT JOIN {forum_digests} dig ON dig.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_subscriptions} sub ON sub.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_track_prefs} pref ON pref.forumid = f.id&lt;br /&gt;
            LEFT JOIN {forum_read} hasread ON hasread.forumid = f.id&lt;br /&gt;
            LEFT JOIN {forum_discussion_subs} dsub ON dsub.forum = f.id&lt;br /&gt;
            {$ratingsql-&amp;gt;join}&lt;br /&gt;
                WHERE (&lt;br /&gt;
                p.userid        = :postuserid OR&lt;br /&gt;
                d.userid        = :discussionuserid OR&lt;br /&gt;
                dig.userid      = :digestuserid OR&lt;br /&gt;
                sub.userid      = :subuserid OR&lt;br /&gt;
                pref.userid     = :prefuserid OR&lt;br /&gt;
                hasread.userid  = :hasreaduserid OR&lt;br /&gt;
                dsub.userid     = :dsubuserid OR&lt;br /&gt;
                {$ratingsql-&amp;gt;userwhere}&lt;br /&gt;
            )&lt;br /&gt;
    &amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    $params = [&lt;br /&gt;
        &#039;modname&#039;           =&amp;gt; &#039;forum&#039;,&lt;br /&gt;
        &#039;contextlevel&#039;      =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;postuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
        &#039;discussionuserid&#039;  =&amp;gt; $userid,&lt;br /&gt;
        &#039;digestuserid&#039;      =&amp;gt; $userid,&lt;br /&gt;
        &#039;subuserid&#039;         =&amp;gt; $userid,&lt;br /&gt;
        &#039;prefuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
        &#039;hasreaduserid&#039;     =&amp;gt; $userid,&lt;br /&gt;
        &#039;dsubuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
    ];&lt;br /&gt;
    $params += $ratingsql-&amp;gt;params;&lt;br /&gt;
&lt;br /&gt;
    $contextlist = new \core_privacy\local\request\contextlist();&lt;br /&gt;
    $contextlist-&amp;gt;add_from_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
    return $contextlist;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Exporting user data====&lt;br /&gt;
&lt;br /&gt;
After determining where in Moodle your plugin holds data about a user, the &#039;&#039;\core_privacy\manager&#039;&#039; will then ask your plugin to export all user data for a subset of those locations.&lt;br /&gt;
&lt;br /&gt;
This is achieved through use of the &#039;&#039;export_user_data&#039;&#039; function which takes the list of approved contexts in a &#039;&#039;\core_privacy\local\request\approved_contextlist&#039;&#039; object.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Export all user data for the specified user, in the specified contexts, using the supplied exporter instance.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   approved_contextlist    $contextlist    The approved contexts to export information for.&lt;br /&gt;
 */&lt;br /&gt;
public static function export_user_data(approved_contextlist $contextlist) {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;approved_contextlist&#039;&#039; includes both the user record, and a list of contexts, which can be retrieved by either processing it as an Iterator, or by calling &#039;&#039;get_contextids()&#039;&#039; or &#039;&#039;get_contexts()&#039;&#039; as required.&lt;br /&gt;
&lt;br /&gt;
Data is exported using a &#039;&#039;\core_privacy\local\request\content_writer&#039;&#039;, which is described in further detail below.&lt;br /&gt;
&lt;br /&gt;
===Plugins which store user preferences===&lt;br /&gt;
&lt;br /&gt;
Many plugins store a variety of user preferences, and must therefore export them.&lt;br /&gt;
&lt;br /&gt;
Since user preferences are a site-wide preference, these are exported separately to other user data.&lt;br /&gt;
In some cases the only data present is user preference data, whilst in others there is a combination of user-provided data, and user preferences.&lt;br /&gt;
&lt;br /&gt;
Storing of user preferences is achieved through implementation of the &#039;&#039;\core_privacy\local\request\preference_provider&#039;&#039; interface which defines one required function -- &#039;&#039;export_user_preferences&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Export all user preferences for the plugin.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   int         $userid The userid of the user whose data is to be exported.&lt;br /&gt;
 */&lt;br /&gt;
public static function export_user_preferences(int $userid) {&lt;br /&gt;
    $markasreadonnotification = get_user_preference(&#039;markasreadonnotification&#039;, null, $userid);&lt;br /&gt;
    if (null !== $markasreadonnotification) {&lt;br /&gt;
        switch ($markasreadonnotification) {&lt;br /&gt;
            case 0:&lt;br /&gt;
                $markasreadonnotificationdescription = get_string(&#039;markasreadonnotificationno&#039;, &#039;mod_forum&#039;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 1:&lt;br /&gt;
            default:&lt;br /&gt;
                $markasreadonnotificationdescription = get_string(&#039;markasreadonnotificationyes&#039;, &#039;mod_forum&#039;);&lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        writer::export_user_preference(&#039;mod_forum&#039;, &#039;markasreadonnotification&#039;, $markasreadonnotification, $markasreadonnotificationdescription);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Plugins which can have own subplugins ===&lt;br /&gt;
&lt;br /&gt;
Many plugin types are also able to define their own subplugins and will need to define a contract between themselves and their subplugins in order to fetch their data.&lt;br /&gt;
&lt;br /&gt;
This is required as the parent plugin and the child subplugin should be separate entities and the parent plugin must be able to function if one or more of its subplugins are uninstalled.&lt;br /&gt;
&lt;br /&gt;
The parent plugin is responsible for defining the contract,  and for interacting with its subplugins, though we intend to create helpers to make this easier.&lt;br /&gt;
&lt;br /&gt;
The parent plugin should define a new interface for each type of subplugin that it defines. This interface should extend the &#039;&#039;\core_privacy\local\request\plugin\subplugin_provider&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
==== When a parent plugin should and should not provide the interface for its subplugins ====&lt;br /&gt;
&lt;br /&gt;
There can be cases when there is no point for a plugin to provide the &amp;quot;subplugin_provider&amp;quot; based interface, even if it has own subplugins. See the Atto or TinyMCE editors as real examples.&lt;br /&gt;
&lt;br /&gt;
If the parent plugin has no data passed through to the subplugins, there is no benefit in defining a subplugin provider. For example, Atto subplugins are just used to enhance the functionality and they never receive anything like a context. Most of the time we need to define a subplugin provider, but in cases where there is no data passed from the plugin to its subplugins, there is no need to define the subplugin provider. If the subplugins still do store personal data that are not related to the parent plugin in any way, then subplugins should define their own standard provider.&lt;br /&gt;
&lt;br /&gt;
Compare with something like mod_assign where the subplugins store data for the parent and that data is contextually relevant to the parent plugin. In those cases the subplugin stores data for the plugin and it only makes sense to do so in the context of its parent plugin.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
The following example defines the contract that assign submission subplugins may be required to implement.&lt;br /&gt;
&lt;br /&gt;
The assignment module is responsible for returning the contexts of all assignments where a user has data, but in some cases it is unaware of all of those cases - for example if a Teacher comments on a student submission it may not be aware of these as the information about this interaction may not be stored within its own tables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/assign/privacy/assignsubmission_provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
&lt;br /&gt;
namespace mod_assign\privacy;&lt;br /&gt;
use \core_privacy\local\metadata\collection;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
interface assignsubmission_provider extends&lt;br /&gt;
    // This Interface defines a subplugin.&lt;br /&gt;
    \core_privacy\local\request\plugin\subplugin_provider {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the SQL required to find all submission items where this user has had any involvements. &lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  \stdClass                   Object containing the join, params, and where used to select a these records from the database.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_items_with_user_interaction(int $userid) : \stdClass ;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export all relevant user submissions information which match the combination of userid and attemptid.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @param   \context      $context      The context to export this submission against.&lt;br /&gt;
     * @param   array         $subcontext   The subcontext within the context to export this information&lt;br /&gt;
     * @param   int           $attid        The id of the submission to export.&lt;br /&gt;
     */&lt;br /&gt;
    public static function export_user_submissions(int $userid, \context $context, array $subcontext, int $attid) ;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Plugins which are subplugins to another plugin===&lt;br /&gt;
&lt;br /&gt;
If you are developing a sub-plugin of another plugin, then you will have to look at the relevant plugin in order to determine the exact contract.&lt;br /&gt;
&lt;br /&gt;
Each subplugin type should define a new interface which extends the &#039;&#039;\core_privacy\local\request\plugin\subplugin_provider&#039;&#039; interface and it is up to the parent plugin to define how they will interact with their children.&lt;br /&gt;
&lt;br /&gt;
The principles remain the same, but the exact implementation will differ depending upon requirements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/pluginname/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
namespace assignsubmission\onlinetext;&lt;br /&gt;
&lt;br /&gt;
class provider implements&lt;br /&gt;
    // This plugin does store personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\provider,&lt;br /&gt;
&lt;br /&gt;
    // This plugin is a subplugin of assign and must meet that contract.&lt;br /&gt;
    \mod_assign\privacy\assignsubmission_provider {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Plugins which are typically called by a Moodle subsystem===&lt;br /&gt;
&lt;br /&gt;
There are a number of plugintypes in Moodle which are typically called by a specific Moodle subsystem.&lt;br /&gt;
&lt;br /&gt;
Some of these are &#039;&#039;only&#039;&#039; called by that subsystem, for example plugins which are of the &#039;&#039;plagiarism&#039;&#039; plugintype should never be called directly, but are always invoked via the &#039;&#039;core_plagiarism&#039;&#039; subsystem.&lt;br /&gt;
&lt;br /&gt;
Conversely, there maybe other plugintypes which can be called both via a subsystem, and in some other fashion. We are still determining whether any plugintypes currently fit this pattern.&lt;br /&gt;
&lt;br /&gt;
If you are developing a plugin which belongs to a specific subsystem, then you will have to look at the relevant plugin in order to determine the exact contract.&lt;br /&gt;
&lt;br /&gt;
Each subsystem will define a new interface which extends the &#039;&#039;\core_privacy\local\request\plugin\subsystem_provider&#039;&#039; interface and it is up to that subsystem to define how they will interact with those plugins.&lt;br /&gt;
&lt;br /&gt;
The principles remain the same, but the exact implementation will differ depending upon requirements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;plagiarism/detectorator/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
namespace plagiarism_detectorator\privacy;&lt;br /&gt;
&lt;br /&gt;
class provider implements&lt;br /&gt;
    // This plugin does export personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\provider,&lt;br /&gt;
&lt;br /&gt;
    // This plugin is always linked against another activity module via the Plagiarism API.&lt;br /&gt;
    \core_plagiarism\privacy\plugin_provider {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Exporting data===&lt;br /&gt;
&lt;br /&gt;
Any plugin which stores data must also export it.&lt;br /&gt;
&lt;br /&gt;
To cater for this the privacy API includes a &#039;&#039;\core_privacy\local\request\content_writer&#039;&#039;, which defines a set of functions to store different types of data.&lt;br /&gt;
&lt;br /&gt;
Broadly speaking data is broken into the following types:&lt;br /&gt;
&lt;br /&gt;
* Data - this is the object being described. For example the post content in a forum post;&lt;br /&gt;
* Related data - this is data related to the object being stored. For example, ratings of a forum post;&lt;br /&gt;
* Metadata - This is metadata about the main object. For example whether you are subscribed to a forum discussion;&lt;br /&gt;
* User preferences - this is data about a site-wide preference;&lt;br /&gt;
* Files - Any files that you are stored within Moodle on behalf of this plugin; and&lt;br /&gt;
* Custom files - For custom file formats - e.g. a calendar feed for calendar data. These should be used sparingly.&lt;br /&gt;
&lt;br /&gt;
Each piece of data is stored against a specific Moodle &#039;&#039;context&#039;&#039;, which will define how the data is structured within the exporter.&lt;br /&gt;
Data, and Related data only accept the &#039;&#039;stdClass&#039;&#039; object, whilst metadata should be stored as a set of key/value pairs which include a description.&lt;br /&gt;
&lt;br /&gt;
In some cases the data being stored belongs within an implicit structure. For example, one forum has many forum discussions, which each have a number of forum posts. This structure is represented by an &#039;&#039;array&#039;&#039; referred to as a &#039;&#039;subcontext&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;content_writer&#039;&#039; must &#039;&#039;always&#039;&#039; be called with a specific context, and can be called as follows:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
use \core_privacy\local\request\writer;&lt;br /&gt;
&lt;br /&gt;
writer::with_context($context)&lt;br /&gt;
    -&amp;gt;export_data($subcontext, $post)&lt;br /&gt;
    -&amp;gt;export_area_files($subcontext, &#039;mod_forum&#039;, &#039;post&#039;, $post-&amp;gt;id)&lt;br /&gt;
    -&amp;gt;export_metadata($subcontext, &#039;postread&#039;, (object) [&#039;firstread&#039; =&amp;gt; $firstread], new \lang_string(&#039;privacy:export:post:postread&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any text field which supports Moodle files must also be rewritten:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
use \core_privacy\local\request\writer;&lt;br /&gt;
&lt;br /&gt;
$post-&amp;gt;message = writer::with_context($context)&lt;br /&gt;
    -&amp;gt;rewrite_pluginfile_urls($subcontext, &#039;mod_forum&#039;, &#039;post&#039;, $post-&amp;gt;id, $post-&amp;gt;message);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Providing a way to delete user data===&lt;br /&gt;
&lt;br /&gt;
Deleting user data is also implemented in the request interface. There are two methods that need to be created. The first one to remove all user data from a context, the other to remove user data for a specific user in a list of contexts.&lt;br /&gt;
&lt;br /&gt;
====Delete for a context====&lt;br /&gt;
&lt;br /&gt;
A context is given and all user data (for all users) is to be deleted from the plugin. This will be called when the retention period for the context has expired to adhere to the privacy by design requirement. Retention periods are set in the Data registry.�&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/choice/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function delete_data_for_all_users_in_context(deletion_criteria $criteria) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
    $context = $criteria-&amp;gt;get_context();&lt;br /&gt;
    if (empty($context)) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    $instanceid = $DB-&amp;gt;get_field(&#039;course_modules&#039;, &#039;instance&#039;, [&#039;id&#039; =&amp;gt; $context-&amp;gt;instanceid], MUST_EXIST);&lt;br /&gt;
    $DB-&amp;gt;delete_records(&#039;choice_answers&#039;, [&#039;choiceid&#039; =&amp;gt; $instanceid]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Delete personal information for a specific user and context(s)====&lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;approved_contextlist&#039;&#039; is given and user data related to that user should either be completely deleted, or overwritten if a structure needs to be maintained. This will be called when a user has requested the right to be forgotten. All attempts should be made to delete this data where practical while still allowing the plugin to be used by other users.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/choice/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function delete_data_for_user(approved_contextlist $contextlist) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
    &lt;br /&gt;
    if (empty($contextlist-&amp;gt;count())) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    $userid = $contextlist-&amp;gt;get_user()-&amp;gt;id;&lt;br /&gt;
    foreach ($contextlist-&amp;gt;get_contexts() as $context) {&lt;br /&gt;
        $instanceid = $DB-&amp;gt;get_field(&#039;course_modules&#039;, &#039;instance&#039;, [&#039;id&#039; =&amp;gt; $context-&amp;gt;instanceid], MUST_EXIST);&lt;br /&gt;
        $DB-&amp;gt;delete_records(&#039;choice_answers&#039;, [&#039;choiceid&#039; =&amp;gt; $instanceid, &#039;userid&#039; =&amp;gt; $userid]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Difference between Moodle 3.3 and more recent versions===&lt;br /&gt;
Moodle 3.3 has a minimum requirement of php 5.6 and so type hinting and return type declarations are not supported in this version. Consequently the privacy API for this version does not have these features.&lt;br /&gt;
====What to do if you have one plugin that supports multiple branches====&lt;br /&gt;
This is something that we have considered and we have put in place a polyfill. This gets around the restrictions of one version having type hinting and return type declarations while another does not.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
To use the polyfill include the legacy polyfill trait and create the necessary static methods but with an underscore (shown below).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class provider implements&lt;br /&gt;
    \core_privacy\local\metadata\provider,&lt;br /&gt;
    \core_privacy\local\request\plugin\provider {&lt;br /&gt;
&lt;br /&gt;
    // This trait must be included.&lt;br /&gt;
    use \core_privacy\local\legacy_polyfill;&lt;br /&gt;
&lt;br /&gt;
    // The required methods must be in this format starting with an underscore.&lt;br /&gt;
    public static function _get_metadata(collection $collection) {&lt;br /&gt;
        // Code for returning metadata goes here.&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====What to do if your must implement a subplugin or subsystem plugin provider====&lt;br /&gt;
For subplugins (e.g. assignsubmission, assignfeedback, quiz report, quiz access rules), or subsystems which have a plugintype relationship (portfolio, plagiarism, and others), they will also define their own legacy polyfill.&lt;br /&gt;
&lt;br /&gt;
In this instance you will need to include the trait for both the core polyfill, and the provider polyfill as appropriate.&lt;br /&gt;
===== Example =====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class provider implements&lt;br /&gt;
    // This plugin has data and must therefore define the metadata provider in order to describe it.&lt;br /&gt;
    \core_privacy\local\metadata\provider,&lt;br /&gt;
&lt;br /&gt;
    // This is a plagiarism plugin. It interacts with the plagiarism subsystem rather than with core.&lt;br /&gt;
    \core_plagiarism\privacy\plagiarism_provider {&lt;br /&gt;
&lt;br /&gt;
    // This trait must be included to provide the relevant polyfill for the metadata provider.&lt;br /&gt;
    use \core_privacy\local\legacy_polyfill;&lt;br /&gt;
&lt;br /&gt;
    // This trait must be included to provide the relevant polyfill for the plagirism provider.&lt;br /&gt;
    use \core_plagiarism\privacy\plagiarism_provider\legacy_polyfill;&lt;br /&gt;
&lt;br /&gt;
    // The required methods must be in this format starting with an underscore.&lt;br /&gt;
    public static function _get_metadata(collection $collection) {&lt;br /&gt;
        // Code for returning metadata goes here.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // This is one of the polyfilled methods from the plagiarism provider.&lt;br /&gt;
    public static function _export_plagiarism_user_data($userid, \context $context, array $subcontext, array $linkarray) {&lt;br /&gt;
        // ...&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tips for development ==&lt;br /&gt;
&lt;br /&gt;
* While implementing the privacy API into your plugin, there are CLI scripts that can help you to test things on the fly. Just don&#039;t forget these are not supposed to replace proper unit tests. See [[Privacy API/Utilities]] for details.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Subject Access Request FAQ]]&lt;br /&gt;
* [[:en:GDPR|GDPR]] in the user documentation&lt;br /&gt;
&lt;br /&gt;
[[Category:Privacy]]&lt;br /&gt;
[[Category:GDPR]]&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=GDPR_for_plugin_developers&amp;diff=53910</id>
		<title>GDPR for plugin developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=GDPR_for_plugin_developers&amp;diff=53910"/>
		<updated>2018-03-26T10:37:37Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Delete personal information for a specific user and context(s) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The General Data Protection Regulation (GDPR) is an EU directive that looks at providing users with more control over their data and how it is processed. This regulation will come into effect on 25th of May 2018 and covers any citizen or permanent resident of the European Union. The directive will be respected by a number of other countries outside of the European Union.&lt;br /&gt;
&lt;br /&gt;
To help institutions become compliant with this new regulation we are adding functionality to Moodle. This includes a number of components, amongst others these include a user’s right to:&lt;br /&gt;
&lt;br /&gt;
* request information on the types of personal data held, the instances of that data, and the deletion policy for each;&lt;br /&gt;
* access all of their data; and&lt;br /&gt;
* be forgotten.&lt;br /&gt;
&lt;br /&gt;
The compliance requirements also extend to installed plugins (including third party plugins). These need to also be able to report what information they store or process regarding users, and have the ability to provide and delete data for a user request.&lt;br /&gt;
&lt;br /&gt;
This document describes the proposed API changes required for plugins which will allow a Moodle installation to become GDPR compliant.&lt;br /&gt;
&lt;br /&gt;
Target Audience: The intended audience for this document is Moodle plugin developers, who are aiming to ensure their plugins are updated to comply with GDPR requirements coming into effect in the EU in May, 2018.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Personal data in Moodle==&lt;br /&gt;
&lt;br /&gt;
From the GDPR Spec, Article 4:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;‘personal data’ means any information relating to an identified or identifiable natural person (‘data subject’); an identifiable natural person is one who can be identified, directly or indirectly, in particular by reference to an identifier such as a name, an identification number, location data, an online identifier or to one or more factors specific to the physical, physiological, genetic, mental, economic, cultural or social identity of that natural person;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In Moodle, we need to consider two main types of personal data; information entered by the user and information stored about the user. The key difference being that information stored about the user will have come from a source other than the user themselves. Both types of data can be used to form a profile of the individual.&lt;br /&gt;
&lt;br /&gt;
The most obvious clue to finding personal data entered by the user is the presence of a userid on a database field. Any data on the record (or linked records) pertaining to that user may be deemed personal data for that user, including things like timestamps and record identification numbers. Additionally, any free text field which allows the user to enter information must also be considered to be the personal data of that user.&lt;br /&gt;
&lt;br /&gt;
Data stored about the user includes things like ratings and comments made on a student submission. These may have been made by an assessor or teacher, but are considered the personal data of the student, as they are considered a reflection of the user’s competency in the subject matter and can be used to form a profile of that individual. &lt;br /&gt;
&lt;br /&gt;
The sections that follow outline what you need to do as a plugin developer to ensure any personal data is advertised and can be accessed and deleted according to the GDPR requirements.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
===Architecture overview===&lt;br /&gt;
&lt;br /&gt;
A new system for Privacy has been created within Moodle. This is broken down into several main parts and forms the &#039;&#039;core_privacy&#039;&#039; subsystem:&lt;br /&gt;
&lt;br /&gt;
* Some metadata providers - a set of PHP interfaces to be implemented by components for that component to describe the kind of data that it stores, and the purpose for its storage;&lt;br /&gt;
* Some request providers - a set of PHP interfaces to be implemented by components to allow that component to act upon user requests such as the Right to be Forgotten, and a Subject Access Request; and&lt;br /&gt;
* A manager - a concrete class used to bridge components which implement the providers with tools which request their data.&lt;br /&gt;
&lt;br /&gt;
All plugins will implement one metadata provider, and zero, one or two request providers.&lt;br /&gt;
&lt;br /&gt;
The fetching of data is broken into two separate steps:&lt;br /&gt;
&lt;br /&gt;
# Detecting in which Moodle contexts the user has any data; and&lt;br /&gt;
# Exporting all data from each of those contexts.&lt;br /&gt;
&lt;br /&gt;
This has been broken into two steps to later allow administrators to exclude certain contexts from an export - e.g. for courses currently in progress.&lt;br /&gt;
&lt;br /&gt;
A third component will later be added to facilitate the deletion of data within these contexts which will help to satisfy the Right to be Forgotten. This will also use the first step.&lt;br /&gt;
&lt;br /&gt;
===Implementing a provider===&lt;br /&gt;
&lt;br /&gt;
All plugins will need to create a concrete class which implements the relevant metadata and request providers. The exact providers you need to implement will depend on what data you store, and the type of plugin. This is covered in more detail in the following sections of the document.&lt;br /&gt;
&lt;br /&gt;
In order to do so:&lt;br /&gt;
&lt;br /&gt;
# You must create a class called &#039;&#039;provider&#039;&#039; within the namespace &#039;&#039;\your_pluginname\privacy&#039;&#039;.&lt;br /&gt;
# This class must be created at &#039;&#039;path/to/your/plugin/classes/privacy/provider.php&#039;&#039;.&lt;br /&gt;
# You must have your class implement the relevant metadata and request interfaces.&lt;br /&gt;
&lt;br /&gt;
==Plugins which do not store personal data==&lt;br /&gt;
&lt;br /&gt;
Many Moodle plugins do not store any personal data. This is usually the case for plugins which just add functionality, or which display the data already stored elsewhere in Moodle.&lt;br /&gt;
&lt;br /&gt;
Some examples of plugin types which might fit this criteria include themes, blocks, filters, editor plugins, etc.&lt;br /&gt;
&lt;br /&gt;
Plugins which cause data to be stored elsewhere in Moodle (e.g. via a subsystem call) are considered to store data.&lt;br /&gt;
&lt;br /&gt;
One examples of a plugin which does not store any data would be the Calendar month block which just displays a view of the user’s calendar. It does not store any data itself.&lt;br /&gt;
&lt;br /&gt;
An example of a plugin which must not use the null provider is the Comments block. The comments block is responsible for data subsequently being stored within Moodle. Although the block doesn’t store anything itself, it interacts with the comments subsystem and is the only component which knows how that data maps to a user.&lt;br /&gt;
&lt;br /&gt;
===Implementation requirements===&lt;br /&gt;
&lt;br /&gt;
In order to let Moodle know that you have audited your plugin, and that you do not store any personal user data, you must implement the &#039;&#039;\core_privacy\local\metadata\null_provider&#039;&#039; interface in your plugin’s provider.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;null_provider&#039;&#039; requires you to define one function &#039;&#039;get_reason()&#039;&#039; which returns the language string identifier within your component.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;block/calendar_month/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
&lt;br /&gt;
namespace block_calendar_month\privacy;&lt;br /&gt;
&lt;br /&gt;
class provider implements &lt;br /&gt;
    # This plugin does not store any personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\null_provider&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the language string identifier with the component&#039;s language&lt;br /&gt;
     * file to explain why this plugin stores no data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return  string&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_reason() : string {&lt;br /&gt;
        return &#039;privacy:null_reason&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;block/calendar_month/lang/en/block_calendar_month.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:null_reason&#039;] = &#039;The calendar month block displays information from the Calendar, but does not effect or store any data itself. All changes are made via the Calendar.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That’s it. Congratulations, your plugin now implements the Privacy API.&lt;br /&gt;
&lt;br /&gt;
==Plugins which store personal data==&lt;br /&gt;
&lt;br /&gt;
Many Moodle plugins do store some form of personal data.&lt;br /&gt;
&lt;br /&gt;
In some cases this will be stored within database tables in your plugin, and in other cases this will be in one of Moodle’s core subsystems - for example your plugin may store files, ratings, comments, or tags.&lt;br /&gt;
&lt;br /&gt;
Plugins which do store data will need to:&lt;br /&gt;
&lt;br /&gt;
* Describe the type of data that they store; &lt;br /&gt;
* Provide a way to export that data; and&lt;br /&gt;
* Provide a way to delete that data.&lt;br /&gt;
&lt;br /&gt;
Data is described via a &#039;&#039;metadata&#039;&#039; provider, and it is both exported and deleted via an implementation of a &#039;&#039;request&#039;&#039; provider.&lt;br /&gt;
&lt;br /&gt;
These are both explained in the sections below.&lt;br /&gt;
&lt;br /&gt;
===Describing the type of data you store===&lt;br /&gt;
&lt;br /&gt;
In order to describe the type of data that you store, you must implement the &#039;&#039;\core_privacy\local\metadata\provider&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
This interfaces requires that you define one function: &#039;&#039;get_metadata&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
There are several types of item to describe the data that you store. These are for:&lt;br /&gt;
&lt;br /&gt;
* Items in the Moodle database;&lt;br /&gt;
* Items stored by you in a Moodle subsystem - for example files, and ratings; and&lt;br /&gt;
* User preferences stored site-wide within Moodle for your plugin&lt;br /&gt;
&lt;br /&gt;
Note: All fields should include a description from a language string within your plugin.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
&lt;br /&gt;
namespace mod_forum\privacy;&lt;br /&gt;
use \core_privacy\local\metadata\collection;&lt;br /&gt;
&lt;br /&gt;
class provider implements &lt;br /&gt;
    # This plugin does store personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\provider&lt;br /&gt;
{&lt;br /&gt;
    public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
        return $collection;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you store content in a Moodle subsystem====&lt;br /&gt;
&lt;br /&gt;
Many plugins will use one of the core Moodle subsystems to store data.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer we do not expect you to describe those subsystems in detail, but we do need to know that you use them and to know what you use them for.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;link_subsystem()&#039;&#039; method on the &#039;&#039;collection&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;link_subsystem(&lt;br /&gt;
        &#039;core_files&#039;,&lt;br /&gt;
        &#039;privacy:metadata:core_files&#039;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/lang/en/forum.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:core_files&#039;] = &#039;The forum stores files which have been uploaded by the user to form part of a forum post.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Describing data stored in database tables====&lt;br /&gt;
&lt;br /&gt;
Most Moodle plugins will store some form of user data in their own database tables.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer you will need to describe each database table, and each field which includes user data.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;add_database_table(&lt;br /&gt;
        &#039;forum_discussion_subs&#039;,&lt;br /&gt;
         [&lt;br /&gt;
            &#039;userid&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:userid&#039;,&lt;br /&gt;
            &#039;discussionid&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:discussionid&#039;,&lt;br /&gt;
            &#039;preference&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:preference&#039;,&lt;br /&gt;
&lt;br /&gt;
         ],&lt;br /&gt;
        &#039;privacy:metadata:forum_discussion_subs&#039;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/lang/en/forum.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs&#039;] = &#039;Information about the subscriptions to individual forum discussions. This includes when a user has chosen to subscribe to a discussion, or to unsubscribe from one where they would otherwise be subscribed.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:userid&#039;] = &#039;The ID of the user with this subscription preference.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:discussionid&#039;] = &#039;The ID of the discussion that was subscribed to.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:preference&#039;] = &#039;The start time of the subscription.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you store site-wide user preferences====&lt;br /&gt;
&lt;br /&gt;
Many plugins will include one or more user preferences. Unfortunately this is one of Moodle’s older components and many of the values stored are not pure user preferences. Each plugin should be aware of how it handles its own preferences and is best placed to determine whether they are site-wide preferences, or per-instance preferences.&lt;br /&gt;
&lt;br /&gt;
Whilst most of these will have a fixed name (e.g. &#039;&#039;filepicker_recentrepository&#039;&#039;), some will include a variable of some kind (e.g. &#039;&#039;tool_usertours_tour_completion_time_2&#039;&#039;). Only the general name needs to be indicated rather than one copy for each preference.&lt;br /&gt;
&lt;br /&gt;
Also, these should only be &#039;&#039;site-wide&#039;&#039; user preferences which do not belong to a specific Moodle context.&lt;br /&gt;
&lt;br /&gt;
In the above examples:&lt;br /&gt;
&lt;br /&gt;
* Preference &#039;&#039;filepicker_recentrepository&#039;&#039; belongs to the file subsystem, and is a site-wide preference affecting the user anywhere that they view the filepicker.&lt;br /&gt;
* Preference &#039;&#039;tool_usertours_tour_completion_time_2&#039;&#039; belongs to user tours. User tours are a site-wide feature which can affect many parts of Moodle and cross multiple contexts.&lt;br /&gt;
&lt;br /&gt;
In some cases a value may be stored in the preferences table but is known to belong to a specific context within Moodle. In these cases they should be stored as metadata against that context rather than as a site-wide user preference.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;add_user_preference()&#039;&#039; method on the &#039;&#039;collection&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Any plugin providing user preferences must also implement the &#039;&#039;\core_privacy\local\request\preference_provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/tool/usertours/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;add_user_preference(&#039;tool_usertours_tour_completion_time,&lt;br /&gt;
        &#039;privacy:metadata:preference:tool_usertours_tour_completion_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/tool/usertours/lang/en/tool_usertours.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:tool_usertours_tour_completion_time&#039;] = &#039;The time that a specific user tour was last completed by a user.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you export data to an external location====&lt;br /&gt;
&lt;br /&gt;
Many plugins will interact with external systems - for example cloud-based services. Often this external location is configurable within the plugin either at the site or the instance level.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer you will need to describe each &#039;&#039;type&#039;&#039; of target destination, alongside a list of each exported field which includes user data.&lt;br /&gt;
The &#039;&#039;actual&#039;&#039; destination does not need to be described as this can change based on configuration.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;link_external_location()&#039;&#039; method on the collection.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/lti/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;link_external_location(&#039;lti_client&#039;, [&lt;br /&gt;
            &#039;userid&#039; =&amp;gt; &#039;privacy:metadata:lti_client:userid&#039;,&lt;br /&gt;
            &#039;fullname&#039; =&amp;gt; &#039;privacy:metadata:lti_client:fullname&#039;,&lt;br /&gt;
        ], &#039;privacy:metadata:lti_client&#039;);&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/tool/usertours/lang/en/tool_usertours.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:lti_client&#039;] = &#039;In order to integrate with a remote LTI service, user data needs to be exchanged with that service.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:lti_client:userid&#039;] = &#039;The userid is sent from Moodle to allow you to access your data on the remote system.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:lti_client:fullname&#039;] = &#039;Your full name is sent to the remote system to allow a better user experience.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Providing a way to export user data===&lt;br /&gt;
&lt;br /&gt;
In order to export the user data that you store, you must implement the relevant request provider.&lt;br /&gt;
&lt;br /&gt;
We have named these request providers because they are called in response to a specific request from a user to access their information.&lt;br /&gt;
&lt;br /&gt;
There are several different types of request provider, and you may need to implement several of these, depending on the type and nature of your plugin.&lt;br /&gt;
&lt;br /&gt;
Broadly speaking plugins will fit into one of the following categories:&lt;br /&gt;
&lt;br /&gt;
* Plugins which are a subplugin of another plugin. Examples include &#039;&#039;assignsubmission&#039;&#039;, &#039;&#039;atto&#039;&#039;, and &#039;&#039;datafield&#039;&#039;;&lt;br /&gt;
* Plugins which are typically called by a Moodle subsystem. Examples include &#039;&#039;qtype&#039;&#039;, and &#039;&#039;profilefield&#039;&#039;;&lt;br /&gt;
* All other plugins which store data.&lt;br /&gt;
&lt;br /&gt;
Most plugins will fit into this final category, whilst other plugins may fall into several categories.&lt;br /&gt;
Plugins which &#039;&#039;define&#039;&#039; a subplugin will also be responsible for  collecting this data from their subplugins.&lt;br /&gt;
&lt;br /&gt;
A final category exists - plugins which store user preferences. In some cases this may be the &#039;&#039;only&#039;&#039; provider implemented.&lt;br /&gt;
&lt;br /&gt;
====Standard plugins which store data====&lt;br /&gt;
&lt;br /&gt;
A majority of Moodle plugins will fit into this category and will be required to implement the &#039;&#039;\core_privacy\local\request\plugin\provider&#039;&#039; interface. This interface requires that you define two functions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;get_contexts_for_userid&#039;&#039; - to explain where data is held within Moodle for your plugin; and&lt;br /&gt;
* &#039;&#039;export_user_data&#039;&#039; - to export a user’s personal data from your plugin.&lt;br /&gt;
&lt;br /&gt;
These APIs make use of the Moodle &#039;&#039;context&#039;&#039; system to hierarchically store this data.&lt;br /&gt;
&lt;br /&gt;
====Retrieving the list of contexts====&lt;br /&gt;
&lt;br /&gt;
Contexts are retrieved using the &#039;&#039;get_contexts_for_userid&#039;&#039; function which takes the ID of the user being fetched, and returns a list of contexts in which the user has any data.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_contexts_for_userid(int $userid) : contextlist {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The function returns a &#039;&#039;\core_privacy\local\request\contextlist&#039;&#039; which is used to keep a set of contexts together in a fixed fashion.&lt;br /&gt;
&lt;br /&gt;
Because a Subject Access Request covers &#039;&#039;every&#039;&#039; piece of data that is held for a user within Moodle, efficiency and performance is highly important. As a result, contexts are added to the &#039;&#039;contextlist&#039;&#039; by defining one or more SQL queries which return just the contextid. Multiple SQL queries can be added as required.&lt;br /&gt;
&lt;br /&gt;
Many plugins will interact with specific subsystems and store data within them.&lt;br /&gt;
These subsystems will also provide a way in which to link the data that you have stored with your own database tables.&lt;br /&gt;
At present these are still a work in progress and only the &#039;&#039;core_ratings&#039;&#039; subsystem includes this.&lt;br /&gt;
&lt;br /&gt;
=====Basic example=====&lt;br /&gt;
&lt;br /&gt;
The following example simply fetches the contextid for all forums where a user has a single discussion (note: this is an incomplete example):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_contexts_for_userid(int $userid) : contextlist {&lt;br /&gt;
        $contextlist = new \core_privacy\local\request\contextlist();&lt;br /&gt;
&lt;br /&gt;
        $sql = &amp;quot;SELECT c.id&lt;br /&gt;
                 FROM {context} c&lt;br /&gt;
           INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel&lt;br /&gt;
           INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname&lt;br /&gt;
           INNER JOIN {forum} f ON f.id = cm.instance&lt;br /&gt;
            LEFT JOIN {forum_discussions} d ON d.forum = f.id&lt;br /&gt;
                WHERE (&lt;br /&gt;
                d.userid        = :discussionuserid&lt;br /&gt;
                )&lt;br /&gt;
        &amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        $params = [&lt;br /&gt;
            &#039;modname&#039;           =&amp;gt; &#039;forum&#039;,&lt;br /&gt;
            &#039;contextlevel&#039;      =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
            &#039;discussionuserid&#039;  =&amp;gt; $userid,&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        $contextlist-&amp;gt;add_from_sql($sql, $params);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====More complete example=====&lt;br /&gt;
&lt;br /&gt;
The following example includes a link to core_rating. &lt;br /&gt;
It will find any forum, forum discussion, or forum post where the user has any data, including:&lt;br /&gt;
&lt;br /&gt;
* Per-forum digest preferences;&lt;br /&gt;
* Per-forum subscription preferences;&lt;br /&gt;
* Per-forum read tracking preferences;&lt;br /&gt;
* Per-discussion subscription preferences;&lt;br /&gt;
* Per-post read data (if a user has read a post or not); and&lt;br /&gt;
* Per-post rating data.&lt;br /&gt;
&lt;br /&gt;
In the case of the rating data, this will include any post where the user has rated the post of another user.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   int           $userid       The user to search.&lt;br /&gt;
 * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
 */&lt;br /&gt;
public static function get_contexts_for_userid(int $userid) : contextlist {&lt;br /&gt;
    $ratingsql = \core_rating\privacy\provider::get_sql_join(&#039;rat&#039;, &#039;mod_forum&#039;, &#039;post&#039;, &#039;p.id&#039;, $userid);&lt;br /&gt;
    // Fetch all forum discussions, and forum posts.&lt;br /&gt;
    $sql = &amp;quot;SELECT c.id&lt;br /&gt;
                FROM {context} c&lt;br /&gt;
        INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel&lt;br /&gt;
        INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname&lt;br /&gt;
        INNER JOIN {forum} f ON f.id = cm.instance&lt;br /&gt;
            LEFT JOIN {forum_discussions} d ON d.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_posts} p ON p.discussion = d.id&lt;br /&gt;
            LEFT JOIN {forum_digests} dig ON dig.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_subscriptions} sub ON sub.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_track_prefs} pref ON pref.forumid = f.id&lt;br /&gt;
            LEFT JOIN {forum_read} hasread ON hasread.forumid = f.id&lt;br /&gt;
            LEFT JOIN {forum_discussion_subs} dsub ON dsub.forum = f.id&lt;br /&gt;
            {$ratingsql-&amp;gt;join}&lt;br /&gt;
                WHERE (&lt;br /&gt;
                p.userid        = :postuserid OR&lt;br /&gt;
                d.userid        = :discussionuserid OR&lt;br /&gt;
                dig.userid      = :digestuserid OR&lt;br /&gt;
                sub.userid      = :subuserid OR&lt;br /&gt;
                pref.userid     = :prefuserid OR&lt;br /&gt;
                hasread.userid  = :hasreaduserid OR&lt;br /&gt;
                dsub.userid     = :dsubuserid OR&lt;br /&gt;
                {$ratingsql-&amp;gt;userwhere}&lt;br /&gt;
            )&lt;br /&gt;
    &amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    $params = [&lt;br /&gt;
        &#039;modname&#039;           =&amp;gt; &#039;forum&#039;,&lt;br /&gt;
        &#039;contextlevel&#039;      =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;postuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
        &#039;discussionuserid&#039;  =&amp;gt; $userid,&lt;br /&gt;
        &#039;digestuserid&#039;      =&amp;gt; $userid,&lt;br /&gt;
        &#039;subuserid&#039;         =&amp;gt; $userid,&lt;br /&gt;
        &#039;prefuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
        &#039;hasreaduserid&#039;     =&amp;gt; $userid,&lt;br /&gt;
        &#039;dsubuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
    ];&lt;br /&gt;
    $params += $ratingsql-&amp;gt;params;&lt;br /&gt;
&lt;br /&gt;
    $contextlist = new \core_privacy\local\request\contextlist();&lt;br /&gt;
    $contextlist-&amp;gt;add_from_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
    return $contextlist;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Exporting user data====&lt;br /&gt;
&lt;br /&gt;
After determining where in Moodle your plugin holds data about a user, the &#039;&#039;\core_privacy\manager&#039;&#039; will then ask your plugin to export all user data for a subset of those locations.&lt;br /&gt;
&lt;br /&gt;
This is achieved through use of the &#039;&#039;export_user_data&#039;&#039; function which takes the list of approved contexts in a &#039;&#039;\core_privacy\local\request\approved_contextlist&#039;&#039; object.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Export all user data for the specified user, in the specified contexts, using the supplied exporter instance.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   approved_contextlist    $contextlist    The approved contexts to export information for.&lt;br /&gt;
 */&lt;br /&gt;
public static function export_user_data(approved_contextlist $contextlist) {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;approved_contextlist&#039;&#039; includes both the user record, and a list of contexts, which can be retrieved by either processing it as an Iterator, or by calling &#039;&#039;get_contextids()&#039;&#039; or &#039;&#039;get_contexts()&#039;&#039; as required.&lt;br /&gt;
&lt;br /&gt;
Data is exported using a &#039;&#039;\core_privacy\local\request\content_writer&#039;&#039;, which is described in further detail below.&lt;br /&gt;
&lt;br /&gt;
===Plugins which store user preferences===&lt;br /&gt;
&lt;br /&gt;
Many plugins store a variety of user preferences, and must therefore export them.&lt;br /&gt;
&lt;br /&gt;
Since user preferences are a site-wide preference, these are exported separately to other user data.&lt;br /&gt;
In some cases the only data present is user preference data, whilst in others there is a combination of user-provided data, and user preferences.&lt;br /&gt;
&lt;br /&gt;
Storing of user preferences is achieved through implementation of the &#039;&#039;\core_privacy\local\request\preference_provider&#039;&#039; interface which defines one required function -- &#039;&#039;export_user_preferences&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Export all user preferences for the plugin.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   int         $userid The userid of the user whose data is to be exported.&lt;br /&gt;
 */&lt;br /&gt;
public static function export_user_preferences(int $userid) {&lt;br /&gt;
    $markasreadonnotification = get_user_preference(&#039;markasreadonnotification&#039;, null, $userid);&lt;br /&gt;
    if (null !== $markasreadonnotification) {&lt;br /&gt;
        switch ($markasreadonnotification) {&lt;br /&gt;
            case 0:&lt;br /&gt;
                $markasreadonnotificationdescription = get_string(&#039;markasreadonnotificationno&#039;, &#039;mod_forum&#039;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 1:&lt;br /&gt;
            default:&lt;br /&gt;
                $markasreadonnotificationdescription = get_string(&#039;markasreadonnotificationyes&#039;, &#039;mod_forum&#039;);&lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        writer::export_user_preference(&#039;mod_forum&#039;, &#039;markasreadonnotification&#039;, $markasreadonnotification, $markasreadonnotificationdescription);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Plugins which define a subplugin===&lt;br /&gt;
&lt;br /&gt;
Many plugin types are also able to define their own subplugins and will need to define a contract between themselves and their subplugins in order to fetch their data.&lt;br /&gt;
&lt;br /&gt;
This is required as the parent plugin and the child subplugin should be separate entities and the parent plugin must be able to function if one or more of its subplugins are uninstalled.&lt;br /&gt;
&lt;br /&gt;
The parent plugin is responsible for defining the contract,  and for interacting with its subplugins, though we intend to create helpers to make this easier.&lt;br /&gt;
&lt;br /&gt;
The parent plugin should define a new interface for each type of subplugin that it defines. This interface should extend the &#039;&#039;\core_privacy\local\request\plugin\subplugin_provider&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
The following example defines the contract that assign submission subplugins may be required to implement.&lt;br /&gt;
&lt;br /&gt;
The assignment module is responsible for returning the contexts of all assignments where a user has data, but in some cases it is unaware of all of those cases - for example if a Teacher comments on a student submission it may not be aware of these as the information about this interaction may not be stored within its own tables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/assign/privacy/assignsubmission_provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
&lt;br /&gt;
namespace mod_assign\privacy;&lt;br /&gt;
use \core_privacy\local\metadata\collection;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
interface assignsubmission_provider extends&lt;br /&gt;
    # This Interface defines a subplugin.&lt;br /&gt;
    \core_privacy\local\request\subplugin_provider&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the SQL required to find all submission items where this user has had any involvements. &lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  \stdClass                   Object containing the join, params, and where used to select a these records from the database.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_items_with_user_interaction(int $userid) : \stdClass ;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export all relevant user submissions information which match the combination of userid and attemptid.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @param   \context      $context      The context to export this submission against.&lt;br /&gt;
     * @param   array         $subcontext   The subcontext within the context to export this information&lt;br /&gt;
     * @param   int           $attid        The id of the submission to export.&lt;br /&gt;
     */&lt;br /&gt;
    public static function export_user_submissions(int $userid, \context $context, array $subcontext, int $attid) ;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Plugins which are subplugins to another plugin===&lt;br /&gt;
&lt;br /&gt;
If you are developing a sub-plugin of another plugin, then you will have to look at the relevant plugin in order to determine the exact contract.&lt;br /&gt;
&lt;br /&gt;
Each subplugin type should define a new interface which extends the &#039;&#039;\core_privacy\local\request\plugin\subplugin_provider&#039;&#039; interface and it is up to the parent plugin to define how they will interact with their children.&lt;br /&gt;
&lt;br /&gt;
The principles remain the same, but the exact implementation will differ depending upon requirements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/pluginname/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
namespace assignsubmission\onlinetext;&lt;br /&gt;
&lt;br /&gt;
class provider implements&lt;br /&gt;
    # This plugin does store personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\provider,&lt;br /&gt;
&lt;br /&gt;
    # This plugin is a subplugin of assign and must meet that contract.&lt;br /&gt;
    \mod_assign\privacy\assignsubmission_provider&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Plugins which are typically called by a Moodle subsystem===&lt;br /&gt;
&lt;br /&gt;
There are a number of plugintypes in Moodle which are typically called by a specific Moodle subsystem.&lt;br /&gt;
&lt;br /&gt;
Some of these are &#039;&#039;only&#039;&#039; called by that subsystem, for example plugins which are of the &#039;&#039;plagiarism&#039;&#039; plugintype should never be called directly, but are always invoked via the &#039;&#039;core_plagiarism&#039;&#039; subsystem.&lt;br /&gt;
&lt;br /&gt;
Conversely, there maybe other plugintypes which can be called both via a subsystem, and in some other fashion. We are still determining whether any plugintypes currently fit this pattern.&lt;br /&gt;
&lt;br /&gt;
If you are developing a plugin which belongs to a specific subsystem, then you will have to look at the relevant plugin in order to determine the exact contract.&lt;br /&gt;
&lt;br /&gt;
Each subsystem will define a new interface which extends the &#039;&#039;\core_privacy\local\request\plugin\subsystem_provider&#039;&#039; interface and it is up to that subsystem to define how they will interact with those plugins.&lt;br /&gt;
&lt;br /&gt;
The principles remain the same, but the exact implementation will differ depending upon requirements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;plagiarism/detectorator/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
namespace plagiarism_detectorator\privacy;&lt;br /&gt;
&lt;br /&gt;
class provider implements&lt;br /&gt;
    # This plugin does export personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\provider,&lt;br /&gt;
&lt;br /&gt;
    # This plugin is always linked against another activity module via the Plagiarism API.&lt;br /&gt;
    \core_plagiarism\privacy\plugin_provider&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Exporting data===&lt;br /&gt;
&lt;br /&gt;
Any plugin which stores data must also export it.&lt;br /&gt;
&lt;br /&gt;
To cater for this the privacy API includes a &#039;&#039;\core_privacy\local\request\content_writer&#039;&#039;, which defines a set of functions to store different types of data.&lt;br /&gt;
&lt;br /&gt;
Broadly speaking data is broken into the following types:&lt;br /&gt;
&lt;br /&gt;
* Data - this is the object being described. For example the post content in a forum post;&lt;br /&gt;
* Related data - this is data related to the object being stored. For example, ratings of a forum post;&lt;br /&gt;
* Metadata - This is metadata about the main object. For example whether you are subscribed to a forum discussion;&lt;br /&gt;
* User preferences - this is data about a site-wide preference;&lt;br /&gt;
* Files - Any files that you are stored within Moodle on behalf of this plugin; and&lt;br /&gt;
* Custom files - For custom file formats - e.g. a calendar feed for calendar data. These should be used sparingly.&lt;br /&gt;
&lt;br /&gt;
Each piece of data is stored against a specific Moodle &#039;&#039;context&#039;&#039;, which will define how the data is structured within the exporter.&lt;br /&gt;
Data, and Related data only accept the &#039;&#039;stdClass&#039;&#039; object, whilst metadata should be stored as a set of key/value pairs which include a description.&lt;br /&gt;
&lt;br /&gt;
In some cases the data being stored belongs within an implicit structure. For example, One forum has many forum discussions, which each have a number of forum posts. This structure is represented by an &#039;&#039;array&#039;&#039; referred to as a &#039;&#039;subcontext&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;content_writer&#039;&#039; must &#039;&#039;always&#039;&#039; be called with a specific context, and can be called as follows:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/pluginname/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
use \core_privacy\local\request\writer;&lt;br /&gt;
&lt;br /&gt;
writer::with_context($context)&lt;br /&gt;
    -&amp;gt;export_data($subcontext, $post)&lt;br /&gt;
    -&amp;gt;export_area_files($subcontext, &#039;mod_forum&#039;, &#039;post&#039;, $post-&amp;gt;id)&lt;br /&gt;
    -&amp;gt;export_metadata($subcontext, &#039;postread&#039;, (object) [&#039;firstread&#039; =&amp;gt; $firstread], new \lang_string(&#039;privacy:export:post:postread&#039;));&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/pluginname/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
use \core_privacy\local\request\writer;&lt;br /&gt;
&lt;br /&gt;
writer::with_context($context)&lt;br /&gt;
    -&amp;gt;export_data($subcontext, $post)&lt;br /&gt;
    -&amp;gt;export_area_files($subcontext, &#039;mod_forum&#039;, &#039;post&#039;, $post-&amp;gt;id)&lt;br /&gt;
    -&amp;gt;export_metadata($subcontext, &#039;postread&#039;, (object) [&#039;firstread&#039; =&amp;gt; $firstread], new \lang_string(&#039;privacy:export:post:postread&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Providing a way to delete user data===&lt;br /&gt;
&lt;br /&gt;
Deleting user data is also implemented in the request interface. There are two methods that need to be created. The first one to remove all user data from a context, the other to remove user data for a specific user in a list of contexts.&lt;br /&gt;
&lt;br /&gt;
====Delete for a context====&lt;br /&gt;
&lt;br /&gt;
A context is given and all user data (for all users) is to be deleted from the plugin. This will be called when the retention period for the plugin has expired to adhere to the privacy by design requirement.�&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/choice/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function delete_data_for_all_users_in_context(deletion_criteria $criteria) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
    $context = $criteria-&amp;gt;get_context();&lt;br /&gt;
    if (empty($context)) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    $instanceid = $DB-&amp;gt;get_field(&#039;course_modules&#039;, &#039;instance&#039;, [&#039;id&#039; =&amp;gt; $context-&amp;gt;instanceid], MUST_EXIST);&lt;br /&gt;
    $DB-&amp;gt;delete_records(&#039;choice_answers&#039;, [&#039;choiceid&#039; =&amp;gt; $instanceid]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Delete personal information for a specific user and context(s)====&lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;approved_contextlist&#039;&#039; is given and user data related to that user should either be completely deleted, or overwritten if a structure needs to be maintained. This will be called when a user has requested the right to be forgotten. All attempts should be made to delete this data where practical while still allowing the plugin to be used by other users.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/choice/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function delete_data_for_user(approved_contextlist $contextlist) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
    &lt;br /&gt;
    if (empty($contextlist-&amp;gt;count())) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    $userid = $contextlist-&amp;gt;get_user()-&amp;gt;id;&lt;br /&gt;
    foreach ($contextlist-&amp;gt;get_contexts() as $context) {&lt;br /&gt;
        $instanceid = $DB-&amp;gt;get_field(&#039;course_modules&#039;, &#039;instance&#039;, [&#039;id&#039; =&amp;gt; $context-&amp;gt;instanceid], MUST_EXIST);&lt;br /&gt;
        $DB-&amp;gt;delete_records(&#039;choice_answers&#039;, [&#039;choiceid&#039; =&amp;gt; $instanceid, &#039;userid&#039; =&amp;gt; $userid]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Subject Access Request FAQ]]&lt;br /&gt;
* [[Privacy API]]&lt;br /&gt;
* [[:en:GDPR|GDPR]] in the user documentation&lt;br /&gt;
&lt;br /&gt;
[[Category:GDPR]]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=GDPR_for_plugin_developers&amp;diff=53909</id>
		<title>GDPR for plugin developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=GDPR_for_plugin_developers&amp;diff=53909"/>
		<updated>2018-03-26T09:41:11Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Delete for a context */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The General Data Protection Regulation (GDPR) is an EU directive that looks at providing users with more control over their data and how it is processed. This regulation will come into effect on 25th of May 2018 and covers any citizen or permanent resident of the European Union. The directive will be respected by a number of other countries outside of the European Union.&lt;br /&gt;
&lt;br /&gt;
To help institutions become compliant with this new regulation we are adding functionality to Moodle. This includes a number of components, amongst others these include a user’s right to:&lt;br /&gt;
&lt;br /&gt;
* request information on the types of personal data held, the instances of that data, and the deletion policy for each;&lt;br /&gt;
* access all of their data; and&lt;br /&gt;
* be forgotten.&lt;br /&gt;
&lt;br /&gt;
The compliance requirements also extend to installed plugins (including third party plugins). These need to also be able to report what information they store or process regarding users, and have the ability to provide and delete data for a user request.&lt;br /&gt;
&lt;br /&gt;
This document describes the proposed API changes required for plugins which will allow a Moodle installation to become GDPR compliant.&lt;br /&gt;
&lt;br /&gt;
Target Audience: The intended audience for this document is Moodle plugin developers, who are aiming to ensure their plugins are updated to comply with GDPR requirements coming into effect in the EU in May, 2018.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Personal data in Moodle==&lt;br /&gt;
&lt;br /&gt;
From the GDPR Spec, Article 4:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;‘personal data’ means any information relating to an identified or identifiable natural person (‘data subject’); an identifiable natural person is one who can be identified, directly or indirectly, in particular by reference to an identifier such as a name, an identification number, location data, an online identifier or to one or more factors specific to the physical, physiological, genetic, mental, economic, cultural or social identity of that natural person;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In Moodle, we need to consider two main types of personal data; information entered by the user and information stored about the user. The key difference being that information stored about the user will have come from a source other than the user themselves. Both types of data can be used to form a profile of the individual.&lt;br /&gt;
&lt;br /&gt;
The most obvious clue to finding personal data entered by the user is the presence of a userid on a database field. Any data on the record (or linked records) pertaining to that user may be deemed personal data for that user, including things like timestamps and record identification numbers. Additionally, any free text field which allows the user to enter information must also be considered to be the personal data of that user.&lt;br /&gt;
&lt;br /&gt;
Data stored about the user includes things like ratings and comments made on a student submission. These may have been made by an assessor or teacher, but are considered the personal data of the student, as they are considered a reflection of the user’s competency in the subject matter and can be used to form a profile of that individual. &lt;br /&gt;
&lt;br /&gt;
The sections that follow outline what you need to do as a plugin developer to ensure any personal data is advertised and can be accessed and deleted according to the GDPR requirements.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
===Architecture overview===&lt;br /&gt;
&lt;br /&gt;
A new system for Privacy has been created within Moodle. This is broken down into several main parts and forms the &#039;&#039;core_privacy&#039;&#039; subsystem:&lt;br /&gt;
&lt;br /&gt;
* Some metadata providers - a set of PHP interfaces to be implemented by components for that component to describe the kind of data that it stores, and the purpose for its storage;&lt;br /&gt;
* Some request providers - a set of PHP interfaces to be implemented by components to allow that component to act upon user requests such as the Right to be Forgotten, and a Subject Access Request; and&lt;br /&gt;
* A manager - a concrete class used to bridge components which implement the providers with tools which request their data.&lt;br /&gt;
&lt;br /&gt;
All plugins will implement one metadata provider, and zero, one or two request providers.&lt;br /&gt;
&lt;br /&gt;
The fetching of data is broken into two separate steps:&lt;br /&gt;
&lt;br /&gt;
# Detecting in which Moodle contexts the user has any data; and&lt;br /&gt;
# Exporting all data from each of those contexts.&lt;br /&gt;
&lt;br /&gt;
This has been broken into two steps to later allow administrators to exclude certain contexts from an export - e.g. for courses currently in progress.&lt;br /&gt;
&lt;br /&gt;
A third component will later be added to facilitate the deletion of data within these contexts which will help to satisfy the Right to be Forgotten. This will also use the first step.&lt;br /&gt;
&lt;br /&gt;
===Implementing a provider===&lt;br /&gt;
&lt;br /&gt;
All plugins will need to create a concrete class which implements the relevant metadata and request providers. The exact providers you need to implement will depend on what data you store, and the type of plugin. This is covered in more detail in the following sections of the document.&lt;br /&gt;
&lt;br /&gt;
In order to do so:&lt;br /&gt;
&lt;br /&gt;
# You must create a class called &#039;&#039;provider&#039;&#039; within the namespace &#039;&#039;\your_pluginname\privacy&#039;&#039;.&lt;br /&gt;
# This class must be created at &#039;&#039;path/to/your/plugin/classes/privacy/provider.php&#039;&#039;.&lt;br /&gt;
# You must have your class implement the relevant metadata and request interfaces.&lt;br /&gt;
&lt;br /&gt;
==Plugins which do not store personal data==&lt;br /&gt;
&lt;br /&gt;
Many Moodle plugins do not store any personal data. This is usually the case for plugins which just add functionality, or which display the data already stored elsewhere in Moodle.&lt;br /&gt;
&lt;br /&gt;
Some examples of plugin types which might fit this criteria include themes, blocks, filters, editor plugins, etc.&lt;br /&gt;
&lt;br /&gt;
Plugins which cause data to be stored elsewhere in Moodle (e.g. via a subsystem call) are considered to store data.&lt;br /&gt;
&lt;br /&gt;
One examples of a plugin which does not store any data would be the Calendar month block which just displays a view of the user’s calendar. It does not store any data itself.&lt;br /&gt;
&lt;br /&gt;
An example of a plugin which must not use the null provider is the Comments block. The comments block is responsible for data subsequently being stored within Moodle. Although the block doesn’t store anything itself, it interacts with the comments subsystem and is the only component which knows how that data maps to a user.&lt;br /&gt;
&lt;br /&gt;
===Implementation requirements===&lt;br /&gt;
&lt;br /&gt;
In order to let Moodle know that you have audited your plugin, and that you do not store any personal user data, you must implement the &#039;&#039;\core_privacy\local\metadata\null_provider&#039;&#039; interface in your plugin’s provider.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;null_provider&#039;&#039; requires you to define one function &#039;&#039;get_reason()&#039;&#039; which returns the language string identifier within your component.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;block/calendar_month/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 &amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
&lt;br /&gt;
namespace block_calendar_month\privacy;&lt;br /&gt;
&lt;br /&gt;
class provider implements &lt;br /&gt;
    # This plugin does not store any personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\null_provider&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the language string identifier with the component&#039;s language&lt;br /&gt;
     * file to explain why this plugin stores no data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return  string&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_reason() : string {&lt;br /&gt;
        return &#039;privacy:null_reason&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;block/calendar_month/lang/en/block_calendar_month.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:null_reason&#039;] = &#039;The calendar month block displays information from the Calendar, but does not effect or store any data itself. All changes are made via the Calendar.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That’s it. Congratulations, your plugin now implements the Privacy API.&lt;br /&gt;
&lt;br /&gt;
==Plugins which store personal data==&lt;br /&gt;
&lt;br /&gt;
Many Moodle plugins do store some form of personal data.&lt;br /&gt;
&lt;br /&gt;
In some cases this will be stored within database tables in your plugin, and in other cases this will be in one of Moodle’s core subsystems - for example your plugin may store files, ratings, comments, or tags.&lt;br /&gt;
&lt;br /&gt;
Plugins which do store data will need to:&lt;br /&gt;
&lt;br /&gt;
* Describe the type of data that they store; &lt;br /&gt;
* Provide a way to export that data; and&lt;br /&gt;
* Provide a way to delete that data.&lt;br /&gt;
&lt;br /&gt;
Data is described via a &#039;&#039;metadata&#039;&#039; provider, and it is both exported and deleted via an implementation of a &#039;&#039;request&#039;&#039; provider.&lt;br /&gt;
&lt;br /&gt;
These are both explained in the sections below.&lt;br /&gt;
&lt;br /&gt;
===Describing the type of data you store===&lt;br /&gt;
&lt;br /&gt;
In order to describe the type of data that you store, you must implement the &#039;&#039;\core_privacy\local\metadata\provider&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
This interfaces requires that you define one function: &#039;&#039;get_metadata&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
There are several types of item to describe the data that you store. These are for:&lt;br /&gt;
&lt;br /&gt;
* Items in the Moodle database;&lt;br /&gt;
* Items stored by you in a Moodle subsystem - for example files, and ratings; and&lt;br /&gt;
* User preferences stored site-wide within Moodle for your plugin&lt;br /&gt;
&lt;br /&gt;
Note: All fields should include a description from a language string within your plugin.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
&lt;br /&gt;
namespace mod_forum\privacy;&lt;br /&gt;
use \core_privacy\local\metadata\collection;&lt;br /&gt;
&lt;br /&gt;
class provider implements &lt;br /&gt;
    # This plugin does store personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\provider&lt;br /&gt;
{&lt;br /&gt;
    public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
        return $collection;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you store content in a Moodle subsystem====&lt;br /&gt;
&lt;br /&gt;
Many plugins will use one of the core Moodle subsystems to store data.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer we do not expect you to describe those subsystems in detail, but we do need to know that you use them and to know what you use them for.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;link_subsystem()&#039;&#039; method on the &#039;&#039;collection&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;link_subsystem(&lt;br /&gt;
        &#039;core_files&#039;,&lt;br /&gt;
        &#039;privacy:metadata:core_files&#039;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/lang/en/forum.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:core_files&#039;] = &#039;The forum stores files which have been uploaded by the user to form part of a forum post.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Describing data stored in database tables====&lt;br /&gt;
&lt;br /&gt;
Most Moodle plugins will store some form of user data in their own database tables.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer you will need to describe each database table, and each field which includes user data.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;add_database_table(&lt;br /&gt;
        &#039;forum_discussion_subs&#039;,&lt;br /&gt;
         [&lt;br /&gt;
            &#039;userid&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:userid&#039;,&lt;br /&gt;
            &#039;discussionid&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:discussionid&#039;,&lt;br /&gt;
            &#039;preference&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:preference&#039;,&lt;br /&gt;
&lt;br /&gt;
         ],&lt;br /&gt;
        &#039;privacy:metadata:forum_discussion_subs&#039;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/lang/en/forum.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs&#039;] = &#039;Information about the subscriptions to individual forum discussions. This includes when a user has chosen to subscribe to a discussion, or to unsubscribe from one where they would otherwise be subscribed.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:userid&#039;] = &#039;The ID of the user with this subscription preference.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:discussionid&#039;] = &#039;The ID of the discussion that was subscribed to.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:preference&#039;] = &#039;The start time of the subscription.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you store site-wide user preferences====&lt;br /&gt;
&lt;br /&gt;
Many plugins will include one or more user preferences. Unfortunately this is one of Moodle’s older components and many of the values stored are not pure user preferences. Each plugin should be aware of how it handles its own preferences and is best placed to determine whether they are site-wide preferences, or per-instance preferences.&lt;br /&gt;
&lt;br /&gt;
Whilst most of these will have a fixed name (e.g. &#039;&#039;filepicker_recentrepository&#039;&#039;), some will include a variable of some kind (e.g. &#039;&#039;tool_usertours_tour_completion_time_2&#039;&#039;). Only the general name needs to be indicated rather than one copy for each preference.&lt;br /&gt;
&lt;br /&gt;
Also, these should only be &#039;&#039;site-wide&#039;&#039; user preferences which do not belong to a specific Moodle context.&lt;br /&gt;
&lt;br /&gt;
In the above examples:&lt;br /&gt;
&lt;br /&gt;
* Preference &#039;&#039;filepicker_recentrepository&#039;&#039; belongs to the file subsystem, and is a site-wide preference affecting the user anywhere that they view the filepicker.&lt;br /&gt;
* Preference &#039;&#039;tool_usertours_tour_completion_time_2&#039;&#039; belongs to user tours. User tours are a site-wide feature which can affect many parts of Moodle and cross multiple contexts.&lt;br /&gt;
&lt;br /&gt;
In some cases a value may be stored in the preferences table but is known to belong to a specific context within Moodle. In these cases they should be stored as metadata against that context rather than as a site-wide user preference.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;add_user_preference()&#039;&#039; method on the &#039;&#039;collection&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Any plugin providing user preferences must also implement the &#039;&#039;\core_privacy\local\request\preference_provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/tool/usertours/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;add_user_preference(&#039;tool_usertours_tour_completion_time,&lt;br /&gt;
        &#039;privacy:metadata:preference:tool_usertours_tour_completion_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/tool/usertours/lang/en/tool_usertours.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:tool_usertours_tour_completion_time&#039;] = &#039;The time that a specific user tour was last completed by a user.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you export data to an external location====&lt;br /&gt;
&lt;br /&gt;
Many plugins will interact with external systems - for example cloud-based services. Often this external location is configurable within the plugin either at the site or the instance level.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer you will need to describe each &#039;&#039;type&#039;&#039; of target destination, alongside a list of each exported field which includes user data.&lt;br /&gt;
The &#039;&#039;actual&#039;&#039; destination does not need to be described as this can change based on configuration.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;link_external_location()&#039;&#039; method on the collection.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/lti/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;link_external_location(&#039;lti_client&#039;, [&lt;br /&gt;
            &#039;userid&#039; =&amp;gt; &#039;privacy:metadata:lti_client:userid&#039;,&lt;br /&gt;
            &#039;fullname&#039; =&amp;gt; &#039;privacy:metadata:lti_client:fullname&#039;,&lt;br /&gt;
        ], &#039;privacy:metadata:lti_client&#039;);&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/tool/usertours/lang/en/tool_usertours.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
$string[&#039;privacy:metadata:lti_client&#039;] = &#039;In order to integrate with a remote LTI service, user data needs to be exchanged with that service.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:lti_client:userid&#039;] = &#039;The userid is sent from Moodle to allow you to access your data on the remote system.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:lti_client:fullname&#039;] = &#039;Your full name is sent to the remote system to allow a better user experience.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Providing a way to export user data===&lt;br /&gt;
&lt;br /&gt;
In order to export the user data that you store, you must implement the relevant request provider.&lt;br /&gt;
&lt;br /&gt;
We have named these request providers because they are called in response to a specific request from a user to access their information.&lt;br /&gt;
&lt;br /&gt;
There are several different types of request provider, and you may need to implement several of these, depending on the type and nature of your plugin.&lt;br /&gt;
&lt;br /&gt;
Broadly speaking plugins will fit into one of the following categories:&lt;br /&gt;
&lt;br /&gt;
* Plugins which are a subplugin of another plugin. Examples include &#039;&#039;assignsubmission&#039;&#039;, &#039;&#039;atto&#039;&#039;, and &#039;&#039;datafield&#039;&#039;;&lt;br /&gt;
* Plugins which are typically called by a Moodle subsystem. Examples include &#039;&#039;qtype&#039;&#039;, and &#039;&#039;profilefield&#039;&#039;;&lt;br /&gt;
* All other plugins which store data.&lt;br /&gt;
&lt;br /&gt;
Most plugins will fit into this final category, whilst other plugins may fall into several categories.&lt;br /&gt;
Plugins which &#039;&#039;define&#039;&#039; a subplugin will also be responsible for  collecting this data from their subplugins.&lt;br /&gt;
&lt;br /&gt;
A final category exists - plugins which store user preferences. In some cases this may be the &#039;&#039;only&#039;&#039; provider implemented.&lt;br /&gt;
&lt;br /&gt;
====Standard plugins which store data====&lt;br /&gt;
&lt;br /&gt;
A majority of Moodle plugins will fit into this category and will be required to implement the &#039;&#039;\core_privacy\local\request\plugin\provider&#039;&#039; interface. This interface requires that you define two functions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;get_contexts_for_userid&#039;&#039; - to explain where data is held within Moodle for your plugin; and&lt;br /&gt;
* &#039;&#039;export_user_data&#039;&#039; - to export a user’s personal data from your plugin.&lt;br /&gt;
&lt;br /&gt;
These APIs make use of the Moodle &#039;&#039;context&#039;&#039; system to hierarchically store this data.&lt;br /&gt;
&lt;br /&gt;
====Retrieving the list of contexts====&lt;br /&gt;
&lt;br /&gt;
Contexts are retrieved using the &#039;&#039;get_contexts_for_userid&#039;&#039; function which takes the ID of the user being fetched, and returns a list of contexts in which the user has any data.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_contexts_for_userid(int $userid) : contextlist {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The function returns a &#039;&#039;\core_privacy\local\request\contextlist&#039;&#039; which is used to keep a set of contexts together in a fixed fashion.&lt;br /&gt;
&lt;br /&gt;
Because a Subject Access Request covers &#039;&#039;every&#039;&#039; piece of data that is held for a user within Moodle, efficiency and performance is highly important. As a result, contexts are added to the &#039;&#039;contextlist&#039;&#039; by defining one or more SQL queries which return just the contextid. Multiple SQL queries can be added as required.&lt;br /&gt;
&lt;br /&gt;
Many plugins will interact with specific subsystems and store data within them.&lt;br /&gt;
These subsystems will also provide a way in which to link the data that you have stored with your own database tables.&lt;br /&gt;
At present these are still a work in progress and only the &#039;&#039;core_ratings&#039;&#039; subsystem includes this.&lt;br /&gt;
&lt;br /&gt;
=====Basic example=====&lt;br /&gt;
&lt;br /&gt;
The following example simply fetches the contextid for all forums where a user has a single discussion (note: this is an incomplete example):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_contexts_for_userid(int $userid) : contextlist {&lt;br /&gt;
        $contextlist = new \core_privacy\local\request\contextlist();&lt;br /&gt;
&lt;br /&gt;
        $sql = &amp;quot;SELECT c.id&lt;br /&gt;
                 FROM {context} c&lt;br /&gt;
           INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel&lt;br /&gt;
           INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname&lt;br /&gt;
           INNER JOIN {forum} f ON f.id = cm.instance&lt;br /&gt;
            LEFT JOIN {forum_discussions} d ON d.forum = f.id&lt;br /&gt;
                WHERE (&lt;br /&gt;
                d.userid        = :discussionuserid&lt;br /&gt;
                )&lt;br /&gt;
        &amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        $params = [&lt;br /&gt;
            &#039;modname&#039;           =&amp;gt; &#039;forum&#039;,&lt;br /&gt;
            &#039;contextlevel&#039;      =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
            &#039;discussionuserid&#039;  =&amp;gt; $userid,&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        $contextlist-&amp;gt;add_from_sql($sql, $params);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====More complete example=====&lt;br /&gt;
&lt;br /&gt;
The following example includes a link to core_rating. &lt;br /&gt;
It will find any forum, forum discussion, or forum post where the user has any data, including:&lt;br /&gt;
&lt;br /&gt;
* Per-forum digest preferences;&lt;br /&gt;
* Per-forum subscription preferences;&lt;br /&gt;
* Per-forum read tracking preferences;&lt;br /&gt;
* Per-discussion subscription preferences;&lt;br /&gt;
* Per-post read data (if a user has read a post or not); and&lt;br /&gt;
* Per-post rating data.&lt;br /&gt;
&lt;br /&gt;
In the case of the rating data, this will include any post where the user has rated the post of another user.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   int           $userid       The user to search.&lt;br /&gt;
 * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
 */&lt;br /&gt;
public static function get_contexts_for_userid(int $userid) : contextlist {&lt;br /&gt;
    $ratingsql = \core_rating\privacy\provider::get_sql_join(&#039;rat&#039;, &#039;mod_forum&#039;, &#039;post&#039;, &#039;p.id&#039;, $userid);&lt;br /&gt;
    // Fetch all forum discussions, and forum posts.&lt;br /&gt;
    $sql = &amp;quot;SELECT c.id&lt;br /&gt;
                FROM {context} c&lt;br /&gt;
        INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel&lt;br /&gt;
        INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname&lt;br /&gt;
        INNER JOIN {forum} f ON f.id = cm.instance&lt;br /&gt;
            LEFT JOIN {forum_discussions} d ON d.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_posts} p ON p.discussion = d.id&lt;br /&gt;
            LEFT JOIN {forum_digests} dig ON dig.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_subscriptions} sub ON sub.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_track_prefs} pref ON pref.forumid = f.id&lt;br /&gt;
            LEFT JOIN {forum_read} hasread ON hasread.forumid = f.id&lt;br /&gt;
            LEFT JOIN {forum_discussion_subs} dsub ON dsub.forum = f.id&lt;br /&gt;
            {$ratingsql-&amp;gt;join}&lt;br /&gt;
                WHERE (&lt;br /&gt;
                p.userid        = :postuserid OR&lt;br /&gt;
                d.userid        = :discussionuserid OR&lt;br /&gt;
                dig.userid      = :digestuserid OR&lt;br /&gt;
                sub.userid      = :subuserid OR&lt;br /&gt;
                pref.userid     = :prefuserid OR&lt;br /&gt;
                hasread.userid  = :hasreaduserid OR&lt;br /&gt;
                dsub.userid     = :dsubuserid OR&lt;br /&gt;
                {$ratingsql-&amp;gt;userwhere}&lt;br /&gt;
            )&lt;br /&gt;
    &amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    $params = [&lt;br /&gt;
        &#039;modname&#039;           =&amp;gt; &#039;forum&#039;,&lt;br /&gt;
        &#039;contextlevel&#039;      =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;postuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
        &#039;discussionuserid&#039;  =&amp;gt; $userid,&lt;br /&gt;
        &#039;digestuserid&#039;      =&amp;gt; $userid,&lt;br /&gt;
        &#039;subuserid&#039;         =&amp;gt; $userid,&lt;br /&gt;
        &#039;prefuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
        &#039;hasreaduserid&#039;     =&amp;gt; $userid,&lt;br /&gt;
        &#039;dsubuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
    ];&lt;br /&gt;
    $params += $ratingsql-&amp;gt;params;&lt;br /&gt;
&lt;br /&gt;
    $contextlist = new \core_privacy\local\request\contextlist();&lt;br /&gt;
    $contextlist-&amp;gt;add_from_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
    return $contextlist;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Exporting user data====&lt;br /&gt;
&lt;br /&gt;
After determining where in Moodle your plugin holds data about a user, the &#039;&#039;\core_privacy\manager&#039;&#039; will then ask your plugin to export all user data for a subset of those locations.&lt;br /&gt;
&lt;br /&gt;
This is achieved through use of the &#039;&#039;export_user_data&#039;&#039; function which takes the list of approved contexts in a &#039;&#039;\core_privacy\local\request\approved_contextlist&#039;&#039; object.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Export all user data for the specified user, in the specified contexts, using the supplied exporter instance.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   approved_contextlist    $contextlist    The approved contexts to export information for.&lt;br /&gt;
 */&lt;br /&gt;
public static function export_user_data(approved_contextlist $contextlist) {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;approved_contextlist&#039;&#039; includes both the user record, and a list of contexts, which can be retrieved by either processing it as an Iterator, or by calling &#039;&#039;get_contextids()&#039;&#039; or &#039;&#039;get_contexts()&#039;&#039; as required.&lt;br /&gt;
&lt;br /&gt;
Data is exported using a &#039;&#039;\core_privacy\local\request\content_writer&#039;&#039;, which is described in further detail below.&lt;br /&gt;
&lt;br /&gt;
===Plugins which store user preferences===&lt;br /&gt;
&lt;br /&gt;
Many plugins store a variety of user preferences, and must therefore export them.&lt;br /&gt;
&lt;br /&gt;
Since user preferences are a site-wide preference, these are exported separately to other user data.&lt;br /&gt;
In some cases the only data present is user preference data, whilst in others there is a combination of user-provided data, and user preferences.&lt;br /&gt;
&lt;br /&gt;
Storing of user preferences is achieved through implementation of the &#039;&#039;\core_privacy\local\request\preference_provider&#039;&#039; interface which defines one required function -- &#039;&#039;export_user_preferences&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Export all user preferences for the plugin.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   int         $userid The userid of the user whose data is to be exported.&lt;br /&gt;
 */&lt;br /&gt;
public static function export_user_preferences(int $userid) {&lt;br /&gt;
    $markasreadonnotification = get_user_preference(&#039;markasreadonnotification&#039;, null, $userid);&lt;br /&gt;
    if (null !== $markasreadonnotification) {&lt;br /&gt;
        switch ($markasreadonnotification) {&lt;br /&gt;
            case 0:&lt;br /&gt;
                $markasreadonnotificationdescription = get_string(&#039;markasreadonnotificationno&#039;, &#039;mod_forum&#039;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 1:&lt;br /&gt;
            default:&lt;br /&gt;
                $markasreadonnotificationdescription = get_string(&#039;markasreadonnotificationyes&#039;, &#039;mod_forum&#039;);&lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        writer::export_user_preference(&#039;mod_forum&#039;, &#039;markasreadonnotification&#039;, $markasreadonnotification, $markasreadonnotificationdescription);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Plugins which define a subplugin===&lt;br /&gt;
&lt;br /&gt;
Many plugin types are also able to define their own subplugins and will need to define a contract between themselves and their subplugins in order to fetch their data.&lt;br /&gt;
&lt;br /&gt;
This is required as the parent plugin and the child subplugin should be separate entities and the parent plugin must be able to function if one or more of its subplugins are uninstalled.&lt;br /&gt;
&lt;br /&gt;
The parent plugin is responsible for defining the contract,  and for interacting with its subplugins, though we intend to create helpers to make this easier.&lt;br /&gt;
&lt;br /&gt;
The parent plugin should define a new interface for each type of subplugin that it defines. This interface should extend the &#039;&#039;\core_privacy\local\request\plugin\subplugin_provider&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
The following example defines the contract that assign submission subplugins may be required to implement.&lt;br /&gt;
&lt;br /&gt;
The assignment module is responsible for returning the contexts of all assignments where a user has data, but in some cases it is unaware of all of those cases - for example if a Teacher comments on a student submission it may not be aware of these as the information about this interaction may not be stored within its own tables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/assign/privacy/assignsubmission_provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
&lt;br /&gt;
namespace mod_assign\privacy;&lt;br /&gt;
use \core_privacy\local\metadata\collection;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
interface assignsubmission_provider extends&lt;br /&gt;
    # This Interface defines a subplugin.&lt;br /&gt;
    \core_privacy\local\request\subplugin_provider&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the SQL required to find all submission items where this user has had any involvements. &lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  \stdClass                   Object containing the join, params, and where used to select a these records from the database.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_items_with_user_interaction(int $userid) : \stdClass ;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export all relevant user submissions information which match the combination of userid and attemptid.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @param   \context      $context      The context to export this submission against.&lt;br /&gt;
     * @param   array         $subcontext   The subcontext within the context to export this information&lt;br /&gt;
     * @param   int           $attid        The id of the submission to export.&lt;br /&gt;
     */&lt;br /&gt;
    public static function export_user_submissions(int $userid, \context $context, array $subcontext, int $attid) ;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Plugins which are subplugins to another plugin===&lt;br /&gt;
&lt;br /&gt;
If you are developing a sub-plugin of another plugin, then you will have to look at the relevant plugin in order to determine the exact contract.&lt;br /&gt;
&lt;br /&gt;
Each subplugin type should define a new interface which extends the &#039;&#039;\core_privacy\local\request\plugin\subplugin_provider&#039;&#039; interface and it is up to the parent plugin to define how they will interact with their children.&lt;br /&gt;
&lt;br /&gt;
The principles remain the same, but the exact implementation will differ depending upon requirements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/pluginname/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
namespace assignsubmission\onlinetext;&lt;br /&gt;
&lt;br /&gt;
class provider implements&lt;br /&gt;
    # This plugin does store personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\provider,&lt;br /&gt;
&lt;br /&gt;
    # This plugin is a subplugin of assign and must meet that contract.&lt;br /&gt;
    \mod_assign\privacy\assignsubmission_provider&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Plugins which are typically called by a Moodle subsystem===&lt;br /&gt;
&lt;br /&gt;
There are a number of plugintypes in Moodle which are typically called by a specific Moodle subsystem.&lt;br /&gt;
&lt;br /&gt;
Some of these are &#039;&#039;only&#039;&#039; called by that subsystem, for example plugins which are of the &#039;&#039;plagiarism&#039;&#039; plugintype should never be called directly, but are always invoked via the &#039;&#039;core_plagiarism&#039;&#039; subsystem.&lt;br /&gt;
&lt;br /&gt;
Conversely, there maybe other plugintypes which can be called both via a subsystem, and in some other fashion. We are still determining whether any plugintypes currently fit this pattern.&lt;br /&gt;
&lt;br /&gt;
If you are developing a plugin which belongs to a specific subsystem, then you will have to look at the relevant plugin in order to determine the exact contract.&lt;br /&gt;
&lt;br /&gt;
Each subsystem will define a new interface which extends the &#039;&#039;\core_privacy\local\request\plugin\subsystem_provider&#039;&#039; interface and it is up to that subsystem to define how they will interact with those plugins.&lt;br /&gt;
&lt;br /&gt;
The principles remain the same, but the exact implementation will differ depending upon requirements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;plagiarism/detectorator/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
namespace plagiarism_detectorator\privacy;&lt;br /&gt;
&lt;br /&gt;
class provider implements&lt;br /&gt;
    # This plugin does export personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\provider,&lt;br /&gt;
&lt;br /&gt;
    # This plugin is always linked against another activity module via the Plagiarism API.&lt;br /&gt;
    \core_plagiarism\privacy\plugin_provider&lt;br /&gt;
{&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Exporting data===&lt;br /&gt;
&lt;br /&gt;
Any plugin which stores data must also export it.&lt;br /&gt;
&lt;br /&gt;
To cater for this the privacy API includes a &#039;&#039;\core_privacy\local\request\content_writer&#039;&#039;, which defines a set of functions to store different types of data.&lt;br /&gt;
&lt;br /&gt;
Broadly speaking data is broken into the following types:&lt;br /&gt;
&lt;br /&gt;
* Data - this is the object being described. For example the post content in a forum post;&lt;br /&gt;
* Related data - this is data related to the object being stored. For example, ratings of a forum post;&lt;br /&gt;
* Metadata - This is metadata about the main object. For example whether you are subscribed to a forum discussion;&lt;br /&gt;
* User preferences - this is data about a site-wide preference;&lt;br /&gt;
* Files - Any files that you are stored within Moodle on behalf of this plugin; and&lt;br /&gt;
* Custom files - For custom file formats - e.g. a calendar feed for calendar data. These should be used sparingly.&lt;br /&gt;
&lt;br /&gt;
Each piece of data is stored against a specific Moodle &#039;&#039;context&#039;&#039;, which will define how the data is structured within the exporter.&lt;br /&gt;
Data, and Related data only accept the &#039;&#039;stdClass&#039;&#039; object, whilst metadata should be stored as a set of key/value pairs which include a description.&lt;br /&gt;
&lt;br /&gt;
In some cases the data being stored belongs within an implicit structure. For example, One forum has many forum discussions, which each have a number of forum posts. This structure is represented by an &#039;&#039;array&#039;&#039; referred to as a &#039;&#039;subcontext&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;content_writer&#039;&#039; must &#039;&#039;always&#039;&#039; be called with a specific context, and can be called as follows:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/pluginname/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
use \core_privacy\local\request\writer;&lt;br /&gt;
&lt;br /&gt;
writer::with_context($context)&lt;br /&gt;
    -&amp;gt;export_data($subcontext, $post)&lt;br /&gt;
    -&amp;gt;export_area_files($subcontext, &#039;mod_forum&#039;, &#039;post&#039;, $post-&amp;gt;id)&lt;br /&gt;
    -&amp;gt;export_metadata($subcontext, &#039;postread&#039;, (object) [&#039;firstread&#039; =&amp;gt; $firstread], new \lang_string(&#039;privacy:export:post:postread&#039;));&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/pluginname/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// …&lt;br /&gt;
use \core_privacy\local\request\writer;&lt;br /&gt;
&lt;br /&gt;
writer::with_context($context)&lt;br /&gt;
    -&amp;gt;export_data($subcontext, $post)&lt;br /&gt;
    -&amp;gt;export_area_files($subcontext, &#039;mod_forum&#039;, &#039;post&#039;, $post-&amp;gt;id)&lt;br /&gt;
    -&amp;gt;export_metadata($subcontext, &#039;postread&#039;, (object) [&#039;firstread&#039; =&amp;gt; $firstread], new \lang_string(&#039;privacy:export:post:postread&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Providing a way to delete user data===&lt;br /&gt;
&lt;br /&gt;
Deleting user data is also implemented in the request interface. There are two methods that need to be created. The first one to remove all user data from a context, the other to remove user data for a specific user in a list of contexts.&lt;br /&gt;
&lt;br /&gt;
====Delete for a context====&lt;br /&gt;
&lt;br /&gt;
A context is given and all user data (for all users) is to be deleted from the plugin. This will be called when the retention period for the plugin has expired to adhere to the privacy by design requirement.�&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/choice/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function delete_data_for_all_users_in_context(deletion_criteria $criteria) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
    $context = $criteria-&amp;gt;get_context();&lt;br /&gt;
    if (empty($context)) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    $instanceid = $DB-&amp;gt;get_field(&#039;course_modules&#039;, &#039;instance&#039;, [&#039;id&#039; =&amp;gt; $context-&amp;gt;instanceid], MUST_EXIST);&lt;br /&gt;
    $DB-&amp;gt;delete_records(&#039;choice_answers&#039;, [&#039;choiceid&#039; =&amp;gt; $instanceid]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Delete personal information for a specific user and context(s)====&lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;approved_contextlist&#039;&#039; is given and user data related to that user should either be completely deleted, or overwritten if a structure needs to be maintained. This will be called when a user has requested the right to be forgotten. All attempts should be made to delete this data where practical while still allowing the plugin to be used by other users.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/choice/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function delete_userdata_for_contexts(approved_contextlist $contextlist) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
    &lt;br /&gt;
    if (empty($contextlist-&amp;gt;count())) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    $userid = $contextlist-&amp;gt;get_user()-&amp;gt;id;&lt;br /&gt;
    foreach ($contextlist-&amp;gt;get_contexts() as $context) {&lt;br /&gt;
        $instanceid = $DB-&amp;gt;get_field(&#039;course_modules&#039;, &#039;instance&#039;, [&#039;id&#039; =&amp;gt; $context-&amp;gt;instanceid], MUST_EXIST);&lt;br /&gt;
        $DB-&amp;gt;delete_records(&#039;choice_answers&#039;, [&#039;choiceid&#039; =&amp;gt; $instanceid, &#039;userid&#039; =&amp;gt; $userid]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Subject Access Request FAQ]]&lt;br /&gt;
* [[Privacy API]]&lt;br /&gt;
* [[:en:GDPR|GDPR]] in the user documentation&lt;br /&gt;
&lt;br /&gt;
[[Category:GDPR]]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53559</id>
		<title>Machine learning backends</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53559"/>
		<updated>2017-12-27T08:06:32Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Regressor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learning training, prediction and models evaluation. May be good that you also read [https://docs.moodle.org/dev/Analytics_API Analytics API] to read some concept definitions, how these concepts are implemented in Moodle and how machine learning backend plugins fit into the analytics API.&lt;br /&gt;
&lt;br /&gt;
The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Backends included in Moodle core ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PHP backend&#039;&#039;&#039; is the default predictions processor as it is written in PHP and do not have any external dependencies. It is using logistic regression.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Python backend&#039;&#039;&#039; requires &#039;&#039;python&#039;&#039; binary (either python 2 or python 3) and [https://pypi.python.org/pypi?name=moodlemlbackend&amp;amp;version=0.0.5&amp;amp;:action=display moodlemlbackend python package] which is maintained by Moodle HQ. It is based on [https://www.tensorflow.org/ Google&#039;s tensorflow library] and it is using a feed-forward neural network with 1 single hidden layer. &#039;&#039;moodlemlbackend&#039;&#039; package does store model performance information that can be visualised using [https://www.tensorflow.org/get_started/summaries_and_tensorboard tensorboard]. Information generated during models evaluation is available through the models management page, under each model &#039;&#039;Actions &amp;gt; Log&#039;&#039; menu. &#039;&#039;moodlemlbackend&#039;&#039; source code is available in https://github.com/moodlehq/moodle-mlbackend-python.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Python backend is recommended over the PHP&#039;&#039;&#039; as it is able to predict more accurately than the PHP backend and it is faster.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
A summary of these interfaces purpose:&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train machine learning algorithms with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
This is the basic interface to be implemented by machine learning backends. Two main types are, &#039;&#039;classifiers&#039;&#039; and &#039;&#039;regressors&#039;&#039;. We provide the &#039;&#039;Regressor&#039;&#039; interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;is_ready&#039;&#039;&#039; to check that the backend is available.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is it ready to predict?&lt;br /&gt;
     *&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_ready();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clear_model&#039;&#039;&#039; and &#039;&#039;&#039;delete_output_dir&#039;&#039;&#039; purpose is to clean up stuff created by the machine learning backend.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete all stored information of the current model id.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when there are important changes to a model,&lt;br /&gt;
     * all previous training algorithms using that version of the model&lt;br /&gt;
     * should be deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid The site model unique id string&lt;br /&gt;
     * @param string $modelversionoutputdir The output dir of this model version&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function clear_model($uniqueid, $modelversionoutputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete the output directory.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when a model is completely deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $modeloutputdir The model directory id (parent of all model versions subdirectories).&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function delete_output_dir($modeloutputdir);&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Statistical_classification classifier] sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
Both these methods and &#039;&#039;Predictor&#039;&#039; methods should be implemented.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Train this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function train_classification($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Classifies the provided dataset samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function classify($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Evaluates this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param float $maxdeviation&lt;br /&gt;
     * @param int $niterations&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function evaluate_classification($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Regression_analysis regressor] predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
Both these methods and &#039;&#039;Predictor&#039;&#039; methods should be implemented.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Train this processor regression model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function train_regression($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Estimates linear values for the provided dataset samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param mixed $outputdir&lt;br /&gt;
     * @return void&lt;br /&gt;
     */&lt;br /&gt;
    public function estimate($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Evaluates this processor regression model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param float $maxdeviation&lt;br /&gt;
     * @param int $niterations&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function evaluate_regression($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53558</id>
		<title>Machine learning backends</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53558"/>
		<updated>2017-12-27T08:06:20Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Classifier */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learning training, prediction and models evaluation. May be good that you also read [https://docs.moodle.org/dev/Analytics_API Analytics API] to read some concept definitions, how these concepts are implemented in Moodle and how machine learning backend plugins fit into the analytics API.&lt;br /&gt;
&lt;br /&gt;
The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Backends included in Moodle core ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PHP backend&#039;&#039;&#039; is the default predictions processor as it is written in PHP and do not have any external dependencies. It is using logistic regression.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Python backend&#039;&#039;&#039; requires &#039;&#039;python&#039;&#039; binary (either python 2 or python 3) and [https://pypi.python.org/pypi?name=moodlemlbackend&amp;amp;version=0.0.5&amp;amp;:action=display moodlemlbackend python package] which is maintained by Moodle HQ. It is based on [https://www.tensorflow.org/ Google&#039;s tensorflow library] and it is using a feed-forward neural network with 1 single hidden layer. &#039;&#039;moodlemlbackend&#039;&#039; package does store model performance information that can be visualised using [https://www.tensorflow.org/get_started/summaries_and_tensorboard tensorboard]. Information generated during models evaluation is available through the models management page, under each model &#039;&#039;Actions &amp;gt; Log&#039;&#039; menu. &#039;&#039;moodlemlbackend&#039;&#039; source code is available in https://github.com/moodlehq/moodle-mlbackend-python.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Python backend is recommended over the PHP&#039;&#039;&#039; as it is able to predict more accurately than the PHP backend and it is faster.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
A summary of these interfaces purpose:&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train machine learning algorithms with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
This is the basic interface to be implemented by machine learning backends. Two main types are, &#039;&#039;classifiers&#039;&#039; and &#039;&#039;regressors&#039;&#039;. We provide the &#039;&#039;Regressor&#039;&#039; interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;is_ready&#039;&#039;&#039; to check that the backend is available.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is it ready to predict?&lt;br /&gt;
     *&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_ready();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clear_model&#039;&#039;&#039; and &#039;&#039;&#039;delete_output_dir&#039;&#039;&#039; purpose is to clean up stuff created by the machine learning backend.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete all stored information of the current model id.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when there are important changes to a model,&lt;br /&gt;
     * all previous training algorithms using that version of the model&lt;br /&gt;
     * should be deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid The site model unique id string&lt;br /&gt;
     * @param string $modelversionoutputdir The output dir of this model version&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function clear_model($uniqueid, $modelversionoutputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete the output directory.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when a model is completely deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $modeloutputdir The model directory id (parent of all model versions subdirectories).&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function delete_output_dir($modeloutputdir);&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Statistical_classification classifier] sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
Both these methods and &#039;&#039;Predictor&#039;&#039; methods should be implemented.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Train this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function train_classification($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Classifies the provided dataset samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function classify($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Evaluates this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param float $maxdeviation&lt;br /&gt;
     * @param int $niterations&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function evaluate_classification($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Regression_analysis regressor] predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Train this processor regression model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function train_regression($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Estimates linear values for the provided dataset samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param mixed $outputdir&lt;br /&gt;
     * @return void&lt;br /&gt;
     */&lt;br /&gt;
    public function estimate($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Evaluates this processor regression model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param float $maxdeviation&lt;br /&gt;
     * @param int $niterations&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function evaluate_regression($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53557</id>
		<title>Machine learning backends</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53557"/>
		<updated>2017-12-27T08:05:36Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Regressor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learning training, prediction and models evaluation. May be good that you also read [https://docs.moodle.org/dev/Analytics_API Analytics API] to read some concept definitions, how these concepts are implemented in Moodle and how machine learning backend plugins fit into the analytics API.&lt;br /&gt;
&lt;br /&gt;
The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Backends included in Moodle core ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PHP backend&#039;&#039;&#039; is the default predictions processor as it is written in PHP and do not have any external dependencies. It is using logistic regression.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Python backend&#039;&#039;&#039; requires &#039;&#039;python&#039;&#039; binary (either python 2 or python 3) and [https://pypi.python.org/pypi?name=moodlemlbackend&amp;amp;version=0.0.5&amp;amp;:action=display moodlemlbackend python package] which is maintained by Moodle HQ. It is based on [https://www.tensorflow.org/ Google&#039;s tensorflow library] and it is using a feed-forward neural network with 1 single hidden layer. &#039;&#039;moodlemlbackend&#039;&#039; package does store model performance information that can be visualised using [https://www.tensorflow.org/get_started/summaries_and_tensorboard tensorboard]. Information generated during models evaluation is available through the models management page, under each model &#039;&#039;Actions &amp;gt; Log&#039;&#039; menu. &#039;&#039;moodlemlbackend&#039;&#039; source code is available in https://github.com/moodlehq/moodle-mlbackend-python.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Python backend is recommended over the PHP&#039;&#039;&#039; as it is able to predict more accurately than the PHP backend and it is faster.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
A summary of these interfaces purpose:&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train machine learning algorithms with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
This is the basic interface to be implemented by machine learning backends. Two main types are, &#039;&#039;classifiers&#039;&#039; and &#039;&#039;regressors&#039;&#039;. We provide the &#039;&#039;Regressor&#039;&#039; interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;is_ready&#039;&#039;&#039; to check that the backend is available.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is it ready to predict?&lt;br /&gt;
     *&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_ready();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clear_model&#039;&#039;&#039; and &#039;&#039;&#039;delete_output_dir&#039;&#039;&#039; purpose is to clean up stuff created by the machine learning backend.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete all stored information of the current model id.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when there are important changes to a model,&lt;br /&gt;
     * all previous training algorithms using that version of the model&lt;br /&gt;
     * should be deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid The site model unique id string&lt;br /&gt;
     * @param string $modelversionoutputdir The output dir of this model version&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function clear_model($uniqueid, $modelversionoutputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete the output directory.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when a model is completely deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $modeloutputdir The model directory id (parent of all model versions subdirectories).&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function delete_output_dir($modeloutputdir);&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Statistical_classification classifier] sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Train this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function train_classification($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Classifies the provided dataset samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function classify($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Evaluates this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param float $maxdeviation&lt;br /&gt;
     * @param int $niterations&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function evaluate_classification($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Regression_analysis regressor] predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Train this processor regression model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function train_regression($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Estimates linear values for the provided dataset samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param mixed $outputdir&lt;br /&gt;
     * @return void&lt;br /&gt;
     */&lt;br /&gt;
    public function estimate($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Evaluates this processor regression model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param float $maxdeviation&lt;br /&gt;
     * @param int $niterations&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function evaluate_regression($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53556</id>
		<title>Machine learning backends</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53556"/>
		<updated>2017-12-27T08:05:14Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Classifier */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learning training, prediction and models evaluation. May be good that you also read [https://docs.moodle.org/dev/Analytics_API Analytics API] to read some concept definitions, how these concepts are implemented in Moodle and how machine learning backend plugins fit into the analytics API.&lt;br /&gt;
&lt;br /&gt;
The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Backends included in Moodle core ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PHP backend&#039;&#039;&#039; is the default predictions processor as it is written in PHP and do not have any external dependencies. It is using logistic regression.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Python backend&#039;&#039;&#039; requires &#039;&#039;python&#039;&#039; binary (either python 2 or python 3) and [https://pypi.python.org/pypi?name=moodlemlbackend&amp;amp;version=0.0.5&amp;amp;:action=display moodlemlbackend python package] which is maintained by Moodle HQ. It is based on [https://www.tensorflow.org/ Google&#039;s tensorflow library] and it is using a feed-forward neural network with 1 single hidden layer. &#039;&#039;moodlemlbackend&#039;&#039; package does store model performance information that can be visualised using [https://www.tensorflow.org/get_started/summaries_and_tensorboard tensorboard]. Information generated during models evaluation is available through the models management page, under each model &#039;&#039;Actions &amp;gt; Log&#039;&#039; menu. &#039;&#039;moodlemlbackend&#039;&#039; source code is available in https://github.com/moodlehq/moodle-mlbackend-python.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Python backend is recommended over the PHP&#039;&#039;&#039; as it is able to predict more accurately than the PHP backend and it is faster.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
A summary of these interfaces purpose:&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train machine learning algorithms with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
This is the basic interface to be implemented by machine learning backends. Two main types are, &#039;&#039;classifiers&#039;&#039; and &#039;&#039;regressors&#039;&#039;. We provide the &#039;&#039;Regressor&#039;&#039; interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;is_ready&#039;&#039;&#039; to check that the backend is available.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is it ready to predict?&lt;br /&gt;
     *&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_ready();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clear_model&#039;&#039;&#039; and &#039;&#039;&#039;delete_output_dir&#039;&#039;&#039; purpose is to clean up stuff created by the machine learning backend.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete all stored information of the current model id.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when there are important changes to a model,&lt;br /&gt;
     * all previous training algorithms using that version of the model&lt;br /&gt;
     * should be deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid The site model unique id string&lt;br /&gt;
     * @param string $modelversionoutputdir The output dir of this model version&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function clear_model($uniqueid, $modelversionoutputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete the output directory.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when a model is completely deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $modeloutputdir The model directory id (parent of all model versions subdirectories).&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function delete_output_dir($modeloutputdir);&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Statistical_classification classifier] sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Train this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function train_classification($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Classifies the provided dataset samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function classify($uniqueid, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Evaluates this processor classification model using the provided supervised learning dataset.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid&lt;br /&gt;
     * @param float $maxdeviation&lt;br /&gt;
     * @param int $niterations&lt;br /&gt;
     * @param \stored_file $dataset&lt;br /&gt;
     * @param string $outputdir&lt;br /&gt;
     * @return \stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function evaluate_classification($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Regression_analysis regressor] predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53555</id>
		<title>Machine learning backends</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53555"/>
		<updated>2017-12-27T07:43:00Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Predictor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learning training, prediction and models evaluation. May be good that you also read [https://docs.moodle.org/dev/Analytics_API Analytics API] to read some concept definitions, how these concepts are implemented in Moodle and how machine learning backend plugins fit into the analytics API.&lt;br /&gt;
&lt;br /&gt;
The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Backends included in Moodle core ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PHP backend&#039;&#039;&#039; is the default predictions processor as it is written in PHP and do not have any external dependencies. It is using logistic regression.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Python backend&#039;&#039;&#039; requires &#039;&#039;python&#039;&#039; binary (either python 2 or python 3) and [https://pypi.python.org/pypi?name=moodlemlbackend&amp;amp;version=0.0.5&amp;amp;:action=display moodlemlbackend python package] which is maintained by Moodle HQ. It is based on [https://www.tensorflow.org/ Google&#039;s tensorflow library] and it is using a feed-forward neural network with 1 single hidden layer. &#039;&#039;moodlemlbackend&#039;&#039; package does store model performance information that can be visualised using [https://www.tensorflow.org/get_started/summaries_and_tensorboard tensorboard]. Information generated during models evaluation is available through the models management page, under each model &#039;&#039;Actions &amp;gt; Log&#039;&#039; menu. &#039;&#039;moodlemlbackend&#039;&#039; source code is available in https://github.com/moodlehq/moodle-mlbackend-python.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Python backend is recommended over the PHP&#039;&#039;&#039; as it is able to predict more accurately than the PHP backend and it is faster.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
A summary of these interfaces purpose:&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train machine learning algorithms with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
This is the basic interface to be implemented by machine learning backends. Two main types are, &#039;&#039;classifiers&#039;&#039; and &#039;&#039;regressors&#039;&#039;. We provide the &#039;&#039;Regressor&#039;&#039; interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;is_ready&#039;&#039;&#039; to check that the backend is available.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is it ready to predict?&lt;br /&gt;
     *&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_ready();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clear_model&#039;&#039;&#039; and &#039;&#039;&#039;delete_output_dir&#039;&#039;&#039; purpose is to clean up stuff created by the machine learning backend.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete all stored information of the current model id.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when there are important changes to a model,&lt;br /&gt;
     * all previous training algorithms using that version of the model&lt;br /&gt;
     * should be deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid The site model unique id string&lt;br /&gt;
     * @param string $modelversionoutputdir The output dir of this model version&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function clear_model($uniqueid, $modelversionoutputdir);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete the output directory.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when a model is completely deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $modeloutputdir The model directory id (parent of all model versions subdirectories).&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function delete_output_dir($modeloutputdir);&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Statistical_classification classifier] sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the &#039;&#039;Predictor&#039;&#039; interface. &lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Regression_analysis regressor] predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53554</id>
		<title>Machine learning backends</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53554"/>
		<updated>2017-12-27T07:42:46Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Predictor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learning training, prediction and models evaluation. May be good that you also read [https://docs.moodle.org/dev/Analytics_API Analytics API] to read some concept definitions, how these concepts are implemented in Moodle and how machine learning backend plugins fit into the analytics API.&lt;br /&gt;
&lt;br /&gt;
The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Backends included in Moodle core ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PHP backend&#039;&#039;&#039; is the default predictions processor as it is written in PHP and do not have any external dependencies. It is using logistic regression.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Python backend&#039;&#039;&#039; requires &#039;&#039;python&#039;&#039; binary (either python 2 or python 3) and [https://pypi.python.org/pypi?name=moodlemlbackend&amp;amp;version=0.0.5&amp;amp;:action=display moodlemlbackend python package] which is maintained by Moodle HQ. It is based on [https://www.tensorflow.org/ Google&#039;s tensorflow library] and it is using a feed-forward neural network with 1 single hidden layer. &#039;&#039;moodlemlbackend&#039;&#039; package does store model performance information that can be visualised using [https://www.tensorflow.org/get_started/summaries_and_tensorboard tensorboard]. Information generated during models evaluation is available through the models management page, under each model &#039;&#039;Actions &amp;gt; Log&#039;&#039; menu. &#039;&#039;moodlemlbackend&#039;&#039; source code is available in https://github.com/moodlehq/moodle-mlbackend-python.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Python backend is recommended over the PHP&#039;&#039;&#039; as it is able to predict more accurately than the PHP backend and it is faster.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
A summary of these interfaces purpose:&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train machine learning algorithms with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
This is the basic interface to be implemented by machine learning backends. Two main types are, &#039;&#039;classifiers&#039;&#039; and &#039;&#039;regressors&#039;&#039;. We provide the &#039;&#039;Regressor&#039;&#039; interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;is_ready&#039;&#039;&#039; to check that the backend is available.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is it ready to predict?&lt;br /&gt;
     *&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_ready();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clear_model&#039;&#039;&#039; and &#039;&#039;&#039;delete_output_dir&#039;&#039;&#039; purpose is to clean up stuff created by the machine learning backend.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete all stored information of the current model id.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when there are important changes to a model,&lt;br /&gt;
     * all previous training algorithms using that version of the model&lt;br /&gt;
     * should be deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $uniqueid The site model unique id string&lt;br /&gt;
     * @param string $modelversionoutputdir The output dir of this model version&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function clear_model($uniqueid, $modelversionoutputdir);&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Delete the output directory.&lt;br /&gt;
     *&lt;br /&gt;
     * This method is called when a model is completely deleted.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $modeloutputdir The model directory id (parent of all model versions subdirectories).&lt;br /&gt;
     * @return null&lt;br /&gt;
     */&lt;br /&gt;
    public function delete_output_dir($modeloutputdir);&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Statistical_classification classifier] sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the &#039;&#039;Predictor&#039;&#039; interface. &lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Regression_analysis regressor] predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53553</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53553"/>
		<updated>2017-12-27T07:14:23Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Time-splitting method (core_analytics\local\time_splitting\base) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4 provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/34/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Documentation available in [https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends].&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends] is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors. Analytics API will be able to find them as long as they follow the namespace conventions described below. &lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this section do not include Machine learning backend interfaces, they are available in https://docs.moodle.org/dev/Machine_learning_backends#Interfaces.&lt;br /&gt;
&lt;br /&gt;
==== Analysable (core_analytics\analysable) ====&lt;br /&gt;
&lt;br /&gt;
Analysables are those elements in Moodle that contain samples. In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity. Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
They list of methods that need to be implemented is quite simple and does not require much explanation.&lt;br /&gt;
&lt;br /&gt;
It is also important to mention that analysable elements should be lazy loaded, otherwise you may have PHP memory issues. The reason is that analysers load all analysable elements in the site to calculate which ones are going to be calculated next (skipping the ones processed recently and stuff like that) You can take core_analytics\course as an example.&lt;br /&gt;
&lt;br /&gt;
Methods to implement:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable unique identifier in the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_id();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable human readable name&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function get_name();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable context.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    public function get_context();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_start&#039;&#039;&#039; and &#039;&#039;&#039;get_end&#039;&#039;&#039; define the start and end times that indicators will use for their calculations.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The start of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_start();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The end of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_end();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Analyser (core_analytics\local\analyser\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_analysables&#039;&#039;&#039; returns the whole list of analysable elements in the site. Each model will later be able to discard analysables that do not match their expectations. &#039;&#039;e.g. if your model is only interested in quizzes with a time close the analyser will return all quizzes, your model will exclude the ones without a time close. This approach is supposed to make analysers more reusable.&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the list of analysable elements available on the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \core_analytics\analysable[] Array of analysable elements using the analysable id as array key.&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analysables();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_all_samples&#039;&#039;&#039; and &#039;&#039;&#039;get_samples&#039;&#039;&#039; should return data associated with the sample ids they provide. This is important for 2 reasons:&lt;br /&gt;
* The data they provide alongside the sample origin is used to filter out indicators that are not related to what this analyser analyses. &#039;&#039;e.g. courses analysers do provide courses and information about courses, but not information about users, a &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator will require the user object to be available. A model using a courses analyser will not be able to use the &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator.&lt;br /&gt;
* The data included here is cached in PHP static vars; on one hand this reduces the amount of db queries indicators need to perform. On the other hand, if not well balanced, it can lead to PHP memory issues.  &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns this analysable list of samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function get_all_samples(\core_analytics\analysable $analysable);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns the samples data from a list of sample ids.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int[] $sampleids&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples($sampleids);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_sample_analysable&#039;&#039;&#039; method is executing during prediction:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analysable of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \core_analytics\analysable&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_sample_analysable($sampleid);&lt;br /&gt;
&lt;br /&gt;
The sample origin is the moodle database table that uses the sample id as primary key.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the sample&#039;s origin in moodle database.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples_origin();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_access_context&#039;&#039;&#039; associates a context to a sampleid. This is important because this sample predictions will only be available for users with &#039;&#039;moodle/analytics:listinsights&#039;&#039; capability in that context.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the context of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_access_context($sampleid);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_description&#039;&#039;&#039; is used to display samples in &#039;&#039;Insights&#039;&#039; report:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Describes a sample with a description summary and a \renderable (an image for example)&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param int $contextid&lt;br /&gt;
     * @param array $sampledata&lt;br /&gt;
     * @return array array(string, \renderable)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_description($sampleid, $contextid, $sampledata);&lt;br /&gt;
&lt;br /&gt;
==== Indicator (core_analytics\local\indicator\base) ====&lt;br /&gt;
&lt;br /&gt;
Indicators should generally extend one of these 3 classes, depending on the values they can return: &#039;&#039;core_analytics\local\indicator\binary&#039;&#039; for &#039;&#039;&#039;yes/no&#039;&#039;&#039; indicators, &#039;&#039;core_analytics\local\indicator\linear&#039;&#039; for indicators that return linear values and &#039;&#039;core_analytics\local\indicator\discrete&#039;&#039; for categorised indicators.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;required_sample_data&#039;&#039;&#039; to specify what your indicator needs to be calculated; you may need a &#039;&#039;user&#039;&#039; object, a &#039;&#039;course&#039;&#039;, a &#039;&#039;grade item&#039;&#039;... The default implementation does not require anything. Models which analysers do not return the required data will not be able to use your indicator so only list here what you really need. e.g. if you need a grade_grades record mark it as required, but there is no need to require the &#039;&#039;user&#039;&#039; object and the &#039;&#039;course&#039;&#039; as well because you can obtain them from the grade_grades item. It is very likely that the analyser will provide them as well because the principle they follow is to include as much related data as possible but do not flag related objects as required because an analyser may, for example, chose to not include the &#039;&#039;user&#039;&#039; object because it is too big and sites can have memory problems.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows indicators to specify data they need.&lt;br /&gt;
     *&lt;br /&gt;
     * e.g. A model using courses as samples will not provide users data, but an indicator like&lt;br /&gt;
     * &amp;quot;user is hungry&amp;quot; needs user data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return null|string[] Name of the required elements (use the database tablename)&lt;br /&gt;
     */&lt;br /&gt;
    public static function required_sample_data() {&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A single method must be implemented, &#039;&#039;&#039;calculate_sample&#039;&#039;&#039;. Most indicators make use of $starttime and $endtime to restrict the time period they consider for their calculations (e.g. read actions during $starttime - $endtime period) but some indicators may not need to apply any restriction (e.g. does this user have a user picture and profile description?) &#039;&#039;self::MIN_VALUE&#039;&#039; is -1 and &#039;&#039;self::MAX_VALUE&#039;&#039; is 1. We do not recommend changing these values.&lt;br /&gt;
 &lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates the sample.&lt;br /&gt;
     *&lt;br /&gt;
     * Return a value from self::MIN_VALUE to self::MAX_VALUE or null if the indicator can not be calculated for this sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param string $sampleorigin&lt;br /&gt;
     * @param integer $starttime Limit the calculation to this timestart&lt;br /&gt;
     * @param integer $endtime Limit the calculation to this timeend&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function calculate_sample($sampleid, $sampleorigin, $starttime, $endtime);&lt;br /&gt;
&lt;br /&gt;
Note that performance here is critical as it runs once for each sample and for each range in the time-splitting method; some tips:  &lt;br /&gt;
* To avoid performance issues or repeated db queries analyser classes provide information about the samples that you can use for your calculations to save some database queries. You can retrieve information about a sample with &#039;&#039;&#039;$user = $this-&amp;gt;retrieve(&#039;user&#039;, $sampleid)&#039;&#039;&#039;. &#039;&#039;retrieve()&#039;&#039; will return false if the requested data is not available.&lt;br /&gt;
* You can also overwrite &#039;&#039;fill_per_analysable_caches&#039;&#039; method if necessary (keep in mind though that PHP memory is unlimited).&lt;br /&gt;
* Indicator instances are reset for each analysable and time range that is processed. This helps keeping the memory usage acceptably low and prevents hard-to-trace caching bugs.&lt;br /&gt;
&lt;br /&gt;
==== Target (core_analytics\local\target\base) ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
The first thing a target must define is the analyser class that it will use. The analyser class is specified in &#039;&#039;&#039;get_analyser_class&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analyser class that should be used along with this target.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string The full class name as a string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analyser_class();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;is_valid_analysable&#039;&#039;&#039; and &#039;&#039;&#039;is_valid_sample&#039;&#039;&#039; are used to discard elements that are not valid for your target.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows the target to verify that the analysable is a good candidate.&lt;br /&gt;
     *&lt;br /&gt;
     * This method can be used as a quick way to discard invalid analysables.&lt;br /&gt;
     * e.g. Imagine that your analysable don&#039;t have students and you need them.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param bool $fortraining&lt;br /&gt;
     * @return true|string&lt;br /&gt;
     */&lt;br /&gt;
    public function is_valid_analysable(\core_analytics\analysable $analysable, $fortraining = true);&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is this sample from the $analysable valid?&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param bool $fortraining&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_valid_sample($sampleid, \core_analytics\analysable $analysable, $fortraining = true);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;calculate_sample&#039;&#039;&#039; is the method that calculates the target value.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates this target for the provided samples.&lt;br /&gt;
     *&lt;br /&gt;
     * In case there are no values to return or the provided sample is not applicable just return null.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param int|false $starttime Limit calculations to start time&lt;br /&gt;
     * @param int|false $endtime Limit calculations to end time&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    protected function calculate_sample($sampleid, \core_analytics\analysable $analysable, $starttime = false, $endtime = false);&lt;br /&gt;
&lt;br /&gt;
==== Time-splitting method (core_analytics\local\time_splitting\base) ====&lt;br /&gt;
&lt;br /&gt;
Time-splitting methods are useful to define when the analytics API will train the predictions processor and when it will generate predictions. As explained above in [[Analytics_API#Time_splitting_methods]], they define time ranges based on analysable elements start and end timestamps.&lt;br /&gt;
&lt;br /&gt;
The base class is &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;; if what you are after is to split the analysable duration in equal parts or in cumulative parts you can extend &#039;&#039;&#039;\core_analytics\local\time_splitting\equal_parts&#039;&#039;&#039; or &#039;&#039;&#039;\core_analytics\local\time_splitting\accumulative_parts&#039;&#039;&#039; instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;define_ranges&#039;&#039;&#039; is the main method to implement and its values mostly depend on the current analysable element (available in &#039;&#039;&#039;$this-&amp;gt;analysable&#039;&#039;&#039;). An array of time ranges should be returned, each of these ranges should contain 3 attributes: A start time (&#039;start&#039;) and an end time (&#039;end&#039;) that will be passed to indicators so they can limit the amount of activity logs they read; the 3rd attribute is &#039;time&#039;, which value will determine when the range will be executed.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define the time splitting methods ranges.&lt;br /&gt;
     *&lt;br /&gt;
     * &#039;time&#039; value defines when predictions are executed, their values will be compared with&lt;br /&gt;
     * the current time in ready_to_predict&lt;br /&gt;
     *&lt;br /&gt;
     * @return array(&#039;start&#039; =&amp;gt; time(), &#039;end&#039; =&amp;gt; time(), &#039;time&#039; =&amp;gt; time())&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_ranges();&lt;br /&gt;
&lt;br /&gt;
A name and description should also be specified:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns a lang_string object representing the name for the time splitting method.&lt;br /&gt;
     *&lt;br /&gt;
     * Used as column identificator.&lt;br /&gt;
     *&lt;br /&gt;
     * If there is a corresponding &#039;_help&#039; string this will be shown as well.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \lang_string&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_name() : \lang_string;&lt;br /&gt;
&lt;br /&gt;
==== Calculable (core_analytics\calculable) ====&lt;br /&gt;
&lt;br /&gt;
Leaving this interface for the end because it is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence)). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
As specified in https://docs.moodle.org/dev/Analytics_API#Target_.28core_analytics.5Clocal.5Ctarget.5Cbase.29.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
You can create the model by specifying at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53552</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53552"/>
		<updated>2017-12-27T06:52:17Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Target (core_analytics\local\target\base) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4 provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/34/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Documentation available in [https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends].&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends] is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors. Analytics API will be able to find them as long as they follow the namespace conventions described below. &lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this section do not include Machine learning backend interfaces, they are available in https://docs.moodle.org/dev/Machine_learning_backends#Interfaces.&lt;br /&gt;
&lt;br /&gt;
==== Analysable (core_analytics\analysable) ====&lt;br /&gt;
&lt;br /&gt;
Analysables are those elements in Moodle that contain samples. In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity. Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
They list of methods that need to be implemented is quite simple and does not require much explanation.&lt;br /&gt;
&lt;br /&gt;
It is also important to mention that analysable elements should be lazy loaded, otherwise you may have PHP memory issues. The reason is that analysers load all analysable elements in the site to calculate which ones are going to be calculated next (skipping the ones processed recently and stuff like that) You can take core_analytics\course as an example.&lt;br /&gt;
&lt;br /&gt;
Methods to implement:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable unique identifier in the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_id();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable human readable name&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function get_name();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable context.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    public function get_context();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_start&#039;&#039;&#039; and &#039;&#039;&#039;get_end&#039;&#039;&#039; define the start and end times that indicators will use for their calculations.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The start of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_start();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The end of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_end();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Analyser (core_analytics\local\analyser\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_analysables&#039;&#039;&#039; returns the whole list of analysable elements in the site. Each model will later be able to discard analysables that do not match their expectations. &#039;&#039;e.g. if your model is only interested in quizzes with a time close the analyser will return all quizzes, your model will exclude the ones without a time close. This approach is supposed to make analysers more reusable.&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the list of analysable elements available on the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \core_analytics\analysable[] Array of analysable elements using the analysable id as array key.&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analysables();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_all_samples&#039;&#039;&#039; and &#039;&#039;&#039;get_samples&#039;&#039;&#039; should return data associated with the sample ids they provide. This is important for 2 reasons:&lt;br /&gt;
* The data they provide alongside the sample origin is used to filter out indicators that are not related to what this analyser analyses. &#039;&#039;e.g. courses analysers do provide courses and information about courses, but not information about users, a &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator will require the user object to be available. A model using a courses analyser will not be able to use the &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator.&lt;br /&gt;
* The data included here is cached in PHP static vars; on one hand this reduces the amount of db queries indicators need to perform. On the other hand, if not well balanced, it can lead to PHP memory issues.  &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns this analysable list of samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function get_all_samples(\core_analytics\analysable $analysable);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns the samples data from a list of sample ids.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int[] $sampleids&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples($sampleids);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_sample_analysable&#039;&#039;&#039; method is executing during prediction:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analysable of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \core_analytics\analysable&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_sample_analysable($sampleid);&lt;br /&gt;
&lt;br /&gt;
The sample origin is the moodle database table that uses the sample id as primary key.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the sample&#039;s origin in moodle database.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples_origin();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_access_context&#039;&#039;&#039; associates a context to a sampleid. This is important because this sample predictions will only be available for users with &#039;&#039;moodle/analytics:listinsights&#039;&#039; capability in that context.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the context of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_access_context($sampleid);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_description&#039;&#039;&#039; is used to display samples in &#039;&#039;Insights&#039;&#039; report:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Describes a sample with a description summary and a \renderable (an image for example)&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param int $contextid&lt;br /&gt;
     * @param array $sampledata&lt;br /&gt;
     * @return array array(string, \renderable)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_description($sampleid, $contextid, $sampledata);&lt;br /&gt;
&lt;br /&gt;
==== Indicator (core_analytics\local\indicator\base) ====&lt;br /&gt;
&lt;br /&gt;
Indicators should generally extend one of these 3 classes, depending on the values they can return: &#039;&#039;core_analytics\local\indicator\binary&#039;&#039; for &#039;&#039;&#039;yes/no&#039;&#039;&#039; indicators, &#039;&#039;core_analytics\local\indicator\linear&#039;&#039; for indicators that return linear values and &#039;&#039;core_analytics\local\indicator\discrete&#039;&#039; for categorised indicators.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;required_sample_data&#039;&#039;&#039; to specify what your indicator needs to be calculated; you may need a &#039;&#039;user&#039;&#039; object, a &#039;&#039;course&#039;&#039;, a &#039;&#039;grade item&#039;&#039;... The default implementation does not require anything. Models which analysers do not return the required data will not be able to use your indicator so only list here what you really need. e.g. if you need a grade_grades record mark it as required, but there is no need to require the &#039;&#039;user&#039;&#039; object and the &#039;&#039;course&#039;&#039; as well because you can obtain them from the grade_grades item. It is very likely that the analyser will provide them as well because the principle they follow is to include as much related data as possible but do not flag related objects as required because an analyser may, for example, chose to not include the &#039;&#039;user&#039;&#039; object because it is too big and sites can have memory problems.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows indicators to specify data they need.&lt;br /&gt;
     *&lt;br /&gt;
     * e.g. A model using courses as samples will not provide users data, but an indicator like&lt;br /&gt;
     * &amp;quot;user is hungry&amp;quot; needs user data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return null|string[] Name of the required elements (use the database tablename)&lt;br /&gt;
     */&lt;br /&gt;
    public static function required_sample_data() {&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A single method must be implemented, &#039;&#039;&#039;calculate_sample&#039;&#039;&#039;. Most indicators make use of $starttime and $endtime to restrict the time period they consider for their calculations (e.g. read actions during $starttime - $endtime period) but some indicators may not need to apply any restriction (e.g. does this user have a user picture and profile description?) &#039;&#039;self::MIN_VALUE&#039;&#039; is -1 and &#039;&#039;self::MAX_VALUE&#039;&#039; is 1. We do not recommend changing these values.&lt;br /&gt;
 &lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates the sample.&lt;br /&gt;
     *&lt;br /&gt;
     * Return a value from self::MIN_VALUE to self::MAX_VALUE or null if the indicator can not be calculated for this sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param string $sampleorigin&lt;br /&gt;
     * @param integer $starttime Limit the calculation to this timestart&lt;br /&gt;
     * @param integer $endtime Limit the calculation to this timeend&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function calculate_sample($sampleid, $sampleorigin, $starttime, $endtime);&lt;br /&gt;
&lt;br /&gt;
Note that performance here is critical as it runs once for each sample and for each range in the time-splitting method; some tips:  &lt;br /&gt;
* To avoid performance issues or repeated db queries analyser classes provide information about the samples that you can use for your calculations to save some database queries. You can retrieve information about a sample with &#039;&#039;&#039;$user = $this-&amp;gt;retrieve(&#039;user&#039;, $sampleid)&#039;&#039;&#039;. &#039;&#039;retrieve()&#039;&#039; will return false if the requested data is not available.&lt;br /&gt;
* You can also overwrite &#039;&#039;fill_per_analysable_caches&#039;&#039; method if necessary (keep in mind though that PHP memory is unlimited).&lt;br /&gt;
* Indicator instances are reset for each analysable and time range that is processed. This helps keeping the memory usage acceptably low and prevents hard-to-trace caching bugs.&lt;br /&gt;
&lt;br /&gt;
==== Target (core_analytics\local\target\base) ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
The first thing a target must define is the analyser class that it will use. The analyser class is specified in &#039;&#039;&#039;get_analyser_class&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analyser class that should be used along with this target.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string The full class name as a string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analyser_class();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;is_valid_analysable&#039;&#039;&#039; and &#039;&#039;&#039;is_valid_sample&#039;&#039;&#039; are used to discard elements that are not valid for your target.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows the target to verify that the analysable is a good candidate.&lt;br /&gt;
     *&lt;br /&gt;
     * This method can be used as a quick way to discard invalid analysables.&lt;br /&gt;
     * e.g. Imagine that your analysable don&#039;t have students and you need them.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param bool $fortraining&lt;br /&gt;
     * @return true|string&lt;br /&gt;
     */&lt;br /&gt;
    public function is_valid_analysable(\core_analytics\analysable $analysable, $fortraining = true);&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Is this sample from the $analysable valid?&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param bool $fortraining&lt;br /&gt;
     * @return bool&lt;br /&gt;
     */&lt;br /&gt;
    public function is_valid_sample($sampleid, \core_analytics\analysable $analysable, $fortraining = true);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;calculate_sample&#039;&#039;&#039; is the method that calculates the target value.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates this target for the provided samples.&lt;br /&gt;
     *&lt;br /&gt;
     * In case there are no values to return or the provided sample is not applicable just return null.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @param int|false $starttime Limit calculations to start time&lt;br /&gt;
     * @param int|false $endtime Limit calculations to end time&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    protected function calculate_sample($sampleid, \core_analytics\analysable $analysable, $starttime = false, $endtime = false);&lt;br /&gt;
&lt;br /&gt;
==== Time-splitting method (core_analytics\local\time_splitting\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Calculable (core_analytics\calculable) ====&lt;br /&gt;
&lt;br /&gt;
Leaving this interface for the end because it is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence)). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
As specified in https://docs.moodle.org/dev/Analytics_API#Target_.28core_analytics.5Clocal.5Ctarget.5Cbase.29.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
You can create the model by specifying at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53551</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53551"/>
		<updated>2017-12-27T06:45:10Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4 provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/34/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Documentation available in [https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends].&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends] is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors. Analytics API will be able to find them as long as they follow the namespace conventions described below. &lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this section do not include Machine learning backend interfaces, they are available in https://docs.moodle.org/dev/Machine_learning_backends#Interfaces.&lt;br /&gt;
&lt;br /&gt;
==== Analysable (core_analytics\analysable) ====&lt;br /&gt;
&lt;br /&gt;
Analysables are those elements in Moodle that contain samples. In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity. Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
They list of methods that need to be implemented is quite simple and does not require much explanation.&lt;br /&gt;
&lt;br /&gt;
It is also important to mention that analysable elements should be lazy loaded, otherwise you may have PHP memory issues. The reason is that analysers load all analysable elements in the site to calculate which ones are going to be calculated next (skipping the ones processed recently and stuff like that) You can take core_analytics\course as an example.&lt;br /&gt;
&lt;br /&gt;
Methods to implement:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable unique identifier in the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_id();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable human readable name&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function get_name();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable context.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    public function get_context();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_start&#039;&#039;&#039; and &#039;&#039;&#039;get_end&#039;&#039;&#039; define the start and end times that indicators will use for their calculations.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The start of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_start();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The end of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_end();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Analyser (core_analytics\local\analyser\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_analysables&#039;&#039;&#039; returns the whole list of analysable elements in the site. Each model will later be able to discard analysables that do not match their expectations. &#039;&#039;e.g. if your model is only interested in quizzes with a time close the analyser will return all quizzes, your model will exclude the ones without a time close. This approach is supposed to make analysers more reusable.&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the list of analysable elements available on the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \core_analytics\analysable[] Array of analysable elements using the analysable id as array key.&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analysables();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_all_samples&#039;&#039;&#039; and &#039;&#039;&#039;get_samples&#039;&#039;&#039; should return data associated with the sample ids they provide. This is important for 2 reasons:&lt;br /&gt;
* The data they provide alongside the sample origin is used to filter out indicators that are not related to what this analyser analyses. &#039;&#039;e.g. courses analysers do provide courses and information about courses, but not information about users, a &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator will require the user object to be available. A model using a courses analyser will not be able to use the &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator.&lt;br /&gt;
* The data included here is cached in PHP static vars; on one hand this reduces the amount of db queries indicators need to perform. On the other hand, if not well balanced, it can lead to PHP memory issues.  &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns this analysable list of samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function get_all_samples(\core_analytics\analysable $analysable);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns the samples data from a list of sample ids.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int[] $sampleids&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples($sampleids);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_sample_analysable&#039;&#039;&#039; method is executing during prediction:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analysable of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \core_analytics\analysable&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_sample_analysable($sampleid);&lt;br /&gt;
&lt;br /&gt;
The sample origin is the moodle database table that uses the sample id as primary key.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the sample&#039;s origin in moodle database.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples_origin();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_access_context&#039;&#039;&#039; associates a context to a sampleid. This is important because this sample predictions will only be available for users with &#039;&#039;moodle/analytics:listinsights&#039;&#039; capability in that context.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the context of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_access_context($sampleid);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_description&#039;&#039;&#039; is used to display samples in &#039;&#039;Insights&#039;&#039; report:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Describes a sample with a description summary and a \renderable (an image for example)&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param int $contextid&lt;br /&gt;
     * @param array $sampledata&lt;br /&gt;
     * @return array array(string, \renderable)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_description($sampleid, $contextid, $sampledata);&lt;br /&gt;
&lt;br /&gt;
==== Indicator (core_analytics\local\indicator\base) ====&lt;br /&gt;
&lt;br /&gt;
Indicators should generally extend one of these 3 classes, depending on the values they can return: &#039;&#039;core_analytics\local\indicator\binary&#039;&#039; for &#039;&#039;&#039;yes/no&#039;&#039;&#039; indicators, &#039;&#039;core_analytics\local\indicator\linear&#039;&#039; for indicators that return linear values and &#039;&#039;core_analytics\local\indicator\discrete&#039;&#039; for categorised indicators.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;required_sample_data&#039;&#039;&#039; to specify what your indicator needs to be calculated; you may need a &#039;&#039;user&#039;&#039; object, a &#039;&#039;course&#039;&#039;, a &#039;&#039;grade item&#039;&#039;... The default implementation does not require anything. Models which analysers do not return the required data will not be able to use your indicator so only list here what you really need. e.g. if you need a grade_grades record mark it as required, but there is no need to require the &#039;&#039;user&#039;&#039; object and the &#039;&#039;course&#039;&#039; as well because you can obtain them from the grade_grades item. It is very likely that the analyser will provide them as well because the principle they follow is to include as much related data as possible but do not flag related objects as required because an analyser may, for example, chose to not include the &#039;&#039;user&#039;&#039; object because it is too big and sites can have memory problems.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows indicators to specify data they need.&lt;br /&gt;
     *&lt;br /&gt;
     * e.g. A model using courses as samples will not provide users data, but an indicator like&lt;br /&gt;
     * &amp;quot;user is hungry&amp;quot; needs user data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return null|string[] Name of the required elements (use the database tablename)&lt;br /&gt;
     */&lt;br /&gt;
    public static function required_sample_data() {&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A single method must be implemented, &#039;&#039;&#039;calculate_sample&#039;&#039;&#039;. Most indicators make use of $starttime and $endtime to restrict the time period they consider for their calculations (e.g. read actions during $starttime - $endtime period) but some indicators may not need to apply any restriction (e.g. does this user have a user picture and profile description?) &#039;&#039;self::MIN_VALUE&#039;&#039; is -1 and &#039;&#039;self::MAX_VALUE&#039;&#039; is 1. We do not recommend changing these values.&lt;br /&gt;
 &lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates the sample.&lt;br /&gt;
     *&lt;br /&gt;
     * Return a value from self::MIN_VALUE to self::MAX_VALUE or null if the indicator can not be calculated for this sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param string $sampleorigin&lt;br /&gt;
     * @param integer $starttime Limit the calculation to this timestart&lt;br /&gt;
     * @param integer $endtime Limit the calculation to this timeend&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function calculate_sample($sampleid, $sampleorigin, $starttime, $endtime);&lt;br /&gt;
&lt;br /&gt;
Note that performance here is critical as it runs once for each sample and for each range in the time-splitting method; some tips:  &lt;br /&gt;
* To avoid performance issues or repeated db queries analyser classes provide information about the samples that you can use for your calculations to save some database queries. You can retrieve information about a sample with &#039;&#039;&#039;$user = $this-&amp;gt;retrieve(&#039;user&#039;, $sampleid)&#039;&#039;&#039;. &#039;&#039;retrieve()&#039;&#039; will return false if the requested data is not available.&lt;br /&gt;
* You can also overwrite &#039;&#039;fill_per_analysable_caches&#039;&#039; method if necessary (keep in mind though that PHP memory is unlimited).&lt;br /&gt;
* Indicator instances are reset for each analysable and time range that is processed. This helps keeping the memory usage acceptably low and prevents hard-to-trace caching bugs.&lt;br /&gt;
&lt;br /&gt;
==== Target (core_analytics\local\target\base) ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
==== Time-splitting method (core_analytics\local\time_splitting\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Calculable (core_analytics\calculable) ====&lt;br /&gt;
&lt;br /&gt;
Leaving this interface for the end because it is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence)). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
As specified in https://docs.moodle.org/dev/Analytics_API#Target_.28core_analytics.5Clocal.5Ctarget.5Cbase.29.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
You can create the model by specifying at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53515</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53515"/>
		<updated>2017-12-13T10:43:16Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Analyser (core_analytics\local\analyser\base) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4 provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/34/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Documentation available in [https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends].&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends] is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors. Analytics API will be able to find them as long as they follow the namespace conventions described below. &lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this section do not include Machine learning backend interfaces, they are available in https://docs.moodle.org/dev/Machine_learning_backends#Interfaces.&lt;br /&gt;
&lt;br /&gt;
==== Analysable (core_analytics\analysable) ====&lt;br /&gt;
&lt;br /&gt;
Analysables are those elements in Moodle that contain samples. In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity. Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
They list of methods that need to be implemented is quite simple and does not require much explanation.&lt;br /&gt;
&lt;br /&gt;
It is also important to mention that analysable elements should be lazy loaded, otherwise you may have PHP memory issues. The reason is that analysers load all analysable elements in the site to calculate which ones are going to be calculated next (skipping the ones processed recently and stuff like that) You can take core_analytics\course as an example.&lt;br /&gt;
&lt;br /&gt;
Methods to implement:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable unique identifier in the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_id();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable human readable name&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function get_name();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable context.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    public function get_context();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_start&#039;&#039;&#039; and &#039;&#039;&#039;get_end&#039;&#039;&#039; define the start and end times that indicators will use for their calculations.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The start of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_start();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The end of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_end();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Analyser (core_analytics\local\analyser\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_analysables&#039;&#039;&#039; returns the whole list of analysable elements in the site. Each model will later be able to discard analysables that do not match their expectations. &#039;&#039;e.g. if your model is only interested in quizzes with a time close the analyser will return all quizzes, your model will exclude the ones without a time close. This approach is supposed to make analysers more reusable.&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the list of analysable elements available on the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \core_analytics\analysable[] Array of analysable elements using the analysable id as array key.&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analysables();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_all_samples&#039;&#039;&#039; and &#039;&#039;&#039;get_samples&#039;&#039;&#039; should return data associated with the sample ids they provide. This is important for 2 reasons:&lt;br /&gt;
* The data they provide alongside the sample origin is used to filter out indicators that are not related to what this analyser analyses. &#039;&#039;e.g. courses analysers do provide courses and information about courses, but not information about users, a &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator will require the user object to be available. A model using a courses analyser will not be able to use the &#039;&#039;&#039;is user profile complete&#039;&#039;&#039; indicator.&lt;br /&gt;
* The data included here is cached in PHP static vars; on one hand this reduces the amount of db queries indicators need to perform. On the other hand, if not well balanced, it can lead to PHP memory issues.  &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns this analysable list of samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function get_all_samples(\core_analytics\analysable $analysable);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns the samples data from a list of sample ids.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int[] $sampleids&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples($sampleids);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_sample_analysable&#039;&#039;&#039; method is executing during prediction:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analysable of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \core_analytics\analysable&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_sample_analysable($sampleid);&lt;br /&gt;
&lt;br /&gt;
The sample origin is the moodle database table that uses the sample id as primary key.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the sample&#039;s origin in moodle database.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples_origin();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_access_context&#039;&#039;&#039; associates a context to a sampleid. This is important because this sample predictions will only be available for users with &#039;&#039;moodle/analytics:listinsights&#039;&#039; capability in that context.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the context of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_access_context($sampleid);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_description&#039;&#039;&#039; is used to display samples in &#039;&#039;Insights&#039;&#039; report:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Describes a sample with a description summary and a \renderable (an image for example)&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param int $contextid&lt;br /&gt;
     * @param array $sampledata&lt;br /&gt;
     * @return array array(string, \renderable)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_description($sampleid, $contextid, $sampledata);&lt;br /&gt;
&lt;br /&gt;
==== Indicator (core_analytics\local\indicator\base) ====&lt;br /&gt;
&lt;br /&gt;
Indicators should generally extend one of these 3 classes, depending on the values they can return: &#039;&#039;core_analytics\local\indicator\binary&#039;&#039; for &#039;&#039;&#039;yes/no&#039;&#039;&#039; indicators, &#039;&#039;core_analytics\local\indicator\linear&#039;&#039; for indicators that return linear values and &#039;&#039;core_analytics\local\indicator\discrete&#039;&#039; for categorised indicators.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;required_sample_data&#039;&#039;&#039; to specify what your indicator needs to be calculated; you may need a &#039;&#039;user&#039;&#039; object, a &#039;&#039;course&#039;&#039;, a &#039;&#039;grade item&#039;&#039;... The default implementation does not require anything. Models which analysers do not return the required data will not be able to use your indicator so only list here what you really need. e.g. if you need a grade_grades record mark it as required, but there is no need to require the &#039;&#039;user&#039;&#039; object and the &#039;&#039;course&#039;&#039; as well because you can obtain them from the grade_grades item. It is very likely that the analyser will provide them as well because the principle they follow is to include as much related data as possible but do not flag related objects as required because an analyser may, for example, chose to not include the &#039;&#039;user&#039;&#039; object because it is too big and sites can have memory problems.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows indicators to specify data they need.&lt;br /&gt;
     *&lt;br /&gt;
     * e.g. A model using courses as samples will not provide users data, but an indicator like&lt;br /&gt;
     * &amp;quot;user is hungry&amp;quot; needs user data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return null|string[] Name of the required elements (use the database tablename)&lt;br /&gt;
     */&lt;br /&gt;
    public static function required_sample_data() {&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A single method must be implemented, &#039;&#039;&#039;calculate_sample&#039;&#039;&#039;. Most indicators make use of $starttime and $endtime to restrict the time period they consider for their calculations (e.g. read actions during $starttime - $endtime period) but some indicators may not need to apply any restriction (e.g. does this user have a user picture and profile description?) &#039;&#039;self::MIN_VALUE&#039;&#039; is -1 and &#039;&#039;self::MAX_VALUE&#039;&#039; is 1. We do not recommend changing these values.&lt;br /&gt;
 &lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates the sample.&lt;br /&gt;
     *&lt;br /&gt;
     * Return a value from self::MIN_VALUE to self::MAX_VALUE or null if the indicator can not be calculated for this sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param string $sampleorigin&lt;br /&gt;
     * @param integer $starttime Limit the calculation to this timestart&lt;br /&gt;
     * @param integer $endtime Limit the calculation to this timeend&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function calculate_sample($sampleid, $sampleorigin, $starttime, $endtime);&lt;br /&gt;
&lt;br /&gt;
Note that performance here is critical as it runs once for each sample and for each range in the time-splitting method; some tips:  &lt;br /&gt;
* To avoid performance issues or repeated db queries analyser classes provide information about the samples that you can use for your calculations to save some database queries. You can retrieve information about a sample with &#039;&#039;&#039;$user = $this-&amp;gt;retrieve(&#039;user&#039;, $sampleid)&#039;&#039;&#039;. &#039;&#039;retrieve()&#039;&#039; will return false if the requested data is not available.&lt;br /&gt;
* You can also overwrite &#039;&#039;fill_per_analysable_caches&#039;&#039; method if necessary (keep in mind though that PHP memory is unlimited).&lt;br /&gt;
* Indicator instances are reset for each analysable and time range that is processed. This helps keeping the memory usage acceptably low and prevents hard-to-trace caching bugs.&lt;br /&gt;
&lt;br /&gt;
==== Target (core_analytics\local\target\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Time-splitting method (core_analytics\local\time_splitting\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Calculable (core_analytics\calculable) ====&lt;br /&gt;
&lt;br /&gt;
Leaving this interface for the end because it is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence)). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
You can create the model by specifying at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53514</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53514"/>
		<updated>2017-12-13T10:35:55Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Indicator (core_analytics\local\indicator\base) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4 provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/34/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Documentation available in [https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends].&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends] is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors. Analytics API will be able to find them as long as they follow the namespace conventions described below. &lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this section do not include Machine learning backend interfaces, they are available in https://docs.moodle.org/dev/Machine_learning_backends#Interfaces.&lt;br /&gt;
&lt;br /&gt;
==== Analysable (core_analytics\analysable) ====&lt;br /&gt;
&lt;br /&gt;
Analysables are those elements in Moodle that contain samples. In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity. Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
They list of methods that need to be implemented is quite simple and does not require much explanation.&lt;br /&gt;
&lt;br /&gt;
It is also important to mention that analysable elements should be lazy loaded, otherwise you may have PHP memory issues. The reason is that analysers load all analysable elements in the site to calculate which ones are going to be calculated next (skipping the ones processed recently and stuff like that) You can take core_analytics\course as an example.&lt;br /&gt;
&lt;br /&gt;
Methods to implement:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable unique identifier in the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_id();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable human readable name&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function get_name();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable context.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    public function get_context();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_start&#039;&#039;&#039; and &#039;&#039;&#039;get_end&#039;&#039;&#039; define the start and end times that indicators will use for their calculations.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The start of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_start();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The end of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_end();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Analyser (core_analytics\local\analyser\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_analysables&#039;&#039;&#039; returns the whole list of analysable elements in the site. Each model will later be able to discard analysables that do not match their expectations. &#039;&#039;e.g. if your model is only interested in quizzes with a time close the analyser will return all quizzes, your model will exclude the ones without a time close. This approach is supposed to make analysers more reusable.&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the list of analysable elements available on the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \core_analytics\analysable[] Array of analysable elements using the analysable id as array key.&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analysables();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_all_samples&#039;&#039;&#039; and &#039;&#039;&#039;get_samples&#039;&#039;&#039; should return the same samples data associated with the sample ids so you may be interested in having a method that they can both call.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns this analysable list of samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function get_all_samples(\core_analytics\analysable $analysable);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns the samples data from a list of sample ids.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int[] $sampleids&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples($sampleids);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_sample_analysable&#039;&#039;&#039; method is executing during prediction:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analysable of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \core_analytics\analysable&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_sample_analysable($sampleid);&lt;br /&gt;
&lt;br /&gt;
The sample origin is the moodle database table that uses the sample id as primary key.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the sample&#039;s origin in moodle database.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples_origin();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_access_context&#039;&#039;&#039; associates a context to a sampleid. This is important because this sample predictions will only be available for users with &#039;&#039;moodle/analytics:listinsights&#039;&#039; capability in that context.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the context of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_access_context($sampleid);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_description&#039;&#039;&#039; is used to display samples in &#039;&#039;Insights&#039;&#039; report:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Describes a sample with a description summary and a \renderable (an image for example)&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param int $contextid&lt;br /&gt;
     * @param array $sampledata&lt;br /&gt;
     * @return array array(string, \renderable)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_description($sampleid, $contextid, $sampledata);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Indicator (core_analytics\local\indicator\base) ====&lt;br /&gt;
&lt;br /&gt;
Indicators should generally extend one of these 3 classes, depending on the values they can return: &#039;&#039;core_analytics\local\indicator\binary&#039;&#039; for &#039;&#039;&#039;yes/no&#039;&#039;&#039; indicators, &#039;&#039;core_analytics\local\indicator\linear&#039;&#039; for indicators that return linear values and &#039;&#039;core_analytics\local\indicator\discrete&#039;&#039; for categorised indicators.&lt;br /&gt;
&lt;br /&gt;
You can use &#039;&#039;&#039;required_sample_data&#039;&#039;&#039; to specify what your indicator needs to be calculated; you may need a &#039;&#039;user&#039;&#039; object, a &#039;&#039;course&#039;&#039;, a &#039;&#039;grade item&#039;&#039;... The default implementation does not require anything. Models which analysers do not return the required data will not be able to use your indicator so only list here what you really need. e.g. if you need a grade_grades record mark it as required, but there is no need to require the &#039;&#039;user&#039;&#039; object and the &#039;&#039;course&#039;&#039; as well because you can obtain them from the grade_grades item. It is very likely that the analyser will provide them as well because the principle they follow is to include as much related data as possible but do not flag related objects as required because an analyser may, for example, chose to not include the &#039;&#039;user&#039;&#039; object because it is too big and sites can have memory problems.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Allows indicators to specify data they need.&lt;br /&gt;
     *&lt;br /&gt;
     * e.g. A model using courses as samples will not provide users data, but an indicator like&lt;br /&gt;
     * &amp;quot;user is hungry&amp;quot; needs user data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return null|string[] Name of the required elements (use the database tablename)&lt;br /&gt;
     */&lt;br /&gt;
    public static function required_sample_data() {&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
A single method must be implemented, &#039;&#039;&#039;calculate_sample&#039;&#039;&#039;. Most indicators make use of $starttime and $endtime to restrict the time period they consider for their calculations (e.g. read actions during $starttime - $endtime period) but some indicators may not need to apply any restriction (e.g. does this user have a user picture and profile description?) &#039;&#039;self::MIN_VALUE&#039;&#039; is -1 and &#039;&#039;self::MAX_VALUE&#039;&#039; is 1. We do not recommend changing these values.&lt;br /&gt;
 &lt;br /&gt;
    /**&lt;br /&gt;
     * Calculates the sample.&lt;br /&gt;
     *&lt;br /&gt;
     * Return a value from self::MIN_VALUE to self::MAX_VALUE or null if the indicator can not be calculated for this sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param string $sampleorigin&lt;br /&gt;
     * @param integer $starttime Limit the calculation to this timestart&lt;br /&gt;
     * @param integer $endtime Limit the calculation to this timeend&lt;br /&gt;
     * @return float|null&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function calculate_sample($sampleid, $sampleorigin, $starttime, $endtime);&lt;br /&gt;
&lt;br /&gt;
Note that performance here is critical as it runs once for each sample and for each range in the time-splitting method; some tips:  &lt;br /&gt;
* To avoid performance issues or repeated db queries analyser classes provide information about the samples that you can use for your calculations to save some database queries. You can retrieve information about a sample with &#039;&#039;&#039;$user = $this-&amp;gt;retrieve(&#039;user&#039;, $sampleid)&#039;&#039;&#039;. &#039;&#039;retrieve()&#039;&#039; will return false if the requested data is not available.&lt;br /&gt;
* You can also overwrite &#039;&#039;fill_per_analysable_caches&#039;&#039; method if necessary (keep in mind though that PHP memory is unlimited).&lt;br /&gt;
* Indicator instances are reset for each analysable and time range that is processed. This helps keeping the memory usage acceptably low and prevents hard-to-trace caching bugs.&lt;br /&gt;
&lt;br /&gt;
==== Target (core_analytics\local\target\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Time-splitting method (core_analytics\local\time_splitting\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Calculable (core_analytics\calculable) ====&lt;br /&gt;
&lt;br /&gt;
Leaving this interface for the end because it is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence)). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
You can create the model by specifying at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53513</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53513"/>
		<updated>2017-12-13T10:06:15Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Design */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4 provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/34/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Documentation available in [https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends].&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends] is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors. Analytics API will be able to find them as long as they follow the namespace conventions described below. &lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this section do not include Machine learning backend interfaces, they are available in https://docs.moodle.org/dev/Machine_learning_backends#Interfaces.&lt;br /&gt;
&lt;br /&gt;
==== Analysable (core_analytics\analysable) ====&lt;br /&gt;
&lt;br /&gt;
Analysables are those elements in Moodle that contain samples. In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity. Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
They list of methods that need to be implemented is quite simple and does not require much explanation.&lt;br /&gt;
&lt;br /&gt;
It is also important to mention that analysable elements should be lazy loaded, otherwise you may have PHP memory issues. The reason is that analysers load all analysable elements in the site to calculate which ones are going to be calculated next (skipping the ones processed recently and stuff like that) You can take core_analytics\course as an example.&lt;br /&gt;
&lt;br /&gt;
Methods to implement:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable unique identifier in the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_id();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable human readable name&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function get_name();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable context.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    public function get_context();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_start&#039;&#039;&#039; and &#039;&#039;&#039;get_end&#039;&#039;&#039; define the start and end times that indicators will use for their calculations.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The start of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_start();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The end of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_end();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Analyser (core_analytics\local\analyser\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_analysables&#039;&#039;&#039; returns the whole list of analysable elements in the site. Each model will later be able to discard analysables that do not match their expectations. &#039;&#039;e.g. if your model is only interested in quizzes with a time close the analyser will return all quizzes, your model will exclude the ones without a time close. This approach is supposed to make analysers more reusable.&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the list of analysable elements available on the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \core_analytics\analysable[] Array of analysable elements using the analysable id as array key.&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_analysables();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_all_samples&#039;&#039;&#039; and &#039;&#039;&#039;get_samples&#039;&#039;&#039; should return the same samples data associated with the sample ids so you may be interested in having a method that they can both call.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns this analysable list of samples.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core_analytics\analysable $analysable&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract protected function get_all_samples(\core_analytics\analysable $analysable);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This function returns the samples data from a list of sample ids.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int[] $sampleids&lt;br /&gt;
     * @return array array[0] = int[] (sampleids) and array[1] = array (samplesdata)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples($sampleids);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;get_sample_analysable&#039;&#039;&#039; method is executing during prediction:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the analysable of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \core_analytics\analysable&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_sample_analysable($sampleid);&lt;br /&gt;
&lt;br /&gt;
The sample origin is the moodle database table that uses the sample id as primary key.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the sample&#039;s origin in moodle database.&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function get_samples_origin();&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_access_context&#039;&#039;&#039; associates a context to a sampleid. This is important because this sample predictions will only be available for users with &#039;&#039;moodle/analytics:listinsights&#039;&#039; capability in that context.&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the context of a sample.&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_access_context($sampleid);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;sample_description&#039;&#039;&#039; is used to display samples in &#039;&#039;Insights&#039;&#039; report:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Describes a sample with a description summary and a \renderable (an image for example)&lt;br /&gt;
     *&lt;br /&gt;
     * @param int $sampleid&lt;br /&gt;
     * @param int $contextid&lt;br /&gt;
     * @param array $sampledata&lt;br /&gt;
     * @return array array(string, \renderable)&lt;br /&gt;
     */&lt;br /&gt;
    abstract public function sample_description($sampleid, $contextid, $sampledata);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Indicator (core_analytics\local\indicator\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Target (core_analytics\local\target\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Time-splitting method (core_analytics\local\time_splitting\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Calculable (core_analytics\calculable) ====&lt;br /&gt;
&lt;br /&gt;
Leaving this interface for the end because it is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence)). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
You can create the model by specifying at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53512</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53512"/>
		<updated>2017-12-13T09:44:13Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Design */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4 provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/34/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Documentation available in [https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends].&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends] is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors. Analytics API will be able to find them as long as they follow the namespace conventions described below. &lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this section do not include Machine learning backend interfaces, they are available in https://docs.moodle.org/dev/Machine_learning_backends#Interfaces.&lt;br /&gt;
&lt;br /&gt;
==== Analysable (core_analytics\analysable) ====&lt;br /&gt;
&lt;br /&gt;
Analysables are those elements in Moodle that contain samples (read related comments above in [[#Analyser]]). In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity. Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
They list of methods that need to be implemented is quite simple and does not require much explanation. get_start() and get_end() are probably the only methods worth commenting about; they define the start and end times that indicators will use for their calculations:&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable unique identifier in the site.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_id();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable human readable name&lt;br /&gt;
     *&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function get_name();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The analysable context.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \context&lt;br /&gt;
     */&lt;br /&gt;
    public function get_context();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The start of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_start();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * The end of the analysable if there is one.&lt;br /&gt;
     *&lt;br /&gt;
     * @return int|false&lt;br /&gt;
     */&lt;br /&gt;
    public function get_end();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Analyser (core_analytics\local\analyser\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Indicator (core_analytics\local\indicator\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Target (core_analytics\local\target\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Time-splitting method (core_analytics\local\time_splitting\base) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Calculable (core_analytics\calculable) ====&lt;br /&gt;
&lt;br /&gt;
Leaving this interface for the end because it is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence)). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
You can create the model by specifying at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53511</id>
		<title>Machine learning backends</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53511"/>
		<updated>2017-12-13T09:28:30Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Interfaces */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learning training, prediction and models evaluation. May be good that you also read [https://docs.moodle.org/dev/Analytics_API Analytics API] to read some concept definitions, how these concepts are implemented in Moodle and how machine learning backend plugins fit into the analytics API.&lt;br /&gt;
&lt;br /&gt;
The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Backends included in Moodle core ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PHP backend&#039;&#039;&#039; is the default predictions processor as it is written in PHP and do not have any external dependencies. It is using logistic regression.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Python backend&#039;&#039;&#039; requires &#039;&#039;python&#039;&#039; binary (either python 2 or python 3) and [https://pypi.python.org/pypi?name=moodlemlbackend&amp;amp;version=0.0.5&amp;amp;:action=display moodlemlbackend python package] which is maintained by Moodle HQ. It is based on [https://www.tensorflow.org/ Google&#039;s tensorflow library] and it is using a feed-forward neural network with 1 single hidden layer. &#039;&#039;moodlemlbackend&#039;&#039; package does store model performance information that can be visualised using [https://www.tensorflow.org/get_started/summaries_and_tensorboard tensorboard]. Information generated during models evaluation is available through the models management page, under each model &#039;&#039;Actions &amp;gt; Log&#039;&#039; menu. &#039;&#039;moodlemlbackend&#039;&#039; source code is available in https://github.com/moodlehq/moodle-mlbackend-python.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Python backend is recommended over the PHP&#039;&#039;&#039; as it is able to predict more accurately than the PHP backend and it is faster.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
A summary of these interfaces purpose:&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train machine learning algorithms with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
This is the basic interface to be implemented by machine learning backends. Two main types are, classifiers and regressors. We provide the &#039;&#039;Regressor&#039;&#039; interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Statistical_classification classifier] sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the &#039;&#039;Predictor&#039;&#039; interface. &lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Regression_analysis regressor] predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53510</id>
		<title>Machine learning backends</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53510"/>
		<updated>2017-12-13T09:22:08Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Backends included in Moodle core */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learning training, prediction and models evaluation. May be good that you also read [https://docs.moodle.org/dev/Analytics_API Analytics API] to read some concept definitions, how these concepts are implemented in Moodle and how machine learning backend plugins fit into the analytics API.&lt;br /&gt;
&lt;br /&gt;
The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Backends included in Moodle core ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PHP backend&#039;&#039;&#039; is the default predictions processor as it is written in PHP and do not have any external dependencies. It is using logistic regression.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Python backend&#039;&#039;&#039; requires &#039;&#039;python&#039;&#039; binary (either python 2 or python 3) and [https://pypi.python.org/pypi?name=moodlemlbackend&amp;amp;version=0.0.5&amp;amp;:action=display moodlemlbackend python package] which is maintained by Moodle HQ. It is based on [https://www.tensorflow.org/ Google&#039;s tensorflow library] and it is using a feed-forward neural network with 1 single hidden layer. &#039;&#039;moodlemlbackend&#039;&#039; package does store model performance information that can be visualised using [https://www.tensorflow.org/get_started/summaries_and_tensorboard tensorboard]. Information generated during models evaluation is available through the models management page, under each model &#039;&#039;Actions &amp;gt; Log&#039;&#039; menu. &#039;&#039;moodlemlbackend&#039;&#039; source code is available in https://github.com/moodlehq/moodle-mlbackend-python.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Python backend is recommended over the PHP&#039;&#039;&#039; as it is able to predict more accurately than the PHP backend and it is faster.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
They have  are a new plugin type with a common interface:&lt;br /&gt;
&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train a machine learning algorithm with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53509</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53509"/>
		<updated>2017-12-13T08:35:39Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Machine learning backends */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4 provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/34/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
Documentation available in [https://docs.moodle.org/dev/Machine_learning_backends Machine learning backends].&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
Machine learning backends is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Extension points ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors.&lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
Moodle components (core subsystems, core plugins and 3rd party plugins) will be able to add and/or redefine any of the entities involved in all the data modeling process.&lt;br /&gt;
&lt;br /&gt;
Some of the base classes to extend or follow as example:&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
This is the basic interface to be implemented by machine learning backends. Two main types are, classifiers and regressors. We provide the &#039;&#039;Regressor&#039;&#039; interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Statistical_classification classifier] sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the &#039;&#039;Predictor&#039;&#039; interface. &lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Regression_analysis regressor] predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
==== Analysable ====&lt;br /&gt;
&lt;br /&gt;
Analysable items are those elements in Moodle that contain samples. In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity.&lt;br /&gt;
&lt;br /&gt;
Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;. They need to provide an id, a name, a &#039;&#039;&#039;\context&#039;&#039;&#039; and &#039;&#039;get_start()&#039;&#039; and &#039;&#039;get_end()&#039;&#039; methods. Read related comments above in [[#Analyser]].&lt;br /&gt;
&lt;br /&gt;
==== Calculable ====&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
It is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence)). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
You can create the model by specifying at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53508</id>
		<title>Machine learning backends</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Machine_learning_backends&amp;diff=53508"/>
		<updated>2017-12-13T08:34:49Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: Created page with &amp;quot; == Introduction ==  Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learni...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Machine learning backends process the datasets generated from the indicators and targets calculated by the Analytics API. They are used for machine learning training, prediction and models evaluation. May be good that you also read [https://docs.moodle.org/dev/Analytics_API Analytics API] to read some concept definitions, how these concepts are implemented in Moodle and how machine learning backend plugins fit into the analytics API.&lt;br /&gt;
&lt;br /&gt;
The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Backends included in Moodle core ==&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;PHP backend&#039;&#039;&#039; is the default predictions processor as it is written in PHP and do not have any external dependencies. It is using logistic regression.&lt;br /&gt;
* The &#039;&#039;&#039;Python backend&#039;&#039;&#039; is using a feed-forward neural network with 1 single hidden layer. It requires [https://pypi.python.org/pypi?name=moodlemlbackend&amp;amp;version=0.0.5&amp;amp;:action=display moodlemlbackend python package] which is maintained by Moodle HQ; its source code is available in https://github.com/moodlehq/moodle-mlbackend-python.&lt;br /&gt;
&lt;br /&gt;
== Interfaces ==&lt;br /&gt;
&lt;br /&gt;
They have  are a new plugin type with a common interface:&lt;br /&gt;
&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train a machine learning algorithm with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Plugin_types&amp;diff=53507</id>
		<title>Plugin types</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Plugin_types&amp;diff=53507"/>
		<updated>2017-12-13T08:19:30Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* List of Moodle plugin types */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Plugins development}}&lt;br /&gt;
&lt;br /&gt;
The M in Moodle stands for modular.  The easiest and most maintainable way to add new functionality to Moodle is by writing one of these types of plugin. &lt;br /&gt;
&lt;br /&gt;
== List of Moodle plugin types ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Plugin type&lt;br /&gt;
! Component name ([[Frankenstyle]])&lt;br /&gt;
! Moodle path&lt;br /&gt;
! Description&lt;br /&gt;
! Moodle versions&lt;br /&gt;
|-&lt;br /&gt;
| [[Activity modules]]&lt;br /&gt;
| mod&lt;br /&gt;
| /mod&lt;br /&gt;
| Activity modules are essential types of plugins in Moodle as they provide activities in courses. For example: Forum, Quiz and Assignment.&lt;br /&gt;
| 1.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Antivirus plugins]]&lt;br /&gt;
| antivirus&lt;br /&gt;
| /lib/antivirus&lt;br /&gt;
| Antivirus scanner plugins provide functionality for virus scanning user uploaded files using third-party virus scanning tools in Moodle. For example: ClamAV.&lt;br /&gt;
| 3.1+&lt;br /&gt;
|-&lt;br /&gt;
| [[Assign_submission_plugins|Assignment submission plugins]]&lt;br /&gt;
| assignsubmission&lt;br /&gt;
| /mod/assign/submission&lt;br /&gt;
| Different forms of assignment submissions&lt;br /&gt;
| 2.3+&lt;br /&gt;
|-&lt;br /&gt;
| [[Assign_feedback_plugins|Assignment feedback plugins]]&lt;br /&gt;
| assignfeedback&lt;br /&gt;
| /mod/assign/feedback&lt;br /&gt;
| Different forms of assignment feedbacks&lt;br /&gt;
| 2.3+&lt;br /&gt;
|-&lt;br /&gt;
| [[Book tools]]&lt;br /&gt;
| booktool&lt;br /&gt;
| /mod/book/tool&lt;br /&gt;
| Small information-displays or tools that can be moved around pages&lt;br /&gt;
| 2.1+&lt;br /&gt;
|-&lt;br /&gt;
| [[Database fields]]&lt;br /&gt;
| datafield&lt;br /&gt;
| /mod/data/field&lt;br /&gt;
| Different types of data that may be added to the Database activity module&lt;br /&gt;
| 1.6+&lt;br /&gt;
|-&lt;br /&gt;
| [[Database presets]]&lt;br /&gt;
| datapreset&lt;br /&gt;
| /mod/data/preset&lt;br /&gt;
| Pre-defined templates for the Database activity module&lt;br /&gt;
| 1.6+&lt;br /&gt;
|-&lt;br /&gt;
| [[External tool source|LTI sources]]&lt;br /&gt;
| ltisource&lt;br /&gt;
| /mod/lti/source&lt;br /&gt;
| LTI providers can be added to external tools easily through the external tools interface see [https://docs.moodle.org/en/External_tool Documentation on External Tools]. This type of plugin is specific to LTI providers that need a plugin that can register custom handlers to process LTI messages&lt;br /&gt;
| 2.7+&lt;br /&gt;
|-&lt;br /&gt;
| [[File Converters]]&lt;br /&gt;
| fileconverter&lt;br /&gt;
| /files/converter&lt;br /&gt;
| Allow conversion between different types of user-submitted file. For example from .doc to PDF.&lt;br /&gt;
| 3.2+&lt;br /&gt;
|-&lt;br /&gt;
| [[LTI services]]&lt;br /&gt;
| ltiservice&lt;br /&gt;
| /mod/lti/service&lt;br /&gt;
| Allows the implementation of LTI services as described by the IMS LTI specification&lt;br /&gt;
| 2.8+&lt;br /&gt;
|-&lt;br /&gt;
| [[Machine learning backends]]&lt;br /&gt;
| mlbackend&lt;br /&gt;
| /lib/mlbackend&lt;br /&gt;
| Prediction processors for analytics API&lt;br /&gt;
| 3.4+&lt;br /&gt;
|-&lt;br /&gt;
| [[Quiz reports]]&lt;br /&gt;
| quiz&lt;br /&gt;
| /mod/quiz/report&lt;br /&gt;
| Display and analyse the results of quizzes, or just plug miscellaneous behaviour into the quiz module&lt;br /&gt;
| 1.1+&lt;br /&gt;
|-&lt;br /&gt;
| [[Quiz access rules]]&lt;br /&gt;
| quizaccess&lt;br /&gt;
| /mod/quiz/accessrule&lt;br /&gt;
| Add conditions to when or where quizzes can be attempted, for example only from some IP addresses, or student must enter a password first&lt;br /&gt;
| 2.2+&lt;br /&gt;
|-&lt;br /&gt;
| [[SCORM reports]]&lt;br /&gt;
| scormreport&lt;br /&gt;
| /mod/scorm/report&lt;br /&gt;
| Analysis of SCORM attempts&lt;br /&gt;
| 2.2+&lt;br /&gt;
|-&lt;br /&gt;
| [[Workshop grading strategies]]&lt;br /&gt;
| workshopform&lt;br /&gt;
| /mod/workshop/form&lt;br /&gt;
| Define the type of the grading form and implement the calculation of the grade for submission in the [[Workshop]] module&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Workshop allocation methods]]&lt;br /&gt;
| workshopallocation&lt;br /&gt;
| /mod/workshop/allocation&lt;br /&gt;
| Define ways how submissions are assigned for assessment in the [[Workshop]] module&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Workshop evaluation methods]]&lt;br /&gt;
| workshopeval&lt;br /&gt;
| /mod/workshop/eval&lt;br /&gt;
| Implement the calculation of the grade for assessment (grading grade) in the [[Workshop]] module&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Blocks]]&lt;br /&gt;
| block&lt;br /&gt;
| /blocks&lt;br /&gt;
| Small information-displays or tools that can be moved around pages&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Question types]]&lt;br /&gt;
| qtype&lt;br /&gt;
| /question/type&lt;br /&gt;
| Different types of question (e.g. multiple-choice, drag-and-drop) that can be used in quizzes and other activities&lt;br /&gt;
| 1.6+&lt;br /&gt;
|-&lt;br /&gt;
| [[Question behaviours]]&lt;br /&gt;
| qbehaviour&lt;br /&gt;
| /question/behaviour&lt;br /&gt;
| Control how student interact with questions during an attempt&lt;br /&gt;
| 2.1+&lt;br /&gt;
|-&lt;br /&gt;
| [[Question formats|Question import/export formats]]&lt;br /&gt;
| qformat&lt;br /&gt;
| /question/format&lt;br /&gt;
| Import and export question definitions to/from the question bank&lt;br /&gt;
| 1.6+&lt;br /&gt;
|-&lt;br /&gt;
| [[Filters|Text filters]]&lt;br /&gt;
| filter&lt;br /&gt;
| /filter&lt;br /&gt;
| Automatically convert, highlight, and transmogrify text posted into Moodle.&lt;br /&gt;
| 1.4+&lt;br /&gt;
|-&lt;br /&gt;
| [[Editors]]&lt;br /&gt;
| editor&lt;br /&gt;
| /lib/editor&lt;br /&gt;
| Alternative text editors for editing content&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Atto|Atto editor plugins]]&lt;br /&gt;
| atto&lt;br /&gt;
| /lib/editor/atto/plugins&lt;br /&gt;
| Extra functionality for the Atto text editor&lt;br /&gt;
| 2.7+&lt;br /&gt;
|-&lt;br /&gt;
| [[TinyMCE editor plugins]]&lt;br /&gt;
| tinymce&lt;br /&gt;
| /lib/editor/tinymce/plugins&lt;br /&gt;
| Extra functionality for the TinyMCE text editor.&lt;br /&gt;
| 2.4+&lt;br /&gt;
|-&lt;br /&gt;
| [[Enrolment plugins]]&lt;br /&gt;
| enrol&lt;br /&gt;
| /enrol&lt;br /&gt;
| Ways to control who is enrolled in courses&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Authentication plugins]]&lt;br /&gt;
| auth&lt;br /&gt;
| /auth&lt;br /&gt;
| Allows connection to external sources of authentication&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Admin tools]]&lt;br /&gt;
| tool&lt;br /&gt;
| /admin/tool&lt;br /&gt;
| Provides utility scripts useful for various site administration and maintenance tasks&lt;br /&gt;
| 2.2+&lt;br /&gt;
|-&lt;br /&gt;
| [[Log stores]]&lt;br /&gt;
| logstore&lt;br /&gt;
| /admin/tool/log/store&lt;br /&gt;
| Event logs storage back-ends&lt;br /&gt;
| 2.7+&lt;br /&gt;
|-&lt;br /&gt;
| [[Availability conditions]]&lt;br /&gt;
| availability&lt;br /&gt;
| /availability/condition&lt;br /&gt;
| Conditions to restrict user access to activities and sections.&lt;br /&gt;
| 2.7+&lt;br /&gt;
|-&lt;br /&gt;
| [[Calendar types]]&lt;br /&gt;
| calendartype&lt;br /&gt;
| /calendar/type&lt;br /&gt;
| Defines how dates are displayed throughout Moodle&lt;br /&gt;
| 2.6+&lt;br /&gt;
|-&lt;br /&gt;
| [[Messaging consumers]]&lt;br /&gt;
| message&lt;br /&gt;
| /message/output&lt;br /&gt;
| Represent various targets where messages and notifications can be sent to (email, sms, jabber, ...)&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Course formats]]&lt;br /&gt;
| format&lt;br /&gt;
| /course/format&lt;br /&gt;
| Different ways of laying out the activities and blocks in a course&lt;br /&gt;
| 1.3+&lt;br /&gt;
|-&lt;br /&gt;
| [[Data formats]]&lt;br /&gt;
| dataformat&lt;br /&gt;
| /dataformat&lt;br /&gt;
| Formats for data exporting and downloading&lt;br /&gt;
| 3.1+&lt;br /&gt;
|-&lt;br /&gt;
| [[User profile fields]]&lt;br /&gt;
| profilefield&lt;br /&gt;
| /user/profile/field&lt;br /&gt;
| Add new types of data to user profiles&lt;br /&gt;
| 1.9+&lt;br /&gt;
|-&lt;br /&gt;
| [[Reports]]&lt;br /&gt;
| report&lt;br /&gt;
| /report&lt;br /&gt;
| Provides useful views of data in a Moodle site for admins and teachers&lt;br /&gt;
| 2.2+&lt;br /&gt;
|-&lt;br /&gt;
| [[Course reports]]&lt;br /&gt;
| coursereport&lt;br /&gt;
| /course/report&lt;br /&gt;
| Reports of activity within the course&lt;br /&gt;
| Up to 2.1 (for 2.2+ see [[Reports]])&lt;br /&gt;
|-&lt;br /&gt;
| [[Gradebook export]]&lt;br /&gt;
| gradeexport&lt;br /&gt;
| /grade/export&lt;br /&gt;
| Export grades in various formats&lt;br /&gt;
| 1.9+&lt;br /&gt;
|-&lt;br /&gt;
| [[Gradebook import]]&lt;br /&gt;
| gradeimport&lt;br /&gt;
| /grade/import&lt;br /&gt;
| Import grades in various formats &lt;br /&gt;
| 1.9+&lt;br /&gt;
|-&lt;br /&gt;
| [[Gradebook reports]]&lt;br /&gt;
| gradereport&lt;br /&gt;
| /grade/report&lt;br /&gt;
| Display/edit grades in various layouts and reports&lt;br /&gt;
| 1.9+&lt;br /&gt;
|-&lt;br /&gt;
| [[Grading methods|Advanced grading methods]]&lt;br /&gt;
| gradingform&lt;br /&gt;
| /grade/grading/form&lt;br /&gt;
| Interfaces for actually performing grading in activity modules (eg Rubrics)&lt;br /&gt;
| 2.2+&lt;br /&gt;
|-&lt;br /&gt;
| [[MNet services]]&lt;br /&gt;
| mnetservice&lt;br /&gt;
| /mnet/service&lt;br /&gt;
| Allows to implement remote services for the [[MNet]] environment (deprecated, use web services instead)&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Webservice protocols]]&lt;br /&gt;
| webservice&lt;br /&gt;
| /webservice&lt;br /&gt;
| Define new protocols for web service communication (such as SOAP, XML-RPC, JSON, REST ...)&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Repository plugins]]&lt;br /&gt;
| repository&lt;br /&gt;
| /repository&lt;br /&gt;
| Connect to external sources of files to use in Moodle&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Portfolio plugins]]&lt;br /&gt;
| portfolio&lt;br /&gt;
| /portfolio&lt;br /&gt;
| Connect external portfolio services as destinations for users to store Moodle content&lt;br /&gt;
| 1.9+&lt;br /&gt;
|-&lt;br /&gt;
| [[Search engines]]&lt;br /&gt;
| search&lt;br /&gt;
| /search/engine&lt;br /&gt;
| Search engine backends to index Moodle&#039;s contents.&lt;br /&gt;
| 3.1+&lt;br /&gt;
|-&lt;br /&gt;
| [[Media players]]&lt;br /&gt;
| media&lt;br /&gt;
| /media/player&lt;br /&gt;
| Pluggable media players&lt;br /&gt;
| 3.2+&lt;br /&gt;
|-&lt;br /&gt;
| [[Plagiarism plugins]]&lt;br /&gt;
| plagiarism&lt;br /&gt;
| /plagiarism&lt;br /&gt;
| Define external services to process submitted files and content&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Cache store]]&lt;br /&gt;
| cachestore&lt;br /&gt;
| /cache/stores&lt;br /&gt;
| Cache storage back-ends.&lt;br /&gt;
| 2.4+&lt;br /&gt;
|-&lt;br /&gt;
| [[Cache locks]]&lt;br /&gt;
| cachelock&lt;br /&gt;
| /cache/locks&lt;br /&gt;
| Cache lock implementations.&lt;br /&gt;
| 2.4+&lt;br /&gt;
|-&lt;br /&gt;
| [[Themes]]&lt;br /&gt;
| theme&lt;br /&gt;
| /theme&lt;br /&gt;
| Change the look of Moodle by changing the the HTML and the CSS. &lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Local plugins]]&lt;br /&gt;
| local&lt;br /&gt;
| /local&lt;br /&gt;
| Generic plugins for local customisations&lt;br /&gt;
| 2.0+&lt;br /&gt;
|-&lt;br /&gt;
| [[Assignment types|Legacy assignment types]]&lt;br /&gt;
| assignment&lt;br /&gt;
| /mod/assignment/type&lt;br /&gt;
| Different forms of assignments to be graded by teachers&lt;br /&gt;
| 1.x - 2.2&lt;br /&gt;
|-&lt;br /&gt;
| [[Admin reports|Legacy admin reports]]&lt;br /&gt;
| report&lt;br /&gt;
| /admin/report&lt;br /&gt;
| Provides useful views of data in a Moodle site, for admins only.&lt;br /&gt;
| Up to 2.1 (for 2.2+ see [[Reports]])&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Obtaining the list of plugin types known to your Moodle ==&lt;br /&gt;
&lt;br /&gt;
To get the most exact list of types in your version of Moodle, use the following script. Put it to a file in the root directory of your Moodle installation and execute it via command line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
define(&#039;CLI_SCRIPT&#039;, true);&lt;br /&gt;
require(&#039;config.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$pluginman = core_plugin_manager::instance();&lt;br /&gt;
&lt;br /&gt;
foreach ($pluginman-&amp;gt;get_plugin_types() as $type =&amp;gt; $dir) {&lt;br /&gt;
    $dir = substr($dir, strlen($CFG-&amp;gt;dirroot));&lt;br /&gt;
    printf(&amp;quot;%-20s %-50s %s&amp;quot;.PHP_EOL, $type, $pluginman-&amp;gt;plugintype_name_plural($type), $dir);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Things you can find in all plugins==&lt;br /&gt;
&lt;br /&gt;
Although there are many different types of plugin, there are some things that work the same way in all plugin types, and we have [[Things that work the same in all plugin types|a page that describes them]].&lt;br /&gt;
&lt;br /&gt;
Additionally you probably want to look at the page [[Plugin files]].&lt;br /&gt;
&lt;br /&gt;
== Naming conventions ==&lt;br /&gt;
&lt;br /&gt;
Warning if you have to choose a plugin (directory) name. The name is validated by the method &amp;lt;tt&amp;gt;lib/classes/component.php::is_valid_plugin_name()&amp;lt;/tt&amp;gt; with a regexp: &amp;lt;tt&amp;gt;/^[a-z](?:[a-z0-9_](?!__))*[a-z0-9]+$/&amp;lt;/tt&amp;gt;. In particular, the minus (-) character is not considered as valid, and the plugin will be silently ignored if the name is not valid.&lt;br /&gt;
&lt;br /&gt;
There is an exception for [[Activity modules|activity modules]] that can not have the underscore in their name for legacy reasons.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Guidelines_for_contributed_code|Guidelines for contributing code]]&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[Frankenstyle]]&lt;br /&gt;
* [http://moodle.org/plugins Moodle Plugins directory] &lt;br /&gt;
* [[Tutorial]] to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way. &lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines|Plugins]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53249</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53249"/>
		<updated>2017-11-14T14:56:57Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
The Moodle Analytics API allows Moodle site managers to define prediction models that combine indicators and a target. The target is the event we want to predict. The indicators are what we think will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the prediction accuracy is high enough, Moodle internally trains a machine learning algorithm by using calculations based on the defined indicators within the site data. Once new data that matches the criteria defined by the model is available, Moodle starts predicting the probability that the target event will occur. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested in is prevention of [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out students at risk of dropping out]: Lack of participation or bad grades in previous activities could be indicators, and the target would be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predicts which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows the main components of the analytics API and the interactions between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through, from the data a Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relationships. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even courses on the same site can vary significantly. Moodle core will only include models that have been proven to be good at predicting in a wide range of sites and courses. Moodle 3.4 provides two built-in models:&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&lt;br /&gt;
* [https://docs.moodle.org/34/en/Analytics#No_teaching No teaching]&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases, the Moodle HQ research team is collecting anonymised Moodle site datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with will obviously better at predicting on the sites of participating institutions, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact [[user:emdalton1|Elizabeth Dalton]] at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
The following definitions are included for people not familiar with machine learning concepts: &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
This is the process to be run on a Moodle site before being able to predict anything. This process records the relationships found in site data from the past so the analytics system can predict what is likely to happen under the same circumstances in the future. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for, and where in the Moodle data to look. A sample is a set of calculations we make using a collection of Moodle site data. These samples are unrelated to testing data or phpunit data, and they are identified by an id matching the data element on which the calculations are based. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on that element. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. See [[Analytics_API#Analyser]] for more information on how to use analyser classes to define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above, a prediction model is a combination of indicators and a target. System models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relationship between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all of a model&#039;s related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing large quantities of data to make accurate predictions. There are obvious events that different stakeholders may be interested in knowing that we can easily calculate. These *Static model* predictions are directly calculated based on indicator values. They are based on the assumptions defined in the target, but they should still be based on indicators so all these indicators can still be reused across different prediction models. For this reason, static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of possible static models:&lt;br /&gt;
* [https://docs.moodle.org/en/Analytics#No_teaching Courses without teaching activity]&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
Moodle could already generate notifications for the examples above, but there are some benefits on doing it using the Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as the analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related actions.&lt;br /&gt;
* The Analytics API tracks user actions after viewing the predictions, so we can know if insights result in actions, which insights are not useful, etc. User responses to insights could themselves be defined as an indicator.&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible for creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers that you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the work. It contains a key abstract method, &#039;&#039;get_all_samples()&#039;&#039;. This method is what defines the sample unique identifier across the site. Analyser classes are also responsible of including all site data related to that sample id; this data will be used when indicators are calculated. e.g. A sample id &#039;&#039;user enrolment&#039;&#039; would include data about the &#039;&#039;course&#039;&#039;, the course &#039;&#039;context&#039;&#039; and the &#039;&#039;user&#039;&#039;. Samples are nothing by themselves, just a list of ids with related data. They are used in calculations once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser class responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser, there is an important non-obvious fact you should know about: for scalability reasons, all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. This is for performance reasons: depending on the sites&#039; size it could take hours to complete the analysis of the entire site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses), &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site) or create your own analyser for activities, categories or any other Moodle entity.&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Targets are the key element that defines the model. As a PHP class, targets represent the event the model is attempting to predict (the [https://en.wikipedia.org/wiki/Dependent_and_independent_variables dependent variable in supervised learning]). They also define the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers, because analysers provide them with the samples they need. Analysers are separate entities from targets because analysers can be reused across different targets. Each target needs to specify which analyser it is using. Here are a few examples to clarify the difference between analysers, samples and targets:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;course enrolments&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides sample&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression, but the machine learning backends included in core do not yet support multiclass classification or regression, so only binary classifications will be initially fully supported. See MDL-59044 and MDL-60523 for more information.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction against using core targets in your own models, in most cases each model will implement a new target. One possible case in which targets might be reused would be to create a new model using the same target and a different sets of indicators, for A/B testing&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is insight generation. Insights represent predictions made about a specific element of the sample within the context of the analyser model. This context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (the teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction. In cases like &#039;&#039;[https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out]&#039;&#039; the actions can be things like sending a message to the student, viewing the student&#039;s course activity report, etc.&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Indicator PHP classes are responsible for calculating indicators (predictor value or [https://en.wikipedia.org/wiki/Dependent_and_independent_variables independent variable in supervised learning]) using the provided sample. Moodle core includes a set of indicators that can be used in your models without additional PHP coding (unless you want to extend their functionality).&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to a single analyser like targets are. This makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and an &#039;&#039;enrolment&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, and the name of the indicator would change according to that. For example, &#039;&#039;User posts in any forum&#039;&#039; could be used in a user-based model like &#039;&#039;Inactive users&#039;&#039; and in any other model where the analyser provides &#039;&#039;user&#039;&#039; data; &#039;&#039;Posts in any of the course forums&#039;&#039; could be used in a course-based model like &#039;&#039;Low participation courses.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This requirement prevents the creation of &amp;quot;raw number&amp;quot; indicators like &#039;&#039;absolute number of write actions,&#039;&#039; because we must limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity. Raw counts of an event like &amp;quot;posts to a forum&amp;quot; must be calculated in a proportion of an expected number of posts. There are several ways of doing this. One is to define a minimum desired number of events, e.g. 3 posts in a forum represents &amp;quot;some&amp;quot; activity, 6 posts represents adequate activity, and 10 or more posts represents the maximum expected activity. Another way is to compare the number of events per individual user to the mean or median value of events by all users in the same context, using statistical values. For example, a value of 0 would represent that the student posted the same number of posts as the mean of all student posts in that context; a value of -1 would indicate that the student is 2 or 3 standard deviations below the mean, and a +1 would indicate that the student is 2 or 3 standard deviations above the mean. &#039;&#039;(Note that this kind of comparative calculation has implications in pedagogy: it suggests that there is a ranking of students from best to worst, rather than a defined standard all students can reach.)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample. This is relatively simple. Things get more complicated when we want to predict what will happen in future. For example, predictions about [https://docs.moodle.org/en/Students_at_risk_of_dropping_out Students at risk of dropping out] are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations involving time ranges can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependent indicators within the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course into time ranges: in weeks, quarters, 8 parts, ten parts (tenths), ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (each one inclusive from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
The time-splitting methods included in Moodle 3.4 assume that there is a fixed start and end date for each course, so the course can be divided into segments of equal length. This allows courses of different lengths to be included in the same prediction model, but makes these time-splitting methods useless for courses without fixed start or end dates, e.g. self-paced courses. These courses might instead use fixed time lengths such as weeks to define the boundaries of prediction calculations.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
They process the datasets generated from the calculated indicators and targets. They are a new plugin type with a common interface:&lt;br /&gt;
&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train a machine learning algorithm with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
The communication between prediction processors and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
Machine learning backends is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Extension points ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors.&lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
Moodle components (core subsystems, core plugins and 3rd party plugins) will be able to add and/or redefine any of the entities involved in all the data modeling process.&lt;br /&gt;
&lt;br /&gt;
Some of the base classes to extend or follow as example:&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
This is the basic interface to be implemented by machine learning backends. Two main types are, classifiers and regressors. We provide the &#039;&#039;Regressor&#039;&#039; interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Statistical_classification classifier] sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the &#039;&#039;Predictor&#039;&#039; interface. &lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
A [https://en.wikipedia.org/wiki/Regression_analysis regressor] predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is &amp;quot;supervised&amp;quot;: It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
==== Analysable ====&lt;br /&gt;
&lt;br /&gt;
Analysable items are those elements in Moodle that contain samples. In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element, e.g. an activity.&lt;br /&gt;
&lt;br /&gt;
Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;. They need to provide an id, a name, a &#039;&#039;&#039;\context&#039;&#039;&#039; and &#039;&#039;get_start()&#039;&#039; and &#039;&#039;get_end()&#039;&#039; methods. Read related comments above in [[#Analyser]].&lt;br /&gt;
&lt;br /&gt;
==== Calculable ====&lt;br /&gt;
&lt;br /&gt;
Both indicators and targets must implement this interface. It defines the data element to be used in calculations, whether as independent (indicator) or dependent (target) variables.&lt;br /&gt;
&lt;br /&gt;
It is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
Start by defining what you want to predict (the target) and the subjects of these predictions (the samples). You can find the descriptions of these concepts above. The API can be used for all kinds of models, though if you want to predict something like &amp;quot;student success,&amp;quot; this definition should probably have some basis in pedagogy. (For example, the included model [https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] is based on the Community of Inquiry theoretical framework, and attempts to predict that students will complete a course based on indicators designed to represent the three components of the CoI framework (teaching presence, social presence, and cognitive presence)). Start by being clear about how the target will be defined. It must be trained using known examples. This means that if, for example, you want to predict the final grade of a course per student, the courses being used to train the model must include accurate final grades.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simpler than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, though processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts).&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (though this is only a default behaviour you can overwrite in your target).&lt;br /&gt;
&lt;br /&gt;
Note that the existing time splitting methods are proportional to the length of the course, e.g. quarters, tenths, etc. This allows courses with different lengths to be included in the same sample, but requires courses to have defined start and end dates. Other time splitting methods are possible which do not depend on the defined length of the course, e.g. weekly. These would be more appropriate for self-paced courses without fixed start and end dates.&lt;br /&gt;
&lt;br /&gt;
You do not need to require a single time splitting method at this stage, and they can be changed whenever the model is trained. You do need to define whether the model will make a single prediction or multiple predictions per analysable.&lt;br /&gt;
&lt;br /&gt;
=== Create the target ===&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Technically targets could be reused between models although it is not very recommendable and you should focus instead in having a single model with a single set of indicators that work together towards predicting accurately. The only valid use case I can think of for models in production is using different time-splitting methods for it although, again, the proper way to solve this is by using a single time-splitting method specific for your needs.&lt;br /&gt;
&lt;br /&gt;
=== Create the model ===&lt;br /&gt;
&lt;br /&gt;
You can create the model by specifying at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target: classify users as spammers&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators: two different indicators that predict that the user is a spammer&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/34/en/Students_at_risk_of_dropping_out Students at risk of dropping out] (based on student&#039;s activity, included in [https://docs.moodle.org/34/en/Analytics Moodle 3.4])&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53165</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53165"/>
		<updated>2017-11-03T16:25:18Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Extension points */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
Analytics API allow Moodle sites managers to define prediction models that combine indicators and a target. The target is what we want to predict, the indicators is what we think that will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the predictions accuracy is good enough, Moodle internally trains a machine learning algorithm by calculating the defined indicators with the site data. Once new data that matches the criteria defined by the model is available Moodle starts predicting what is most likely to happen. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested on is prevention of students at risk of drop out: Lack of participation or bad grades in previous activities could be indicators, the target could be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predict which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows how the main components of the analytics API interact between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through. From the data any Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relations. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even same site courses can vary significantly. Moodle core should only include models that have been proven to be good at predicting in a wide range of sites and courses.&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases Moodle HQ research team is collecting anonymised Moodle site&#039;s datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with are obviously better at predicting on these institutions sites, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact Elizabeth Dalton at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
Definition for people not familiar with machine learning concepts: It is a process we need to run before being able to predict anything, we record what already happened so we can predict later what is likely to happen under the same circumstances. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for. We use Moodle sites data for it, a sample is a set of calculations we make using the site data. These samples are unrelated to testing data, phpunit and stuff like that and they are identified by an id. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on it. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. Further info in Analytics_API#Analyser as analyser classes define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above a prediction model is a combination of indicators and a target. Your system models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relation between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all models related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing tons of data to make more or less accurate predictions. There are obvious things different stakeholders may be interested in knowing that we can easily calculate. These *Static models* predictions are directly based on indicators calculations. They are based on the assumptions defined in the target but they should still be based on indicators so all these indicators can still be reused across different prediction models, therefore static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of static models:&lt;br /&gt;
* Courses without teaching activity&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
These cases are nothing new and we could be already generating notifications for the examples above but there are some benefits on doing it using Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related stuff.&lt;br /&gt;
* Analytics API tracks user actions after viewing the predictions, so we can know if insights derive in actions, which insights are not useful...&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible of creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the stuff, it contains a key abstract method though, &#039;&#039;get_all_samples()&#039;&#039;, this method is what defines what is a sample. A sample can be any moodle entity: a course, a user, an enrolment, a quiz attempt... Samples are nothing by themselves, just a list of ids with related data, they make sense once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser classes responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser there is an important non-obvious fact you should know about: For scalability reasons all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. We do it this way because depending on the sites&#039; size it could take hours to complete the analysis of all the site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses) or &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site)&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Target are the key element that defines the model. Targets are coded as PHP classes and they define what we want to predict and calculate it across the site. It also defines the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers because analysers provide them with the samples they need. Analysers are separate entities to targets because analysers can be reused across different targets. Each target needs to specify what analyser it is using. A few examples in case it is not clear the difference between analysers, samples and targets:&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;course student&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression but the machine learning backends included in core do not yet support multiclass classification nor regression so only binary classifications will be initially fully supported. See [https://tracker.moodle.org/browse/MDL-59044 MDL-59044] and [https://tracker.moodle.org/browse/MDL-60523 https://tracker.moodle.org/browse/MDL-60523] for more info.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction to directly use core targets in your own models it does not make much sense in most of the cases. One possible case would be to create a new 2 models using the same target and different sets of indicators.&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is the insights generation. Analysers samples always have a context, the context level (activity module, course, user...) depends on the sample but they always have a context, this context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction, in cases like &#039;&#039;Students at risk of dropping out&#039;&#039; the actions can be things like to send a message to the student, to view their course activity report...&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Also defined as PHP classes, their responsibility is quite simple, to calculate the indicator using the provided sample. Moodle core includes a set of indicators that can be used in your models without any PHP coding (unless you want to extend their functionality)&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to one single analyser like targets are, this makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and a &#039;&#039;user&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, the name of the indicator would change according to that: &#039;&#039;User posts in any forum&#039;&#039;, which could be used in models like &#039;&#039;Inactive users&#039;&#039; or &#039;&#039;Posts in any of the course forums&#039;&#039;, which could be used in models like &#039;&#039;Low participation courses&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This guarantees that we will not have indicators like &#039;&#039;absolute number of write actions&#039;&#039; because we will be forced to limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity.&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting methods is what defines when you will get predictions and the activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample, that is fine, things get more complicated when we want to predict what will happen in future. E.g. predictions about students at risk of dropping out are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations in time ranges is can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependant indicators to the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course in time ranges: in weeks, quarters, 8 parts, ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
They process the datasets generated from the calculated indicators and targets. They are a new plugin type with a common interface:&lt;br /&gt;
&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train a machine learning algorithm with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
The communication between prediction processors and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
Machine learning backends is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Extension points ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors.&lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
Moodle components (core subsystems, core plugins and 3rd party plugins) will be able to add and/or redefine any of the entities involved in all the data modeling process.&lt;br /&gt;
&lt;br /&gt;
Some of the base classes to extend or follow as example:&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
Basic interface to be implemented by machine learning backends, pretty useless by itself (continue reading below)&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support classification; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support regression; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
==== Analysable ====&lt;br /&gt;
&lt;br /&gt;
Analysable items are analysed by analysers :P In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element. e.g. an activity.&lt;br /&gt;
&lt;br /&gt;
Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;. They need to provide an id, a name, a &#039;&#039;&#039;\context&#039;&#039;&#039; and &#039;&#039;get_start()&#039;&#039; and &#039;&#039;get_end()&#039;&#039; methods. Read related comments above in [[#Analyser]].&lt;br /&gt;
&lt;br /&gt;
==== Calculable ====&lt;br /&gt;
&lt;br /&gt;
Indicators and targets must implement this interface.&lt;br /&gt;
&lt;br /&gt;
It is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
To define what you want to predict (the target) and the subjects of these predictions (the samples) is the best way to start. You can find the descriptions of these concepts above.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simplier than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts)&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (not so important, just a default behaviour you can overwrite in your target)&lt;br /&gt;
&lt;br /&gt;
==== Create the target ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can create the model by specifying at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators.&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
Students at risk of dropping out (based on student&#039;s activity, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53164</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53164"/>
		<updated>2017-11-03T16:23:59Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Create the target */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
Analytics API allow Moodle sites managers to define prediction models that combine indicators and a target. The target is what we want to predict, the indicators is what we think that will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the predictions accuracy is good enough, Moodle internally trains a machine learning algorithm by calculating the defined indicators with the site data. Once new data that matches the criteria defined by the model is available Moodle starts predicting what is most likely to happen. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested on is prevention of students at risk of drop out: Lack of participation or bad grades in previous activities could be indicators, the target could be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predict which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows how the main components of the analytics API interact between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through. From the data any Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relations. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even same site courses can vary significantly. Moodle core should only include models that have been proven to be good at predicting in a wide range of sites and courses.&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases Moodle HQ research team is collecting anonymised Moodle site&#039;s datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with are obviously better at predicting on these institutions sites, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact Elizabeth Dalton at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
Definition for people not familiar with machine learning concepts: It is a process we need to run before being able to predict anything, we record what already happened so we can predict later what is likely to happen under the same circumstances. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for. We use Moodle sites data for it, a sample is a set of calculations we make using the site data. These samples are unrelated to testing data, phpunit and stuff like that and they are identified by an id. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on it. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. Further info in Analytics_API#Analyser as analyser classes define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above a prediction model is a combination of indicators and a target. Your system models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relation between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all models related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing tons of data to make more or less accurate predictions. There are obvious things different stakeholders may be interested in knowing that we can easily calculate. These *Static models* predictions are directly based on indicators calculations. They are based on the assumptions defined in the target but they should still be based on indicators so all these indicators can still be reused across different prediction models, therefore static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of static models:&lt;br /&gt;
* Courses without teaching activity&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
These cases are nothing new and we could be already generating notifications for the examples above but there are some benefits on doing it using Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related stuff.&lt;br /&gt;
* Analytics API tracks user actions after viewing the predictions, so we can know if insights derive in actions, which insights are not useful...&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible of creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the stuff, it contains a key abstract method though, &#039;&#039;get_all_samples()&#039;&#039;, this method is what defines what is a sample. A sample can be any moodle entity: a course, a user, an enrolment, a quiz attempt... Samples are nothing by themselves, just a list of ids with related data, they make sense once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser classes responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser there is an important non-obvious fact you should know about: For scalability reasons all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. We do it this way because depending on the sites&#039; size it could take hours to complete the analysis of all the site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses) or &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site)&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Target are the key element that defines the model. Targets are coded as PHP classes and they define what we want to predict and calculate it across the site. It also defines the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers because analysers provide them with the samples they need. Analysers are separate entities to targets because analysers can be reused across different targets. Each target needs to specify what analyser it is using. A few examples in case it is not clear the difference between analysers, samples and targets:&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;course student&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression but the machine learning backends included in core do not yet support multiclass classification nor regression so only binary classifications will be initially fully supported. See [https://tracker.moodle.org/browse/MDL-59044 MDL-59044] and [https://tracker.moodle.org/browse/MDL-60523 https://tracker.moodle.org/browse/MDL-60523] for more info.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction to directly use core targets in your own models it does not make much sense in most of the cases. One possible case would be to create a new 2 models using the same target and different sets of indicators.&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is the insights generation. Analysers samples always have a context, the context level (activity module, course, user...) depends on the sample but they always have a context, this context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction, in cases like &#039;&#039;Students at risk of dropping out&#039;&#039; the actions can be things like to send a message to the student, to view their course activity report...&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Also defined as PHP classes, their responsibility is quite simple, to calculate the indicator using the provided sample. Moodle core includes a set of indicators that can be used in your models without any PHP coding (unless you want to extend their functionality)&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to one single analyser like targets are, this makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and a &#039;&#039;user&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, the name of the indicator would change according to that: &#039;&#039;User posts in any forum&#039;&#039;, which could be used in models like &#039;&#039;Inactive users&#039;&#039; or &#039;&#039;Posts in any of the course forums&#039;&#039;, which could be used in models like &#039;&#039;Low participation courses&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This guarantees that we will not have indicators like &#039;&#039;absolute number of write actions&#039;&#039; because we will be forced to limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity.&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting methods is what defines when you will get predictions and the activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample, that is fine, things get more complicated when we want to predict what will happen in future. E.g. predictions about students at risk of dropping out are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations in time ranges is can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependant indicators to the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course in time ranges: in weeks, quarters, 8 parts, ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
They process the datasets generated from the calculated indicators and targets. They are a new plugin type with a common interface:&lt;br /&gt;
&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train a machine learning algorithm with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
The communication between prediction processors and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
Machine learning backends is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Extension points ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors.&lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
Moodle components (core subsystems, core plugins and 3rd party plugins) will be able to add and/or redefine any of the entities involved in all the data modeling process.&lt;br /&gt;
&lt;br /&gt;
Some of the base classes to extend or follow as example:&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
Basic interface to be implemented by machine learning backends, pretty useless by itself (continue reading below)&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support classification; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support regression; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
==== Analysable ====&lt;br /&gt;
&lt;br /&gt;
Analysable items are analysed by analysers :P In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element. e.g. an activity.&lt;br /&gt;
&lt;br /&gt;
Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;. They need to provide an id, a name, a &#039;&#039;&#039;\context&#039;&#039;&#039; and &#039;&#039;get_start()&#039;&#039; and &#039;&#039;get_end()&#039;&#039; methods. Read related comments above in [[#Analyser]].&lt;br /&gt;
&lt;br /&gt;
==== Calculable ====&lt;br /&gt;
&lt;br /&gt;
Indicators and targets must implement this interface.&lt;br /&gt;
&lt;br /&gt;
It is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
To define what you want to predict (the target) and the subjects of these predictions (the samples) is the best way to start. You can find the descriptions of these concepts above.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simplier than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts)&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (not so important, just a default behaviour you can overwrite in your target)&lt;br /&gt;
&lt;br /&gt;
==== Create the target ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can create the model by specifying at least its target and, optionally, a set of indicators and a time splitting method:&lt;br /&gt;
&lt;br /&gt;
    // Instantiate the target&lt;br /&gt;
    $target = \core_analytics\manager::get_target(&#039;\mod_yours\analytics\target\spammer_users&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Instantiate indicators.&lt;br /&gt;
    $indicator1 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_straight_after_new_account_created&#039;);&lt;br /&gt;
    $indicator2 = \core_analytics\manager::get_indicator(&#039;\mod_yours\analytics\indicator\posts_contain_important_viagra&#039;);&lt;br /&gt;
    $indicators = array($indicator1-&amp;gt;get_id() =&amp;gt; $indicator1, $indicator2-&amp;gt;get_id() =&amp;gt; $indicator2);&lt;br /&gt;
&lt;br /&gt;
    // Create the model.&lt;br /&gt;
    $model = \core_analytics\model::create($target, $indicators, &#039;\core\analytics\time_splitting\single_range&#039;);&lt;br /&gt;
&lt;br /&gt;
Models are disabled by default because you may be interested in evaluating how good the model is at predicting before enabling them. You can enable models using Moodle UI or the analytics API:&lt;br /&gt;
 &lt;br /&gt;
    $model-&amp;gt;enable();&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
Students at risk of dropping out (based on student&#039;s activity, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53146</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53146"/>
		<updated>2017-10-27T10:46:35Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* API usage examples */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
Analytics API allow Moodle sites managers to define prediction models that combine indicators and a target. The target is what we want to predict, the indicators is what we think that will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the predictions accuracy is good enough, Moodle internally trains a machine learning algorithm by calculating the defined indicators with the site data. Once new data that matches the criteria defined by the model is available Moodle starts predicting what is most likely to happen. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested on is prevention of students at risk of drop out: Lack of participation or bad grades in previous activities could be indicators, the target could be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predict which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows how the main components of the analytics API interact between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through. From the data any Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relations. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even same site courses can vary significantly. Moodle core should only include models that have been proven to be good at predicting in a wide range of sites and courses.&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases Moodle HQ research team is collecting anonymised Moodle site&#039;s datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with are obviously better at predicting on these institutions sites, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact Elizabeth Dalton at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
Definition for people not familiar with machine learning concepts: It is a process we need to run before being able to predict anything, we record what already happened so we can predict later what is likely to happen under the same circumstances. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for. We use Moodle sites data for it, a sample is a set of calculations we make using the site data. These samples are unrelated to testing data, phpunit and stuff like that and they are identified by an id. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on it. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. Further info in Analytics_API#Analyser as analyser classes define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above a prediction model is a combination of indicators and a target. Your system models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relation between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all models related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing tons of data to make more or less accurate predictions. There are obvious things different stakeholders may be interested in knowing that we can easily calculate. These *Static models* predictions are directly based on indicators calculations. They are based on the assumptions defined in the target but they should still be based on indicators so all these indicators can still be reused across different prediction models, therefore static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of static models:&lt;br /&gt;
* Courses without teaching activity&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
These cases are nothing new and we could be already generating notifications for the examples above but there are some benefits on doing it using Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related stuff.&lt;br /&gt;
* Analytics API tracks user actions after viewing the predictions, so we can know if insights derive in actions, which insights are not useful...&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible of creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the stuff, it contains a key abstract method though, &#039;&#039;get_all_samples()&#039;&#039;, this method is what defines what is a sample. A sample can be any moodle entity: a course, a user, an enrolment, a quiz attempt... Samples are nothing by themselves, just a list of ids with related data, they make sense once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser classes responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser there is an important non-obvious fact you should know about: For scalability reasons all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. We do it this way because depending on the sites&#039; size it could take hours to complete the analysis of all the site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses) or &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site)&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Target are the key element that defines the model. Targets are coded as PHP classes and they define what we want to predict and calculate it across the site. It also defines the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers because analysers provide them with the samples they need. Analysers are separate entities to targets because analysers can be reused across different targets. Each target needs to specify what analyser it is using. A few examples in case it is not clear the difference between analysers, samples and targets:&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;course student&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression but the machine learning backends included in core do not yet support multiclass classification nor regression so only binary classifications will be initially fully supported. See [https://tracker.moodle.org/browse/MDL-59044 MDL-59044] and [https://tracker.moodle.org/browse/MDL-60523 https://tracker.moodle.org/browse/MDL-60523] for more info.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction to directly use core targets in your own models it does not make much sense in most of the cases. One possible case would be to create a new 2 models using the same target and different sets of indicators.&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is the insights generation. Analysers samples always have a context, the context level (activity module, course, user...) depends on the sample but they always have a context, this context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction, in cases like &#039;&#039;Students at risk of dropping out&#039;&#039; the actions can be things like to send a message to the student, to view their course activity report...&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Also defined as PHP classes, their responsibility is quite simple, to calculate the indicator using the provided sample. Moodle core includes a set of indicators that can be used in your models without any PHP coding (unless you want to extend their functionality)&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to one single analyser like targets are, this makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and a &#039;&#039;user&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, the name of the indicator would change according to that: &#039;&#039;User posts in any forum&#039;&#039;, which could be used in models like &#039;&#039;Inactive users&#039;&#039; or &#039;&#039;Posts in any of the course forums&#039;&#039;, which could be used in models like &#039;&#039;Low participation courses&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This guarantees that we will not have indicators like &#039;&#039;absolute number of write actions&#039;&#039; because we will be forced to limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity.&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting methods is what defines when you will get predictions and the activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample, that is fine, things get more complicated when we want to predict what will happen in future. E.g. predictions about students at risk of dropping out are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations in time ranges is can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependant indicators to the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course in time ranges: in weeks, quarters, 8 parts, ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
They process the datasets generated from the calculated indicators and targets. They are a new plugin type with a common interface:&lt;br /&gt;
&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train a machine learning algorithm with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
The communication between prediction processors and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
Machine learning backends is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Extension points ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors.&lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
Moodle components (core subsystems, core plugins and 3rd party plugins) will be able to add and/or redefine any of the entities involved in all the data modeling process.&lt;br /&gt;
&lt;br /&gt;
Some of the base classes to extend or follow as example:&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
Basic interface to be implemented by machine learning backends, pretty useless by itself (continue reading below)&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support classification; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support regression; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
==== Analysable ====&lt;br /&gt;
&lt;br /&gt;
Analysable items are analysed by analysers :P In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element. e.g. an activity.&lt;br /&gt;
&lt;br /&gt;
Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;. They need to provide an id, a name, a &#039;&#039;&#039;\context&#039;&#039;&#039; and &#039;&#039;get_start()&#039;&#039; and &#039;&#039;get_end()&#039;&#039; methods. Read related comments above in [[#Analyser]].&lt;br /&gt;
&lt;br /&gt;
==== Calculable ====&lt;br /&gt;
&lt;br /&gt;
Indicators and targets must implement this interface.&lt;br /&gt;
&lt;br /&gt;
It is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
To define what you want to predict (the target) and the subjects of these predictions (the samples) is the best way to start. You can find the descriptions of these concepts above.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simplier than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts)&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (not so important, just a default behaviour you can overwrite in your target)&lt;br /&gt;
&lt;br /&gt;
==== Create the target ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
Students at risk of dropping out (based on student&#039;s activity, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Late assignment submissions (based on student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; close to the analysable end date (1 week before, X days before...)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; assignment submissions (analysable elements are activities)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the assignment is open for submissions&lt;br /&gt;
** For training = past assignment due date&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on previous students activity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53145</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53145"/>
		<updated>2017-10-27T10:41:55Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Indicators */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
Analytics API allow Moodle sites managers to define prediction models that combine indicators and a target. The target is what we want to predict, the indicators is what we think that will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the predictions accuracy is good enough, Moodle internally trains a machine learning algorithm by calculating the defined indicators with the site data. Once new data that matches the criteria defined by the model is available Moodle starts predicting what is most likely to happen. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested on is prevention of students at risk of drop out: Lack of participation or bad grades in previous activities could be indicators, the target could be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predict which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows how the main components of the analytics API interact between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through. From the data any Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relations. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even same site courses can vary significantly. Moodle core should only include models that have been proven to be good at predicting in a wide range of sites and courses.&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases Moodle HQ research team is collecting anonymised Moodle site&#039;s datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with are obviously better at predicting on these institutions sites, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact Elizabeth Dalton at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
Definition for people not familiar with machine learning concepts: It is a process we need to run before being able to predict anything, we record what already happened so we can predict later what is likely to happen under the same circumstances. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for. We use Moodle sites data for it, a sample is a set of calculations we make using the site data. These samples are unrelated to testing data, phpunit and stuff like that and they are identified by an id. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on it. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. Further info in Analytics_API#Analyser as analyser classes define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above a prediction model is a combination of indicators and a target. Your system models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relation between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all models related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing tons of data to make more or less accurate predictions. There are obvious things different stakeholders may be interested in knowing that we can easily calculate. These *Static models* predictions are directly based on indicators calculations. They are based on the assumptions defined in the target but they should still be based on indicators so all these indicators can still be reused across different prediction models, therefore static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of static models:&lt;br /&gt;
* Courses without teaching activity&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
These cases are nothing new and we could be already generating notifications for the examples above but there are some benefits on doing it using Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related stuff.&lt;br /&gt;
* Analytics API tracks user actions after viewing the predictions, so we can know if insights derive in actions, which insights are not useful...&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible of creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the stuff, it contains a key abstract method though, &#039;&#039;get_all_samples()&#039;&#039;, this method is what defines what is a sample. A sample can be any moodle entity: a course, a user, an enrolment, a quiz attempt... Samples are nothing by themselves, just a list of ids with related data, they make sense once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser classes responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser there is an important non-obvious fact you should know about: For scalability reasons all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. We do it this way because depending on the sites&#039; size it could take hours to complete the analysis of all the site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses) or &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site)&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Target are the key element that defines the model. Targets are coded as PHP classes and they define what we want to predict and calculate it across the site. It also defines the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers because analysers provide them with the samples they need. Analysers are separate entities to targets because analysers can be reused across different targets. Each target needs to specify what analyser it is using. A few examples in case it is not clear the difference between analysers, samples and targets:&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;course student&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression but the machine learning backends included in core do not yet support multiclass classification nor regression so only binary classifications will be initially fully supported. See [https://tracker.moodle.org/browse/MDL-59044 MDL-59044] and [https://tracker.moodle.org/browse/MDL-60523 https://tracker.moodle.org/browse/MDL-60523] for more info.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction to directly use core targets in your own models it does not make much sense in most of the cases. One possible case would be to create a new 2 models using the same target and different sets of indicators.&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is the insights generation. Analysers samples always have a context, the context level (activity module, course, user...) depends on the sample but they always have a context, this context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction, in cases like &#039;&#039;Students at risk of dropping out&#039;&#039; the actions can be things like to send a message to the student, to view their course activity report...&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Also defined as PHP classes, their responsibility is quite simple, to calculate the indicator using the provided sample. Moodle core includes a set of indicators that can be used in your models without any PHP coding (unless you want to extend their functionality)&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to one single analyser like targets are, this makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and a &#039;&#039;user&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, the name of the indicator would change according to that: &#039;&#039;User posts in any forum&#039;&#039;, which could be used in models like &#039;&#039;Inactive users&#039;&#039; or &#039;&#039;Posts in any of the course forums&#039;&#039;, which could be used in models like &#039;&#039;Low participation courses&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This guarantees that we will not have indicators like &#039;&#039;absolute number of write actions&#039;&#039; because we will be forced to limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity.&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting methods is what defines when you will get predictions and the activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample, that is fine, things get more complicated when we want to predict what will happen in future. E.g. predictions about students at risk of dropping out are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations in time ranges is can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependant indicators to the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course in time ranges: in weeks, quarters, 8 parts, ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
They process the datasets generated from the calculated indicators and targets. They are a new plugin type with a common interface:&lt;br /&gt;
&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train a machine learning algorithm with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
The communication between prediction processors and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
Machine learning backends is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Extension points ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors.&lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
Moodle components (core subsystems, core plugins and 3rd party plugins) will be able to add and/or redefine any of the entities involved in all the data modeling process.&lt;br /&gt;
&lt;br /&gt;
Some of the base classes to extend or follow as example:&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
Basic interface to be implemented by machine learning backends, pretty useless by itself (continue reading below)&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support classification; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support regression; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
==== Analysable ====&lt;br /&gt;
&lt;br /&gt;
Analysable items are analysed by analysers :P In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element. e.g. an activity.&lt;br /&gt;
&lt;br /&gt;
Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;. They need to provide an id, a name, a &#039;&#039;&#039;\context&#039;&#039;&#039; and &#039;&#039;get_start()&#039;&#039; and &#039;&#039;get_end()&#039;&#039; methods. Read related comments above in [[#Analyser]].&lt;br /&gt;
&lt;br /&gt;
==== Calculable ====&lt;br /&gt;
&lt;br /&gt;
Indicators and targets must implement this interface.&lt;br /&gt;
&lt;br /&gt;
It is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
To define what you want to predict (the target) and the subjects of these predictions (the samples) is the best way to start. You can find the descriptions of these concepts above.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simplier than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts)&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (not so important, just a default behaviour you can overwrite in your target)&lt;br /&gt;
&lt;br /&gt;
==== Create the target ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to create your own indicators specific to the target you want to predict.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&amp;quot;&#039; to see the list of available indicators and add some of them to your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
Students at risk of dropping out (based on student&#039;s activity, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53144</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53144"/>
		<updated>2017-10-27T10:27:22Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
Analytics API allow Moodle sites managers to define prediction models that combine indicators and a target. The target is what we want to predict, the indicators is what we think that will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the predictions accuracy is good enough, Moodle internally trains a machine learning algorithm by calculating the defined indicators with the site data. Once new data that matches the criteria defined by the model is available Moodle starts predicting what is most likely to happen. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested on is prevention of students at risk of drop out: Lack of participation or bad grades in previous activities could be indicators, the target could be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predict which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows how the main components of the analytics API interact between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through. From the data any Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relations. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even same site courses can vary significantly. Moodle core should only include models that have been proven to be good at predicting in a wide range of sites and courses.&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases Moodle HQ research team is collecting anonymised Moodle site&#039;s datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with are obviously better at predicting on these institutions sites, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact Elizabeth Dalton at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
Definition for people not familiar with machine learning concepts: It is a process we need to run before being able to predict anything, we record what already happened so we can predict later what is likely to happen under the same circumstances. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for. We use Moodle sites data for it, a sample is a set of calculations we make using the site data. These samples are unrelated to testing data, phpunit and stuff like that and they are identified by an id. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on it. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. Further info in Analytics_API#Analyser as analyser classes define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above a prediction model is a combination of indicators and a target. Your system models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relation between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all models related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing tons of data to make more or less accurate predictions. There are obvious things different stakeholders may be interested in knowing that we can easily calculate. These *Static models* predictions are directly based on indicators calculations. They are based on the assumptions defined in the target but they should still be based on indicators so all these indicators can still be reused across different prediction models, therefore static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of static models:&lt;br /&gt;
* Courses without teaching activity&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
These cases are nothing new and we could be already generating notifications for the examples above but there are some benefits on doing it using Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related stuff.&lt;br /&gt;
* Analytics API tracks user actions after viewing the predictions, so we can know if insights derive in actions, which insights are not useful...&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible of creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the stuff, it contains a key abstract method though, &#039;&#039;get_all_samples()&#039;&#039;, this method is what defines what is a sample. A sample can be any moodle entity: a course, a user, an enrolment, a quiz attempt... Samples are nothing by themselves, just a list of ids with related data, they make sense once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser classes responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser there is an important non-obvious fact you should know about: For scalability reasons all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. We do it this way because depending on the sites&#039; size it could take hours to complete the analysis of all the site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses) or &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site)&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Target are the key element that defines the model. Targets are coded as PHP classes and they define what we want to predict and calculate it across the site. It also defines the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers because analysers provide them with the samples they need. Analysers are separate entities to targets because analysers can be reused across different targets. Each target needs to specify what analyser it is using. A few examples in case it is not clear the difference between analysers, samples and targets:&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;course student&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression but the machine learning backends included in core do not yet support multiclass classification nor regression so only binary classifications will be initially fully supported. See [https://tracker.moodle.org/browse/MDL-59044 MDL-59044] and [https://tracker.moodle.org/browse/MDL-60523 https://tracker.moodle.org/browse/MDL-60523] for more info.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction to directly use core targets in your own models it does not make much sense in most of the cases. One possible case would be to create a new 2 models using the same target and different sets of indicators.&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is the insights generation. Analysers samples always have a context, the context level (activity module, course, user...) depends on the sample but they always have a context, this context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction, in cases like &#039;&#039;Students at risk of dropping out&#039;&#039; the actions can be things like to send a message to the student, to view their course activity report...&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Also defined as PHP classes, their responsibility is quite simple, to calculate the indicator using the provided sample. Moodle core includes a set of indicators that can be used in your models without any PHP coding (unless you want to extend their functionality)&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to one single analyser like targets are, this makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and a &#039;&#039;user&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, the name of the indicator would change according to that: &#039;&#039;User posts in any forum&#039;&#039;, which could be used in models like &#039;&#039;Inactive users&#039;&#039; or &#039;&#039;Posts in any of the course forums&#039;&#039;, which could be used in models like &#039;&#039;Low participation courses&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This guarantees that we will not have indicators like &#039;&#039;absolute number of write actions&#039;&#039; because we will be forced to limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity.&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting methods is what defines when you will get predictions and the activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample, that is fine, things get more complicated when we want to predict what will happen in future. E.g. predictions about students at risk of dropping out are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations in time ranges is can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependant indicators to the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course in time ranges: in weeks, quarters, 8 parts, ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
They process the datasets generated from the calculated indicators and targets. They are a new plugin type with a common interface:&lt;br /&gt;
&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train a machine learning algorithm with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
The communication between prediction processors and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
Machine learning backends is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Extension points ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors.&lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
Moodle components (core subsystems, core plugins and 3rd party plugins) will be able to add and/or redefine any of the entities involved in all the data modeling process.&lt;br /&gt;
&lt;br /&gt;
Some of the base classes to extend or follow as example:&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
Basic interface to be implemented by machine learning backends, pretty useless by itself (continue reading below)&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support classification; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support regression; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
==== Analysable ====&lt;br /&gt;
&lt;br /&gt;
Analysable items are analysed by analysers :P In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element. e.g. an activity.&lt;br /&gt;
&lt;br /&gt;
Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;. They need to provide an id, a name, a &#039;&#039;&#039;\context&#039;&#039;&#039; and &#039;&#039;get_start()&#039;&#039; and &#039;&#039;get_end()&#039;&#039; methods. Read related comments above in [[#Analyser]].&lt;br /&gt;
&lt;br /&gt;
==== Calculable ====&lt;br /&gt;
&lt;br /&gt;
Indicators and targets must implement this interface.&lt;br /&gt;
&lt;br /&gt;
It is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
To define what you want to predict (the target) and the subjects of these predictions (the samples) is the best way to start. You can find the descriptions of these concepts above.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simplier than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s &#039;&#039;is_valid_sample()&#039;&#039; method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s &#039;&#039;is_valid_analysable()&#039;&#039; method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts)&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (not so important, just a default behaviour you can overwrite in your target)&lt;br /&gt;
&lt;br /&gt;
==== Create the target ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to add your own indicators.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;Analytic models&amp;quot; tool to see the list of indicators and edit your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
Students at risk of dropping out (based on student&#039;s activity, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53143</id>
		<title>Analytics API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_API&amp;diff=53143"/>
		<updated>2017-10-27T10:25:56Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
&lt;br /&gt;
Analytics API allow Moodle sites managers to define prediction models that combine indicators and a target. The target is what we want to predict, the indicators is what we think that will lead to an accurate prediction of the target. Moodle is able to evaluate these models and, if the predictions accuracy is good enough, Moodle internally trains a machine learning algorithm by calculating the defined indicators with the site data. Once new data that matches the criteria defined by the model is available Moodle starts predicting what is most likely to happen. Targets are free to define what actions will be performed for each prediction, from sending messages or feeding reports to building new adaptive learning activities.&lt;br /&gt;
&lt;br /&gt;
An obvious example of a model you may be interested on is prevention of students at risk of drop out: Lack of participation or bad grades in previous activities could be indicators, the target could be whether the student is able to complete the course or not. Moodle calculates these indicators and the target for each student in a finished course and predict which students are at risk of dropping out in ongoing courses.&lt;br /&gt;
&lt;br /&gt;
=== API components ===&lt;br /&gt;
&lt;br /&gt;
This diagram shows how the main components of the analytics API interact between them.&lt;br /&gt;
 &lt;br /&gt;
[[File:Inspire_API_components.png]]&lt;br /&gt;
&lt;br /&gt;
=== Data flow ===&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the different stages data goes through. From the data any Moodle site contains to actionable insights. &lt;br /&gt;
&lt;br /&gt;
[[File:Inspire_data_flow.png]]&lt;br /&gt;
&lt;br /&gt;
=== API classes diagram ===&lt;br /&gt;
&lt;br /&gt;
This is a summary of the API classes and their relations. It groups the different parts of the framework that can be extended by 3rd parties to create your own prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:Analytics_API_classes_diagram_(summary).svg]]&lt;br /&gt;
&lt;br /&gt;
(Click on the image to expand, it is an SVG)&lt;br /&gt;
&lt;br /&gt;
== Built-in models ==&lt;br /&gt;
&lt;br /&gt;
People use Moodle in very different ways and even same site courses can vary significantly. Moodle core should only include models that have been proven to be good at predicting in a wide range of sites and courses.&lt;br /&gt;
&lt;br /&gt;
To diversify the samples and to cover a wider range of cases Moodle HQ research team is collecting anonymised Moodle site&#039;s datasets from collaborating institutions and partners to train the machine learning algorithms with them. The models that Moodle is shipped with are obviously better at predicting on these institutions sites, although some other datasets are used as test data for the machine learning algorithm to ensure that the models are good enough to predict accurately in any Moodle site. If you are interested in collaborating please contact Elizabeth Dalton at [[mailto:elizabeth@moodle.com elizabeth@moodle.com]] to get information about the process.&lt;br /&gt;
&lt;br /&gt;
Even if the models we include in Moodle core are already trained by Moodle HQ, each different site will continue training that site machine learning algorithms with its own data, which should lead to better prediction accuracy over time.&lt;br /&gt;
&lt;br /&gt;
== Concepts == &lt;br /&gt;
&lt;br /&gt;
=== Training ===&lt;br /&gt;
&lt;br /&gt;
Definition for people not familiar with machine learning concepts: It is a process we need to run before being able to predict anything, we record what already happened so we can predict later what is likely to happen under the same circumstances. What we train are machine learning algorithms.&lt;br /&gt;
&lt;br /&gt;
=== Samples ===&lt;br /&gt;
&lt;br /&gt;
The machine learning backends we use to make predictions need to know what sort of patterns to look for. We use Moodle sites data for it, a sample is a set of calculations we make using the site data. These samples are unrelated to testing data, phpunit and stuff like that and they are identified by an id. The id of a sample can be any Moodle entity id: a course, a user, an enrolment, a quiz attempt, etc. and the calculations the sample contains depend on it. Each type of Moodle entity used as a sample helps develop the predictions that involve that kind of entity. For example, samples based on Quiz attempts will help develop the potential insights that the analytics might offer that are related to the Quiz attempts by a particular group of students. Further info in Analytics_API#Analyser as analyser classes define what is a sample.&lt;br /&gt;
&lt;br /&gt;
=== Prediction model ===&lt;br /&gt;
&lt;br /&gt;
As explained above a prediction model is a combination of indicators and a target. Your system models can be viewed in &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The relation between indicators and targets is stored in &#039;&#039;analytics_models&#039;&#039; database table.&lt;br /&gt;
&lt;br /&gt;
The class &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; manages all models related actions. &#039;&#039;evaluate()&#039;&#039;, &#039;&#039;train()&#039;&#039; and &#039;&#039;predict()&#039;&#039; forward the calculated indicators to the machine learning backends. &#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; delegates all heavy processing to analysers and machine learning backends. It also manages prediction models evaluation logs.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;\core_analytics\model&#039;&#039;&#039; class is not expected to be extended.&lt;br /&gt;
&lt;br /&gt;
==== Static models ====&lt;br /&gt;
&lt;br /&gt;
Some prediction models do not need a powerful machine learning algorithm behind them processing tons of data to make more or less accurate predictions. There are obvious things different stakeholders may be interested in knowing that we can easily calculate. These *Static models* predictions are directly based on indicators calculations. They are based on the assumptions defined in the target but they should still be based on indicators so all these indicators can still be reused across different prediction models, therefore static models are not editable through &#039;&#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039;&#039; user interface.&lt;br /&gt;
&lt;br /&gt;
Some examples of static models:&lt;br /&gt;
* Courses without teaching activity&lt;br /&gt;
* Courses with students submissions requiring attention and no teachers accessing the course&lt;br /&gt;
* Courses that started 1 month ago and never accessed by anyone&lt;br /&gt;
* Students that have never logged into the system&lt;br /&gt;
* ....&lt;br /&gt;
&lt;br /&gt;
These cases are nothing new and we could be already generating notifications for the examples above but there are some benefits on doing it using Moodle analytics API:&lt;br /&gt;
* Everything is easier and faster to code from a dev point of view as analytics subsystem provides APIs for everything&lt;br /&gt;
* New Indicators will be part of the core indicators pool that researchers (and 3rd party developers in general) can reuse in their own models&lt;br /&gt;
* Existing core indicators can be reused as well (the same indicators used for insights that depend on machine learning backends)&lt;br /&gt;
* Notifications are displayed using the core insights system, which is also responsible of sending the notifications and all related stuff.&lt;br /&gt;
* Analytics API tracks user actions after viewing the predictions, so we can know if insights derive in actions, which insights are not useful...&lt;br /&gt;
&lt;br /&gt;
=== Analyser ===&lt;br /&gt;
&lt;br /&gt;
Analysers are responsible of creating the dataset files that will be sent to the machine learning processors. They are coded as PHP classes. Moodle core includes some analysers you can use in your models.&lt;br /&gt;
&lt;br /&gt;
The base class &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039; does most of the stuff, it contains a key abstract method though, &#039;&#039;get_all_samples()&#039;&#039;, this method is what defines what is a sample. A sample can be any moodle entity: a course, a user, an enrolment, a quiz attempt... Samples are nothing by themselves, just a list of ids with related data, they make sense once they are combined with the target and the indicator classes.&lt;br /&gt;
&lt;br /&gt;
Other analyser classes responsibilities:&lt;br /&gt;
* Define the context of the predictions&lt;br /&gt;
* Discard invalid data&lt;br /&gt;
* Filter out already trained samples&lt;br /&gt;
* Include the time factor (time range processors, explained below)&lt;br /&gt;
* Forward calculations to indicators and target classes&lt;br /&gt;
* Record all calculations in a file&lt;br /&gt;
* Record all analysed sample ids in the database&lt;br /&gt;
&lt;br /&gt;
If you are introducing a new analyser there is an important non-obvious fact you should know about: For scalability reasons all calculations at course level are executed in per-course basis and the resulting datasets are merged together once all site courses analysis is complete. We do it this way because depending on the sites&#039; size it could take hours to complete the analysis of all the site. This is a good way to break the process up into pieces. When coding a new analyser you need to decide if you want to extend &#039;&#039;&#039;\core_analytics\local\analyser\by_course&#039;&#039;&#039; (your analyser will process a list of courses) or &#039;&#039;&#039;\core_analytics\local\analyser\sitewide&#039;&#039;&#039; (your analyser will receive just one analysable element, the site)&lt;br /&gt;
&lt;br /&gt;
=== Target ===&lt;br /&gt;
&lt;br /&gt;
Target are the key element that defines the model. Targets are coded as PHP classes and they define what we want to predict and calculate it across the site. It also defines the actions to perform depending on the received predictions.&lt;br /&gt;
&lt;br /&gt;
Targets depend on analysers because analysers provide them with the samples they need. Analysers are separate entities to targets because analysers can be reused across different targets. Each target needs to specify what analyser it is using. A few examples in case it is not clear the difference between analysers, samples and targets:&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;students at risk of dropping out&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;course student&#039; &lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;spammer&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;site users&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;ineffective course&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;courses&#039;&lt;br /&gt;
* &#039;&#039;&#039;Target&#039;&#039;&#039;: &#039;difficulties to pass a specific quiz&#039;. &#039;&#039;&#039;Analyser provides&#039;&#039;&#039;: &#039;quiz attempts in a specific quiz&#039;&lt;br /&gt;
&lt;br /&gt;
A callback defined by the target will be executed once new predictions start coming so each target have control over the prediction results.&lt;br /&gt;
&lt;br /&gt;
The API supports binary classification, multiclass classification and regression but the machine learning backends included in core do not yet support multiclass classification nor regression so only binary classifications will be initially fully supported. See [https://tracker.moodle.org/browse/MDL-59044 MDL-59044] and [https://tracker.moodle.org/browse/MDL-60523 https://tracker.moodle.org/browse/MDL-60523] for more info.&lt;br /&gt;
&lt;br /&gt;
Although there is no technical restriction to directly use core targets in your own models it does not make much sense in most of the cases. One possible case would be to create a new 2 models using the same target and different sets of indicators.&lt;br /&gt;
&lt;br /&gt;
==== Insights ====&lt;br /&gt;
&lt;br /&gt;
Another aspect controlled by targets is the insights generation. Analysers samples always have a context, the context level (activity module, course, user...) depends on the sample but they always have a context, this context will be used to notify users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability (teacher role by default) about new insights being available. These users will receive a notification with a link to the predictions page where all predictions of that context are listed.&lt;br /&gt;
&lt;br /&gt;
A set of suggested actions will be available for each prediction, in cases like &#039;&#039;Students at risk of dropping out&#039;&#039; the actions can be things like to send a message to the student, to view their course activity report...&lt;br /&gt;
&lt;br /&gt;
=== Indicator ===&lt;br /&gt;
&lt;br /&gt;
Also defined as PHP classes, their responsibility is quite simple, to calculate the indicator using the provided sample. Moodle core includes a set of indicators that can be used in your models without any PHP coding (unless you want to extend their functionality)&lt;br /&gt;
&lt;br /&gt;
Indicators are not limited to one single analyser like targets are, this makes indicators easier to reuse in different models. Indicators specify a minimum set of data they need to perform the calculation. The indicator developer should also make an effort to imagine how the indicator will work when different analysers are used. For example an indicator named &#039;&#039;Posts in any forum&#039;&#039; could be initially coded for a &#039;&#039;Shy students in a course&#039;&#039; target; this target would use &#039;&#039;course enrolments&#039;&#039; analyser, so the indicator developer knows that a &#039;&#039;course&#039;&#039; and a &#039;&#039;user&#039;&#039; will be provided by that analyser, but this indicator can be easily coded so the indicator can be reused by other analysers like &#039;&#039;courses&#039;&#039; or &#039;&#039;users&#039;. In this case the developer can chose to require &#039;&#039;course&#039;&#039; &#039;&#039;&#039;or&#039;&#039;&#039; &#039;&#039;user&#039;&#039;, the name of the indicator would change according to that: &#039;&#039;User posts in any forum&#039;&#039;, which could be used in models like &#039;&#039;Inactive users&#039;&#039; or &#039;&#039;Posts in any of the course forums&#039;&#039;, which could be used in models like &#039;&#039;Low participation courses&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The calculated value can go from -1 (minimum) to 1 (maximum). This guarantees that we will not have indicators like &#039;&#039;absolute number of write actions&#039;&#039; because we will be forced to limit the calculation to a range, e.g. -1 = 0 actions, -0.33 = some basic activity, 0.33 = activity, 1 = plenty of activity.&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
A time splitting methods is what defines when you will get predictions and the activity logs that will be considered for those predictions. They are coded as PHP classes and Moodle core includes some time splitting methods you can use in your models.&lt;br /&gt;
&lt;br /&gt;
In some cases the time factor is not important and we just want to classify a sample, that is fine, things get more complicated when we want to predict what will happen in future. E.g. predictions about students at risk of dropping out are not useful once the course is over or when it is too late for any intervention.&lt;br /&gt;
&lt;br /&gt;
Calculations in time ranges is can be a challenging aspect of some prediction models. Indicators need to be designed with this in mind and we need to include time-dependant indicators to the calculated indicators so machine learning algorithms are smart enough to avoid mixing calculations belonging to the beginning of the course with calculations belonging to the end of the course.&lt;br /&gt;
&lt;br /&gt;
There are many different ways to split up a course in time ranges: in weeks, quarters, 8 parts, ranges with longer periods at the beginning and shorter periods at the end... And the ranges can be accumulative (from the beginning of the course) or only from the start of the time range.&lt;br /&gt;
&lt;br /&gt;
=== Machine learning backends ===&lt;br /&gt;
&lt;br /&gt;
They process the datasets generated from the calculated indicators and targets. They are a new plugin type with a common interface:&lt;br /&gt;
&lt;br /&gt;
* Evaluate a provided prediction model&lt;br /&gt;
* Train a machine learning algorithm with the existing site data&lt;br /&gt;
* Predict targets based on previously trained algorithms&lt;br /&gt;
&lt;br /&gt;
The communication between prediction processors and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.&lt;br /&gt;
&lt;br /&gt;
== Design ==&lt;br /&gt;
&lt;br /&gt;
The system is designed as a Moodle subsystem and API. It lives in &#039;&#039;&#039;analytics/&#039;&#039;&#039;. All analytics base classes are located here.&lt;br /&gt;
&lt;br /&gt;
Machine learning backends is a new Moodle plugin type. They are stored in &#039;&#039;&#039;lib/mlbackend&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Uses of the analytics API are located in different Moodle components, being core (&#039;&#039;&#039;lib/classes/analytics&#039;&#039;&#039;) the component that hosts general purpose uses of the API.&lt;br /&gt;
&lt;br /&gt;
=== Extension points ===&lt;br /&gt;
&lt;br /&gt;
This API aims to be as extendable as possible. Any moodle component, including third party plugins, is be able to define indicators, targets, analysers and time splitting processors.&lt;br /&gt;
&lt;br /&gt;
An example of a possible extension would be a plugin with indicators that fetch student academic records from the Universities&#039; student information system; the site admin could build a new model on top of the built-in &#039;students at risk of drop out detection&#039; adding the SIS indicators to improve the model accuracy or for research purposes.&lt;br /&gt;
&lt;br /&gt;
Moodle components (core subsystems, core plugins and 3rd party plugins) will be able to add and/or redefine any of the entities involved in all the data modeling process.&lt;br /&gt;
&lt;br /&gt;
Some of the base classes to extend or follow as example:&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\analyser\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\time_splitting\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Interfaces ===&lt;br /&gt;
&lt;br /&gt;
==== Predictor ====&lt;br /&gt;
&lt;br /&gt;
Basic interface to be implemented by machine learning backends, pretty useless by itself (continue reading below)&lt;br /&gt;
&lt;br /&gt;
===== Classifier =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support classification; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
===== Regressor =====&lt;br /&gt;
&lt;br /&gt;
Interface to be implemented by machine learning backends that support regression; it includes methods to train, predict and evaluate datasets. It extends &#039;&#039;Predictor&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
==== Analysable ====&lt;br /&gt;
&lt;br /&gt;
Analysable items are analysed by analysers :P In most of the cases an analysable will be a course, although it can also be the site or any other Moodle element. e.g. an activity.&lt;br /&gt;
&lt;br /&gt;
Moodle core include two analysers &#039;&#039;&#039;\core_analytics\course&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\site&#039;&#039;&#039;. They need to provide an id, a name, a \context and get_start() and get_end() methods. Read related comments above in [[#Analyser]].&lt;br /&gt;
&lt;br /&gt;
==== Calculable ====&lt;br /&gt;
&lt;br /&gt;
Indicators and targets must implement this interface.&lt;br /&gt;
&lt;br /&gt;
It is already implemented by &#039;&#039;&#039;\core_analytics\local\indicator\base&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; but you can still code targets or indicators from the &#039;&#039;&#039;\core_analytics\calculable&#039;&#039;&#039; base if you need more control.&lt;br /&gt;
&lt;br /&gt;
== How to create a model ==&lt;br /&gt;
&lt;br /&gt;
=== Define the problem ===&lt;br /&gt;
&lt;br /&gt;
To define what you want to predict (the target) and the subjects of these predictions (the samples) is the best way to start. You can find the descriptions of these concepts above.&lt;br /&gt;
&lt;br /&gt;
=== How many predictions for each sample? ===&lt;br /&gt;
&lt;br /&gt;
The next decision should be how many predictions you want to get for each sample (e.g. just one prediction before the course starts or a prediction every week). A single prediction for each sample is simplier than multiple predictions at different points in time in terms of how deep into the API you will need to go to code it.&lt;br /&gt;
&lt;br /&gt;
These are not absolute statements, but in general:&lt;br /&gt;
* If you want a single prediction for each sample at a specific point in time you can reuse a sitewide analyser or define your own and control samples validity through your target&#039;s is_valid_sample() method.&lt;br /&gt;
* If you want multiple predictions at different points in time for each sample reuse an analysable element or define your own (extending &#039;&#039;&#039;\core_analytics\analysable&#039;&#039;&#039;) and reuse or define your own analyser to retrieve these analysable elements. You can control analysers validity through your target&#039;s is_valid_analysable() method.&lt;br /&gt;
* If you want predictions at activity level use a &amp;quot;by_course&amp;quot; analyser as otherwise you may have scalability problems (imagine storing in memory calculations for each grade_grades record in your site, processing elements by courses help as we clean memory after each course is processed) &lt;br /&gt;
&lt;br /&gt;
This decision is important because:&lt;br /&gt;
* Time splitting methods are applied to analysable time start and time end (e.g. &#039;&#039;&#039;Quarters&#039;&#039;&#039; can split the duration of a course in 4 parts)&lt;br /&gt;
* Prediction results are grouped by analysable in the admin interface to list predictions.&lt;br /&gt;
* By default, insights are notified to users with &#039;&#039;&#039;moodle/analytics:listinsights&#039;&#039;&#039; capability at analysable level (not so important, just a default behaviour you can overwrite in your target)&lt;br /&gt;
&lt;br /&gt;
==== Create the target ====&lt;br /&gt;
&lt;br /&gt;
Targets must extend &#039;&#039;&#039;\core_analytics\local\target\base&#039;&#039;&#039; or its main child class &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;. Even if Moodle core includes &#039;&#039;&#039;\core_analytics\local\target\discrete&#039;&#039;&#039; and &#039;&#039;&#039;\core_analytics\local\target\linear&#039;&#039;&#039; Moodle 3.4 machine learning backends only support binary classifications. So unless you are using your own machine learning backend you need to extend &#039;&#039;&#039;\core_analytics\local\target\binary&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To be completed...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Indicators ===&lt;br /&gt;
&lt;br /&gt;
You already know the analyser your target needs (the analyser is what provides samples) and, more or less, what time splitting method may be better for you. You can now select a list of indicators that you think will lead to accurate predictions. You may need to add your own indicators.&lt;br /&gt;
&lt;br /&gt;
You can use &amp;quot;Analytic models&amp;quot; tool to see the list of indicators and edit your model.&lt;br /&gt;
&lt;br /&gt;
== API usage examples ==&lt;br /&gt;
&lt;br /&gt;
This is a list of prediction models and how they could be coded using the Analytics API:&lt;br /&gt;
&lt;br /&gt;
Students at risk of dropping out (based on student&#039;s activity, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles, deciles accumulative... &lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing courses&lt;br /&gt;
** For training = finished courses with activity&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on finished courses data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Not engaging course contents (based on the course contents)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = the course is close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, a simple look at the course activities should be enough (e.g. are the course activities engaging?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No teaching (courses close to the start date without a teacher assigned, included in Moodle 3.4)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; courses (the analysable elements is the site) it would also work using course as analysable&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = course close to the start date&lt;br /&gt;
** For training = no training&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: yes, just check if there are teachers&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Spam users (based on suspicious activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; 2 parts, one after 4h since user creation and another one after 2 days (just an example)&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; users (analysable elements are users)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = 4h or 2 days passed since the user was created&lt;br /&gt;
** For training = 2 days passed since the user was created (spammer flag somewhere recorded to calculate target = 1, otherwise no spammer)&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, predictions should be based on users activity logs, although this could also be done as a static model&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Students having a bad time&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters accumulative or deciles accumulative&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student enrolments (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing and course activity&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, ideally it should be based on previous cases&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Course not engaging for students (checking student&#039;s activity)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; quarters, quarters accumulative, deciles...&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; course (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039; = true&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course&lt;br /&gt;
** For training = finished courses&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it should be based on activity logs&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Student will fail a quiz (based on things like other students quiz attempts, the student in other activities, number of attempts to pass the quiz...)&lt;br /&gt;
* &#039;&#039;&#039;Time splitting:&#039;&#039;&#039; single range&lt;br /&gt;
* &#039;&#039;&#039;Analyser samples:&#039;&#039;&#039; student grade on an activity, aka grade_grades id (analysable elements are courses)&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_analysable&#039;&#039;&#039;&lt;br /&gt;
** For prediction = ongoing course with quizzes&lt;br /&gt;
** For training = ongoing course with quizzes&lt;br /&gt;
* &#039;&#039;&#039;target::is_valid_sample&#039;&#039;&#039;&lt;br /&gt;
** For prediction = more than the X% of the course students attempted the quiz and the sample (a student) has not attempted it yet&lt;br /&gt;
** For training = the student has attempted the quiz at least X times (X because if after X attempts has not passed counts as failed) or the student passed the quiz&lt;br /&gt;
* &#039;&#039;&#039;Based on assumptions (static)&#039;&#039;&#039;: no, it is based on previous students records&lt;br /&gt;
&lt;br /&gt;
== Clustered environments ==&lt;br /&gt;
&lt;br /&gt;
&#039;analytics/outputdir&#039; setting can be used by Moodle sites with multiple frontend nodes to specify a shared directory across nodes. This directory can be used by machine learning backends to store trained algorithms (its internal variables weights and stuff like that) to use them later to get predictions. Moodle cron lock will prevent multiple executions of the analytics tasks that train machine learning algorithms and get predictions from them.&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_models&amp;diff=52995</id>
		<title>Analytics models</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_models&amp;diff=52995"/>
		<updated>2017-10-11T10:05:12Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Settings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes the Analytics models tool used to visualise, manage and evaluate prediction models.&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
&lt;br /&gt;
You can access &#039;&#039;Analytics settings&#039;&#039; from &#039;&#039;Site administration &amp;gt; Analytics &amp;gt; Analytics settings&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Predictions processor ===&lt;br /&gt;
&lt;br /&gt;
Prediction processors are the machine learning backends that process the datasets generated from the calculated indicators and targets and return predictions. This plugin is shipped with 2 prediction processors:&lt;br /&gt;
&lt;br /&gt;
* The PHP one is the default&lt;br /&gt;
* The Python one is more powerful and it generates graphs with the model performance but it requires setting up extra stuff like Python itself (https://wiki.python.org/moin/BeginnersGuide/Download) and the moodlemlbackend package.&lt;br /&gt;
&lt;br /&gt;
    pip install moodlemlbackend&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
The time splitting method divides the course duration in parts, the predictions engine will run at the end of these parts. It is recommended that you only enable the time splitting methods you could be interested on using; the site contents analyser will calculate all indicators using each of the enabled time splitting methods. The more enabled time splitting methods the slower the evaluation process will be.&lt;br /&gt;
&lt;br /&gt;
== Models management ==&lt;br /&gt;
&lt;br /&gt;
You can access the tool from &#039;&#039;Site Administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039; to see the list of prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:prediction-models-list.jpeg]]&lt;br /&gt;
&lt;br /&gt;
These are some of the actions you can perform on a model:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;Edit:&#039;&#039; You can edit the models by modifying the list of indicators or the time-splitting method. All previous predictions will be deleted when a model is modified. Models based on assumptions (static models) can not be edited.&lt;br /&gt;
* &#039;&#039;Enable / Disable:&#039;&#039; The scheduled task that trains machine learning algorithms with the new data available on the system and gets predictions for ongoing courses skips disabled models. Previous predictions generated by disabled models are not available until the model is enabled again.&lt;br /&gt;
* &#039;&#039;Evaluate:&#039;&#039; Evaluate the prediction model by getting all the training data available on the site, calculating all the indicators and the target and passing the resulting dataset to machine learning backends, they will split the dataset into training data and testing data and calculate its accuracy. Note that the evaluation process use all information available on the site, even if it is very old, the accuracy returned by the evaluation process will generally be lower than the real model accuracy as indicators are more reliably calculated straight after training data is available because the site state changes along time. The metric used as accuracy is the &#039;&#039;Matthew’s correlation coefficient&#039;&#039; (good metric for binary classifications)&lt;br /&gt;
* &#039;&#039;Log:&#039;&#039; View previous evaluations log, including the model accuracy as well as other technical information generated by the machine learning backends like ROC curves, learning curves graphs, the tensorboard log dir or the model&#039;s Matthew’s correlation coefficient. The information available will depend on the machine learning backend in use.&lt;br /&gt;
* &#039;&#039;Get predictions:&#039;&#039; Train machine learning algorithms with the new data available on the system and get predictions for ongoing courses. &#039;&#039;Predictions are not limited to ongoing courses, this depends on the model.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:model-evaluation.jpeg]]&lt;br /&gt;
&lt;br /&gt;
== Predictions and Insights ==&lt;br /&gt;
&lt;br /&gt;
Models will start generating predictions at different point in time, depending on the site prediction models and the site courses start and end dates. &lt;br /&gt;
&lt;br /&gt;
Each model defines which predictions will generate insights and which predictions will be ignored. This is an example of &#039;&#039;Students at risk of dropping out&#039;&#039; prediction model; if a student is predicted as not at risk no insight is generated as what is interesting is to know which students are at risk of dropping out of courses, not which students are not at risk.&lt;br /&gt;
&lt;br /&gt;
[[File:prediction-model-insights.jpeg]]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Analytics_models&amp;diff=52994</id>
		<title>Analytics models</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Analytics_models&amp;diff=52994"/>
		<updated>2017-10-11T10:04:57Z</updated>

		<summary type="html">&lt;p&gt;Dmonllao: /* Models management */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes the Analytics models tool used to visualise, manage and evaluate prediction models.&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
&lt;br /&gt;
You can access &#039;&#039;Analytics settings&#039;&#039; from &#039;&#039;Site administration &amp;gt; Appearance &amp;gt; Analytics settings&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Predictions processor ===&lt;br /&gt;
&lt;br /&gt;
Prediction processors are the machine learning backends that process the datasets generated from the calculated indicators and targets and return predictions. This plugin is shipped with 2 prediction processors:&lt;br /&gt;
&lt;br /&gt;
* The PHP one is the default&lt;br /&gt;
* The Python one is more powerful and it generates graphs with the model performance but it requires setting up extra stuff like Python itself (https://wiki.python.org/moin/BeginnersGuide/Download) and the moodlemlbackend package.&lt;br /&gt;
&lt;br /&gt;
    pip install moodlemlbackend&lt;br /&gt;
&lt;br /&gt;
=== Time splitting methods ===&lt;br /&gt;
&lt;br /&gt;
The time splitting method divides the course duration in parts, the predictions engine will run at the end of these parts. It is recommended that you only enable the time splitting methods you could be interested on using; the site contents analyser will calculate all indicators using each of the enabled time splitting methods. The more enabled time splitting methods the slower the evaluation process will be.&lt;br /&gt;
&lt;br /&gt;
== Models management ==&lt;br /&gt;
&lt;br /&gt;
You can access the tool from &#039;&#039;Site Administration &amp;gt; Analytics &amp;gt; Analytics models&#039;&#039; to see the list of prediction models.&lt;br /&gt;
&lt;br /&gt;
[[File:prediction-models-list.jpeg]]&lt;br /&gt;
&lt;br /&gt;
These are some of the actions you can perform on a model:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;Edit:&#039;&#039; You can edit the models by modifying the list of indicators or the time-splitting method. All previous predictions will be deleted when a model is modified. Models based on assumptions (static models) can not be edited.&lt;br /&gt;
* &#039;&#039;Enable / Disable:&#039;&#039; The scheduled task that trains machine learning algorithms with the new data available on the system and gets predictions for ongoing courses skips disabled models. Previous predictions generated by disabled models are not available until the model is enabled again.&lt;br /&gt;
* &#039;&#039;Evaluate:&#039;&#039; Evaluate the prediction model by getting all the training data available on the site, calculating all the indicators and the target and passing the resulting dataset to machine learning backends, they will split the dataset into training data and testing data and calculate its accuracy. Note that the evaluation process use all information available on the site, even if it is very old, the accuracy returned by the evaluation process will generally be lower than the real model accuracy as indicators are more reliably calculated straight after training data is available because the site state changes along time. The metric used as accuracy is the &#039;&#039;Matthew’s correlation coefficient&#039;&#039; (good metric for binary classifications)&lt;br /&gt;
* &#039;&#039;Log:&#039;&#039; View previous evaluations log, including the model accuracy as well as other technical information generated by the machine learning backends like ROC curves, learning curves graphs, the tensorboard log dir or the model&#039;s Matthew’s correlation coefficient. The information available will depend on the machine learning backend in use.&lt;br /&gt;
* &#039;&#039;Get predictions:&#039;&#039; Train machine learning algorithms with the new data available on the system and get predictions for ongoing courses. &#039;&#039;Predictions are not limited to ongoing courses, this depends on the model.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:model-evaluation.jpeg]]&lt;br /&gt;
&lt;br /&gt;
== Predictions and Insights ==&lt;br /&gt;
&lt;br /&gt;
Models will start generating predictions at different point in time, depending on the site prediction models and the site courses start and end dates. &lt;br /&gt;
&lt;br /&gt;
Each model defines which predictions will generate insights and which predictions will be ignored. This is an example of &#039;&#039;Students at risk of dropping out&#039;&#039; prediction model; if a student is predicted as not at risk no insight is generated as what is interesting is to know which students are at risk of dropping out of courses, not which students are not at risk.&lt;br /&gt;
&lt;br /&gt;
[[File:prediction-model-insights.jpeg]]&lt;/div&gt;</summary>
		<author><name>Dmonllao</name></author>
	</entry>
</feed>