Как удалить дублирующиеся строки в списке строк с помощью регулярного выражения в Python?

#python #regex #pandas #string #substring

Вопрос:

У меня есть фрейм данных, как показано ниже

 df

Index   Lines

0  /// User states this is causing a problem and but the problem can only be fixed by the user. /// User states this is causing a problem and but the problem can only be fixed by the user.
1  //- How to fix the problem is stated below. Below are the list of solutions to the problem. //- How to fix the problem is stated below. Below are the list of solutions to the problem.
2 \ User describes the problem in the problem report.
 

Я хочу удалить повторяющиеся предложения, но не дублированные слова.

Я попробовал следующее решение, но оно также удаляет дублирующиеся слова в процессе.

 df['cleaned'] = (df['lines'].str.split()
                                  .apply(lambda x: OrderedDict.fromkeys(x).keys())
                                  .str.join(' '))
 

Это приводит к

 Index   cleaned

0  /// User states this is causing a problem and but the can only be fixed by user.
1  //- How to fix the problem is stated below. Below are list of solutions problem.
2  User describes the problem in report.
 

Но ожидаемое решение таково :

 Index   cleaned

0  /// User states this is causing a problem and but the problem can only be fixed by the user.
1  //- How to fix the problem is stated below. Below are the list of solutions to the problem.
2 \ User describes the problem in the problem report.
 

Как мне заставить его удалить повторяющиеся строки, но не повторяющиеся слова? Есть ли способ сделать это ?

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

Пожалуйста, посоветуйте или предложите. Спасибо!!

Комментарии:

1. Если я правильно понял, у вас есть фрейм данных, который содержит предложения для каждого элемента, верно? Что-то вроде этого: df = { 0: «Первое предложение», 1: «Второе предложение», …}? Затем, если предложение появляется в этой большой строке более одного раза, удалите дубликаты. Правильно ли так думать?

2. @NickS1 Почти правильно, за исключением того, что мне нужно удалить только повторяющиеся строки, а не повторяющиеся слова в строках. Например, 0: «a a», где a-большая строка, повторяемая дважды. Я хочу, чтобы это было 0:»a», но любые дублированные слова, находящиеся внутри a, не должны удаляться.

3. Я понял, спасибо за объяснение. Есть еще один вопрос. У вас есть что-то, отделяющее каждое предложение от следующего? Как пустое место? Я думаю, вы тоже хотели бы их удалить, верно?

4. Я думаю, что даже пустое место может остаться до тех пор, пока строки не будут повторяться @NickS1

5. Извините, @2e0byo уже решил эту проблему. Я не обратил внимания на то, что каждое предложение заканчивается точкой и пробелом. Мне действительно жаль, ха-ха

Ответ №1:

IIUC:

 out = df['Lines'].str.findall(r'[^.] ').explode() 
                 .reset_index().drop_duplicates() 
                 .groupby('Index')['Lines'] 
                 .apply(lambda x: '.'.join(x))
 
 >>> out[0]
 /// User states this is causing a problem and but the problem can only be fixed by the user

>>> out[1]
 //- How to fix the problem is stated below. Below are the list of solutions to the problem

>>> print(out[2])
\ User describes the problem in the problem report
 

Комментарии:

1. @code_learner. Можете ли вы проверить это возможное решение. Дайте мне знать, если что-то не так.

2. Хорошо подходит для этого примера. Мне было интересно, что, если в элементе столбца есть несколько строк, таких как «это здорово. работает хорошо. это здорово. работает хорошо». Это закончится так: «это здорово. работает хорошо. это здорово». Вместо поиска «.» можем ли мы найти первую строку «это здорово» и проверить внутри большой строки, появится ли снова первая строка, и удалить все после?

3. Для следующей строки, каков ожидаемый результат: «это здорово. работает хорошо. это здорово. работает достаточно хорошо».

4. Предполагаемый результат должен быть «это здорово. работает хорошо. «поскольку эти две строки повторяются.

5. «это здорово. работает хорошо. это здорово. работает достаточно хорошо». <<

Ответ №2:

Поскольку ваш фрейм данных просто хранит строки, давайте просто сделаем это вручную:

 seen = set()
for i, row in enumerate(df["lines"]):
    lines = row.split(". ")
    keep = []
    for line in lines:
        line = line.strip()
            # if you want to clean up
            line = line.strip("\/-").strip()
        if line[-1] != ".":
            line  = "."
        if line not in seen:
            keep.append(line)
            seen.add(line)
    df["lines"][i] = " ".join(keep)
 

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

Поскольку токен, на который мы разделяемся, удален, мы добавляем «.» к каждому предложению, которое не заканчивается на».».

Комментарии:

1. Проблема в том, что объект серии не имеет «итераций».

2. да, беспокоит, извините; обновлено. забыл о последовательностях.

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

4. @code_learner о , черт возьми, я должен перестать отвечать на вопросы сегодня вечером и лечь спать; есть еще одна опечатка—не должно быть lines , должно быть keep …..

5. Протестировано, и теперь это действительно работает . Также добавлена очистка, но вы, возможно, этого не захотите.