поиск похожих фраз в файле текст. txt

ChatGPT 4o-mini, языковая модель, разработанная OpenAI,

Так, здесь нам нужно сравнивать группы слов (биграммы) всех фраз из файла текст.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.



Если нужна помощь с оптимизацией или разбиением задачи — пишите.


Рецензии