Skip to content

Akhunzianov/Rewritings-Analyser

Repository files navigation

Rewritings-Analyser

В данном репизитории реализованы 3 метода выявления рерайтинга алгоритмическими методами.

Подход 1: Расстояние Левенштейна

Данный алгоритм реализован Ахунзяновым Ренатом. В реализации используются файлы LevenshteinDistance.py, sample.json, rewritings_levenshtein.json

Результат работы данного метода записан в файле rewritings_levenshtein.json

Рассмотрим реализацию подробнее:

Метод main не имеет реализации какого-либо процесса, а просто поочередно вызывает функции, реализующие алгоритм

  def main():
    file = "sample.json"
    data_dictionary = convert_json_into_comparing_dictionary(file)
    rewriting_dictionary = find_rewriting(data_dictionary)
    full_data_dictionary = unpack_json(file)
    create_rewritings_file(rewriting_dictionary, full_data_dictionary)
Рассмотри методы вызываемые в main по очередности:
  1. Посмотрим на функцию convert_json_into_comparing_dictionary:
def convert_json_into_comparing_dictionary(file):
    with open(file, 'r', encoding='utf-8') as f:
        data = json.load(f)
        data_dictionary = {}
        for item in data:
            shorten_listed_text = delete_short_words_and_punctuation(item["text"])
            data_dictionary[item["id"]] = shorten_listed_text
        return data_dictionary

Данная функция открывает файл с данными, создаёт пустой словарь data_dictionary, затем проходит по всем текстам в предложенном файле и записывает в словарь пары ключ-значение, где ключ - это id текста, а значение - это текст, обработанный функцией delete_short_words_and_punctuation, рассмотрим работу этой функции:

def delete_short_words_and_punctuation(text_sample):
    no_punctuation_text = re.sub(r'[?,.!:;\"\'1234567890-]', '', text_sample)
    text_list = no_punctuation_text.split()
    for i in range(len(text_list) - 1, -1, -1):
        if len(text_list[i]) <= 2:  # можно менять резмер коротких слов
            del text_list[i]
    return text_list

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

Таким образом функция convert_json_into_comparing_dictionary записывает в значения словаря список длины не менее 3 слов текста и возвращает полученный таким образом словарь, который записывается в переменную data_dictionary в методе main

  1. Теперь рассотрим функцию find_rewriting:
def find_rewriting(data_dictionary):
    length_data = len(data_dictionary)
    rewriting_dictionary = {i: [] for i in range(1, length_data + 1)}
    for i in range(1, length_data + 1):
        first_listed_text_sample = data_dictionary[i]
        for j in range(i + 1, length_data + 1):
            second_listed_text_sample = data_dictionary[j]
            if is_it_rewriting(first_listed_text_sample, second_listed_text_sample):
                rewriting_dictionary[i] += [j]
    return rewriting_dictionary

Данная функция принимает на вход словарь, полученный на предыдущем шаге, затем записывает его длинну в переменную length_data, создаёт словарь, ключами которого являются все id наших текстов (то есть числа от 1 до длинны датасета). Далее циклом for мы проходим по всем id наших текстов и записываем в переменную first_listed_text_sample список слов длины не менее 3 текста с id равным i. Далее мы проходим по всем текстам, у которых id больше id текста first_listed_text_sample. Мы идём не по всем текстам для экономии времени, т.е. для избежания ситуации, когда какие-то два текста сравниваются несколько раз. Затем мы вызываем фцнкцию is_it_rewriting для определения, являются ли предложения реерайтингом.

def is_it_rewriting(first_listed_text_sample, second_listed_text_sample):
    first_listed_text_sample_length = len(first_listed_text_sample)
    second_listed_text_sample_length = len(second_listed_text_sample)
    rewrote_words_cnt = 0
    percentage_for_word_to_be_rewriting = 60  # можно менять процентовку
    percentage_for_text_to_be_rewriting = 75
    for i in range(first_listed_text_sample_length):
        min_distance = 10 ** 9
        for j in range(second_listed_text_sample_length):
            editing_distance = levenshtein_distance(first_listed_text_sample[i], second_listed_text_sample[j])
            if editing_distance < min_distance:
                min_distance = editing_distance
        if min_distance / len(first_listed_text_sample[i]) * 100 <= 100 - percentage_for_word_to_be_rewriting:
            rewrote_words_cnt += 1
    if rewrote_words_cnt / max(first_listed_text_sample_length,
                               second_listed_text_sample_length) * 100 >= percentage_for_text_to_be_rewriting:
        return True
    return False

Данная функция принимает на вход списки слов длины хотя бы 3 двух текстов и определяет являются ли они ререайтингом. Для этого мы сначала задаём критерии того, что слово являестя рерайтингом и, что предложение является ререайтингом, записывая в переменные percentage_for_word_to_be_rewriting и percentage_for_text_to_be_rewriting процент совпадения, которого достаточно для того, чтобы назвать слово/текст рерайтиногм. Далее с помощью циклов for мы для каждого слова из первого текста проверяем слова из второго текста на рерайтинг. Для этого мы находим для каждого слова первого предложения слово из второго предложения с минимальным расстоянием Левенштейна, далее если процент правок для получения из первого слова второго по отношению к длине первого слова не превосходит 100 - percentage_for_word_to_be_rewriting, то считаем слово рерайтингом и прибавляем к счётчику слов-рерайтингов rewrote_words_cnt 1. Когда такая операция проделана для всех слов, находим процент рерайтингов от количества слов в наиболее длинном тексе. Если этот процент не меньше percentage_for_text_to_be_rewriting, то считаем предложение рерайтингом и возвращаем True, иначе False

Ремарка по поводу реализации алгоритма поиска расстоянил Левенштейна:

Данный алгорит реализован 2 функциями

def substitute_difference(letter1, letter2):
    return letter1 != letter2


def levenshtein_distance(word1, word2):
    if len(word2) < len(word1):
        word1, word2 = word2, word1
    previous = [z for z in range(len(word1) + 1)]
    current = []
    for i in range(1, len(word2) + 1):
        for j in range(len(word1) + 1):
            if j == 0:
                current.append(i)
            else:
                insertation = current[j - 1] + 1
                delete = previous[j] + 1
                substitute = previous[j - 1] + substitute_difference(word1[j - 1], word2[i - 1])
                current.append(min(insertation, delete, substitute))
        previous, current = current, []
    return previous[-1]

Реализован алгоритм итеративным подходом с минимальными затратами по памяти. Мы храним только 2 массива: previous и current. Алгоритм расчитывает очередное значения для массива current, как мининмум из insertation = current[j - 1] + 1, delete = previous[j] + 1, substitute = previous[j - 1] + substitute_difference(word1[j - 1], word2[i - 1]), то есть выбирая наболее благоприятный случай из удаления элемента из сторки, вставкой элемента в строку и заменой элемента на другой. В данном случае функция substitute_difference не несёт большой смысловой нагрузки и только отвечает на вопрос, равны ли элементы, но в перспективе данную функцию можно сделать сложнее, добавив разные веса замене разных букв. Таким образом мы реализуем алгоритм вычисления рассотяния Левенштейна, находя его для префиксов исходных слов и итеративно доходя до полных слов, при этом не храня в памяти всю матрицу сравнения для всех префиксов, а лишь последние её 2 строки. Также можно заметить, что возможно назначить разным операциям (вставка, удаление, замена) разные веса для более точных результатов.

Теперь мы выяснили, являются ли данные два текста рерайтингом. Тогда вернёмся к функции find_rewriting. Если мы поняли, что очередные два текста являются рерайтингом, то в словарь rewriting_dictionary по ключу равному id первого такста добавляется значение, равное id второго текста. И после прохода по всем парам предложений функция возвращает словарь rewriting_dictionary. Заметим, что если у нас есть два предложения с id равными n и m где n<=m, то в полученном словаре в списке значений ключа n будет находиться m, однако в списке значений ключа m не будет n. Это не ошибка, так происходит именно потому, что каждая пара текстов сравнивается только однажды, а также это уменьшает затраты по памяти и упрощает запись результатов в файл.

  1. Рассмотри функцию unpack_json:
def unpack_json(file):
    with open(file, 'r', encoding='utf-8') as f:
        data = json.load(f)
        data_dictionary = {}
        for item in data:
            data_dictionary[item["id"]] = item["text"]
        return data_dictionary

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

  1. Посмотрим на create_rewritings_file:
def create_rewritings_file(rewriting_dictionary, full_data_dictionary):
    data = []
    length = len(rewriting_dictionary)
    used_text_samples_ids = set()
    for i in range(1, length + 1):
        current_set = []
        if i not in used_text_samples_ids and len(rewriting_dictionary[i]) != 0:
            current_set.append({"id": i, "text": full_data_dictionary[i]})
            used_text_samples_ids.add(i)
            for el in rewriting_dictionary[i]:
                current_set.append({"id": el, "text": full_data_dictionary[el]})
                used_text_samples_ids.add(el)
            data.append(current_set)

    with open("rewritings_levenshtein_distance.json", "w") as json_file:
        json.dump(data, json_file, ensure_ascii=False, indent=2)

Данный метод проходит по словарю rewriting_dictionary и при условии, что список рерайтингов для данного текста не пуст, добавляет словарь со значениями id и text для каждого рерайтинги и самого текста в список current_set, а id рерайтингов и самого текста в множество used_text_samples_ids (это делается, чтобы в файл болки с рерайтингами не записывались по несколько раз), а затем список current_set добавляется в массив data, который в после конца цикла представляет собой массив, который включает в себя списки рерайтингов, объединённые в массивы. Этот список и записывается в файл rewritings_levenshtein.json.

Достоинства подхода:
  • Сравнительно небольшое время работы. Алгоритм работает за время O(n2m2l2), где n – количество текстов в датасете, m – cреднее количество слов длинны не менее 3 в одном тексте, l – среднее количество букв в слове длинны хотя бы 3 в датасете
  • Алгоритм точно работает для рерайтингов, в которых используются перестановка слов, удаление слов, использование параллельных конструкций, изменение прямой речи на косвенную
  • Есть возможность добавить веса для разных операций (замена, удаление, вставка) в алгоритм нахождения расстояния Левенштейна для более точных сравнений
Недостатки подхода:
  • Алгоритм не учитывает использование синонимов для рерайтинга и для текстов, в которых этот приём используется часто выдаёт неточные результаты
  • Не очень точено работает для текстов с маленьким количеством слов длины хотя бы 3. Это можно исправить, не удаляя «короткие» слова, но в этом случае увеличивается время работы и может теряться точность в иных случаях.

Подход 2: Поиск рерайтингов при помощи синсетов(наборов синонимов)

Данный алгоритм реализован Красновым Владиславом. В реализации используются файлы synsets.py, synsets-rewritings.json, sample.json, морфологический анализатор pymorphy2 и база данных WikiWordnet

Рассмотрим реализацию подробнее:

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

  1. Посмотрим на функцию normal_form:
def normal_form(word):
    word_info = morph.parse(word)[0]
    return word_info.normal_form

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

  1. Теперь рассмотрим функцию find_synonyms:
def find_synonyms(word):
    word_info = morph.parse(word)[0]
    normal_form = word_info.normal_form
    synonyms = [word_info.word]
    synsets = wikiwordnet.get_synsets(normal_form)
    for i in range(len(synsets)):
        x = synsets[i]
        for w in x.get_words():
            synonyms.append(w.lemma())
    return synonyms

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

  1. Рассмотрим функцию is_it_rewriting2:
def is_it_rewriting2(first_listed_text_sample, second_listed_text_sample):
    percentage_of_synsets_to_be_rewriting = 70
    first_listed_text_sample_length = len(first_listed_text_sample)
    second_listed_text_sample_length = len(second_listed_text_sample)
    synsets = []
    cnt_synsets = 0
    for i in range(first_listed_text_sample_length):
        synsets.append(find_synonyms(first_listed_text_sample[i]))
    synonyms = [element for row in synsets for element in row]
    for j in range(second_listed_text_sample_length):
        if normal_form(second_listed_text_sample[j]) in synonyms:
            cnt_synsets += 1
    if (cnt_synsets / max(first_listed_text_sample_length, second_listed_text_sample_length)) > \
            percentage_of_synsets_to_be_rewriting / 100:
        return True
    else:
        return False

Данная функция принимает на вход списки слов длины хотя бы 3 двух текстов и определяет являются ли они ререайтингом. Для этого мы сначала задаём критерий того, что предложение является ререайтингом, записывая в переменную percentage_of_synsets_to_be_rewriting процент совпадения, которого достаточно для того, чтобы назвать текст рерайтиногм. Далее с помощью циклов for мы для каждого слова из первого текста создаем список синонимов, который затем объединяем в один список всех синонимов первого текста. Затем мы ищем каждое слово второго текста в списке синонимов и если находим, то увеличиваем переменную cnt_synsets на 1. Когда такая операция проделана для всех слов, находим процент рерайтингов от количества слов в наиболее длинном тексе. Если этот процент не меньше percentage_for_text_to_be_rewriting, то считаем предложение рерайтингом и возвращаем True, иначе False.

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

Достоинства подхода:

• Высокая точность определения рерайтингов: алгоритм учитывает все основные приёмы рерайтинага и с высокой точностью определяет, являестся ли предложение рерайтингом • Есть возможность добавить веса для разных операций (замена, удаление, вставка) в алгоритм нахождения расстояния Левенштейна для более точных сравнений • Есть возможность добавить проверку на другие лексические средства, кроме синонимов(Антонимы, паронимы и др.)

Недостатки подхода:

• Достаточно большое время работы: Алгоритм работает за время $O(n^2m^2(l^2+k))$, где n – количество текстов в датасете, m – cреднее количество слов длинны не менее 3 в одном тексте, l – среднее количество букв в слове длинны хотя бы 3 в датасете, k – среднеколичество синонимов у слова длинны хотя бы 3 в датасете

Подход 3: Поиск рерайтингов при помощи коэффицента Жаккара

Данный алгоритм реализовал Костенко Александр. В реализации используются файлы JaccardIndex.py, rewritings_jaccard_index.json, sample.json,

Рассмотрим реализацию подробнее:

Открытие файла, запись файла, метод main, и другие методы можно подробнее рассмотреть в подходе 1, поэтому рассмотрим только реализацию поиска рерайтингов при помощи коэффицента Жаккара.

  1. Посмотрим на функцию jaccard_index:
def jaccard_index(word1: str, word2: str):
    set_w1 = set(word1)
    set_w2 = set(word2)
    shared = set_w1.intersection(set_w2)
    total = set_w1.union(set_w2)
    jaccard_ind = len(shared) / len(total)
    return jaccard_ind

Эта функция получает на вход два слова и вычисляет коэффициент сходства Жаккара для этих слов, который определяется как отношение количества общих уникальных букв к общему количеству уникальных букв в обоих словах.

  1. Теперь рассмотрим функцию is_it_rewriting:
def is_it_rewriting(first_listed_text_sample, second_listed_text_sample):
    first_listed_text_sample_length = len(first_listed_text_sample)
    second_listed_text_sample_length = len(second_listed_text_sample)
    rewrote_words_cnt = 0
    percentage_for_word_to_be_rewriting = 75  # можно менять процентовку
    percentage_for_text_to_be_rewriting = 75
    for i in range(first_listed_text_sample_length):
        max_index = -1
        for j in range(second_listed_text_sample_length):
            cur_jaccard_index = jaccard_index(first_listed_text_sample[i], second_listed_text_sample[j])
            if cur_jaccard_index > max_index:
                max_index = cur_jaccard_index
        if max_index * 100 > percentage_for_word_to_be_rewriting:
            rewrote_words_cnt += 1
    if rewrote_words_cnt / max(first_listed_text_sample_length,
                               second_listed_text_sample_length) * 100 >= percentage_for_text_to_be_rewriting:
        return True
    return False

Эта функция определяет, можно ли считать одну текстовую выборку переработкой другой на основе индекса Жаккара. Она принимает два параметра: first_listed_text_sample и second_listed_text_sample, которые являются списками строк. Вот последовательное описание функции:

• Инициализирует переменные для отслеживания длин двух текстовых выборок и счетчика для числа переписанных слов.

• Устанавливает пороговые проценты для слова и всего текста, которые должны быть превышены, чтобы считать текст переработкой.

• Проходит по словам в первой текстовой выборке.

• Для каждого слова проходит по словам во второй текстовой выборке.

• Вызывает функцию jaccard_index для вычисления индекса Жаккара между текущей парой слов.

• Обновляет максимальный индекс Жаккара (max_index), если текущий индекс Жаккара больше.

• Проверяет, превышает ли максимальный индекс Жаккара, умноженный на 100, пороговый процент для того, чтобы считать слово переписанным.

• Если слово соответствует критерию переписывания, увеличивает счетчик переписанных слов.

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

• Проверяет, превышает ли процент переписанных слов пороговый процент для того, чтобы считать весь текст переписанным.

• Возвращает True, если текстовую выборку можно считать переработкой, и False в противном случае.

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

Достоинства подхода:

• Сравнительно небольшое время работы. Алгоритм работает за время O(2ln2m2), где n – количество текстов в датасете, m – cреднее количество слов длинны не менее 3 в одном тексте, l – среднее количество букв в слове длинны хотя бы 3 в датасете

• Простота и понятность: Индекс Жаккара и его применение в данном контексте легко понять и реализовать. Это делает его доступным для широкого круга разработчиков и аналитиков данных.

• Независимость от размера данных: Алгоритм Сходства Жаккара не зависит от размера слов или строк, что делает его эффективным для работы с различными объемами данных.

• Учет уникальности элементов: Индекс Жаккара учитывает только уникальные элементы в каждом наборе, что может быть полезно при работе с текстами, где повторение слов может быть несущественным.

Недостатки подхода:

• Игнорирование порядка слов: Индекс Жаккара не учитывает порядок слов в тексте. Это может быть проблемой, поскольку порядок слов часто имеет большое значение в контексте текста.

• Игнорирование частоты слов: Индекс Жаккара также не учитывает частоту слов. Это может быть недостатком, поскольку частота слов может играть важную роль в определении сходства текстов.

• Не учитывает использование синонимов при рерайтинге, из-за чего не всегда резултаты получаются точными.

Подход 4: Поиск рерайтингов при помощи косинусного сходства

Данный алгоритм реализовал Краснов Владислав. В реализации используются файлы CosineSimilarity.py, sample.json, rewritings_cosine_similarity и билиотеки math и collections.

Рассмотрим реализацию подробнее:

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

  1. Посмотрим на функцию text_to_vector:
def text_to_vector(text):
    words = WORD.findall(text)
    return Counter(words)

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

  1. Теперь рассмотрим функцию get_cosine:
   def get_cosine(first_listed_text_sample, second_listed_text_sample):
    percentage_for_text_to_be_rewriting = 0
    first_listed_text_sample = ' '.join(first_listed_text_sample)
    second_listed_text_sample = ' '.join(second_listed_text_sample)
    vec1 = text_to_vector(first_listed_text_sample)
    vec2 = text_to_vector(second_listed_text_sample)
    intersection = set(vec1.keys()) & set(vec2.keys())
    numerator = sum([vec1[x] * vec2[x] for x in intersection])
    sum1 = sum([vec1[x] ** 2 for x in list(vec1.keys())])
    sum2 = sum([vec2[x] ** 2 for x in list(vec2.keys())])
    denominator = math.sqrt(sum1) * math.sqrt(sum2)

    if not denominator:
        return False
    else:
        percentage_for_text_to_be_rewriting = float(numerator) / denominator
        if percentage_for_text_to_be_rewriting > 0.75:
            return True
        else:
            return False

Данная функция считает косинусное сходство при помощи формулы image. Сначала считаем пересечения, то есть слова, которые есть в обоих предложениях, затем считаем числитель и знаменатель и сравниваем, получается ли сходство > 0.75, если да, то предложения можно считать очень близкими.

Достоинства подхода:

• Быстрая скорость работы O(n2m2) где n – количество текстов в датасете, m – cреднее количество слов длины не менее 3 в одном тексте.

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

Недостатки подхода:

• Алгоритм не учитывает использование синонимов для рерайтинга и для текстов, в которых этот приём используется часто выдаёт неточные результаты

• Не очень точечно работает для текстов с маленьким количеством слов длины хотя бы 3. Это можно исправить, не удаляя «короткие» слова, но в этом случае увеличивается время работы и может теряться точность в иных случаях.

Подход 5: TF-IDF (Term Frequency - Inverse Document Frequency)

Данный алгоритм реализован Ахунзяновым Ренатом. В реализации используются файлы sample.json, TF-IDF.py.

Результат работы данного метода записан в файле rewritings_tf-idf.json.

Рассмотрим реализацию подробнее:

Метод main не имеет реализации какого-либо процесса, а просто поочередно вызывает функции, реализующие алгоритм

    file = "sample.json"
    data_dictionary = convert_json_into_comparing_dictionary(file)
    dictionary_add_tf(data_dictionary)
    idf_dictionary = idf_computation(unpack_json_text_only(file))
    rewriting_dictionary = find_tfidf_rewritings(data_dictionary, idf_dictionary)
    full_data_dictionary = unpack_json(file)
    create_rewritings_file(rewriting_dictionary, full_data_dictionary, 'tf')
Рассмотри методы вызываемые в main по очередности:
  1. Считывание из файла выполняется аналогично с другими подходами

  2. Рассмотрим функцию dictionary_add_tf:

     length_data = len(data_dictionary)
     for i in range(1, length_data + 1):
         data_dictionary[i] = [data_dictionary.get(i, 0), tf_computation(data_dictionary[i])]
    

    Эта функция добавляет в словарь data_dictionary список TF для слов данного текста, которое считается в функции tf_computation.

  3. Рассмотрим функцию tf_computation:

     word_count = Counter(words)
     total_words = len(words)
     tf = {word: count / total_words for word, count in word_count.items()}
     return tf
    

Для каждого слова заданного текста она вычисляет отношение количества повторений этого слова в тексте и общего числа слов в тексте, что и является TF. Возвращает она словарь с ключами - словами текста и значениями - TF слов.

  1. Рассмотрим функцию idf_computation:

     total_documents = len(corpus)
     idf = {}
     for document in corpus:
         words = set(document.split())
         for word in words:
             idf[word] = idf.get(word, 0) + 1
    
     idf = {word: math.log(total_documents / (count + 1)) for word, count in idf.items()}
     return idf
    

    Данная функция проходит по всем текстам и каждое слово добавляет в словарь, в котором считает количество текстов, в которые входит слово, а затем вычисляет логарифм отношения общего числа документов и значения словаря для каждого слова. Благодаря этому алгоритм присваивает большие значения более редким словам в датасете, что даёт возможность выше ценить повотрение редких слов в текстах.

  2. Рассмотрим функцию find_tfidf_rewritings:

     length_data = len(data_dictionary)
     for i in range(1, length_data + 1):
         data_dictionary[i][1] = tfidf_computation(data_dictionary[i][1], idf_dictionary)
     rewriting_dictionary = {i: [] for i in range(1, length_data + 1)}
     for h in range(2, length_data + 1):
         first_tfidf = data_dictionary[h][1]
         for j in range(h + 1, length_data + 1):
             second_tfidf = data_dictionary[j][1]
             if is_it_rewriting_tfidf(first_tfidf, second_tfidf):
                 rewriting_dictionary[h] += [j]
     return rewriting_dictionary
    

    Данная функция для каждого предложения вычисляет TF-IDF для каждого слова, что являеся произведением TF и IDF очередного слова. Затем мы сравниваем кадые тексты попарно, вычисляя евклидово рассотяние между векторам TF-IDF. В нашем случае это значит, что мы проверяем, что в предложениях хотя бы 75% слов совпадает и тогда считаем корень из суммы квадратов разностей TF-IDF слов, которые встречаются в обоих текстах. И если данная велчина оказалась не больше 1, считаем тексты ререайтиногом и записываем их в словарь рерайтингов.

  3. Запись в файл происходит аналогично осталным подходам

Достоинства подхода:

• Достаточно высокая скорость работы алгоритма. Он выполняется за время O(n2m2+mn), где n – количество текстов в датасете, m – cреднее количество слов длины не менее 3 в одном тексте • Достаточно высокая эффективность выявления рерайтингов, в которых используются перестановка слов, удаление слов, использование параллельных конструкций • Благодаря умножению на IDF алгоритм хорошо выявляет ререайтинги, в которых используются редкие слова для данного датасета • Хорошо преминем для сравнения больших текстов

Недостатки подхода:

• Алгоритм плохо выявляет рерайтинги, в которых форма многих слов изменена и в которых используются синонимы, из-за этого результаты его работы иногда могут быть не совсем точными

About

Поиск рерайтингов алгоритмическими методами

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages