我有这样的数据集:
a = sc.parallelize([[1,2,3],[0,2,1],[9,8,7]]).toDF(["one", "two", "three"])
我希望有一个数据集添加一个新列,该列等于其他三列中的最大值。 输出看起来像这样:
+----+----+-----+-------+
|one |two |three|max_col|
+----+----+-----+-------+
| 1| 2| 3| 3|
| 0| 2| 1| 2|
| 9| 8| 7| 9|
+----+----+-----+-------+
我以为我会使用withColumn
,就像这样:
b = a.withColumn("max_col", max(a["one"], a["two"], a["three"]))
但这会产生错误
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/spark152/python/pyspark/sql/column.py", line 418, in __nonzero__
raise ValueError("Cannot convert column into bool: please use '&' for 'and', '|' for 'or', "
ValueError: Cannot convert column into bool: please use '&' for 'and', '|' for 'or', '~' for 'not' when building DataFrame boolean expressions.
奇。 max
会返回bool
吗?不是根据the documentation on max
。好的。怪异。
我觉得这很奇怪:
b = a.withColumn("max_col", a["one"] + a["two"] + a["three"]))
它运作的事实让我更加强烈地认为max
表现得某种我不理解的方式。
我还尝试了b = a.withColumn("max_col", max([a["one"], a["two"], a["three"]]))
,它将三列作为列表而不是3个separte元素传递。这会产生与上面相同的错误。
答案 0 :(得分:6)
实际上,您需要的是greatest
而不是max
:
from pyspark.sql.functions import greatest
a.withColumn("max_col", greatest(a["one"], a["two"], a["three"]))
为了完整起见,您可以使用least
找到最低要求:
from pyspark.sql.functions import least
a.withColumn("min_col", least(a["one"], a["two"], a["three"]))
关于错误,您会发现它非常简单。 max
取决于丰富的比较。比较两列时,您会得到Column
:
type(col("a") < col("b")
## pyspark.sql.column.Column
PySpark明确禁止将列转换为布尔值(您可以检查Column.__nonzero__
源)因为它毫无意义。它只是一个逻辑表达式,无法在驱动程序上下文中进行评估。
答案 1 :(得分:1)
如果我理解正确,那么您的列最大值和行的最大值不匹配。实际上.withColumn需要接收一个列,你需要的是一个行操作。
b=a.map(lambda row: (row.one, row.two, row.three, max(row)))
b然后是rdd,您可以将其转换为dataframe
b.toDF('one','two','three','max')
答案 2 :(得分:0)
您不能使用python中的max
,因为它不会返回预期的pyspark.sql.Column
。 pyspark DataFrame函数的一个示例是array
,它从几列构建一个列表,请注意返回:
http://spark.apache.org/docs/latest/api/python/_modules/pyspark/sql/functions.html#array
为了达到你所需要的,你可以编写一个用户定义的函数,如(UNTESTED)
from pyspark.sql.types import IntegerType
from pyspark.sql.functions import udf
def my_max(*cols):
return max(cols)
udf_my_max = udf(my_max, IntegerType)
df.withColumn('max_col', udf_my_max(a.columns))