Комментарии 4
Спасибо за статью!
А как бы вы решили такую задачу?
Есть, скажем, некие анкеты с определенными вопросами. Каждый вопрос имеет определенный приоритет при подборе (например, Высокий, Средний, Низкий). И, соответственно, необходимо под одну заполненную анкету подбирать наиболее похожие другие анкеты.
Я думал бы как-то так:
Каждый ответ на вопрос-"предложение" в анкете необходимо переводить через SentenceTransformer, чтобы получить векторное представление
Все эти вектора суммируются, получается один "общий" вектор. При этом для того, чтобы "обыграть" приоритет при суммировании вектора умножаются на соответствующий коэффициент (пусть для Высокого - 3, для Среднего - 2, для Низкого - 1).
"Общий" вектор сохраняется для этой анкеты, по нему и будет идти семантический поиск при подборе
Похоже ли это на правду, как думаете? Или получу чушь?
В принципе можно так сделать, особенно, если анкеты состоят только из свободных ответов (то есть без выбора вариантов), ну и опять же тут надо смотреть на количество ответов в анкете и характер вопросов. Иногда в такой ситуации лучше применить не суммирование, а конкатенацию векторных представлений отдельных вопросов.
можно набросать простой скрипт типа такого, посмотреть как это все будет работать на небольшой выборке, если что-то похожее на правду, то можно уже сформировать более существенную выборку и попробовать оценить качество работы такого подхода на ней. Ну и поиграться с суммой против конкатенации, вариантами нормализации и прочим.
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.preprocessing import normalize, MinMaxScaler
from sentence_transformers import SentenceTransformer
import matplotlib.pyplot as plt
import seaborn as sns
# Инициализация модели
model = SentenceTransformer('sergeyzh/LaBSE-ru-turbo')
# Пример данных
surveys = [
{
'answers': {
'q1': 'Ежедневно',
'q2': 4,
'q3': 'Прекрасный сервис и дружелюбный персонал.'
}
},
{
'answers': {
'q1': 'Часто',
'q2': 5,
'q3': 'Отличное обслуживание.'
}
},
{
'answers': {
'q1': 'Часто',
'q2': 4,
'q3': 'Обслуживание отстойное. Персонал - идиоты'
}
},
{
'answers': {
'q1': 'Иногда',
'q2': 1,
'q3': 'Плохое обслуживание. Крайне недоволен работой.'
}
},
{
'answers': {
'q1': 'Никогда',
'q2': 3,
'q3': 'Абсолютно неудовлетворен'
}
},
{
'answers': {
'q1': 'Ежедневно',
'q2': 4,
'q3': 'Кретины! Худшее, что я когда-либо видел!'
}
},
# ... другие анкеты
]
# Приоритеты вопросов
question_weights = {
'q1': 0,
'q2': 0,
'q3': 5
}
# Кодирование категориальных ответов
categorical_mapping = {
'Никогда': 0,
'Иногда': 1,
'Часто': 2,
'Ежедневно': 3
}
# Собираем и масштабируем значения q1 и q2
q1_q2_values = []
for survey in surveys:
q1_value = categorical_mapping.get(survey['answers'].get('q1'), 0)
q1_weighted = question_weights['q1'] * q1_value
q2_value = survey['answers'].get('q2', 0)
q2_weighted = question_weights['q2'] * q2_value
q1_q2_values.append([q1_weighted, q2_weighted])
q1_q2_values = np.array(q1_q2_values)
# Масштабирование значений q1 и q2
scaler = MinMaxScaler()
q1_q2_scaled = scaler.fit_transform(q1_q2_values)
# Предварительная обработка текстовых ответов с использованием эмбеддингов
text_answers = [survey['answers']['q3'] for survey in surveys]
# Вычисление эмбеддингов для текстовых ответов
embeddings = model.encode(text_answers)
# Применение веса к эмбеддингам
embeddings_weighted = embeddings * question_weights['q3']
# Формирование векторов анкет
survey_vectors = []
for idx in range(len(surveys)):
vector = q1_q2_scaled[idx]
embedding_vector = embeddings_weighted[idx]
full_vector = np.concatenate([vector, embedding_vector])
survey_vectors.append(full_vector)
# Нормализация итоговых векторов
survey_vectors = np.array(survey_vectors)
survey_vectors_normalized = normalize(survey_vectors)
# Расчет косинусного сходства между всеми анкетами
similarities = cosine_similarity(survey_vectors_normalized)
# Вывод матрицы сходства
print("Матрица сходства:")
print(similarities)
# Построение тепловой карты
plt.figure(figsize=(8, 6))
sns.heatmap(similarities, annot=True, cmap='Blues',
xticklabels=[f'Анкета {i}' for i in range(len(surveys))],
yticklabels=[f'Анкета {i}' for i in range(len(surveys))])
plt.title('Матрица косинусного сходства между анкетами')
plt.show()
Что ищет он в краю далёком? Как найти смысл жизни с PostgreSQL