【问题标题】:How to build a content-based recommender system that uses multiple attributes?如何构建使用多个属性的基于内容的推荐系统?
【发布时间】:2018-06-23 01:40:34
【问题描述】:

我想用 Python 构建一个基于内容的推荐系统,它使用多个属性来判断两个项目是否相似。在我的例子中,“项目”是由 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 与其他相似性度量(基于同一作者、相似姓名、共享标签等)结合起来,为我的推荐提供更多背景信息?

【问题讨论】:

  • 您可以在tfidf_matrix 中添加适当的详细信息,然后将它们发送到linear_kernel 以计算余弦分数。
  • @VivekKumar 你是什么意思,在将dataframe['id'] 连接到dataframe['description'] 之前将其提供给fit_transform?我认为这种方法不适用于共享标签。
  • 我的意思是在计算'description'的tfidf之后
  • @VivekKumar 你能发布一个答案来证明这一点吗?我会为你点赞。我是 ML 的新手(实际上也是 Python),所以我并不完全熟悉所有内容。

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


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    在某些情况下,我与基于内容的推荐器的工作主要围绕原始文本和分类数据/特征展开。这是我采用的一种高级方法,效果很好,实施起来也很简单。

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

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

    不过,请注意串联,因为在nametag 等特征的情况下,保留给定单词来自哪一列可能对您有利,这假设基数比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”。如果您只是连接该文字字符串,分词器会将其拆分并将“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 列,您就可以创建最终的“语料库”并将其作为输入插入到您的推荐系统中。

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

    【讨论】:

      【解决方案3】:

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

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

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

      我说的是第一个。

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

      现在假设您对其他列(“作者”、“id”等)进行了一些特征处理,这会产生 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()
      combined_matrix = sparse.hstack((tfidf_matrix, other_matrix))
      
      cosine_similarities = linear_kernel(combined_matrix, combined_matrix)
      

      【讨论】:

      • 你从哪里得到combined_matrix
      • @Banik 是sparse.hstack() 的输出。我已经编辑了反映这一点的代码。
      猜你喜欢
      • 2011-09-04
      • 2015-12-26
      • 1970-01-01
      • 2014-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-15
      • 2015-01-16
      相关资源
      最近更新 更多