Полезным примером того, как наука о данных влияет на людей изо дня в день, являются системы рекомендаций или поиск по сходству.

Добро пожаловать на bigstore.com, вы искали коричневый диван, вам, вероятно, тоже понравятся эти стулья. Вы недавно слушали Beatles. Вот несколько исполнителей, которые могут вам понравиться. Понравилась эта статья? Нажмите здесь, чтобы увидеть похожие истории.

Эти рекомендательные системы принимают участие пользователя и находят похожие примеры на основе ключевых характеристик. Существует несколько подходов к рекомендации (совместная или основанная на содержании) и более одного подхода к каждому.

Недавно я разработал свою первую систему рекомендаций, основанную на содержании, используя данные о штаммах каннабиса из Kaggle для группового проекта с Lambda School. Вот как я подошел к этому, используя машинное обучение (k-ближайшие соседи) и методы обработки естественного языка (TFIDF-векторизатор).

Импорт и очистка данных

Медицинский каннабис быстро становится легальной альтернативой рецептам во многих штатах. Помогать новым пользователям ориентироваться в жаргоне, включающем названия штаммов, эффекты, вкусы и облегчение симптомов, очень ценно. Веб-приложение, в котором пользователи выбирают описания или пишут свои собственные, чтобы найти похожие штаммы, которые могут помочь в их ситуации, может быть жизнеспособным решением. Чтобы проверить эту идею, я начал со свободно доступных данных о каннабисе из Kaggle, в то время как мои товарищи по команде сосредоточились на веб-интерфейсе / серверной части и нашем API для анализа данных. Для начала импортируйте данные из Kaggle, как хотите.

# Example import structure and basic cleaning of Kaggle dataset
import pandas as pd
# Create Pandas DF from cannabis.csv
df = pd.read_csv(".../cannabis.csv")
# Remove rows with missing values
df = df.dropna()
df.head()

Приведенный выше код импортирует каннабис .csv в DataFrame с помощью pandas. Используя .head (), мы можем увидеть первые пять записей и способ форматирования данных.

Данные выглядят достаточно чистыми. Во-первых, похоже, что в наборе данных есть 2277 штаммов после удаления тех, у которых отсутствуют значения. У каждого из этих штаммов есть название, рейтинг, описание, тип, эффекты и вкус. Примечание. Мы не будем использовать рейтинг (число) так часто, как будем уделять внимание естественному языку в других функциях.

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

import re
# Create a list of text features
df_features = ['Strain', 'Description', 'Effects', 'Flavor', 'Type']
# Lowercase and remove symbols
for each in df_features:
 df[each] = df[each].apply(lambda x: x.lower())
 df[each] = df[each].apply(lambda x: re.sub('[^a-zA-Z 0-9]', ' ',x))
# Combine text features into new feature
df['combined_text'] = df['Type'] + ' ' + df['Effects'] + ' ' + df['Flavor'] + df['Description']

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

# Example combined_text for 100 OG strain
hybrid creative energetic tingly euphoric relaxed earthy sweet citrus 100 og is a 50 50 hybrid strain that packs a strong punch  the name supposedly refers to both its strength and high price when it first started showing up in hollywood  as a plant   100 og tends to produce large dark green buds with few stems  users report a strong body effect of an indica for pain relief with the more alert  cerebral feeling thanks to its sativa side

Векторизация с помощью TFIDF

Чтобы наша модель могла использовать слова, слова необходимо преобразовать во что-то, что компьютер может анализировать лучше, чем текст. В комплект входит векторизатор TFIDF от SK-Learn. TFIDF - это t erm f требование - обратное d значение f требование, которое - статистика, отражающая, насколько важно слово в документе с учетом того, насколько оно распространено среди документов. Этот подход берет наш объединенный текст, выполняет счетчик-векторизатор и преобразует текст в матрицу функций TFIDF. Каждая функция во вновь созданной атриксе d ocument- t erm m (dtm) представляет собой слово или инграмму в текст, и каждое значение - это значение TFIDF этого слова, представляющее его важность для документа, отягощенную тем, насколько распространено это слово повсюду.

from sklearn.feature_extraction.text import TfidfVectorizer
# Instantiate TFIDF vectorizer
tfidf = TfidfVectorizer(stop_words = 'english', ngram_range = (1,2), min_df = 5, max_df = 0.8, max_features = 5000)
# Transform strain texts to produce document-term-matrix(dtm)
dtm=pd.DataFrame(tfidf.fit_transform(df['combined_text']).todense(), columns=tfidf.get_feature_names())

Приведенный выше код создаст матрицу после преобразования текста с использованием английских стоп-слов по умолчанию, включая униграммы и биграммы, включает только термины, найденные как минимум в пяти штаммах, но не более 80%, и сохраняет термины максимум до 5000. Ниже это пример строки из dtm:

Кластеризация с K-ближайшими соседями

Теперь, когда наш текст был соответствующим образом преобразован в матрицу терминов и их частоту / важность, мы можем создать и обучить модель. Один из подходов к поиску похожих элементов в нашей матрице деформаций и условий - использовать модель k-ближайших соседей (KNN). Модели KNN существуют уже несколько десятилетий, и при наличии набора точек данных (деформация в этом примере) они могут находить соседние точки (деформации) в векторном пространстве, используя какую-то меру расстояния. Ниже приведен код для соответствия модели k-ближайших соседей матрице документа-члена.

from sklearn.neighbors import NearestNeighbors
# Fit on DTM
nn = NearestNeighbors(n_neighbors=3, algorithm='kd_tree')
nn.fit(dtm)

Мы устанавливаем KNN на поиск трех ближайших соседей-деформаций с использованием алгоритма kd_tree. При этом наша модель ближайшего соседа готова принять некоторую новую информацию о деформации и найти аналогичные деформации, используя модель соответствия.

Поиск похожих штаммов

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

user_strain = "I am interested in a sativa that makes me feel creative, happy, and energetic. I'd like a strain with a berry flavor."

Затем нам нужно выполнить ту же очистку и преобразования текста, что и исходный текст.

# Remove symbols and lower case
user_strain = user_strain.lower()
user_strain = [re.sub('[^a-zA-Z 0-9]', ' ', user_strain)]

И, наконец, для сбора трех прогнозов нужна всего одна строка кода. Примечание: мы вызываем коленки (в нашем случае 3) для нашего векторизованного пользовательского штамма TFIDF. Метод .todense () уплотняет преобразованный вектор в читаемый мини- dtm.

# Find 3 nearest neighbor strains to user input
pred_strains=nn.kneighbors((tfidf.transform(user_strain)).todense())

Теперь мы можем проверить наши прогнозы. Созданная нами переменная должна быть набором идентификационных номеров, соответствующих индексам деформации из нашего исходного DataFrame.

pred_strains[1][0]
> array([1919, 1390, 1625]

Наконец, нам нужно определить, какие штаммы # 1919, # 1390 и # 1625, чтобы вернуться к нашему пользователю. Для группового проекта мы разработали модель для создания полезной нагрузки JSON для нашей веб-команды. А пока мы можем исследовать деформации с помощью быстрой петли.

# Print recommendations
for each in pred_strains[1][0]:
 print(each)
 print(df.iloc[each], '\n----')

Теперь мы можем порекомендовать нашему пользователю три сорта марихуаны: штамм 1919 - земляничный штамм, штамм 1390 - утренняя звезда и штамм 1625 - пурпурный куст!

В заключение и в будущее

Этот подход творил чудеса для нашего проекта кросс-функциональной сборки. База данных штаммов, векторизатор TFIDF и KNN были обработаны, чтобы не обрабатывать их каждый раз на лету. Наш API принимает полезную нагрузку JSON, содержащую вводимые пользователем данные, а наша модель выводит JSON с рекомендованными значениями деформации. Команда веб-разработчиков добавила дополнительные функции на сайт проекта, чтобы также было удобнее для пользователей. Бэкэнд был ограничен только одной рекомендацией, но это также упрощает работу для пользователя.

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