001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 the ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package org.conqat.lib.commons.datamining;
018
019import java.util.HashSet;
020import java.util.Set;
021
022import org.conqat.lib.commons.assertion.CCSMAssert;
023
024/**
025 * User represented by a shopping basket, i.e. a set of purchased items. The
026 * similarity measure used is cosine similarity (see
027 * http://en.wikipedia.org/wiki/Cosine_similarity).
028 */
029public class ShoppingBasketUser<T> implements IRecommenderUser {
030
031        /** The set of items */
032        private Set<T> items;
033
034        /** Constructor */
035        public ShoppingBasketUser(Set<T> items) {
036                CCSMAssert.isFalse(items.isEmpty(), "Items must not be empty");
037                this.items = items;
038        }
039
040        /** Returns the items. */
041        public Set<T> getItems() {
042                return items;
043        }
044
045        /** {@inheritDoc} */
046        @Override
047        public double similarity(IRecommenderUser other) {
048                if (!(other instanceof ShoppingBasketUser<?>)) {
049                        throw new IllegalArgumentException();
050                }
051                ShoppingBasketUser<?> user = (ShoppingBasketUser<?>) other;
052                return similarity(items, user.items);
053        }
054
055        /** Computes the cosine similarity of two non-empty sets */
056        private static double similarity(Set<?> set1, Set<?> set2) {
057                CCSMAssert.isFalse(set1.isEmpty() || set2.isEmpty(), "Sets must not be empty");
058                Set<?> intersection = new HashSet<Object>(set1);
059                intersection.retainAll(set2);
060                double numerator = intersection.size();
061                double denominator = Math.sqrt(set1.size()) * Math.sqrt(set2.size());
062                return numerator / denominator;
063        }
064
065        /** {@inheritDoc} */
066        @Override
067        public String toString() {
068                return items.toString();
069        }
070
071}