【问题标题】:Removing a list of words from sentences using lambda使用 lambda 从句子中删除单词列表
【发布时间】:2018-03-14 14:09:08
【问题描述】:

我有一个数据框,其中每一行对应一个字符串。我想从这些字符串中删除某些单词 - 这是我使用 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, " ")

这不会清除所有 out 或 in

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

【问题讨论】:

  • lambda x: [x for x in x if x not in... 你知道你可以使用任何你想要的变量名,对吧?将 lambda 参数和迭代变量都命名为 x 是一种混淆读者的好方法。

标签: python list lambda


【解决方案1】:

使用正则表达式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 由任何其他name

升起

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

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

有了这个注释,最终的解决方案就变成了:

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

【讨论】:

    【解决方案2】:

    在这种情况下,使用 .apply() 和 lambda 有点低效。 Pandas 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) 每个单独“单元格”的连接操作。

    更新后的案例:

    >>> 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 方法应该很快,即使它们是方法链的。

    【讨论】:

    • 我喜欢这种方法,但它似乎并不适用于所有情况。我在 OP 中做了一个示例,它不会删除所有不需要的单词的实例
    • 感谢您更新您的答案。还有 1 个 potential 情况,我已经突出显示匹配发生在字符串末尾的位置,例如 re.sub(r' *\bHi\b| *\bname\b| *\bis\b', '', 'Hi my name is Joe') 将需要在开头去除空格
    【解决方案3】:

    这大概?

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

    【讨论】:

      【解决方案4】:

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

      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'])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-03-17
        • 2021-08-20
        • 2018-09-28
        • 2018-01-15
        • 2021-12-29
        • 2011-11-04
        • 1970-01-01
        相关资源
        最近更新 更多