@Test
  public void testStrategy() throws TasteException {
    FastIDSet itemIDsFromUser123 = new FastIDSet();
    itemIDsFromUser123.add(1L);

    FastIDSet itemIDsFromUser456 = new FastIDSet();
    itemIDsFromUser456.add(1L);
    itemIDsFromUser456.add(2L);

    List<Preference> prefs = new ArrayList<Preference>();
    prefs.add(new GenericPreference(123L, 1L, 1.0f));
    prefs.add(new GenericPreference(456L, 1L, 1.0f));
    PreferenceArray preferencesForItem1 = new GenericItemPreferenceArray(prefs);

    DataModel dataModel = EasyMock.createMock(DataModel.class);
    EasyMock.expect(dataModel.getPreferencesForItem(1L)).andReturn(preferencesForItem1);
    EasyMock.expect(dataModel.getItemIDsFromUser(123L)).andReturn(itemIDsFromUser123);
    EasyMock.expect(dataModel.getItemIDsFromUser(456L)).andReturn(itemIDsFromUser456);

    PreferenceArray prefArrayOfUser123 =
        new GenericUserPreferenceArray(Arrays.asList(new GenericPreference(123L, 1L, 1.0f)));

    CandidateItemsStrategy strategy = new PreferredItemsNeighborhoodCandidateItemsStrategy();

    EasyMock.replay(dataModel);

    FastIDSet candidateItems = strategy.getCandidateItems(123L, prefArrayOfUser123, dataModel);
    assertEquals(1, candidateItems.size());
    assertTrue(candidateItems.contains(2L));

    EasyMock.verify(dataModel);
  }
 @Override
 public void setPreference(long userID, long itemID, float value) throws TasteException {
   DataModel dataModel = getDataModel();
   double prefDelta;
   try {
     Float oldPref = dataModel.getPreferenceValue(userID, itemID);
     prefDelta = oldPref == null ? value : value - oldPref;
   } catch (NoSuchUserException nsee) {
     prefDelta = value;
   }
   super.setPreference(userID, itemID, value);
   try {
     buildAveragesLock.writeLock().lock();
     RunningAverage itemAverage = itemAverages.get(itemID);
     if (itemAverage == null) {
       RunningAverage newItemAverage = new FullRunningAverage();
       newItemAverage.addDatum(prefDelta);
       itemAverages.put(itemID, newItemAverage);
     } else {
       itemAverage.changeDatum(prefDelta);
     }
     RunningAverage userAverage = userAverages.get(userID);
     if (userAverage == null) {
       RunningAverage newUserAveragae = new FullRunningAverage();
       newUserAveragae.addDatum(prefDelta);
       userAverages.put(userID, newUserAveragae);
     } else {
       userAverage.changeDatum(prefDelta);
     }
     overallAveragePrefValue.changeDatum(prefDelta);
   } finally {
     buildAveragesLock.writeLock().unlock();
   }
 }
 @Override
 public float estimatePreference(long userID, long itemID) throws TasteException {
   DataModel dataModel = getDataModel();
   Float actualPref = dataModel.getPreferenceValue(userID, itemID);
   if (actualPref != null) {
     return actualPref;
   }
   return doEstimatePreference(userID, itemID);
 }
 /**
  * Exports the simple user IDs and associated item IDs in the data model.
  *
  * @return a {@link FastByIDMap} mapping user IDs to {@link FastIDSet}s representing that user's
  *     associated items
  */
 public static FastByIDMap<FastIDSet> toDataMap(DataModel dataModel) throws TasteException {
   FastByIDMap<FastIDSet> data = new FastByIDMap<>(dataModel.getNumUsers());
   LongPrimitiveIterator it = dataModel.getUserIDs();
   while (it.hasNext()) {
     long userID = it.nextLong();
     data.put(userID, dataModel.getItemIDsFromUser(userID));
   }
   return data;
 }
 @Override
 public double itemSimilarity(long itemID1, long itemID2) throws TasteException {
   int preferring1and2 = dataModel.getNumUsersWithPreferenceFor(itemID1, itemID2);
   if (preferring1and2 == 0) {
     return Double.NaN;
   }
   int preferring1 = dataModel.getNumUsersWithPreferenceFor(itemID1);
   int preferring2 = dataModel.getNumUsersWithPreferenceFor(itemID2);
   int numUsers = dataModel.getNumUsers();
   double logLikelihood =
       twoLogLambda(
           preferring1and2, preferring1 - preferring1and2, preferring2, numUsers - preferring2);
   return 1.0 - 1.0 / (1.0 + logLikelihood);
 }
  @Override
  public double userSimilarity(long userID1, long userID2) throws TasteException {

    FastIDSet prefs1 = dataModel.getItemIDsFromUser(userID1);
    FastIDSet prefs2 = dataModel.getItemIDsFromUser(userID2);

    int prefs1Size = prefs1.size();
    int prefs2Size = prefs2.size();
    int intersectionSize =
        prefs1Size < prefs2Size ? prefs2.intersectionSize(prefs1) : prefs1.intersectionSize(prefs2);
    if (intersectionSize == 0) {
      return Double.NaN;
    }

    // int numItems = dataModel.getNumItems();
    // int numItems = Math.max(prefs1Size, prefs2Size);

    // int numItems = prefs1Size;

    //    double distance1 =  (double) (prefs1Size - intersectionSize)/(double) 2;
    //    double distance2 =  (double) (prefs2Size - intersectionSize)/(double) 2;
    //    double distance = (distance1 + distance2);

    double distance = (double) (prefs1Size - intersectionSize);

    double similarity = 1.0 / (1.0 + distance);
    ////// System.out.println( prefs1Size  + ", " + prefs2Size + ", " + intersectionSize + ", " +
    // similarity);
    return similarity;
  }
 public CachingUserNeighborhood(UserNeighborhood neighborhood, DataModel dataModel)
     throws TasteException {
   Preconditions.checkArgument(neighborhood != null, "neighborhood is null");
   this.neighborhood = neighborhood;
   int maxCacheSize = dataModel.getNumUsers(); // just a dumb heuristic for sizing
   this.neighborhoodCache =
       new Cache<Long, long[]>(new NeighborhoodRetriever(neighborhood), maxCacheSize);
 }
Example #8
0
  public static void main(String[] args) throws IOException, TasteException {
    String file = "datafile/item.csv";
    DataModel model = new FileDataModel(new File(file));
    UserSimilarity user = new EuclideanDistanceSimilarity(model);
    NearestNUserNeighborhood neighbor = new NearestNUserNeighborhood(NEIGHBORHOOD_NUM, user, model);
    Recommender r = new GenericUserBasedRecommender(model, neighbor, user);
    LongPrimitiveIterator iter = model.getUserIDs();

    while (iter.hasNext()) {
      long uid = iter.nextLong();
      List<RecommendedItem> list = r.recommend(uid, RECOMMENDER_NUM);
      System.out.printf("uid:%s", uid);
      for (RecommendedItem ritem : list) {
        System.out.printf("(%s,%f)", ritem.getItemID(), ritem.getValue());
      }
      System.out.println();
    }
  }
  @Override
  public double userSimilarity(long userID1, long userID2) throws TasteException {

    FastIDSet prefs1 = dataModel.getItemIDsFromUser(userID1);
    FastIDSet prefs2 = dataModel.getItemIDsFromUser(userID2);

    int prefs1Size = prefs1.size();
    int prefs2Size = prefs2.size();
    int intersectionSize =
        prefs1Size < prefs2Size ? prefs2.intersectionSize(prefs1) : prefs1.intersectionSize(prefs2);
    if (intersectionSize == 0) {
      return Double.NaN;
    }
    int numItems = dataModel.getNumItems();
    double logLikelihood =
        twoLogLambda(
            intersectionSize, prefs1Size - intersectionSize, prefs2Size, numItems - prefs2Size);
    return 1.0 - 1.0 / (1.0 + logLikelihood);
  }
 private void buildAverageDiffs() throws TasteException {
   try {
     buildAveragesLock.writeLock().lock();
     DataModel dataModel = getDataModel();
     LongPrimitiveIterator it = dataModel.getUserIDs();
     while (it.hasNext()) {
       long userID = it.nextLong();
       PreferenceArray prefs = dataModel.getPreferencesFromUser(userID);
       int size = prefs.length();
       for (int i = 0; i < size; i++) {
         long itemID = prefs.getItemID(i);
         float value = prefs.getValue(i);
         addDatumAndCreateIfNeeded(itemID, value, itemAverages);
         addDatumAndCreateIfNeeded(userID, value, userAverages);
         overallAveragePrefValue.addDatum(value);
       }
     }
   } finally {
     buildAveragesLock.writeLock().unlock();
   }
 }
 /** Creates a possibly weighted AbstractSimilarity. */
 AbstractSimilarity(final DataModel dataModel, Weighting weighting, boolean centerData)
     throws TasteException {
   if (dataModel == null) {
     throw new IllegalArgumentException("dataModel is null");
   }
   this.dataModel = dataModel;
   this.weighted = weighting == Weighting.WEIGHTED;
   this.centerData = centerData;
   this.cachedNumItems = dataModel.getNumItems();
   this.cachedNumUsers = dataModel.getNumUsers();
   this.refreshHelper =
       new RefreshHelper(
           new Callable<Object>() {
             @Override
             public Object call() throws TasteException {
               cachedNumItems = dataModel.getNumItems();
               cachedNumUsers = dataModel.getNumUsers();
               return null;
             }
           });
   this.refreshHelper.addDependency(this.dataModel);
 }
  public static void main(String args[]) {

    try {

      // Loading the DATA;

      DataModel dm =
          new FileDataModel(
              new File(
                  "C:\\Users\\bryce\\Course Work\\3. Full Summer\\Big Data\\Final Project\\Yelp\\FINAL CODE\\Mahout\\data\\busirec_new.csv"));

      // We use the below line to relate businesses.
      // ItemSimilarity sim = new LogLikelihoodSimilarity(dm);

      TanimotoCoefficientSimilarity sim = new TanimotoCoefficientSimilarity((dm));

      // Using the below line get recommendations
      GenericItemBasedRecommender recommender = new GenericItemBasedRecommender(dm, sim);

      // Looping through every business.
      for (LongPrimitiveIterator items = dm.getItemIDs(); items.hasNext(); ) {
        long itemId = items.nextLong();

        // For each business we recommend 3 businesses.

        List<RecommendedItem> recommendations = recommender.mostSimilarItems(itemId, 2);

        for (RecommendedItem recommendation : recommendations) {

          System.out.println(
              itemId + "," + recommendation.getItemID() + "," + recommendation.getValue());
        }
      }
    } catch (IOException | TasteException e) {
      System.out.println(e);
    }
  }
  @Override
  public double userSimilarity(long userID1, long userID2) throws TasteException {

    DataModel dataModel = getDataModel();

    FastIDSet xPrefs = dataModel.getItemIDsFromUser(userID1);
    FastIDSet yPrefs = dataModel.getItemIDsFromUser(userID2);

    int xPrefsSize = xPrefs.size();
    int yPrefsSize = yPrefs.size();
    if (xPrefsSize == 0 && yPrefsSize == 0) {
      return Double.NaN;
    }
    if (xPrefsSize == 0 || yPrefsSize == 0) {
      return 0.0;
    }

    double intersection = 0.0;
    double union = 0.0;

    for (LongPrimitiveIterator it_item = xPrefs.iterator(); it_item.hasNext(); ) {
      long itemID = (long) it_item.nextLong();
      double weight = (double) getDataModel().getNumUsers() / mItemPrefNum.get(itemID);
      if (yPrefs.contains(itemID)) {
        intersection += weight;
        union -= weight;
      }
      union += weight;
    }
    for (LongPrimitiveIterator it_item = yPrefs.iterator(); it_item.hasNext(); ) {
      long itemID = (long) it_item.nextLong();
      double weight = (double) getDataModel().getNumUsers() / mItemPrefNum.get(itemID);
      union += weight;
    }

    return Math.log(intersection) / Math.log(union);
  }
  public static void main(String[] args)
      throws FileNotFoundException, TasteException, IOException, OptionException {
    DataModel model;
    model = new FileDataModel(new File("datasets/ratingsForMahout.dat"));

    File movieMapFile = new File("datasets/moviesForMahout.dat");
    HashMap<Long, String> movieMap = new HashMap<Long, String>();
    Scanner scan = new Scanner(movieMapFile);
    while (scan.hasNextLine()) {
      String[] line = scan.nextLine().split("\\|");
      movieMap.put(Long.parseLong(line[0]), line[1]);
    }
    scan.close();

    UserSimilarity userSimilarity = new PearsonCorrelationSimilarity(model);
    UserNeighborhood neighborhood = new NearestNUserNeighborhood(3, userSimilarity, model);
    Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, userSimilarity);
    Recommender cachingRecommender = new CachingRecommender(recommender);

    for (LongPrimitiveIterator it = model.getUserIDs(); it.hasNext(); ) {
      long userId = it.nextLong();
      List<RecommendedItem> recommendations = cachingRecommender.recommend(userId, 10);
      if (recommendations.size() == 0) {
        System.out.println("User " + userId + ": no recommendations");
      }
      for (RecommendedItem recommendedItem : recommendations) {
        System.out.println(
            "User "
                + userId
                + ": "
                + movieMap.get(recommendedItem.getItemID())
                + "; value="
                + recommendedItem.getValue());
      }
    }
  }
  public void testIUF() throws Exception {
    DataModel dataModel =
        getDataModel(
            new long[] {1, 2, 3, 4, 5},
            new Double[][] {
              {0.1}, {0.2, 0.3}, {0.4, 0.5, 0.6}, {0.7, 0.8, 0.9, 1.0}, {1.0, 1.0, 1.0, 1.0, 1.0},
            });

    InverseUserFrequency iuf = new InverseUserFrequency(dataModel, 10.0);

    PreferenceArray user5Prefs = dataModel.getPreferencesFromUser(5);

    for (int i = 0; i < 5; i++) {
      Preference pref = user5Prefs.get(i);
      assertNotNull(pref);
      assertEquals(
          Math.log(5.0 / (double) (5 - i)) / Math.log(iuf.getLogBase()),
          iuf.getTransformedValue(pref),
          EPSILON);
    }

    // Make sure this doesn't throw an exception
    iuf.refresh(null);
  }
 @Override
 public void removePreference(long userID, long itemID) throws TasteException {
   DataModel dataModel = getDataModel();
   Float oldPref = dataModel.getPreferenceValue(userID, itemID);
   super.removePreference(userID, itemID);
   if (oldPref != null) {
     try {
       buildAveragesLock.writeLock().lock();
       RunningAverage itemAverage = itemAverages.get(itemID);
       if (itemAverage == null) {
         throw new IllegalStateException("No preferences exist for item ID: " + itemID);
       }
       itemAverage.removeDatum(oldPref);
       RunningAverage userAverage = userAverages.get(userID);
       if (userAverage == null) {
         throw new IllegalStateException("No preferences exist for user ID: " + userID);
       }
       userAverage.removeDatum(oldPref);
       overallAveragePrefValue.removeDatum(oldPref);
     } finally {
       buildAveragesLock.writeLock().unlock();
     }
   }
 }
  /** 对用户性别进行过滤 */
  public static void filterGender(
      long uid, RecommenderBuilder recommenderBuilder, DataModel dataModel, String gender)
      throws TasteException, IOException {
    Set<Long> userids = getByGender("datafile/book/user.csv", gender);

    // 计算指定性别用户打分过的图书
    Set<Long> bookids = new HashSet<Long>();
    for (long uids : userids) {
      LongPrimitiveIterator iter = dataModel.getItemIDsFromUser(uids).iterator();
      while (iter.hasNext()) {
        long bookid = iter.next();
        bookids.add(bookid);
      }
    }

    IDRescorer rescorer = new FilterRescorer(bookids);
    List<RecommendedItem> list =
        recommenderBuilder.buildRecommender(dataModel).recommend(uid, RECOMMENDER_NUM, rescorer);
    RecommendFactory.showItems(uid, list, false);
  }
  private void splitOneUsersPrefs(
      double trainingPercentage,
      FastByIDMap<PreferenceArray> trainingPrefs,
      FastByIDMap<PreferenceArray> testPrefs,
      long userID,
      DataModel dataModel)
      throws TasteException {
    List<Preference> oneUserTrainingPrefs = null;
    List<Preference> oneUserTestPrefs = null;
    PreferenceArray prefs = dataModel.getPreferencesFromUser(userID);
    int size = prefs.length();
    boolean isInstanceOfContextualUserPreferenceArray =
        prefs instanceof ContextualUserPreferenceArray;

    for (int i = 0; i < size; i++) {
      Preference newPref =
          isInstanceOfContextualUserPreferenceArray
              ? new ContextualPreference(
                  userID,
                  prefs.getItemID(i),
                  prefs.getValue(i),
                  ((ContextualUserPreferenceArray) prefs).getContextualPreferences(i))
              : new GenericPreference(userID, prefs.getItemID(i), prefs.getValue(i));

      if (this.idrescorer != null && this.idrescorer.isFiltered(newPref.getItemID())) { // adiciona
        // ratings
        // de
        // source
        // domain
        // sempre
        // em
        // training
        // set
        if (oneUserTrainingPrefs == null) {
          oneUserTrainingPrefs = Lists.newArrayListWithCapacity(3);
        }
        oneUserTrainingPrefs.add(newPref);
        totalOfTrainingRatingsFromSource++;
        continue;
      }

      if (this.contextualCriteria != null
          && isInstanceOfContextualUserPreferenceArray) { // adiciona
        // ratings
        // de outro
        // contexto
        // sempre em
        // training
        // set
        ContextualPreference contextualPref = (ContextualPreference) newPref;
        if (!this.contextualCriteria.containsAllContextualAttributes(
            contextualPref.getContextualPreferences())) {
          if (oneUserTrainingPrefs == null) {
            oneUserTrainingPrefs = Lists.newArrayListWithCapacity(3);
          }
          oneUserTrainingPrefs.add(newPref);
          totalOfTrainingRatingsFromTargetWithoutContext++;
          continue;
        }
      }

      // para ratings do target e do contexto, fazer proporcao definida
      if (random.nextDouble() < trainingPercentage) {
        if (oneUserTrainingPrefs == null) {
          oneUserTrainingPrefs = Lists.newArrayListWithCapacity(3);
        }
        oneUserTrainingPrefs.add(newPref);
        totalOfTrainingRatingsFromTargetWithContext++;
      } else {
        if (oneUserTestPrefs == null) {
          oneUserTestPrefs = Lists.newArrayListWithCapacity(3);
        }
        oneUserTestPrefs.add(newPref);
        totalOfTestRatings++;
      }

      // OLD training/test set
      /*
       * if (random.nextDouble() < trainingPercentage) { if
       * (oneUserTrainingPrefs == null) { oneUserTrainingPrefs =
       * Lists.newArrayListWithCapacity(3); }
       * oneUserTrainingPrefs.add(newPref); totalOfTrainingRatings++; }
       * else { if (oneUserTestPrefs == null) { oneUserTestPrefs =
       * Lists.newArrayListWithCapacity(3); } //testa somente com um tipo
       * de rating (rescorer e/ou context) if(this.idrescorer == null &&
       * this.contextualCriteria == null){ oneUserTestPrefs.add(newPref);
       * totalOfTestRatings++; }else{ if(this.idrescorer != null &&
       * !this.idrescorer.isFiltered(newPref.getItemID())){
       * if(this.contextualCriteria != null &&
       * isInstanceOfContextualUserPreferenceArray){ ContextualPreference
       * contextualPref = (ContextualPreference) newPref;
       * if(this.contextualCriteria
       * .containsAllContextualAttributes(contextualPref
       * .getContextualPreferences())){ oneUserTestPrefs.add(newPref);
       * totalOfTestRatings++; } }else{ oneUserTestPrefs.add(newPref);
       * totalOfTestRatings++; } }else if(this.idrescorer == null &&
       * this.contextualCriteria != null &&
       * isInstanceOfContextualUserPreferenceArray){ ContextualPreference
       * contextualPref = (ContextualPreference) newPref;
       * if(this.contextualCriteria
       * .containsAllContextualAttributes(contextualPref
       * .getContextualPreferences())){ oneUserTestPrefs.add(newPref);
       * totalOfTestRatings++; } } } }
       */
    }
    if (oneUserTrainingPrefs != null) {
      trainingPrefs.put(
          userID,
          isInstanceOfContextualUserPreferenceArray
              ? new ContextualUserPreferenceArray(oneUserTrainingPrefs)
              : new GenericUserPreferenceArray(oneUserTrainingPrefs));
      if (oneUserTestPrefs != null) {
        testPrefs.put(
            userID,
            isInstanceOfContextualUserPreferenceArray
                ? new ContextualUserPreferenceArray(oneUserTestPrefs)
                : new GenericUserPreferenceArray(oneUserTestPrefs));
      }
    }
  }
  @Override
  public double userSimilarity(long userID1, long userID2) throws TasteException {
    PreferenceArray xPrefs = dataModel.getPreferencesFromUser(userID1);
    PreferenceArray yPrefs = dataModel.getPreferencesFromUser(userID2);
    int xLength = xPrefs.length();
    int yLength = yPrefs.length();

    if ((xLength == 0) || (yLength == 0)) {
      return Double.NaN;
    }

    long xIndex = xPrefs.getItemID(0);
    long yIndex = yPrefs.getItemID(0);
    int xPrefIndex = 0;
    int yPrefIndex = 0;

    double sumX = 0.0;
    double sumX2 = 0.0;
    double sumY = 0.0;
    double sumY2 = 0.0;
    double sumXY = 0.0;
    double sumXYdiff2 = 0.0;
    int count = 0;

    boolean hasInferrer = inferrer != null;
    boolean hasPrefTransform = prefTransform != null;

    while (true) {
      int compare = xIndex < yIndex ? -1 : xIndex > yIndex ? 1 : 0;
      if (hasInferrer || compare == 0) {
        double x;
        double y;
        if (xIndex == yIndex) {
          // Both users expressed a preference for the item
          if (hasPrefTransform) {
            x = prefTransform.getTransformedValue(xPrefs.get(xPrefIndex));
            y = prefTransform.getTransformedValue(yPrefs.get(yPrefIndex));
          } else {
            x = xPrefs.getValue(xPrefIndex);
            y = yPrefs.getValue(yPrefIndex);
          }
        } else {
          // Only one user expressed a preference, but infer the other one's preference and tally
          // as if the other user expressed that preference
          if (compare < 0) {
            // X has a value; infer Y's
            x =
                hasPrefTransform
                    ? prefTransform.getTransformedValue(xPrefs.get(xPrefIndex))
                    : xPrefs.getValue(xPrefIndex);
            y = inferrer.inferPreference(userID2, xIndex);
          } else {
            // compare > 0
            // Y has a value; infer X's
            x = inferrer.inferPreference(userID1, yIndex);
            y =
                hasPrefTransform
                    ? prefTransform.getTransformedValue(yPrefs.get(yPrefIndex))
                    : yPrefs.getValue(yPrefIndex);
          }
        }
        sumXY += x * y;
        sumX += x;
        sumX2 += x * x;
        sumY += y;
        sumY2 += y * y;
        double diff = x - y;
        sumXYdiff2 += diff * diff;
        count++;
      }
      if (compare <= 0) {
        if (++xPrefIndex >= xLength) {
          if (hasInferrer) {
            // Must count other Ys; pretend next X is far away
            if (yIndex == Long.MAX_VALUE) {
              // ... but stop if both are done!
              break;
            }
            xIndex = Long.MAX_VALUE;
          } else {
            break;
          }
        } else {
          xIndex = xPrefs.getItemID(xPrefIndex);
        }
      }
      if (compare >= 0) {
        if (++yPrefIndex >= yLength) {
          if (hasInferrer) {
            // Must count other Xs; pretend next Y is far away
            if (xIndex == Long.MAX_VALUE) {
              // ... but stop if both are done!
              break;
            }
            yIndex = Long.MAX_VALUE;
          } else {
            break;
          }
        } else {
          yIndex = yPrefs.getItemID(yPrefIndex);
        }
      }
    }

    // "Center" the data. If my math is correct, this'll do it.
    double result;
    if (centerData) {
      double n = count;
      double meanX = sumX / n;
      double meanY = sumY / n;
      // double centeredSumXY = sumXY - meanY * sumX - meanX * sumY + n * meanX * meanY;
      double centeredSumXY = sumXY - meanY * sumX;
      // double centeredSumX2 = sumX2 - 2.0 * meanX * sumX + n * meanX * meanX;
      double centeredSumX2 = sumX2 - meanX * sumX;
      // double centeredSumY2 = sumY2 - 2.0 * meanY * sumY + n * meanY * meanY;
      double centeredSumY2 = sumY2 - meanY * sumY;
      result = computeResult(count, centeredSumXY, centeredSumX2, centeredSumY2, sumXYdiff2);
    } else {
      result = computeResult(count, sumXY, sumX2, sumY2, sumXYdiff2);
    }

    if (similarityTransform != null) {
      result = similarityTransform.transformSimilarity(userID1, userID2, result);
    }

    if (!Double.isNaN(result)) {
      result = normalizeWeightResult(result, count, cachedNumItems);
    }
    return result;
  }
  @Override
  public final double itemSimilarity(long itemID1, long itemID2) throws TasteException {
    PreferenceArray xPrefs = dataModel.getPreferencesForItem(itemID1);
    PreferenceArray yPrefs = dataModel.getPreferencesForItem(itemID2);
    int xLength = xPrefs.length();
    int yLength = yPrefs.length();

    if ((xLength == 0) || (yLength == 0)) {
      return Double.NaN;
    }

    long xIndex = xPrefs.getUserID(0);
    long yIndex = yPrefs.getUserID(0);
    int xPrefIndex = 0;
    int yPrefIndex = 0;

    double sumX = 0.0;
    double sumX2 = 0.0;
    double sumY = 0.0;
    double sumY2 = 0.0;
    double sumXY = 0.0;
    double sumXYdiff2 = 0.0;
    int count = 0;

    // No, pref inferrers and transforms don't appy here. I think.

    while (true) {
      int compare = xIndex < yIndex ? -1 : xIndex > yIndex ? 1 : 0;
      if (compare == 0) {
        // Both users expressed a preference for the item
        double x = xPrefs.getValue(xPrefIndex);
        double y = yPrefs.getValue(yPrefIndex);
        sumXY += x * y;
        sumX += x;
        sumX2 += x * x;
        sumY += y;
        sumY2 += y * y;
        double diff = x - y;
        sumXYdiff2 += diff * diff;
        count++;
      }
      if (compare <= 0) {
        if (++xPrefIndex == xLength) {
          break;
        }
        xIndex = xPrefs.getUserID(xPrefIndex);
      }
      if (compare >= 0) {
        if (++yPrefIndex == yLength) {
          break;
        }
        yIndex = yPrefs.getUserID(yPrefIndex);
      }
    }

    double result;
    if (centerData) {
      // See comments above on these computations
      double n = (double) count;
      double meanX = sumX / n;
      double meanY = sumY / n;
      // double centeredSumXY = sumXY - meanY * sumX - meanX * sumY + n * meanX * meanY;
      double centeredSumXY = sumXY - meanY * sumX;
      // double centeredSumX2 = sumX2 - 2.0 * meanX * sumX + n * meanX * meanX;
      double centeredSumX2 = sumX2 - meanX * sumX;
      // double centeredSumY2 = sumY2 - 2.0 * meanY * sumY + n * meanY * meanY;
      double centeredSumY2 = sumY2 - meanY * sumY;
      result = computeResult(count, centeredSumXY, centeredSumX2, centeredSumY2, sumXYdiff2);
    } else {
      result = computeResult(count, sumXY, sumX2, sumY2, sumXYdiff2);
    }

    if (similarityTransform != null) {
      result = similarityTransform.transformSimilarity(itemID1, itemID2, result);
    }

    if (!Double.isNaN(result)) {
      result = normalizeWeightResult(result, count, cachedNumUsers);
    }
    return result;
  }
 /** @throws IllegalArgumentException if {@link DataModel} does not have preference values */
 public EuclideanDistanceSimilarity(DataModel dataModel, Weighting weighting)
     throws TasteException {
   super(dataModel, weighting, false);
   Preconditions.checkArgument(
       dataModel.hasPreferenceValues(), "DataModel doesn't have preference values");
 }
  @Override
  public double evaluate(
      RecommenderBuilder recommenderBuilder,
      DataModelBuilder dataModelBuilder,
      DataModel dataModel,
      double trainingPercentage,
      double evaluationPercentage)
      throws TasteException {
    Preconditions.checkNotNull(recommenderBuilder);
    Preconditions.checkNotNull(dataModel);
    Preconditions.checkArgument(
        trainingPercentage >= 0.0 && trainingPercentage <= 1.0,
        "Invalid trainingPercentage: "
            + trainingPercentage
            + ". Must be: 0.0 <= trainingPercentage <= 1.0");
    Preconditions.checkArgument(
        evaluationPercentage >= 0.0 && evaluationPercentage <= 1.0,
        "Invalid evaluationPercentage: "
            + evaluationPercentage
            + ". Must be: 0.0 <= evaluationPercentage <= 1.0");

    log.info("Beginning evaluation using {} of {}", trainingPercentage, dataModel);

    int numUsers = dataModel.getNumUsers();
    FastByIDMap<PreferenceArray> trainingPrefs =
        new FastByIDMap<PreferenceArray>(1 + (int) (evaluationPercentage * numUsers));
    FastByIDMap<PreferenceArray> testPrefs =
        new FastByIDMap<PreferenceArray>(1 + (int) (evaluationPercentage * numUsers));

    totalOfTrainingRatingsFromSource = 0;
    totalOfTrainingRatingsFromTargetWithContext = 0;
    totalOfTrainingRatingsFromTargetWithoutContext = 0;
    totalOfTestRatings = 0;

    LongPrimitiveIterator it = dataModel.getUserIDs();
    while (it.hasNext()) {
      long userID = it.nextLong();
      if (random.nextDouble() < evaluationPercentage) {
        splitOneUsersPrefs(trainingPercentage, trainingPrefs, testPrefs, userID, dataModel);
      }
    }

    // System.out.println("Training (Source, TargetWithoutContext, TargetWithContext):
    // "+totalOfTrainingRatingsFromSource+"/"+totalOfTrainingRatingsFromTargetWithoutContext+"/"+totalOfTrainingRatingsFromTargetWithContext);
    // int totalTraining =
    // (totalOfTrainingRatingsFromSource+totalOfTrainingRatingsFromTargetWithContext+totalOfTrainingRatingsFromTargetWithoutContext);
    // System.out.println("Training/Test: "+totalTraining+"/"+totalOfTestRatings);

    DataModel newDataModel =
        dataModel instanceof ContextualDataModel
            ? new ContextualDataModel(trainingPrefs)
            : new GenericDataModel(trainingPrefs);

    DataModel trainingModel =
        dataModelBuilder == null ? newDataModel : dataModelBuilder.buildDataModel(trainingPrefs);

    Recommender recommender = recommenderBuilder.buildRecommender(trainingModel);

    double result = getEvaluation(testPrefs, recommender);
    log.info("Evaluation result: {}", result);
    return result;
  }