You are here

protected function CorrelationRecommender::computePredictionMemory in Recommender API 6.2

Overrides Recommender::computePredictionMemory

2 calls to CorrelationRecommender::computePredictionMemory()
CorrelationRecommender::computePrediction in ./Recommender.php
Item2ItemRecommender::computePredictionMemory in ./Recommender.php
1 method overrides CorrelationRecommender::computePredictionMemory()
Item2ItemRecommender::computePredictionMemory in ./Recommender.php

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();
}