代码之家  ›  专栏  ›  技术社区  ›  revy

R tm包和Spark/python为文档术语频率任务提供了不同的词汇表大小

  •  0
  • revy  · 技术社区  · 7 年前

    我有一个csv,只有一列,每一行是一个文本文档。所有文本都已规范化:

    • 全部小写
    • 没有标点符号
    • 单词之间不超过一个空格
    • 无标记(xml、html)

    第一步是生成文档术语矩阵,其中每个术语都有文档中的相对频率计数。问题是,相对于spark api或pythonskilearn,我使用R获得不同的词汇表大小(spark和python在结果中是一致的)。

    这是R的相关代码:

    library(RJDBC)
    library(Matrix)
    library(tm)
    library(wordcloud)
    library(devtools)
    library(lsa)
    library(data.table)
    library(dplyr)
    library(lubridate)
    
    corpus <- read.csv(paste(inputDir, "corpus.csv", sep="/"), stringsAsFactors=FALSE)
    DescriptionDocuments<-c(corpus$doc_clean)
    DescriptionDocuments <- VCorpus(VectorSource(DescriptionDocuments))
    DescriptionDocuments.DTM <- DocumentTermMatrix(DescriptionDocuments, control = list(tolower = FALSE,
                                                                                        stopwords = FALSE,
                                                                                        removeNumbers = FALSE,
                                                                                        removePunctuation = FALSE,
                                                                                        stemming=FALSE))
    
    # VOCABULARY SIZE = 83758
    



    这是Spark(1.6.0,Scala 2.10)中的相关代码:

    import org.apache.spark.ml.feature.{CountVectorizer, CountVectorizerModel, RegexTokenizer}
    
    var corpus = sqlContext.read.format("com.databricks.spark.csv").option("header", "true").option("inferSchema", "false").load("/path/to/corpus.csv")
    
    // RegexTokenizer splits by default on one or more spaces, which is ok
    val rTokenizer = new RegexTokenizer().setInputCol("doc").setOutputCol("words")
    val words = rTokenizer.transform(corpus)
    
    val cv = new CountVectorizer().setInputCol("words").setOutputCol("tf")
    val cv_model = cv.fit(words)
    var dtf = cv_model.transform(words)
    
    // VOCABULARY SIZE = 84290
    



    我还签了python sklearn,得到了与spark一致的结果:

    import pandas as pd
    from sklearn.feature_extraction.text import CountVectorizer
    
    corpus = pd.read_csv("/path/to/corpus.csv")
    docs = corpus.loc[:, "doc"].values
    
    def tokenizer(text):
        return text.split
    
    cv = CountTokenizer(tokenizer=tokenizer, stop_words=None)
    dtf = cv.fit_transform(docs)
    print len(dtf.vocabulary_)
    
    # VOCABULARY SIZE = 84290
    



    R tm package 但在我看来,默认情况下应该在空白处标记。有人告诉我为什么我的词汇量不一样了?

    1 回复  |  直到 7 年前
        1
  •  1
  •   phiver    7 年前

    产生差异的原因是在创建文档术语矩阵时有一个默认选项。如果你检查 ?termFreq 您可以找到wordlenges选项:

    长度为2的整数向量。短于最小单词的单词 字长[2]被丢弃。默认为c(3,Inf),即最小值 字长为3个字符。

    默认设置c(3,Inf)删除所有小于3的单词,如“at”、“in”、“I”等。

    这个默认值是导致tm和spark/python之间差异的原因

    请参阅下面示例中wordLengths设置的差异。

    library(tm)
    
    data("crude")
    
    dtm <- DocumentTermMatrix(crude)
    nTerms(dtm)
    [1] 1266
    
    dtm2 <- DocumentTermMatrix(crude, control = list(wordLengths = c(1, Inf)))
    nTerms(dtm2)
    [1] 1305