我有两个熊猫数据框。一个包含文本,另一个包含我要在文本中搜索和替换的一组术语。我有一种方法可以执行此操作,但是我想添加条件。条件是,如果该术语包含的单词“ no”或“ none”不超过三个单词,则该条件不能替代。

在下面的示例中,根据上述条件,ID 2被错误地替换。

示例文字:

d = {'ID': [1, 2, 3], 'Text': ['here is some random text', 'no such random text, none here', 'more random text']}
text_df = pd.DataFrame(data=d)


术语示例:

d = {'Replace_item': ['<RANDOM_REPLACED>', '<HERE_REPLACED>', '<SOME_REPLACED>'], 'Text': ['random', 'here', 'some']}
replace_terms_df = pd.DataFrame(data=d)


替换字词的方法(根据条件ID 2不正确):

text_df['Text'] = [z.replace(x, y) for (x, y, z) in zip(replace_terms_df.Text, replace_terms_df.Replace_item, text_df.Text)]


目标数据框(考虑条件):

d = {'ID': [1, 2, 3], 'Text': ['<HERE_REPLACED> is <SOME_REPLACED> <RANDOM_REPLACED> text', 'no such random text, none here', 'more  <RANDOM_REPLACED> text']}
target_df = pd.DataFrame(data=d)


请询问您是否需要澄清。谢谢。

最佳答案

使用正则表达式解决方案检查以下代码:

import re

# set up the regex pattern
# the words which should be skipped, must be whole word and case-insensitive
ptn_to_skip = re.compile(r'\b(?:no|none)\b', re.IGNORECASE)

# the pattern for mapping
# Note: any regex meta charaters need to be escaped, or it will fail.
ptn_to_map = re.compile(r'\b(' + '|'.join(replace_terms_df.Text.tolist()) + r')\b')

# map from text to Replace_item
terms_map = replace_terms_df.set_index('Text').Replace_item

def adjust_text(x):
    # if 1 - 3 ptn_to_skip found, return x,
    # otherwise, map the matched group \1 with terms_map
    if 0 < len(ptn_to_skip.findall(x)) <= 3:
        return x
    else:
        return ptn_to_map.sub(lambda y: terms_map[y.group(1)], x)

# do the conversion:
text_df['new_text'] = text_df.Text.apply(adjust_text)


一些注意事项:


我将replace_terms_df.Text中的文本转换为正则表达式。默认情况下,所有文本均为纯文本,不含正则表达式元字符。
如果有诸如“ $”,“]”等任何正则表达式元字符,则必须将其转义。正则表达式通常会变慢,特别是对于元字符而言,如果您有大量的数据,请不要向您建议这种解决方案。


更新:

添加了新的逻辑以首先检查排除的单词['no','none'],如果匹配,然后查找下一个本身不是排除的单词的0-3个单词,将它们保存为\ 1,即实际匹配的单词搜索词将保存在\ 2中。然后在正则表达式替换部分中,以不同的方式处理它们。

以下是新代码:

import re

# pattern to excluded words (must match whole-word and case insensitive)
ptn_to_excluded = r'\b(?i:no|none)\b'

# ptn_1 to match the excluded-words ['no', 'none'] and the following maximal 3 words which are not excluded-words
# print(ptn_1)  -->    \b(?i:no|none)\b\s*(?:(?!\b(?i:no|none)\b)\S+\s*){,3}
# where (?:(?!\b(?i:no|none)\b)\S+\s*) matches any words '\S+' which is not in ['no', 'none'] followed by optional white-spaces
# {,3} to specify matches up to 3 words
ptn_1 = r'{0}\s*(?:(?!{0})\S+\s*){{,3}}'.format(ptn_to_excluded)

# ptn_2 is the list of words you want to convert with your terms_map
# print(ptn_2)    -->    \b(?:random|here|some)\b
ptn_2 = r'\b(?:' + '|'.join(replace_terms_df.Text.tolist()) + r')\b'

# new pattern based on the alternation using ptn_1 and ptn_2
# regex:  (ptn_1)|(ptn_2)
new_ptn = re.compile('({})|({})'.format(ptn_1, ptn_2))

# map from text to Replace_item
terms_map = replace_terms_df.set_index('Text').Replace_item

# regex function to do the convertion
def adjust_map(x):
    return new_ptn.sub(lambda m:  m.group(1) or terms_map[m.group(2)], x)

# do the conversion:
text_df['new_text'] = text_df.Text.apply(adjust_map)


说明:

我定义了两个子模式:


ptn_1:尝试匹配您要排除的单词,即单词“ no”,“ none”和最多三个不包含在['no','none']中的单词
ptn_2:尝试根据replace_terms_df匹配要转换的单词之一。


怎么运行的:


如果使用替换项'|',则正则表达式引擎将确保ptn_1在ptn_2之前匹配,如果两者均不匹配,则保留原始文本。
匹配的ptn_1文本将保存在m.group(1)中,而ptn_2结果将保存到m.group(2)
在替换部分。如果m.group(1)不为Empty(意味着ptn_1已匹配),则返回m.group(1)(因此这部分匹配未被更改),否则返回terms_map [y.group(2)]


以下是一些测试:

In []: print(new_ptn)
re.compile('(\\b(?i:no|none)\\b\\s*(?:(?!\\b(?i:no|none)\\b)\\S+\\s*){,3})|(\\b(random|here|some)\\b)')

In[]: for i in [
    'yes, no such a random text'
  , 'yes, no such a a random text'
  , 'no no no such a random text no such here here here no'
 ]: print('{}:\n  [{}]'.format(i, adjust_map(i)))
...:
yes, no such a random text:
  [yes, no such a random text]
yes, no such a a random text:
  [yes, no such a a <RANDOM_REPLACED> text]
no no no such a random text no such here here here no:
  [no no no such a random text no such here here <HERE_REPLACED> no]


让我知道这个是否奏效。

更多考虑:


在ptn_1中,使用'\ S +'定义WORD,如果其中一个单词类似于',none',则会出现问题,前面的'逗号'将使其跳过(?!\ b(?:no |无))测试。
实际上,应该排除',no','“ none”'吗?这将影响单词的计数方式。修改ptn_to_excluded就足够了。

关于python - 字符串替换为条件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50080353/

10-14 17:42
查看更多