第三章:数据表示
推荐质量和数据的数量和质量关系很大,通常来说,数据越多越好,数据质量越高越好
推荐算法的性能和可扩展性与数据的表示关系很大,因为推荐都是数据密集的(data-intensive)
preference data 表示
单独的一个preference包括user id,item id,preference value的元组,有时候preference value可以没有
preference data是这些元组的一个集合。
在mahout中,Preference是一个接口,需要有一个实现,通常使用GenericPreference
先看Preference代码:
public interface Preference { /** @return ID of user who prefers the item */ long getUserID(); /** @return item ID that is preferred */ long getItemID(); /** * @return strength of the preference for that item. Zero should indicate "no preference either way"; * positive values indicate preference and negative values indicate dislike */ float getValue(); /** * Sets the strength of the preference for this item * * @param value * new preference */ void setValue(float value); }
public class GenericPreference implements Preference, Serializable { private final long userID; private final long itemID; private float value; public GenericPreference(long userID, long itemID, float value) { Preconditions.checkArgument(!Float.isNaN(value), "NaN value"); this.userID = userID; this.itemID = itemID; this.value = value; } @Override public long getUserID() { return userID; } @Override public long getItemID() { return itemID; } @Override public float getValue() { return value; } @Override public void setValue(float value) { Preconditions.checkArgument(!Float.isNaN(value), "NaN value"); this.value = value; } @Override public String toString() { return "GenericPreference[userID: " + userID + ", itemID:" + itemID + ", value:" + value + ']'; } }
使用也很简单了,例如:new GenericPreference(123, 456, 3.0f)
这里存在的一个问题是有效数据20字节,而其overhead却占据了28字节,浪费严重,需要找方法解决,试看mahout是怎么做的
PreferenceArray
public interface PreferenceArray extends Cloneable, Serializable, Iterable<Preference> { /** * @return size of length of the "array" */ int length(); /** * @param i * index * @return a materialized {@link Preference} representation of the preference at i */ Preference get(int i); /** * Sets preference at i from information in the given {@link Preference} * * @param i * @param pref */ void set(int i, Preference pref); /** * @param i * index * @return user ID from preference at i */ long getUserID(int i); /** * Sets user ID for preference at i. * * @param i * index * @param userID * new user ID */ void setUserID(int i, long userID); /** * @param i * index * @return item ID from preference at i */ long getItemID(int i); /** * Sets item ID for preference at i. * * @param i * index * @param itemID * new item ID */ void setItemID(int i, long itemID); /** * @return all user or item IDs */ long[] getIDs(); /** * @param i * index * @return preference value from preference at i */ float getValue(int i); /** * Sets preference value for preference at i. * * @param i * index * @param value * new preference value */ void setValue(int i, float value); /** * @return independent copy of this object */ PreferenceArray clone(); /** * Sorts underlying array by user ID, ascending. */ void sortByUser(); /** * Sorts underlying array by item ID, ascending. */ void sortByItem(); /** * Sorts underlying array by preference value, ascending. */ void sortByValue(); /** * Sorts underlying array by preference value, descending. */ void sortByValueReversed(); /** * @param userID * user ID * @return true if array contains a preference with given user ID */ boolean hasPrefWithUserID(long userID); /** * @param itemID * item ID * @return true if array contains a preference with given item ID */ boolean hasPrefWithItemID(long itemID);这个接口的一个实现类是GenericUserPreferenceArray,是针对单个user的所有preference,其内部包含单个userid,一个item id集合和评分集合,这样一个preference所占用的空间减小到12字节稍多,和前面的48字节相比下降了大约四分之三
其属性定义为:
private final long[] ids; private long id; private final float[] values;
FastByIDMap and FastIDSet
为了节省内存,mahout还使用了FastByIDMap和FastIDSet