特征的转换_01-自然语言相关特征转换

来源:互联网 发布:java生成时间戳 编辑:程序博客网 时间:2024/05/22 06:32

笔记整理时间:2017年1月11日
笔记整理者:王小草


SparkML 2.1.0的官方文档给出了21类特征转换的方法,其中关于自然语言处理领域的有3类,分别是:Tokenizer分词,StopWordsRemover去停用词,n-gram。本文主要介绍这三种方法的使用。

1. Tokenizer分词

在对文本做数据挖掘的时候,分词往往是第一步:将一个句子拆分成单词的集合。
在文本特征的提取笔记中,讲到可以用TF-IDF文档矩阵,word2vec词嵌入矩阵来做词或文档的向量表征,这些都是基于分词的基础上的。准确的分词是接下来特征提取与模型建立的成功垫脚石。

英文的分词很简单,只需按照标点与空格就可以提取word,而中文的分词就有点让人头痛了呢。sparkml此处提供的只是基于英文的分词方法。关于中文分词,我们还需要对其在巨大的语料库上进行训练而得到,常见的模型有隐马尔科夫模型HMM,条件随机场模型CRF等,这些模型的介绍请参见我的机器学习笔记哦~

Sparkml的分词提供了两种方法:

1.Tokenization,将英文句子分成单个的term。

    // 创建一个dataframe,第二列是句子    val sentenceDataFrame = spark.createDataFrame(Seq(      (0, "Hi I heard about Spark"),      (1, "I wish Java could use case classes"),      (2, "Logistic,regression,models,are,neat")    )).toDF("id", "sentence")    // 默认的分词(自动转成小写)    val tokenizer = new Tokenizer().setInputCol("sentence").setOutputCol("words")    val tokenized = tokenizer.transform(sentenceDataFrame)    tokenized.show(false)

输出结果:

+---+-----------------------------------+------------------------------------------+|id |sentence                           |words                                     |+---+-----------------------------------+------------------------------------------+|0  |Hi I heard about Spark             |[hi, i, heard, about, spark]              ||1  |I wish Java could use case classes |[i, wish, java, could, use, case, classes]||2  |Logistic,regression,models,are,neat|[logistic,regression,models,are,neat]     |+---+-----------------------------------+------------------------------------------+

2.RegexTokenizer ,根据正则表达式去匹配单词。
默认情况下是pattern的参数是(regex, default: “\ \s+”) ,即按照正则表达式匹配的词进行分割。
\ \s表示 空格,回车,换行等空白符,
+号表示一个或多个的意思

// 利用正则表达式分词    val regexTokenizer = new RegexTokenizer()      .setInputCol("sentence")      .setOutputCol("words")    val regexTokenized = regexTokenizer.transform(sentenceDataFrame)    regexTokenized.show(false)

输出结果:

+---+-----------------------------------+------------------------------------------+|id |sentence                           |words                                     |+---+-----------------------------------+------------------------------------------+|0  |Hi I heard about Spark             |[hi, i, heard, about, spark]              ||1  |I wish Java could use case classes |[i, wish, java, could, use, case, classes]||2  |Logistic,regression,models,are,neat|[logistic,regression,models,are,neat]     |+---+-----------------------------------+------------------------------------------+

另外,还可以这样做:在pattern中传入要取出的东东的正则表达式,比如说想得到一句话中的word,就可以设置.setPattern(“\ \W”),如果光这样,表示是按照词去分割,输出结果是酱紫的:

+---+-----------------------------------+------------------+|id |sentence                           |words             |+---+-----------------------------------+------------------+|0  |Hi I heard about Spark             |[ ,  ,  ,  ]      ||1  |I wish Java could use case classes |[ ,  ,  ,  ,  ,  ]||2  |Logistic,regression,models,are,neat|[,, ,, ,, ,]      |+---+-----------------------------------+------------------+

需要再设置.setGaps(false),表示把正则表达式匹配的东东取出来而不是用其去分割。

    val regexTokenizer = new RegexTokenizer()      .setInputCol("sentence")      .setOutputCol("words")      .setPattern("\\w+").setGaps(false)    val regexTokenized = regexTokenizer.transform(sentenceDataFrame)    regexTokenized.show(false)

输出结果:

+---+-----------------------------------+------------------------------------------+|id |sentence                           |words                                     |+---+-----------------------------------+------------------------------------------+|0  |Hi I heard about Spark             |[hi, i, heard, about, spark]              ||1  |I wish Java could use case classes |[i, wish, java, could, use, case, classes]||2  |Logistic,regression,models,are,neat|[logistic, regression, models, are, neat] |+---+-----------------------------------+------------------------------------------+

2. StopWordsRemover去停用词

分词之后,句子变成了单词的集合,但是并非每一个单词都有意义,比如冠词the, 人称代词I,等等出现频率高单又缺乏意义的词。在很多需求中去掉这些无意义的停用词可以使得建模更加准确。

StopWordsRemover这个方法,输入一个字符串组成的列表,输出一个去掉了停用词的列表。

不同需求中的停用词有不同的定义,这个我们可以自己出传入参数设置。若要使用默认的停用词可以调用StopWordsRemover.loadDefaultStopWords(language),目前有的language有: “danish”, “dutch”, “english”, “finnish”, “french”, “german”, “hungarian”, “italian”, “norwegian”, “portuguese”, “russian”, “spanish”, “swedish” and “turkish”.(恩,看了好几遍的确没有中文。。再见,朋友。。。)

还有一个布尔类型的参数 caseSensitive,表示是都对大小写敏感,默认是false.

看一个例子:
比如有这样2句话:

id raw 0 [I, saw, the, red, baloon] 1 [Mary, had, a, little, lamb]

然后去停后输出了新的过滤后的分词组合:

id raw filtered 0 [I, saw, the, red, baloon] [saw, red, baloon] 1 [Mary, had, a, little, lamb] [Mary, little, lamb]

停用词“I”, “the”, “had”, and “a” 被过滤掉了。

代码:

   // 创建一个DataFrame    val dataSet = spark.createDataFrame(Seq(      (0, Seq("I", "saw", "the", "red", "balloon")),      (1, Seq("Mary", "had", "a", "little", "lamb"))    )).toDF("id", "raw")    // 创建一个新的对象,并设置参数    val remover = new StopWordsRemover()      .setInputCol("raw")      .setOutputCol("filtered")    // 转换    remover.transform(dataSet).show(false)

输出:

+---+----------------------------+--------------------+|id |raw                         |filtered            |+---+----------------------------+--------------------+|0  |[I, saw, the, red, balloon] |[saw, red, balloon] ||1  |[Mary, had, a, little, lamb]|[Mary, little, lamb]|+---+----------------------------+--------------------+

3. n-gram

经常有这样的需求,需要将词进行窗口为n的遍历,说多了更混乱,一个例子一目了然:
输入一句分好词的句子:

[Hi, I, heard, about, Spark]

如果窗口大小设置为2,那么输出的是:

[Hi I, I heard, heard about, about Spark] 

可见,每个词都在窗口为2的组合中被遍历了一次。

这个在中文分词中其实可以应用,将中文按字拆分,如果某个组合出现的次数很多,是不是可以换衣这个组合的词是一个真正的词语呢。

来看一下代码的实现:

   //创建dataframe   val wordDataFrame = spark.createDataFrame(Seq(      (0, Array("Hi", "I", "heard", "about", "Spark")),      (1, Array("I", "wish", "Java", "could", "use", "case", "classes")),      (2, Array("Logistic", "regression", "models", "are", "neat"))    )).toDF("id", "words")    // 创建新对象,并设置参数,窗口长度为3    val ngram = new NGram().setN(3).setInputCol("words").setOutputCol("ngrame")    //转换    val ngramDataFrame = ngram.transform(wordDataFrame)    ngramDataFrame.show(false)

输出结果:

+---+------------------------------------------+---------------------------------+|id |words                                     |ngrame                                                            |+---+------------------------------------------+---------------------------------+|0  |[Hi, I, heard, about, Spark]              |[Hi I, I heard, heard about, about                                                       Spark]                         ||1  |[I, wish, Java, could, use, case, classes]|[I wish, wish Java, Java could,                                              could use, use case, case classes]||2  |[Logistic, regression, models, are, neat] |[Logistic regression, regression                                                models, models are, are neat]    |+---+------------------------------------------+---------------------------------+
0 0