поиск похожих фраз в файле текст. txt
Так, здесь нам нужно сравнивать группы слов (биграммы) всех фраз из файла текст.txt
и находить в нём похожие пары слов фраз, а затем группировать похожие фразы в группы по три фразы
Вот код, который выполняет эту задачу:
python
import re
from collections import defaultdict
def preprocess_text(text):
# Удаляем специальные символы и переводим текст в нижний регистр
text = re.sub(r'[^\w\s]', '', text)
return text.lower()
def get_bigrams(text):
words = text.split()
return [(words[i], words[i + 1]) for i in range(len(words) - 1)]
def find_similar_phrases(phrases, threshold=0.5):
bigram_groups = defaultdict(list)
# Сохраняем биграммы для каждой фразы
for phrase in phrases:
bigrams = get_bigrams(preprocess_text(phrase))
# Используем множество для уникальных биграмм
bigram_set = set(bigrams)
bigram_groups[frozenset(bigram_set)].append(phrase)
similar_groups = []
# Группируем фразы по схожим биграммам
for group in bigram_groups.values():
if len(group) > 1: # Если есть похожие фразы
similar_groups.append(group)
return similar_groups
def read_phrases_from_file(filename):
with open(filename, 'r', encoding='utf-8') as f:
return [line.strip() for line in f if line.strip()]
# Пример использования
phrases = read_phrases_from_file('текст.txt')
# Находим похожие фразы
similar_groups = find_similar_phrases(phrases)
# Группируем похожие фразы по три
grouped_phrases = [group[:3] for group in similar_groups]
# Выводим результаты
for idx, group in enumerate(grouped_phrases):
print(f"Группа {idx + 1}: {', '.join(group)}")
Объяснение кода:
preprocess_text: Эта функция очищает текст и переводит его в нижний регистр.
get_bigrams: Функция для получения биграмм из текста.
find_similar_phrases:
Создает словарь, где ключом являются уникальные биграммы (в виде frozenset), а значением — список фраз, которые содержат эти биграммы.
Если в словаре есть более одной фразы для одной группы биграмм, они добавляются в список similar_groups.
read_phrases_from_file: Читает фразы из файла текст.txt.
Группировка: После нахождения похожих фраз, мы группируем их по три и выводим результат.
Как использовать:
Создайте файл текст.txt и добавьте в него фразы, каждая на новой строке.
Запустите скрипт, и он выведет группы из похожих фраз, ограниченные тремя фразами в каждой группе.
Этот код будет находить группы схожих фраз на основе их биграмм и выводить их в удобном формате.
Понял:
нужно вывести группы из 3 похожих фраз, при этом фразы не должны повторяться между группами, а внутри группы фразы нужно выводить с переносом строки.
Вот исправленный и улучшенный вариант этого кода с комментариями:
```python
import re
from collections import defaultdict
def preprocess_text(text):
# Удаляем специальные символы и переводим текст в нижний регистр
text = re.sub(r'[^\w\s]', '', text)
return text.lower()
def get_bigrams(text):
words = text.split()
return [(words[i], words[i + 1]) for i in range(len(words) - 1)]
def jaccard_similarity(set1, set2):
# Вычисляем коэффициент Жаккара для двух множеств
intersection = len(set1.intersection(set2))
union = len(set1.union(set2))
return intersection / union if union != 0 else 0
def find_similar_phrases(phrases, threshold=0.5):
# Предобрабатываем фразы и собираем биграммы
phrase_bigrams = []
for phrase in phrases:
bigrams = set(get_bigrams(preprocess_text(phrase)))
phrase_bigrams.append((phrase, bigrams))
used = set() # Чтобы не повторять фразы в группах
similar_groups = []
# Проходим по всем фразам и ищем похожие
for i, (phrase_i, bigrams_i) in enumerate(phrase_bigrams):
if phrase_i in used:
continue
group = [phrase_i]
used.add(phrase_i)
for j in range(i+1, len(phrase_bigrams)):
phrase_j, bigrams_j = phrase_bigrams[j]
if phrase_j in used:
continue
sim = jaccard_similarity(bigrams_i, bigrams_j)
if sim >= threshold:
group.append(phrase_j)
used.add(phrase_j)
if len(group) == 3:
break
# Добавляем группу, только если в ней 3 фразы
if len(group) == 3:
similar_groups.append(group)
return similar_groups
def read_phrases_from_file(filename):
with open(filename, 'r', encoding='utf-8') as f:
return [line.strip() for line in f if line.strip()]
# Пример использования
phrases = read_phrases_from_file('текст.txt')
# Находим похожие фразы
similar_groups = find_similar_phrases(phrases, threshold=0.5)
# Выводим результаты с переносом строк внутри группы
for idx, group in enumerate(similar_groups):
print(f"{idx + 1}:")
print('\n'.join(group))
print() # Пустая строка между группами
```
Что изменено:
- Добавлена функция `jaccard_similarity` для вычисления похожести биграмм по коэффициенту Жаккара.
- Используем жадный алгоритм, который последовательно формирует группы из 3 похожих фраз, не допуская повторений.
- В выводе фразы внутри группы разделены переносом строки.
- Между группами добавлен пустой вывод для удобства чтения.
Если нужно, могу помочь с дополнительной настройкой порога похожести или логики группировки.
import re
def preprocess_text(text):
text = re.sub(r'[^\w\s]', '', text)
return text.lower()
def get_bigrams(text):
words = text.split()
return [(words[i], words[i + 1]) for i in range(len(words) - 1)]
def jaccard_similarity(set1, set2):
intersection = len(set1.intersection(set2))
union = len(set1.union(set2))
return intersection / union if union != 0 else 0
def find_similar_phrases(phrases, threshold=0.3): # Понизил порог для теста
phrase_bigrams = []
for phrase in phrases:
bigrams = set(get_bigrams(preprocess_text(phrase)))
phrase_bigrams.append((phrase, bigrams))
used = set()
similar_groups = []
for i, (phrase_i, bigrams_i) in enumerate(phrase_bigrams):
if phrase_i in used:
continue
group = [phrase_i]
used.add(phrase_i)
for j in range(i+1, len(phrase_bigrams)):
phrase_j, bigrams_j = phrase_bigrams[j]
if phrase_j in used:
continue
sim = jaccard_similarity(bigrams_i, bigrams_j)
# Выводим для отладки
print(f"Similarity between:\n '{phrase_i}'\n '{phrase_j}'\n = {sim:.2f}")
if sim >= threshold:
group.append(phrase_j)
used.add(phrase_j)
if len(group) == 3:
break
if len(group) == 3:
similar_groups.append(group)
return similar_groups
def read_phrases_from_file(filename):
with open(filename, 'r', encoding='utf-8') as f:
return [line.strip() for line in f if line.strip()]
# Замените 'текст.txt' на ваш файл
phrases = read_phrases_from_file('текст.txt')
similar_groups = find_similar_phrases(phrases, threshold=0.3)
if not similar_groups:
print("Не найдено групп из трёх похожих фраз с заданным порогом.")
for idx, group in enumerate(similar_groups):
print(f"\nГруппа {idx + 1}:")
print('\n'.join(group))
При 40 тысячах фраз поиск групп похожих фраз с жёстким порогом и жадной логикой может не найти подходящих троек, особенно если порог слишком высок или фразы сильно различаются.
Рекомендации для вашего случая:
Снизьте порог похожести (например, 0.2 или даже 0.1) — при большом объёме данных можно позволить более слабые совпадения.
Добавьте вывод статистики, чтобы понять распределение похожести,
например, соберите все пары с похожестью выше 0.1 и посчитайте их количество.
Оптимизируйте алгоритм — перебор всех пар 40 000 фраз (~800 млн пар) очень дорог по времени.
Можно:
- Использовать индексацию, например, MinHash или Locality Sensitive Hashing (LSH) для быстрого поиска похожих наборов биграмм.
- Сократить поиск только до фраз, которые имеют хотя бы несколько общих слов (например, через обратный индекс).
Упростите задачу** — например, ищите группы из 2 похожих фраз, а не 3.
Пример сбора статистики похожести
import re
from collections import defaultdict
def preprocess_text(text):
text = re.sub(r'[^\w\s]', '', text)
return text.lower()
def get_bigrams(text):
words = text.split()
return set((words[i], words[i+1]) for i in range(len(words)-1))
def jaccard_similarity(set1, set2):
intersection = len(set1.intersection(set2))
union = len(set1.union(set2))
return intersection / union if union else 0
phrases = []
with open('текст.txt', encoding='utf-8') as f:
for line in f:
line = line.strip()
if line:
phrases.append(line)
phrase_bigrams = [(p, get_bigrams(preprocess_text(p))) for p in phrases]
similar_pairs = []
threshold = 0.1 # низкий порог для сбора статистики
# Для примера проверим только первые 1000 фраз, чтобы не ждать слишком долго
N = 1000
for i in range(N):
p1, b1 = phrase_bigrams[i]
for j in range(i+1, N):
p2, b2 = phrase_bigrams[j]
sim = jaccard_similarity(b1, b2)
if sim >= threshold:
similar_pairs.append((p1, p2, sim))
print(f"Найдено {len(similar_pairs)} пар с похожестью >= {threshold} из {N} фраз")
# Можно вывести несколько примеров
for p1, p2, sim in similar_pairs[:10]:
print(f"Similarity {sim:.2f}:\n {p1}\n {p2}\n")
Что дальше
- Если при 1000 фраз вы уже видите много похожих пар, значит порог адекватен.
- Если нет, снизьте порог или попробуйте увеличить количество фраз постепенно.
- Для обработки всех 40 000 фраз лучше применять более эффективные методы (MinHash, LSH).
- Если хотите, могу помочь с примером реализации MinHash на Python.
Если нужна помощь с оптимизацией или разбиением задачи — пишите.
Свидетельство о публикации №125072300489