我的原始模式包含许多我想在ML模型中使用的映射类型,因此我需要将它们转换为SparkML稀疏向量。
root
|-- colA: map (nullable = true)
| |-- key: string
| |-- value: double (valueContainsNull = true)
|-- colB: map (nullable = true)
| |-- key: string
| |-- value: string (valueContainsNull = true)
|-- colC: map (nullable = true)
| |-- key: string
| |-- value: string (valueContainsNull = true)
背景:SparkML模型要求将数据形成特征向量。有一些实用程序可以生成特征向量,但都不支持maptype类型。e、 g.SparkML VectorAssembler允许组合多个列(所有数字类型、布尔类型或向量类型)。
编辑:
到目前为止,我的解决方案是将映射分解为单独的列,然后使用向量汇编程序:
val listkeysColA = df.select(explode($"colA"))
.select($"key").as[Int].distinct.collect.sorted
val exploded= df.select(listkeysColA.map(x =>
$"colA".getItem(x).alias(x.toString)): _*).na.fill(0)
val columnNames = exploded.columns
val assembler = new VectorAssembler().setInputCols(columnNames).setOutputCol("features")
编辑2:
我应该补充一点,我的地图中的数据非常稀疏,事先没有已知的键集。这就是为什么在我当前的解决方案中,我首先对data进行一次传递以收集和排序键。然后我使用getItem(keyName)访问值。
据我所知,Spark中没有用于此的内置方法,因此在这种情况下,UDF将是合适的解决方案。这里是一个采用映射[字符串,双精度]的列并返回ML向量的方法:
val toVector = udf((m: Map[String, Double]) => Vectors.dense(m.values.toArray).toSparse)
由于映射没有阶,因此也不能保证生成的向量具有特定阶。
示例输入(df
):
+---------------------------------+---------------------------------+
|colA |colB |
+---------------------------------+---------------------------------+
|Map(a -> 1.0, b -> 2.0, c -> 3.0)|Map(a -> 1.0, b -> 2.0, c -> 3.0)|
+---------------------------------+---------------------------------+
并使用UDF,
val df2 = df.withColumn("colA", toVector($"colA")).withColumn("colB", toVector($"colB"))
给出以下输出:
+-------------+-------------+
|colA |colB |
+-------------+-------------+
|[1.0,2.0,3.0]|[1.0,2.0,3.0]|
+-------------+-------------+
其中两列都是向量类型。
root
|-- colA: vector (nullable = true)
|-- colB: vector (nullable = true)
如果您想将所有列合并到一个向量中,这里可以使用向量汇编程序(VectorAssembler),如问题编辑中所示。
编辑:
如果您需要保持值的特定顺序,那么您需要像以前一样首先收集所有键。但是,您可以避免使用
爆炸
:
val keys = df.select($"colA")
.flatMap(_.getAs[Map[String, Int]]("colA").keys)
.distinct
.collect
.sorted
然后适当更改自定义项,以考虑键的顺序,默认值为0.0:
val toVector = udf((m: Map[String, Double]) =>
Vectors.dense(keys.map(key => m.getOrElse(key, 0.0))).toSparse
)
但它给出了一个错误。 我对Spark是新手,所以这可能很明显,在我的代码行中可能有明显的错误。请帮忙。谢谢!
我需要将POJO转换成地图。我尝试使用对象映射器,但是像timestamp这样的类型在最终的映射中要么以字符串的形式出现,要么以长的形式出现。有没有什么工具可以做一个简单的转换,使映射具有与POJO中完全相同的对象?(我知道我可以使用反射,但想看看是否有更简单的方法。)
我在Spark中有一个数据框,看起来像这样: 它有30列:只显示其中的一些! 因此,我必须在Scala中将这个数据帧转换成一个键值对,使用键作为数据帧中的一些列,并为这些键分配从索引0到计数(不同的键数)的唯一值。 例如:使用上面的案例,我希望在Scala中的map(key-value)集合中有一个输出,如下所示: 我对斯卡拉和斯帕克是新手,我试着做这样的事情。 但是,这不起作用。:/此操作完成后
问题内容: 我有〜10种不同的文档类型,它们共享10-15个通用字段。但是每种文档类型都有其他字段,其中3个字段最多可以有30-40个其他字段。 我正在考虑为每种文档类型使用不同的映射类型。但是,如果我正确理解了映射的工作方式,ElasticSearch将在内部使用一个包含150-200个字段的映射。因为没有文档对每个字段都有值,所以我最终会得到很多稀疏数据。 根据本文(索引与类型),Elasti
我需要在代码的几个地方将这个映射转换为我的case类,如下所示: 最简单的方法是什么?我能用隐式吗?
我是java新手,正在尝试学习objectmapper。我正在使用它将地图转换为pojo。地图中的键是字符串,所有值都是字符串值,除了我想转换为地图的值。请仔细阅读下面的示例代码,以获得更清晰的图片。 POJO类: 测试代码: 例外: 尝试的变体选项: 我知道我可以将map1字段也保留为String,然后使用另一个对象映射器实例将其转换为map,但我想避免它。有没有办法直接将测试代码中的字符串转换