如何构建一个使用多个属性的基于内容的推荐系统?

时间:2018-01-14 01:04:23

标签: python pandas machine-learning scikit-learn recommender-systems

我想在Python中构建一个基于内容的推荐系统,它使用多个属性来决定两个项是否相似。在我的例子中,“items”是由C#包管理器(example)托管的包,它们具有各种属性,例如名称,描述,标签,可以帮助识别类似的包。

我有一个原型推荐系统here,它目前只使用一个属性(描述)来决定包是否相似。它计算描述的TF-IDF排名,并根据以下内容打印出前10个建议:

# Code mostly stolen from http://blog.untrod.com/2016/06/simple-similar-products-recommendation-engine-in-python.html
def train(dataframe):
    tfidf = TfidfVectorizer(analyzer='word',
                            ngram_range=(1, 3),
                            min_df=0,
                            stop_words='english')
    tfidf_matrix = tfidf.fit_transform(dataframe['description'])
    cosine_similarities = linear_kernel(tfidf_matrix, tfidf_matrix)
    for idx, row in dataframe.iterrows():
        similar_indices = cosine_similarities[idx].argsort()[:-10:-1]
        similar_items = [(dataframe['id'][i], cosine_similarities[idx][i])
                        for i in similar_indices]

        id = row['id']
        similar_items = [it for it in similar_items if it[0] != id]
        # This 'sum' is turns a list of tuples into a single tuple:
        # [(1,2), (3,4)] -> (1,2,3,4)
        flattened = sum(similar_items, ())
        try_print("Top 10 recommendations for %s: %s" % (id, flattened))

如何将cosine_similarities与其他相似性度量(基于同一作者,相似名称,共享标签等)结合起来,为我的推荐提供更多背景信息?

3 个答案:

答案 0 :(得分:5)

在某些情况下,我对基于内容的推荐人的工作主要围绕原始文本和分类数据/功能。这是我采取的一种高级方法,该方法运行良好且实现起来非常简单。

假设我有三个功能列,我可以用来提出建议:descriptionnametags。对我而言,阻力最小的路径需要以有用的方式组合这三个特征集。

您使用TF-IDF对description进行编码,这是一个良好的开端。那么,为什么不通过创建功能"语料库"以类似的方式对待nametags。由descriptionnametags组成?从字面上看,这意味着将三列中每一列的内容连接成一个长文本列。

但是,对于连接是明智的,因为在name这样的功能的情况下,保留从给定单词的哪一列可能对你有利。和tag,假设基数低于description。更明确地说:而不是像这样创建语料库列:

df['corpus'] = (pd.Series(df[['description', 'name', 'tags']]
                .fillna('')
                .values.tolist()
                ).str.join(' ')

您可以尝试保留有关nametags中特定数据点的来源的信息。像这样:

df['name_feature'] = ['name_{}'.format(x) for x in df['name']]
df['tags_feature'] = ['tags_{}'.format(x) for x in df['tags']]

在您这样做之后,我会更进一步考虑默认标记生成器(您在上面使用它)在TfidfVectorizer中的工作原理。假设你有一个给定包的作者的名字:" Johnny' Lightning' Thundersmith&#34 ;.如果你只是连接那个文字字符串,那么标记器就会将它拆分并滚动每一个" Johnny"," Lightning"和" Thundersmith"进入单独的功能,这可能会减少该行name的值所添加的信息。我认为最好保留这些信息。所以我会对每个低级基数文本列(例如nametags)执行类似的操作:

def raw_text_to_feature(s, sep=' ', join_sep='x', to_include=string.ascii_lowercase):
    def filter_word(word):
        return ''.join([c for c in word if c in to_include])
    return join_sep.join([filter_word(word) for word in text.split(sep)])

def['name_feature'] = df['name'].apply(raw_text_to_feature)

同样的批判性思维应该适用于tags。如果你有一个以逗号分隔的"列表"对于标签,您可能需要单独解析这些标签并找出使用它们的正确方法。

最终,一旦您创建了所有<x>_feature列,您就可以创建最终的&#34;语料库&#34;并将其作为输入插入推荐系统。

这个整个系统需要一些工程,但我发现它是从其他具有不同基数的列中引入新信息的最简单方法。

答案 1 :(得分:2)

你有一个用户$ \ gamma_u $的矢量和$ \ gamma_i $项目。您推荐的评分函数是:

f = \alpha + \beta_u +\beta_i + \gamma_u^T \gamma_i

现在你说你的特征向量只有一个项目,但是一旦你得到更多,这个模型将为此扩展。

在这种情况下,您已经设计了矢量,但通常在推荐器中,通过矩阵分解来学习该特征。这被称为潜在因子模型,而你有一个手工制作的模型。

答案 2 :(得分:2)

据我理解你的问题,有两种方法可以做到:

1)将其他特征与tfidf_matrix组合,然后计算余弦相似度

2)使用其他方法计算其他特征的相似度,然后以某种方式将它们与tfidf_matrix的余弦相似度组合以获得有意义的度量。

我在谈论第一个。

例如,对于您的数据,tfidf_matrix(仅针对'description'列)的形状为(3000, 4000)  其中3000是数据中的行,4000是TfidfVectorizer找到的唯一单词(词汇)。

现在假设您在其他列(&#39; authors&#39;,&#39; id&#39;等)上执行了一些功能处理,并生成了5列。因此,该数据的形状为(3000, 5)

我说要合并两个矩阵(合并列),以便数据的新形状为(3000, 4005),然后计算cosine_similarity。

见下面的例子:

from scipy import sparse

# This is your original matrix
tfidf_matrix = tfidf.fit_transform(dataframe['description'])

# This is the other features
other_matrix = some_processing_on_other_columns()
sparse.hstack((tfidf_matrix, other_matrix))

cosine_similarities = linear_kernel(combined_matrix, combined_matrix)