protected function CorrelationRecommender::computePredictionMemory in Recommender API 6.2
Overrides Recommender::computePredictionMemory
2 calls to CorrelationRecommender::computePredictionMemory()
1 method overrides CorrelationRecommender::computePredictionMemory()
File
- ./
Recommender.php, line 530
Class
- CorrelationRecommender
- The recommender implementation for the classical correlation-coefficient based algorithm
Code
protected function computePredictionMemory() {
// we do the computation based on $this->directMatrix loaded in memory, not on database
$this->mouseVectors = $this->directMatrix
->row_vectors();
$aux_matrix = array();
// this is to store the normalized data (rating minus mean)
$m = $this
->getMouseNum();
$n = $this
->getCheeseNum();
$nan = $this->missing == 'none' ? TRUE : FALSE;
$data = array();
// calculate the difference matrix
foreach ($this->mouseVectors as $mouse_index => $mouse_vec) {
$mean = $mouse_vec
->mean(TRUE);
for ($cheese_index = 0; $cheese_index < $n; $cheese_index++) {
if (!is_nan($mouse_vec
->get($cheese_index))) {
$aux_matrix[$mouse_index][$cheese_index] = $mouse_vec
->get($cheese_index) - $mean;
}
}
}
$values = $this->similarityMatrix
->raw_values();
// not needed 'cause data will be saved directly to db.
$this->predictionMatrix = Matrix::create('SparseMatrix', $m, $n);
// calculate prediction for each mouse-cheese pair, and (optionally) save
foreach ($this->mouseMap as $mouse_id => $mouse_index) {
// (note: to improve performance w/ knn, move the for($j) loop here.)
// implement knn
if ($this->knn > 0) {
$sim_scores = $values[$mouse_index];
// make another copy
if (empty($sim_scores)) {
continue;
}
// if there's no knn, just skip.
arsort($sim_scores);
$sim_scores = array_slice($sim_scores, 0, $this->knn);
$neighbor = array_keys($sim_scores);
}
foreach ($this->cheeseMap as $cheese_id => $cheese_index) {
if ($this->duplicate == 'remove' && $this
->recordExists($mouse_id, $cheese_id, $nan)) {
continue;
}
$numerator = 0;
$denomenator = 0;
for ($j = 0; $j < $m; $j++) {
if (isset($neighbor) && !in_array($j, $neighbor)) {
continue;
}
// if not k-nearest-neighbor, skip
if (!array_key_exists($cheese_index, $aux_matrix[$j])) {
continue;
}
// if no rating, skip.
if ($j == $mouse_index) {
continue;
}
// skip my own rating
$norm_weight = $aux_matrix[$j][$cheese_index];
$sim = $this->similarityMatrix
->get($j, $mouse_index);
if (is_nan($sim)) {
continue;
}
$numerator += $norm_weight * $sim;
$denomenator += abs($sim);
}
if ($denomenator != 0) {
$prediction = $this->mouseVectors[$mouse_index]
->mean(TRUE, $nan) + $numerator / $denomenator;
// note: we use the same lowerbound setting for prediction generation.
if ($prediction > $this->lowerbound) {
$data[] = "({$this->appId}, {$mouse_id}, {$cheese_id}, {$prediction}, {$this->created})";
}
}
}
}
$this
->batchInsert($this
->savePredictionSql(), $data);
$this
->purgeOutdatedRecords('prediction');
$this
->cleanupMemory();
}