我有一个包含2列tag
和value
的数据框。
我想添加一个包含max
value
列val df2 = df.withColumn("max",max($"value"))
的新列。 (每行的值相同。)
我尝试按照以下方式执行操作,但它无法正常工作。
max
如何将<td >
<button id="cat" type="button" name="button[]" class="w3-btn w3-dark-grey w3-hover-light-grey" onclick="openCateg(<?php echo $row["idEmpresa"]?>);">Categorias</button>
</td>
列添加到数据集?
答案 0 :(得分:4)
有三种方法可以做到(一个你已经从另一个答案中得知)。我避免使用collect
,因为它并不是真的需要。
这是最大值为3的数据集出现两次。
val tags = Seq(
("tg1", 1), ("tg2", 2), ("tg1", 3), ("tg4", 4), ("tg3", 3)
).toDF("tag", "value")
scala> tags.show
+---+-----+
|tag|value|
+---+-----+
|tg1| 1|
|tg2| 2|
|tg1| 3| <-- maximum value
|tg4| 4|
|tg3| 3| <-- another maximum value
+---+-----+
我将使用tags
的笛卡尔联接和具有最大值的单行数据集。
val maxDF = tags.select(max("value") as "max")
scala> maxDF.show
+---+
|max|
+---+
| 4|
+---+
val solution = tags.crossJoin(maxDF)
scala> solution.show
+---+-----+---+
|tag|value|max|
+---+-----+---+
|tg1| 1| 4|
|tg2| 2| 4|
|tg1| 3| 4|
|tg4| 4| 4|
|tg3| 3| 4|
+---+-----+---+
我并不担心这里的笛卡尔联盟,因为它只是一个单行数据集。
我最喜欢的窗口聚合非常适合这个问题。另一方面,由于使用的分区数量很少,我并不认为这是最有效的方法,即只有1,这给出了最差的并行性。
诀窍是在空窗口规范上使用聚合函数max
,该规范通知Spark SQL以任何顺序使用所有行。
val solution = tags.withColumn("max", max("value") over ())
scala> solution.show
18/05/31 21:59:40 WARN WindowExec: No Partition Defined for Window operation! Moving all data to a single partition, this can cause serious performance degradation.
+---+-----+---+
|tag|value|max|
+---+-----+---+
|tg1| 1| 4|
|tg2| 2| 4|
|tg1| 3| 4|
|tg4| 4| 4|
|tg3| 3| 4|
+---+-----+---+
请注意这一切的警告。
WindowExec:没有为Window操作定义分区!将所有数据移动到单个分区,这可能会导致严重的性能下降。
我不会在给出其他解决方案的情况下使用这种方法,并将其留在这里用于教育目的。
答案 1 :(得分:3)
如果您想要所有行的列的最大值,您将需要比较某种形式的所有行。这意味着要进行聚合。 withColumn仅在单行上运行,因此您无法获取DataFrame最大值。
最简单的方法如下:
val data = Seq(("a", 1), ("b", 2), ("c", 3), ("d", 4))
val df = sc.parallelize(data).toDF("name", "value")
// first is an action, so this will execute spark stages to compute the value
val maxValue = df.groupBy().agg(max($"value")).first.getInt(0)
// Now you can add it to your original DF
val updatedDF = df.withColumn("max", lit(maxValue))
updatedDF.show
还有一种替代方案可能会快一点。如果你不需要最大值直到你的处理结束(在你已经运行了一个spark动作之后),你可以通过编写自己的Spark Acccumulator来计算它,而不是在做任何其他Spark Action工作的时候收集值请求。