Method: Evoc::Evaluate.average_precision

Defined in:
lib/evoc/evaluate.rb

.average_precision(recommendation, expected_outcome) ⇒ Float

calculate the average precision of the result based on an expected outcome

Parameters:

  • recommendation (Array)

    a sorted array

  • expected_outcome (Array)

    an array of items

Returns:

  • (Float)

    the average precision



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/evoc/evaluate.rb', line 281

def self.average_precision(recommendation,expected_outcome)
    raise Error.new "#average_precision has been deprecated, use #ap instead"
    if !expected_outcome.is_a?(Array) then expected_outcome = [expected_outcome] end
    if (expected_outcome.size > 0) & !recommendation.empty?
      average_precision = 0
      correct_items = []
      total_items_considered = []
      # sort rules by weight
      # we first group rules with equal weights
      # and then sort the groups by weight
      recommendation.each do |items|
        if !items.is_a?(Array) then items = [items] end
        if items.first.class != expected_outcome.first.class
            raise ArgumentError, "Expected outcome was of type #{expected_outcome.first.class}, while the item in the recommendation was of type #{items.first.class}"
        end
        # skip already considered items
        if (new_items = items - total_items_considered).size > 0
          new_items.each {|item| total_items_considered << item}
          if correct_in_rule = (items & expected_outcome)
            if correct_in_rule.size > 0
              # make sure that the new items havent already been added earlier
              new_correct = (correct_in_rule - correct_items)
              # add new items
              new_correct.each {|item| correct_items << item}
              change_in_recall = new_correct.size.to_r/expected_outcome.size
              precision_at_k = correct_items.size.to_r/total_items_considered.size
              average_precision += (precision_at_k * change_in_recall)
            end
          end
        end
      end
      average_precision.to_f
    else
      nil
    end
end