首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >稀疏向量pyspark

稀疏向量pyspark
EN

Stack Overflow用户
提问于 2017-05-06 00:18:56
回答 2查看 12K关注 0票数 6

我想找到一种有效的方法来使用数据帧在PySpark中创建备用向量。

假设给定了事务性输入:

代码语言:javascript
复制
df = spark.createDataFrame([
    (0, "a"),
    (1, "a"),
    (1, "b"),
    (1, "c"),
    (2, "a"),
    (2, "b"),
    (2, "b"),
    (2, "b"),
    (2, "c"),
    (0, "a"),
    (1, "b"),
    (1, "b"),
    (2, "cc"),
    (3, "a"),
    (4, "a"),
    (5, "c")
], ["id", "category"])
代码语言:javascript
复制
+---+--------+
| id|category|
+---+--------+
|  0|       a|
|  1|       a|
|  1|       b|
|  1|       c|
|  2|       a|
|  2|       b|
|  2|       b|
|  2|       b|
|  2|       c|
|  0|       a|
|  1|       b|
|  1|       b|
|  2|      cc|
|  3|       a|
|  4|       a|
|  5|       c|
+---+--------+

汇总格式如下:

代码语言:javascript
复制
df.groupBy(df["id"],df["category"]).count().show()
代码语言:javascript
复制
+---+--------+-----+
| id|category|count|
+---+--------+-----+
|  1|       b|    3|
|  1|       a|    1|
|  1|       c|    1|
|  2|      cc|    1|
|  2|       c|    1|
|  2|       a|    1|
|  1|       a|    1|
|  0|       a|    2|
+---+--------+-----+

我的目标是通过id获得以下输出:

代码语言:javascript
复制
+---+-----------------------------------------------+
| id|                                       feature |
+---+-----------------------------------------------+
|  2|SparseVector({a: 1.0, b: 3.0, c: 1.0, cc: 1.0})|

你能告诉我正确的方向吗?有了Java的mapreduce,这对我来说似乎更容易了。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-05-06 14:23:51

使用pivotVectorAssembler可以很容易地做到这一点。将聚合替换为pivot

代码语言:javascript
复制
 pivoted = df.groupBy("id").pivot("category").count().na.fill(0)

和组装:

代码语言:javascript
复制
from pyspark.ml.feature import VectorAssembler

input_cols = [x for x in pivoted.columns if x != id]

result = (VectorAssembler(inputCols=input_cols, outputCol="features")
    .transform(pivoted)
    .select("id", "features"))

结果如下所示。这将根据稀疏性选择更有效的表示:

代码语言:javascript
复制
+---+---------------------+
|id |features             |
+---+---------------------+
|0  |(5,[1],[2.0])        |
|5  |(5,[0,3],[5.0,1.0])  |
|1  |[1.0,1.0,3.0,1.0,0.0]|
|3  |(5,[0,1],[3.0,1.0])  |
|2  |[2.0,1.0,3.0,1.0,1.0]|
|4  |(5,[0,1],[4.0,1.0])  |
+---+---------------------+

当然,您仍然可以将其转换为单一表示:

代码语言:javascript
复制
from pyspark.ml.linalg import SparseVector, VectorUDT
import numpy as np

def to_sparse(c):
    def to_sparse_(v):
        if isinstance(v, SparseVector):
            return v
        vs = v.toArray()
        nonzero = np.nonzero(vs)[0]
        return SparseVector(v.size, nonzero, vs[nonzero])
    return udf(to_sparse_, VectorUDT())(c)
代码语言:javascript
复制
+---+-------------------------------------+
|id |features                             |
+---+-------------------------------------+
|0  |(5,[1],[2.0])                        |
|5  |(5,[0,3],[5.0,1.0])                  |
|1  |(5,[0,1,2,3],[1.0,1.0,3.0,1.0])      |
|3  |(5,[0,1],[3.0,1.0])                  |
|2  |(5,[0,1,2,3,4],[2.0,1.0,3.0,1.0,1.0])|
|4  |(5,[0,1],[4.0,1.0])                  |
+---+-------------------------------------+
票数 16
EN

Stack Overflow用户

发布于 2017-05-06 01:10:57

如果您将数据帧转换为RDD,则可以遵循类似mapreduce的框架reduceByKey。这里唯一真正棘手的部分是格式化spark的sparseVector的日期

导入包,创建数据

代码语言:javascript
复制
from pyspark.ml.feature import StringIndexer
from pyspark.ml.linalg import Vectors
df = sqlContext.createDataFrame([
    (0, "a"),
    (1, "a"),
    (1, "b"),
    (1, "c"),
    (2, "a"),
    (2, "b"),
    (2, "b"),
    (2, "b"),
    (2, "c"),
    (0, "a"),
    (1, "b"),
    (1, "b"),
    (2, "cc"),
    (3, "a"),
    (4, "a"),
    (5, "c")
], ["id", "category"])

为类别创建数字表示(稀疏向量需要)

代码语言:javascript
复制
indexer = StringIndexer(inputCol="category", outputCol="categoryIndex")
df = indexer.fit(df).transform(df) 

Group by索引,get计数

代码语言:javascript
复制
df = df.groupBy(df["id"],df["categoryIndex"]).count()

转换为rdd,将数据映射到id & categoryIndex、count的键值对

代码语言:javascript
复制
rdd = df.rdd.map(lambda x: (x.id, [(x.categoryIndex, x['count'])]))

按键减去,以获得id的键值对&所有categoryIndex的列表,该id的计数

代码语言:javascript
复制
rdd = rdd.reduceByKey(lambda a, b: a + b)

映射数据以将所有计数的列表、每个id的categoryIndex转换为稀疏向量

代码语言:javascript
复制
rdd = rdd.map(lambda x: (x[0], Vectors.sparse(len(x[1]), x[1])))

转换回数据帧

代码语言:javascript
复制
finalDf = sqlContext.createDataFrame(rdd, ['id', 'feature'])

数据检查

代码语言:javascript
复制
finalDf.take(5)

 [Row(id=0, feature=SparseVector(1, {1: 2.0})),
  Row(id=1, feature=SparseVector(3, {0: 3.0, 1: 1.0, 2: 1.0})),
  Row(id=2, feature=SparseVector(4, {0: 3.0, 1: 1.0, 2: 1.0, 3: 1.0})),
  Row(id=3, feature=SparseVector(1, {1: 1.0})),
  Row(id=4, feature=SparseVector(1, {1: 1.0}))]
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43809587

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档