语料库中的 Pyspark CountVectorizer 和词频

pla*_*nne 6 python text-mining pyspark

我目前正在研究文本语料库。
假设我清理了我的逐字记录并且我有以下 pyspark DataFrame :

df = spark.createDataFrame([(0, ["a", "b", "c"]),
                            (1, ["a", "b", "b", "c", "a"])],
                            ["label", "raw"])
df.show()

+-----+---------------+
|label|            raw|
+-----+---------------+
|    0|      [a, b, c]|
|    1|[a, b, b, c, a]|
+-----+---------------+
Run Code Online (Sandbox Code Playgroud)

我现在想实现一个 CountVectorizer。所以,我使用pyspark.ml.feature.CountVectorizer如下:

cv = CountVectorizer(inputCol="raw", outputCol="vectors")
model = cv.fit(df)
model.transform(df).show(truncate=False)

+-----+---------------+-------------------------+
|label|raw            |vectors                  |
+-----+---------------+-------------------------+
|0    |[a, b, c]      |(3,[0,1,2],[1.0,1.0,1.0])|
|1    |[a, b, b, c, a]|(3,[0,1,2],[2.0,2.0,1.0])|
+-----+---------------+-------------------------+
Run Code Online (Sandbox Code Playgroud)

现在,我还想获取 CountVectorizer 选择的词汇表,以及语料库中相应的词频。
Using cvmodel.vocabularyonly 提供词汇表:

voc = cvmodel.vocabulary
voc
[u'b', u'a', u'c']
Run Code Online (Sandbox Code Playgroud)

我想得到这样的东西:

voc = {u'a':3,u'b':3,u'c':2}
Run Code Online (Sandbox Code Playgroud)

你有什么想法做这样的事情吗?

编辑
我使用的是 Spark 2.1

pau*_*ult 6

调用cv.fit()返回 a CountVectorizerModel,它(AFAIK)存储词汇但不存储计数。词汇表是模型的属性(它需要知道要计算哪些单词),但计数是 DataFrame(而不是模型)的属性。您可以应用拟合模型的变换函数来获取任何 DataFrame 的计数。

话虽如此,这里有两种方法可以获得您想要的输出。

1. 使用现有的计数向量化模型

您可以使用pyspark.sql.functions.explode()pyspark.sql.functions.collect_list()将整个语料库收集到一行中。出于说明目的,让我们考虑一个新的 DataFrame df2,其中包含一些安装者看不到的词CountVectorizer

import pyspark.sql.functions as f

df2 = sqlCtx.createDataFrame([(0, ["a", "b", "c", "x", "y"]),
                            (1, ["a", "b", "b", "c", "a"])],
                            ["label", "raw"])

combined_df = (
    df2.select(f.explode('raw').alias('col'))
      .select(f.collect_list('col').alias('raw'))
)
combined_df.show(truncate=False)
#+------------------------------+
#|raw                           |
#+------------------------------+
#|[a, b, c, x, y, a, b, b, c, a]|
#+------------------------------+
Run Code Online (Sandbox Code Playgroud)

然后使用拟合模型将其转换为计数并收集结果:

counts = model.transform(combined_df).select('vectors').collect()
print(counts)
#[Row(vectors=SparseVector(3, {0: 3.0, 1: 3.0, 2: 2.0}))]
Run Code Online (Sandbox Code Playgroud)

接下来zip将计数和词汇放在一起,并使用dict构造函数来获得所需的输出:

print(dict(zip(model.vocabulary, counts[0]['vectors'].values)))
#{u'a': 3.0, u'b': 3.0, u'c': 2.0}
Run Code Online (Sandbox Code Playgroud)

正如您在评论中正确指出的那样,这只会考虑属于CountVectorizerModel词汇表的单词。任何其他词都将被忽略。因此,我们看不到"x"或 的任何条目"y"

2.使用DataFrame聚合函数

或者您可以跳过CountVectorizer并使用groupBy(). 这是一个更通用的解决方案,因为它将提供DataFrame 中所有单词的计数,而不仅仅是词汇表中的单词:

counts = df2.select(f.explode('raw').alias('col')).groupBy('col').count().collect()
print(counts)
#[Row(col=u'x', count=1), Row(col=u'y', count=1), Row(col=u'c', count=2), 
# Row(col=u'b', count=3), Row(col=u'a', count=3)]
Run Code Online (Sandbox Code Playgroud)

现在简单地使用一个dict理解:

print({row['col']: row['count'] for row in counts})
#{u'a': 3, u'b': 3, u'c': 2, u'x': 1, u'y': 1}
Run Code Online (Sandbox Code Playgroud)

下面我们就针对计数"x""y"也。