Как построить основанную на контенте систему рекомендаций, которая использует несколько атрибутов?

Я новичок в машинном обучении. Я хочу построить основанную на контенте систему рекомендаций в Python, которая использует несколько атрибутов, чтобы решить, похожи ли два элемента. В моем случае "элементы" - это пакеты, размещаемые менеджером пакетов C# ( пример), которые имеют различные атрибуты, такие как имя, описание, теги, которые могут помочь идентифицировать подобные пакеты.

У меня есть система рекомендаций прототипа, которая в настоящее время использует только один атрибут, описание, чтобы решить, похожи ли пакеты. Он вычисляет рейтинги 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 ответа

Для некоторого контекста моя работа с рекомендациями, основанными на контенте, вращалась вокруг необработанного текста и категориальных данных / функций. Вот подход высокого уровня, который я выбрал, который хорошо сработал и довольно прост в реализации.

Предположим, у меня есть три функциональных столбца, которые я могу потенциально использовать для выработки рекомендаций: description, name, а также tags, Для меня путь наименьшего сопротивления влечет за собой сочетание этих трех наборов функций в полезной форме.

Вы хорошо начали, используя TF-IDF для кодирования description, Так почему бы не лечить name а также tags аналогичным образом, создавая "корпус", состоящий из description, name, а также tags? В буквальном смысле это будет означать объединение содержимого каждого из трех столбцов в один длинный текстовый столбец.

Будьте внимательны в отношении конкатенации, так как, вероятно, в ваших интересах сохранить, из какого столбца происходит данное слово, в случае таких функций, как name а также tagкоторые, как предполагается, имеют гораздо меньшую мощность, чем description, Чтобы выразить это более явно: вместо того, чтобы просто создать столбец корпуса, как это:

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

Вы можете попытаться сохранить информацию о том, где конкретные данные указывают на name а также tags родом из. Что-то вроде этого:

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

И после того, как вы это сделаете, я бы пошел дальше, рассмотрев, как работает токенайзер по умолчанию (который вы используете выше) в TfidfVectorizer, Предположим, у вас есть имя автора данного пакета: "Джонни" Молния "Громовержец". Если вы просто объедините эту литеральную строку, токенизатор разделит ее на части и свернет каждый из "Джонни", "Молния" и "Тандерсмит" в отдельные функции, которые потенциально могут уменьшить информацию, добавляемую значением этой строки для name, Я думаю, что лучше попытаться сохранить эту информацию. Поэтому я хотел бы сделать что-то подобное для каждого из ваших текстовых столбцов с меньшим количеством элементов (например, name или же tags):

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 После создания столбцов вы можете создать свой окончательный "корпус" и подключить его к вашей рекомендательной системе в качестве входных данных.

Конечно, вся эта система требует некоторой разработки, но я обнаружил, что это самый простой способ ввода новой информации из других столбцов, имеющих разный кардинал.

Насколько я понимаю ваш вопрос, это можно сделать двумя способами:

1) Объедините другие функции с tfidf_matrix а затем рассчитать косинус сходства

2) Рассчитайте сходство других признаков, используя другие методы, а затем каким-то образом объедините их с косинусным сходством tfidf_matrix чтобы получить значимую метрику.

Я говорил о первом.

Например, скажем, для ваших данных, tfidf_matrix (только для 'description' колонна) имеет форму (3000, 4000) где 3000 - строки в данных, а 4000 - уникальные слова (словарь), найденные TfidfVectorizer.

Теперь предположим, что вы выполняете некоторую обработку объектов в других столбцах ("авторы", "идентификатор" и т. Д.), И получается 5 столбцов. Таким образом, форма этих данных (3000, 5),

Я говорил объединить две матрицы (объединить столбцы) так, чтобы новая форма ваших данных была (3000, 4005) и затем вычислите косинус сходства.

Смотрите ниже пример:

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)

У вас есть вектор для пользователя $\gamma_u$ и элемент $\gamma_i$. Функция оценки по вашей рекомендации:

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

Прямо сейчас вы сказали, что у вашего векторного элемента есть только 1 элемент, но как только вы получите больше, эта модель будет масштабироваться для этого.

В этом случае вы уже спроектировали свои векторы, но, как правило, в рекомендациях, функция изучается посредством матричной факторизации. Это называется моделью скрытого фактора, тогда как у вас есть модель, созданная вручную.

Другие вопросы по тегам