У меня есть список твитов, содержащих слова отрицания, такие как «не, никогда, редко».
Я хочу преобразовать «нехорошо» в «нехорошо» (разделенные знаком подчеркивания).
Как я могу присоединиться ко всем «не» в твитах со словами, которые следуют за ними?
Я пытался сделать это, но это ничего не меняет, предложения остаются прежними без изменений.
def combine(negation_words, word_scan):
if type(negation_words) != list:
negation_words = [negation_words]
n_index = []
for i in negation_words:
index_replace = [(m.end(0)) for m in re.finditer(i,word_scan)]
n_index += index_replace
for rep in n_index:
letters = [x for x in word_scan]
letters[rep] = "_"
word_scan = "".join(letters)
return word_scan
negation_words = ["no", "not"]
word_scan = df
combine(negation_words, word_scan)
df['clean'] = df['tweets'].apply(lambda x: combine(str(x), word_scan))
df
Вы можете использовать re.sub или Series.str.replace с регулярным выражением, чтобы найти любое слово в вашем списке negation_words, за которым следуют пробелы, и заменить его символом подчеркивания.
import re
negation_words = ["no", "not"]
escaped_words = "|".join(re.escape(word) for word in negation_words)
print(repr(escaped_words))
# 'no|not'
regex = fr"({escaped_words})\s+"
print(repr(regex))
# '(no|not)\\s+'
Объяснение регулярного выражения:
(no|not)\s+
( ) : Capturing group. Whatever is matched inside is available to the replace string as \1 (since this is the first capturing group)
no|not : Either of (no, not). If there are more words, then any one of these words
\s+ : One or more whitespace
Теперь вызовите Series.str.replace с case=False, чтобы выполнить поиск без учета регистра:
df = pd.DataFrame({'tweets': ['this is a tweet', 'this is not a tweet', 'no', 'Another tweet', 'Not another tweet', 'Tweet not']})
df['clean'] = df['tweets'].str.replace(regex, r'\1_', case=False, regex=True)
Который дает:
tweets clean
0 this is a tweet this is a tweet
1 No tweeting No_tweeting
2 no no
3 Another tweet Another tweet
4 Not another tweet Not_another tweet
5 Tweet not Tweet not
Соединить два слова после появления одного из negation_words немного сложнее:
regex = fr"({escaped_words})\s+(\w+)\s+"
print(repr(regex))
# '(no|not)\\s+(\\w+)\\s+'
Объяснение:
(no|not)\s+(\w+)\s+
( ) : Capturing group. Whatever is matched inside is available to the replace string as \1 (since this is the first capturing group)
no|not : Either of (no, not). If there are more words, then any one of these words
\s+ : One or more whitespace
( ) : Capturing group #2
\w+ : One or more word characters
\s+ : One or more whitespace
df = pd.DataFrame({'tweets': ['this is a tweet', 'this is not a tweet', 'no', 'Another tweet', 'Not another tweet', 'Tweet not']})
df['clean'] = df['tweets'].str.replace(regex, r'\1_\2_', case=False, regex=True)
Который дает:
tweets clean
0 this is a tweet this is a tweet
1 this is not a tweet this is not_a_tweet
2 no no
3 Another tweet Another tweet
4 Not another tweet Not_another_tweet
5 Tweet not Tweet not
@ZulfiA re.escape экранирует любые специальные символы при вводе, например. (, [ и т. д., чтобы их особое значение игнорировалось, и они считались буквальными символами. Это не обязательно для конкретного negation_words, который вы указали в своем вопросе, но полезно для обобщения подхода к случаям, когда могут существовать такие специальные символы. Если ваш исходный фрейм данных содержит весь текст в нижнем регистре, вы можете опустить аргумент case, но его не помешает сохранить.
Так что все в порядке, если я удалю экранированные слова, верно? в данных моих твитов нет специальных символов, потому что я уже очистил их все :) и получил его предупреждение :FutureWarning: Значение регулярного выражения по умолчанию изменится с True на False в будущей версии. Что это значит?
Недопустимо удалять escaped_words, потому что эта строка также соединяет все слова с вертикальной чертой, что в регулярном выражении означает word1 or word2 or word3 or .... вы можете изменить его на '|'.join(negation_words), но, честно говоря, это не будет иметь значения, если у вас нет специальных символов.
Предупреждение связано с тем, что функция str.replace имеет аргумент regex, который по умолчанию равен true. Поскольку это будет изменено в будущей версии False, вы можете явно указать это, чтобы удалить предупреждение @ZulfiA.
Ага, понятно! что, если я хочу объединить слова с двумя словами, которые следуют за словами отрицания? пример: вместо "некрасиво" я хочу сделать так "некрасиво_действительно_".
Затем вы просто добавляете регулярное выражение, чтобы оно соответствовало слову после \s+ в regex, см. stackoverflow.com/a/20956093/843953
Я думаю, что это немного отличается от того, что я ищу :( можете ли вы объяснить, что означает «r'\1_'»? Большое спасибо!
R обозначает необработанный строковый литерал. \1 означает первую группу захвата (которая заключена в круглые скобки, в данном случае negatiin_word присутствует в тексте), а _ — буквальное подчеркивание. Завтра я обновлю свой ответ, чтобы он соответствовал двум словам
@ZulfiA смотрите мой обновленный ответ, чтобы захватить два слова и соединить их с подчеркиванием
Я не могу отблагодарить вас за вашу помощь. хорошего дня!
Используйте re.sub().