withColumn不允许我使用max()函数生成新列

时间:2016-06-15 14:30:50

标签: python apache-spark pyspark apache-spark-sql

我有这样的数据集:

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元素传递。这会产生与上面相同的错误。

3 个答案:

答案 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))