Spark MLlib中两种常见的产生文本化向量的方法 TF-IDF & Word2Vec

本文重点介绍了自然语言处理技术中两种常见的产生文本化向量的方法 TF-IDF 和 Word2Vec,并且利用Spark MLlib进行代码实现。

1. TF-IDF (term frequency - inverse document frequency)

词频-逆文档频率(TF-IDF)是文本挖掘领域广泛使用的一种特征向量化方法,用来评估一个词在一个文档的重要性。

仅仅考虑词频TF是不正确的。如在挑选关键词时,以上一段话可能选出的关键词是“”这个词,但是这个词是个常见词,不能表示出这句话的关键信息,所以引申出了IDF。

(1)定义:

  • TF: 词频(Term Frequency)是指某一个给定的词语在该文件中出现的次数。
    $$
    TF =TermCounts
    $$

  • IDF: 反文档频率(Inverse Document Frequency)是指如果包含词条的文档越少,IDF越大, 则说明词条的类别区分能力越强。
    $$
    IDF = ln(\frac{Total Doc Counts + 1}{Doc Counts(which\ contain\ the\ term)+1})
    $$
    注:IDF分子分母加1是为了解决所有文档都不包含这个单词时候分母为0程序报错的问题

    注:取对数是为了平滑曲线,当总文件数固定时,IDF关于包含这个单词的文件数成反比,分母过小时容易受极端值影响,取ln曲线会变的平滑。

  • TF-IDF: 某个词在文章中的TF-IDF越大,那么一般而言这个词在这篇文章的重要性会越高,所以通过计算文章中各个词的TF-IDF,由大到小排序,排在最前面的几个词,就是该文章的关键词。
    $$
    TF \text{-} IDF = TF \times IDF
    $$

(2)缺点:

  • 无法捕捉语义信息,示例:”机器学习”和”AI”会被视为完全无关的词汇。
  • 维度通常会很高

2. Word2Vec

(1)核心内容:

Word2Vec的关键假设为出现在相似上下文中的单词,其语义也相似。它是一种高效训练词向量的模型,基本出发点是上下文相似的两个词,它们的词向量也应该相似,比如苹果和梨在句子中可能经常出现在相同的上下文中,因此这两个词的表示向量应该就比较相似。

Word2Vec模型通过预测上下文来建立神经网络,最终目的不是为了得到一个语言模型,也不是要把神经网络训练得多么完美,而是只关心模型训练完后的副产物:神经网络的权重,这些参数向量化就是词向量。

Word2Vec有两种不同的架构:

  • CBOW(连续词袋法 contiuous bags of words):根据前后词预测中心词

  • skip-gram(推荐):通过中心词预测上下文

(2)缺点:

  • 无法处理多义词,如 “苹果”(公司 vs 水果)只有一个向量。

  • 窗口长度有限,没有考虑全局的文本信息

  • 无法理解语序,如“我爱你”和“你爱我”,我和你的词向量相同。

代码实现

1. Tokenizer

class pyspark.ml.feature.Tokenizer(inputCol = None, outputCol = None)

  1. inputCol : 输入列名
  2. outputCol: 输出列名
  • Tokenizer首先将所有的字母变成小写然后按空格分隔,它是一个transformer

  • 创建了Tokenizer后使用.Transform()方法把原始dataframe转换成另一个dataframe。

Refer to the Tokenizer Python docs for more details.

2. StopWordsRemover

class pyspark.ml.feature.StopWordsRemover(inputCol = None, outputCol = None, stopWords = None, caseSensitive = False, locale = None, inputCols = None, outputCols = None)

  1. inputCol : 输入列名(单个输入列时使用)
  2. outputCol : 输出列名(单个输出列时使用)
  3. stopWords: 自定义停用词列表,如果不指定,将使用默认的英语停用词列表
  4. caseSensitive : 是否区分大小写
  5. locale : 区域设置,用于根据语言获取停用词
  6. inputCols : 多个输入列名(多列输入时使用)
  7. outputCols : 多个输出列名(多列输出时使用)
  • 停用词(Stop words)是指在文本处理过程中被忽略或删除的常见词汇。这些词汇通常是频繁出现的功能词或无实际意义的词语。停用词通常对于文本的含义分析没有太大贡献,且会占据大量的存储空间和计算资源。因此,在文本处理任务(如文本分类、信息检索等)中,常常会预先定义一组停用词,并在处理过程中将它们从文本中移除。
  • StopWordsRemover删去所有的stopwords,它是一个transformer
  • 创建了StopWordsRemover后使用.transform()方法把原始dataframe转换成另一个dataframe。

Refer to the StopWordsRemover Python docs for more details on the API.

3. HashingTF

class pyspark.ml.feature.HashingTF(numFeatures = 262144 = 2^18 , binary = False, inputCol= None, outputCol = None)

  1. inputCol : 输入列名
  2. outputCol : 输出列名
  3. binary :二进制开关参数(将非零频次全部设为1)
  4. numFeatures: 哈希桶的数量(默认为2^18=262,144),建议使用2的幂
  • 是一种transformer,每个单词通过MurmurHash3算法计算哈希值,哈希值通过模运算(hash % numFeatures)映射到0-numFeatures的索引位置

Refer to the HashingTF Python docs for more details on the API.

4. CountVectorizer

class pyspark.ml.feature.CountVectorizer(minTF = 1.0, minDF = 1.0, maxDF = 9223372036854775807, vocabSize = 262144, binary = False, inputCol = None, outputCol = None)

  1. inputCol : 输入列名
  2. outputCol : 输出列名
  3. binary :二进制开关参数(将非零频次全部设为1)
  4. minTF:词语在文档中的最低出现次数
  5. minDF:词语最少出现的文档数(<1.0时为比例)
  6. maxDF:词语最多出现的文档数(过滤高频词)
  7. vocabSize:词汇表最大大小
  • 是一种estimater,创建了CountVectorizer后使用.fit()方法产生一个CVModel,再用.transform()方法产生dataframe

  • 直接计数法

  • model.vocabulary #可以看词汇表从高到低排序

    Refer to the CountVectorizer Python docs for more details on the API.

5. HashingTF VS CountVectorizer

HashingTF的优势

  • CountVectorizer 需要维护一个 词汇表(Vocabulary),将所有单词映射到索引。当词汇量很大时(例如百万级单词),这个词汇表会消耗大量内存。

  • HashingTF 不需要存储词汇表,而是通过哈希函数直接计算单词的位置,内存占用固定(由 numFeatures 决定),适合处理海量文本。

  • 如果有100万个单词,CountVectorizer需要存储100万条映射关系。HashingTF 只需存储 numFeatures(如2^18=262144)个特征,内存消耗与词汇量无关。

  • CountVectorizer 对新出现的单词(未在词汇表中)无法处理,必须重新训练模型。

  • HashingTF 可以动态处理新词,因为哈希函数对任何单词都返回有效索引。

CountVectorizer的优势

  • 需要解释特征:例如调试模型时,需要知道哪些单词对预测影响最大。

  • 词汇量可控:处理小规模数据时,词汇表不会导致内存问题。

  • 严格避免哈希冲突:当不同单词映射到同一位置会严重影响模型性能时(如医疗文本中的关键术语)。

6. IDF

class pyspark.ml.feature.IDF(minDocFreq = 0, inputCol = None, outputCol = None)

  1. inputCol : 输入列名
  2. outputCol : 输出列名
  3. minDocFreq: 词的最小文档频率,低于此值的词会被忽略
  • 是一种estimater,创建了IDF后使用.fit()方法产生一个IDFModel,再用.transform()方法产生dataframe
  • 创建TF-IDF值

Refer to the IDF Python docs for more details on the API.

7. Word2Vec

class pyspark.ml.feature.Word2Vec(vectorSize = 100, minCount = 5, numPartitions = 1, stepSize = 0.025, maxIter = 1, seed = None, inputCol = None, outputCol = None, windowSize = 5, maxSentenceLength = 1000)

  1. inputCol : 输入列名
  2. outputCol : 输出列名
  3. vectorSize : 词向量的维度大小
  4. minCount : 词语的最小出现频率
  5. numPartitions : 训练数据的分区数
  6. stepSize : 学习率
  7. maxIter : 训练的最大迭代次数
  8. seed : 种子
  9. windowSize : 目标词左右考虑的词语数
  10. **maxSentenceLength **: 单个句子的最大长度
  • 是一种estimater, 创建了Word2Vec后使用.fit()方法产生一个model,再用.transform()方法产生dataframe

  • Spark MLlib使用的是skip-gram。Word2Vec训练出的模型是一个映射结构(Map(String, Vector)),其功能是将词语转换为向量编码,这种向量表示可用于后续的自然语言处理或机器学习任务。

  • model.getVectors() #找出所有的词向量

  • model.findSynonyms(String, number) #找到相似词

Refer to the Word2Vec Python docs for more details on the API.