Найти слово рядом с другим словом, в пределах N # слов

Мне нужна перечисляющая функция регулярного выражения, которая идентифицирует экземпляры в строке, когда «Слово 1» находится в пределах N # слов «Слова 2».

Например, вот мой фрейм данных и цель:

Ввод данных Pandas

data = [['ABC123', 'This is the first example sentence the end of 
sentence one'], ['ABC456', 'This is the second example sentence one more 
sentence to come'], ['ABC789', 'There are no more example sentences']]
df = pd.DataFrame(data, columns=['Record ID', 'String'])
print(df)

Record ID | String
----------|-----------------------
ABC123    | This is the first example sentence the end of sentence one
ABC456    | This is the second example sentence one more sentence to come
ABC789    | There are no more example sentences

Слово 1 = «предложение» Слово 2 = 'то' В пределах N# слов (смещенных) = 3

Желаемый вывод кадра данных

output_data = [['ABC123', 3], ['ABC456', 1], ['ABC789', 0]]
df = pd.DataFrame(output_data, columns=['Record ID', 'Occurrences Identified'])
print(df)

Record ID | Occurrences Identified
----------|-----------------------
ABC123    | 3
ABC456    | 1
ABC789    | 0

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

\b(?:'sentence'\W+(?:\w+\W+){0,3}?'the'|'the'\W+(?:\w+\W+){0,3}?'sentence')\b

Меня также интересуют более простые решения без регулярных выражений, если таковые имеются.

Data = pd.read_sql(query, engine)

# Convert to Pandas DataFrame
nearwordDF = pd.DataFrame(Data)

# Remove non-alpha characters and make all lowercase
nearwordDF['text'] = nearwordDF['text'].str.replace(',', ' ')
nearwordDF['text'] = nearwordDF['text'].str.replace('.', '')
nearwordDF['text'] = nearwordDF['text'].str.replace('?', '')
nearwordDF['text'] = nearwordDF['text'].str.replace('\r', '')
nearwordDF['text'] = nearwordDF['text'].str.lower()

print(nearwordDF)
--------------------------
id        text
ABC123    how much money do i have in my money account
ABC456    where is my money
ABC789    hello  how are you today what is your name
DEF123    my money market fund is my only money of my account

import re
import pandas as pd

output = []
for i in nearwordDF:
    regex = r'(?:my(?:\s\w+){0,2})\s(?=money)|(?:money(?:\s\w+){0,2})\s(?=my)'
    nearwordDF = re.findall(regex, i[1])
    output.append([i[0], len(nearwordDF)])

df = pd.DataFrame(output, columns=['Record ID', 'Occurrences'])
print(df)

-----------------------------------
# Output
Record ID    Occurrences
i            0
t            0

Можете ли вы объяснить, почему ABC123 получил 3 вхождения?

Ramesh 11.01.2023 06:23

@ Рамеш, конечно, без проблем. Вот визуальное объяснение того, почему для каждой записи: imgur.com/hMpHIBn

tshobe 11.01.2023 07:35
This is the first example sentence the end of sentence one в этом тексте всего 2 вхождения the и sentence это правильно?
Ramesh 11.01.2023 09:05

@Ramesh Есть три случая: (1) «первое примерное предложение», (2) «предложение», (3) «конец предложения». (1) и (2) перекрываются.

Green绿色 11.01.2023 10:41

@ Рамеш да, утвердительно. Есть ли способ закрыть этот вопрос как «решенный» или я должен просто поделиться с вами предпочтительным решением в сообщении?

tshobe 18.01.2023 22:27

Если вопрос решен, то «примите» ответ с решением. Если ни один из существующих ответов не является правильным или достаточным, напишите полный ответ и примите его. См. страницы Справочного центра для получения дополнительной информации о принятии ответов.

AdrianHHH 19.01.2023 18:28
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Отказ от ответственности: Эта статья предназначена только для демонстрации и не должна использоваться в качестве инвестиционного совета.
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
Потяните за рычаг выброса энергососущих проектов
Потяните за рычаг выброса энергососущих проектов
На этой неделе моя команда отменила проект, над которым я работал. Неделя усилий пошла насмарку.
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Привет, люди RPA, это снова я и я несу подарки! В очередном моем приключении о том, как создавать ботов для облегчения рутины. Вот, думаю, стоит...
1
6
141
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Возможно, регулярное выражение здесь не подходит.

Если вы разделите свою входную строку на список, вы сможете найти индексы слов 1 и 2 и вычислить, насколько далеко они друг от друга:

string = 'This is the first example sentence the end of sentence one'
string_list = string.split(' ')
indices_word_1 = [i for i, x in enumerate(string_list) if x == "sentence"]
indices_word_2 = [i for i, x in enumerate(string_list) if x == "the"]
result = 0
for i in indices_word_1:
    for j in indices_word_2:
        _distance = abs(i - j)
        if _distance <= 3:
            result += 1

В этом случае результат равен 3.

@tshobe, вот один из способов реализовать мое предложение:

import pandas


def check_occurences(string, word_1='sentence', word_2='the', allowed_distance=3):
    string_list = string.split(' ')
    indices_word_1 = [i for i, x in enumerate(string_list) if x == word_1]
    indices_word_2 = [i for i, x in enumerate(string_list) if x == word_2]
    result = 0
    for i in indices_word_1:
        for j in indices_word_2:
            _distance = abs(i - j)
            if _distance <= allowed_distance:
                result += 1
    return result


def main():
    data = [['ABC123', 'This is the first example sentence the end of sentence one'],
        ['ABC456', 'This is the second example sentence one more sentence to come'],
        ['ABC789', 'There are no more example sentences']]
    df = pandas.DataFrame(data, columns=['Record ID', 'String'])

    results_df = pandas.DataFrame(columns=['Record ID', 'Occurrences'])

    results_df['Record ID'] = df['Record ID']
    results_df['Occurrences'] = df['String'].apply(lambda x: check_occurences(x))

    print(results_df)


if __name__ == "__main__":
    main()

Это хорошее решение с использованием перечисления и индекса :).

Ramesh 11.01.2023 12:56

Как использовать это в уже существующем кадре данных Pandas с определенным столбцом для строки? Когда я запускаю это, ничего не происходит, ничего не возвращается. Я использую это в начале? string_list = pandasDF['Имя столбца'].str.split(' ') Кроме того, как мне получить вывод в нужном мне формате, где это новый фрейм данных с двумя столбцами (идентификатор записи и идентифицированные вхождения)?

tshobe 11.01.2023 17:10

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

O-O-O 11.01.2023 17:33

@tshobe, пожалуйста, посмотрите мое решение, я добавил реализацию

O-O-O 11.01.2023 17:45

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

>>> re.compile(r'\b(?:sentence\W+(?:\w+\W+){0,3}?the|the\W+(?:\w+\W+){0,3}?sentence)\b', re.I).finditer("This is the first example sentence the end of sentence one")
[<_sre.SRE_Match object; span=(8, 34), match='the first example sentence'>,
 <_sre.SRE_Match object; span=(35, 54), match='the end of sentence'>]

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

Вы можете использовать положительный взгляд вперед (?=), чтобы подтвердить слово sentence.

import re
import pandas as pd
data = [['ABC123', 'This is the first example sentence the end of sentence one'],
        ['ABC456', 'This is the second example sentence one more sentence to come'],
        ['ABC789', 'There are no more example sentences']]
output = []
for i in data:
    regex = r'(?:the(?:\s\w+){0,2})\s(?=sentence)|(?:sentence(?:\s\w+){0,2})\s(?=the)'
    data = re.findall(regex, i[1])
    output.append([i[0], len(data)])
print(output)
df = pd.DataFrame(output, columns=['Record ID', 'Occurrences Identified'])
print(df)

Выход

[['ABC123', 3], ['ABC456', 1], ['ABC789', 0]]

  Record ID  Occurrences Identified
0    ABC123                       3
1    ABC456                       1
2    ABC789                       0

Это здорово, но как и где именно мне вставить уже созданный ранее существующий фреймворк данных? Мои данные уже в формате Pandas Dataframe и содержат тысячи строк (из запроса SQL). Когда я пытаюсь подключить его к вашему фрагменту кода, он просто получает сообщения об ошибках, например, длина не соответствует или «Серия» не может быть вызвана, или вывод просто пуст.

tshobe 11.01.2023 17:05

Если регулярное выражение работает, вы можете добавить его в предложение выбора sql вместо того, чтобы запрашивать ваши данные, а затем запускать регулярное выражение на вашем df из python.

O-O-O 11.01.2023 19:26

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

tshobe 12.01.2023 06:58

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

Ramesh 12.01.2023 07:04

Другие вопросы по теме