在 python 中完全复制 R 文本预处理
Posted
技术标签:
【中文标题】在 python 中完全复制 R 文本预处理【英文标题】:Exactly replicating R text preprocessing in python 【发布时间】:2014-05-12 21:45:12 【问题描述】:我想使用 Python 以与在 R 中相同的方式预处理文档语料库。例如,给定一个初始语料库corpus
,我希望最终得到一个与使用以下 R 代码生成的:
library(tm)
library(SnowballC)
corpus = tm_map(corpus, tolower)
corpus = tm_map(corpus, removePunctuation)
corpus = tm_map(corpus, removeWords, c("myword", stopwords("english")))
corpus = tm_map(corpus, stemDocument)
是否有一种简单或直接(最好是预先构建)的方法在 Python 中执行此操作?有没有办法确保完全相同的结果?
比如我要预处理
@Apple 耳塞太棒了!我用过的入耳式耳机的最佳声音 曾经有过!
进入
ear pod amaz 有史以来最好的入耳式耳机
【问题讨论】:
在 Python 中使用 nltk 进行自然语言处理。 @ramcdougal:我收集了这么多,但我正在为文档而苦苦挣扎。 看看这个tutorial。它涵盖了标记化、停用词和词干。 @ramcdougal:这是一个好的开始。我缺少的是如何将其应用于大型数据集(例如在 Pandas 数据框中)或在scikit-learn
's CountVectorizer
之类的上下文中使用它,这似乎能够将预处理器作为参数。跨度>
【参考方案1】:
在预处理步骤上让nltk
和tm
之间的东西完全相同似乎很棘手,所以我认为最好的方法是使用rpy2
在R 中运行预处理并将结果拉入python:
import rpy2.robjects as ro
preproc = [x[0] for x in ro.r('''
tweets = read.csv("tweets.csv", stringsAsFactors=FALSE)
library(tm)
library(SnowballC)
corpus = Corpus(VectorSource(tweets$Tweet))
corpus = tm_map(corpus, tolower)
corpus = tm_map(corpus, removePunctuation)
corpus = tm_map(corpus, removeWords, c("apple", stopwords("english")))
corpus = tm_map(corpus, stemDocument)''')]
然后,您可以将其加载到 scikit-learn
中——要使 CountVectorizer
和 DocumentTermMatrix
之间匹配,您唯一需要做的就是删除长度小于 3 的术语:
from sklearn.feature_extraction.text import CountVectorizer
def mytokenizer(x):
return [y for y in x.split() if len(y) > 2]
# Full document-term matrix
cv = CountVectorizer(tokenizer=mytokenizer)
X = cv.fit_transform(preproc)
X
# <1181x3289 sparse matrix of type '<type 'numpy.int64'>'
# with 8980 stored elements in Compressed Sparse Column format>
# Sparse terms removed
cv2 = CountVectorizer(tokenizer=mytokenizer, min_df=0.005)
X2 = cv2.fit_transform(preproc)
X2
# <1181x309 sparse matrix of type '<type 'numpy.int64'>'
# with 4669 stored elements in Compressed Sparse Column format>
让我们用 R 来验证这个匹配:
tweets = read.csv("tweets.csv", stringsAsFactors=FALSE)
library(tm)
library(SnowballC)
corpus = Corpus(VectorSource(tweets$Tweet))
corpus = tm_map(corpus, tolower)
corpus = tm_map(corpus, removePunctuation)
corpus = tm_map(corpus, removeWords, c("apple", stopwords("english")))
corpus = tm_map(corpus, stemDocument)
dtm = DocumentTermMatrix(corpus)
dtm
# A document-term matrix (1181 documents, 3289 terms)
#
# Non-/sparse entries: 8980/3875329
# Sparsity : 100%
# Maximal term length: 115
# Weighting : term frequency (tf)
sparse = removeSparseTerms(dtm, 0.995)
sparse
# A document-term matrix (1181 documents, 309 terms)
#
# Non-/sparse entries: 4669/360260
# Sparsity : 99%
# Maximal term length: 20
# Weighting : term frequency (tf)
如您所见,现在两种方法之间存储的元素和术语的数量完全匹配。
【讨论】:
有没有办法将此传递给scikit-learn
的CountVectorizer
构造函数。文档使它看起来应该是可能的,但我不知道如何。
@raxacoricofallapatorius 更新为包含CountVectorizer
。很高兴看到有人在 python 中处理 15.071x 内容!
谢谢。我是 R(我讨厌它)Python(很棒)和分析的新手,所以很难。我希望这门课程是用 Python 教授的!
整个课程团队都对 R 充满热情(这就是我们选择 R 作为课程的原因),但很高兴您找到了适合您的软件包!
在调用removeSparseTerms
之前,3462 将与您的DocumentTermMatrix
中的术语数相匹配。你能用sort(colnames(as.matrix(sparseDTM)))
从R中输出排序后的名称并与sorted(vectorizer.get_feature_names())
的输出进行比较吗?【参考方案2】:
CountVectorizer
和TfidfVectorizer
可以按照docs 中的说明进行自定义。特别是,您需要编写一个自定义标记器,它是一个接收文档并返回术语列表的函数。使用 NLTK:
import nltk.corpus.stopwords
import nltk.stem
def smart_tokenizer(doc):
doc = doc.lower()
doc = re.findall(r'\w+', doc, re.UNICODE)
return [nltk.stem.PorterStemmer().stem(term)
for term in doc
if term not in nltk.corpus.stopwords.words('english')]
演示:
>>> v = CountVectorizer(tokenizer=smart_tokenizer)
>>> v.fit_transform([doc]).toarray()
array([[1, 1, 1, 2, 1, 1, 1, 1, 1]])
>>> from pprint import pprint
>>> pprint(v.vocabulary_)
u'amaz': 0,
u'appl': 1,
u'best': 2,
u'ear': 3,
u'ever': 4,
u'headphon': 5,
u'pod': 6,
u'sound': 7,
u've': 8
(我链接到的示例实际上使用了一个类来缓存词形分析器,但是一个函数也可以。)
【讨论】:
这不处理标点符号或自定义词(如josilber's answer 中的“apple”)。 @raxacoricofallapatorius 这只是一个例子。关键是你可以写一个 Python 函数并将其插入;该功能的作用完全取决于您。您几乎可以插入 josilber 的功能。以上是关于在 python 中完全复制 R 文本预处理的主要内容,如果未能解决你的问题,请参考以下文章