python清洗数据去除停用词_关于regex:在Python中删除停用词的快捷方法

我正在尝试从文本字符串中删除停用词:

1

2

3from nltk.corpus import stopwords

text = 'hello bye the the hi'

text = ' '.join([word for word in text.split() if word not in (stopwords.words('english'))])

我正在处理600万这种字符串,因此速度很重要。 分析我的代码,最慢的部分是上面的几行,是否有更好的方法来做到这一点? 我正在考虑使用正则表达式的re.sub之类的东西,但是我不知道如何为一组单词写模式。 有人可以帮我吗,我也很高兴听到其他可能更快的方法。

注意:我尝试过有人建议用set()包装stopwords.words('english'),但这没什么区别。

谢谢。

stopwords.words(english)有多大?

@SteveBarnes 127个单词的列表

您将其包装在列表理解内还是外部? 尝试添加stw_set = set(stopwords.words(english))并使用此对象代替

@alko我以为我将其包装在外面并没有任何效果,但是我只是再次尝试了一下,现在我的代码运行速度至少快了10倍!!!

您是逐行处理文本还是一起处理文本?

@glasslion逐行

NLTK可能会删除停用词

尝试缓存停用词对象,如下所示。每次调用函数时都要构造它,这似乎是瓶颈。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16from nltk.corpus import stopwords

cachedStopWords = stopwords.words("english")

def testFuncOld():

text = 'hello bye the the hi'

text = ' '.join([word for word in text.split() if word not in stopwords.words("english")])

def testFuncNew():

text = 'hello bye the the hi'

text = ' '.join([word for word in text.split() if word not in cachedStopWords])

if __name__ =="__main__":

for i in xrange(10000):

testFuncOld()

testFuncNew()

我通过探查器运行了此命令:python -m cProfile -s累积test.py。相关行如下。

nCalls累积时间

10000 7.723个单词.py:7(testFuncOld)

10000 0.140个单词。py:11(testFuncNew)

因此,缓存停用词实例可以使速度提高约70倍。

同意性能的提高来自缓存停用词,而不是真正创建set。

当然,您不必每次都从磁盘读取列表,因此会得到极大的提升,因为那是最耗时的操作。但是,如果您现在将"已缓存"列表变成一组(当然只有一次),您将获得另一个提升。

谁能告诉我这是否支持日语?

它给了我这个UnicodeWarning:Unicode相等比较无法将两个参数都转换为Unicode-将它们解释为不相等的text = .join([如果不是stop_words中的单词,则为text.split()中的单词)] Salomone为我提供了解决方案这个

它也可以与pandas数据帧一起使用吗(加速)df[column]=df[column].apply(lambda x: [item for item in x if item not in cachedStopWords])

使用正则表达式删除所有不匹配的单词:

1

2

3import re

pattern = re.compile(r'\b(' + r'|'.join(stopwords.words('english')) + r')\b\s*')

text = pattern.sub('', text)

这可能比循环您自己快得多,特别是对于大型输入字符串。

如果由此删除了文本中的最后一个单词,则您可能会有尾随空格。我建议分开处理。

知道这有多复杂吗?如果w =我的文本中的单词数,而s =停止列表中的单词数,我认为循环将以w log s的顺序进行。在这种情况下,w约为s,因此其w log w。 grep会不会慢一些,因为它(必须)逐个字符地匹配?

实际上,我认为O(...)含义的复杂性是相同的。两者都是O(w log s),是的。但是,正则表达式是在较低的级别上实现的,并且进行了优化。单词拆分已经导致复制所有内容,创建字符串列表以及列表本身,所有这一切都花费了宝贵的时间。

首先,您要为每个字符串创建停用词。创建一次。集合确实在这里很棒。

1forbidden_words = set(stopwords.words('english'))

稍后,摆脱join内部的[]。请改用生成器。

1' '.join([x for x in ['a', 'b', 'c']])

替换为

1' '.join(x for x in ['a', 'b', 'c'])

接下来要处理的是使.split()产生值,而不是返回数组。 我相信regex在这里将是很好的替代品。 s>有关为什么s.split()确实很快的原因,请参见此内容。

最后,并行执行此作业(删除6m字符串中的停用词)。那是一个完全不同的话题。

我怀疑使用正则表达式会有所改进,请参见stackoverflow.com/questions/7501609/python-re-split-vs-split/

刚刚发现它。 :)

谢谢。 set至少使速度提高了8倍。为什么使用生成器有帮助? RAM对我来说不是问题,因为每段文本都非常小,大约100-200个字。

实际上,我已经看到join在列表理解方面的性能要优于等效的生成器表达式。

抱歉回复晚了。

将会对新用户有用。

使用集合库创建停用词词典

使用该字典进行非常快速的搜索(时间= O(1)),而不要在列表上进行搜索(时间= O(停用词))

1

2

3

4from collections import Counter

stop_words = stopwords.words('english')

stopwords_dict = Counter(stop_words)

text = ' '.join([word for word in text.split() if word not in stopwords_dict])

与基于正则表达式的方法相比,确实确实可以大大加快速度。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值