使用lambda从句子中删除单词列表

时间:2018-03-14 14:09:08

标签: python list lambda

我有一个数据框,每行对应一个字符串。我想从这些字符串中删除某些单词 - 这是我使用lambda函数的方法:

def remove_words(s):    
    return s.apply(lambda x: [x for x in x if x not in ["name", "is", "m"]])

s = pd.DataFrame({"s":["Hi my name is Joe", "Hi my name is Hannah", "Hi my name is Brian"]})
remove_words(s.s)

这不会产生正确的结果,因为它会从所有单词中删除m

0        [H, i,  , y,  , n, a, e,  , i, s,  , J, o, e]
1    [H, i,  , y,  , n, a, e,  , i, s,  , H, a, n, ...
2    [H, i,  , y,  , n, a, e,  , i, s,  , B, r, i, ...
Name: s, dtype: object

然而,我想要的结果是

0        ["Hi my Joe"]
1    ["Hi my Hannah"]
2    ["Hi my Brian"]
Name: s, dtype: object
  • 所以它应该只删除m,如果它是字符串中的单独字母。是否可以用lambdas做到这一点?

使用正则表达式时请查看此反例:

regex = '|'.join((' %s ' % word for word in ["in", "out", "between"])) 
test = pd.DataFrame({"s": ["hello in out between inner in"]})
test.s.str.replace(regex, " ")

这并没有排除所有outin

0    hello out inner in
Name: s, dtype: object

4 个答案:

答案 0 :(得分:2)

对于这种情况,使用.apply()和lambda有点效率低下。熊猫string methods是专门为此而建的:

>>> s1 = pd.Series(["Hi my name is Joe", "Hi my name is Hannah", "Hi my name isn't Brian"])   
>>> words = ['name', 'is']
>>> regex = r' *\b(?:{})\b'.format('|'.join(words))
>>> s.str.replace(regex, '').str.strip()
0       Hi my Joe
1    Hi my Hannah
2     Hi my isn't Brian
dtype: object

为什么不在这里使用.apply()?此方法是一种将(本机Python)可调用对象逐个映射到Pandas对象的每个元素的方法。通常,它可以导致以比必要的更慢的速度完成更多的工作。例如,在["".join([x for x in x if x not in ["name", "is"]])]中,您有(1)列表推导,(2).split(),以及(3)每个个体" cell"的加入操作。

根据您更新的案例:

>>> s2 = pd.Series(["hello in out between inner in"])
>>> words = ['in', 'out', 'between']
>>> regex = r' *\b(?:{})\b'.format('|'.join(words)) 
>>> s2.str.replace(regex, '').str.strip()
0    hello inner
dtype: object

构建str.strip()是为了处理结果在其中一侧或两侧用空格填充的情况。即使它们是方法链接的,使用.str方法也应该非常快。

答案 1 :(得分:2)

使用正则表达式re.sub

import re
# construct the regex pattern
words = ['name', 'is']
pattern = re.compile(r'\b({})\b'.format('|'.join(words)))

# apply the function on the series
s.s.apply(lambda x: re.sub('\s+', ' ', re.sub(pattern, '', x)))

re.sub使用两次,首先删除单词,然后替换额外的空格。

输出:

0       Hi my Joe
1    Hi my Hannah
2     Hi my Brian

\b是字边界的正则表达式模式。 \b(name|is|a)\b将匹配以下通过删除线指示的匹配

a 以任何其他名称

上升

正如您所看到的,即使是单字母单词也能正确匹配。但是,还有一个问题是上述解决方案尚未解决。

句子末尾的匹配将留下一个未被re.sub(r'\s+', ' ',...清理的空格。所以,也可能需要strip个空格。这取决于您的数据

根据该说明,最终解决方案变为:

s.s.apply(lambda x: re.sub('\s+', ' ', re.sub(pattern, '', x)).strip())

答案 2 :(得分:1)

这可能吗?

def remove_words(s):    
    return s.apply(lambda x: ["".join([x for x in x if x not in ["name", "is"]])])

答案 3 :(得分:1)

你的问题是对字符串的列表理解(它将返回每个字符)。首先对句子进行拆分,如:

def remove_words(s, stop_words):    
    return s.apply(lambda x: ' '.join(w for w in x.split() if w not in stop_words))

如果你想在列表中返回句子:

def remove_words_return_list(s, stop_words):    
    return s.apply(lambda x: [' '.join(w for w in x.split() if w not in stop_words)])

称之为:

remove_words(s, ['name', 'is', 'm'])
remove_words_return_list(s, ['name', 'is', 'm'])