Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Recommender system specification: Difference between revisions

From MoodleDocs
(Created page with "This is a proposal for a [https://en.wikipedia.org/wiki/Recommender_system recommender system] in Moodle. A recommender system ''"seeks to predict the "rating" or "preference"...")
 
No edit summary
Line 62: Line 62:
namespace \core_course\analytics\recommender;
namespace \core_course\analytics\recommender;
class activity extends \core_analytics\recommender_dimension {
class activity extends \core_analytics\recommender_dimension {
    private $acceptedfilters = ['modulename', 'coursecategory'];


     public function get_items(array $filters) {
     public function get_items(array $filters) {
        // This is not real code, it is just to get the idea.
         // The context filtering would not make sense applied to context module if what we want is a list of activities.
         // The context filtering would not make sense applied to context module if
        // what we want is a list of activities.
         return $DB->get_recordset_sql("SELECT cm.*, c.* FROM {course_modules} cm
         return $DB->get_recordset_sql("SELECT cm.*, c.* FROM {course_modules} cm
                                         JOIN {course} c on cm.course = c.id
                                         JOIN {course} c on cm.course = c.id
                                         JOIN {context} ctx ON ctx.contextlevel = CONTEXT_COURSE AND ctx.instanceid = c.id
                                         JOIN {context} ctx ON ctx.contextlevel = CONTEXT_COURSE AND ctx.instanceid = c.id
                                         WHERE ctx.id IN $contexts");
                                         WHERE ctx.id IN $contexts AND modulename = $filters['modulename']");
     }
     }
}
}
Line 77: Line 77:
class user extends \core_analytics\recommender_dimension {
class user extends \core_analytics\recommender_dimension {


     public function get_items(array $contexts) {
     public function get_items(array $filters) {
       // $contexts is ignored as users depend on the system context.
       // $contexts is ignored as users depend on the system context.
         return $DB->get_recordset_sql("SELECT * FROM {user}");
         return $DB->get_recordset_sql("SELECT * FROM {user}");
Line 93: Line 93:
     }
     }


     public function recommend($yitem, $nrecommendations = 1) {
     public function recommend($yid, $nrecommendations = 1) {
         // Collaborative filtering or any other alternative.
        $trainingdata = $dataset->get_training_data();
 
         // Collaborative filtering or any other alternative. This is just an example.
        $model = $this->get_embeddings($trainingdata);
 
        $y = $trainingdata[$yid];
        return $model->recommend($y, $nrecommendations);
     }
     }
}
}
</code>
</code>

Revision as of 15:27, 7 May 2019

This is a proposal for a recommender system in Moodle. A recommender system "seeks to predict the "rating" or "preference" a user would give to an item.", in other words, it tries to identify items that would be interesting for a user.

This code snippet below is an example using the proposed public API. This generates two recommended activities of type page for the user with id 111 in the course with id 222 based on the values in an hypothetical user_activity_rates table. The recommender system should only consider users whose city is Barcelona.

// The 'contexts' filter is used to restrict the recommender system to a specific set of contexts. It can be used to restrict a recommender // system to the activities of a single course or to restrict a recommender system to the entries of a single glossary activity. // The filters in 'dimensions' are applied to each of the dimensions used by the recommender system. $coursecontext = \context_course::instance(222); $filters = [

   'contexts' => [$coursecontext->id],
   'dimensions' => [
       'user' => ['city' => 'Barcelona'],
       'activity' => ['modulename' => 'page']
   ]

];

$dataset = new \core_course\analytics\recommender\dataset\activities($filters);

$recommender = \core_analytics\recommender($dataset); $recommendations = $recommender->recommend(111, 2);

This is an overview of the classes involved.

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 recommender_dataset class are responsible of instantiating their dimensions and to fill the two-dimensional matrix.

We could replace x and y for items and users if we can not find use cases that do not directly involve users.

Example of a recommender_dataset class.

namespace \core_course\analytics\recommender\dataset; class activities implements \core_analytics\recommender_dataset {

   public function __construct(array $filters) {
       $this->filters = $filters;
       $this->x = new \core_course\analytics\recommender\dimension\activity();
       $this->y = new \core_user\analytics\recommender\dimension\user();
   }
   public function get_training_data() {
       $courseids = $this->get_course_ids_from_context_filter();
       $activityrates = $DB->get_records("SELECT * FROM {user_activity_rates} where courseid IN $courseids");
       $xitems = $this->x->get_items($this->filters);
       $yitems = $this->y->get_items($this->filters);
       // Iterate through both $xitems and $yitems filling $trainingdata two-dimensional array with $activityrates values.
       return $trainingdata;
   }

}

Classes like user' or activity that extend the base class recommender_dimension represent each of dimensions in the two-dimensional matrix. They basically return the list of records used by the implementation of the recommender_dataset class. They are separated from the recommender_dataset class for re-usability in different recommender systems.

We can remove this recommender_dataset - recommender_dimension separation if we don't find enough use cases that justify the separation.

These implementations serve as example of recommender_dimension classes. namespace \core_course\analytics\recommender; class activity extends \core_analytics\recommender_dimension {

   private $acceptedfilters = ['modulename', 'coursecategory'];
   public function get_items(array $filters) {
       // The context filtering would not make sense applied to context module if what we want is a list of activities.
       return $DB->get_recordset_sql("SELECT cm.*, c.* FROM {course_modules} cm
                                        JOIN {course} c on cm.course = c.id
                                        JOIN {context} ctx ON ctx.contextlevel = CONTEXT_COURSE AND ctx.instanceid = c.id
                                       WHERE ctx.id IN $contexts AND modulename = $filters['modulename']");
   }

}

namespace \core_user\analytics\recommender; class user extends \core_analytics\recommender_dimension {

   public function get_items(array $filters) {
      // $contexts is ignored as users depend on the system context.
       return $DB->get_recordset_sql("SELECT * FROM {user}");
   }

}

This is the recommender class skeleton. namespace \core_analytics; class recommender {

   public function __construct(\core_analytics\recommender_dataset $dataset) {
       $this->dataset = $dataset;
   }
   public function recommend($yid, $nrecommendations = 1) {
       $trainingdata = $dataset->get_training_data();
       // Collaborative filtering or any other alternative. This is just an example.
       $model = $this->get_embeddings($trainingdata);
       $y = $trainingdata[$yid];
       return $model->recommend($y, $nrecommendations);
   }

}