使用Spark Dataframe列中的数据作为条件或输入另一个列表达式

时间:2016-08-30 19:05:52

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

我想在PySpark 2.0中执行一项操作,这种操作很容易作为df.rdd.map执行,但由于出于性能原因我宁愿呆在Dataframe执行引擎内,我想找一个仅使用Dataframe操作执行此操作的方法。

RDD风格的操作是这样的:

def precision_formatter(row):
    formatter = "%.{}f".format(row.precision)
    return row + [formatter % row.amount_raw / 10 ** row.precision]
df = df.rdd.map(precision_formatter)

基本上,我有一个列告诉我,对于每一行,我的字符串格式化操作的精度应该是多少,并且我希望根据该精度选择性地将'amount_raw'列格式化为字符串。

2 个答案:

答案 0 :(得分:0)

我不知道如何使用一列或多列的内容作为另一列操作的输入。我最接近的是建议使用Column.when一组外部定义的布尔运算,这些运算对应于列或列中可能的布尔条件/个案集合。

在这种特定情况下,例如,如果您可以获得(或更好地,已经拥有)row.precision的所有可能值,那么您可以迭代该集合并应用Column.when操作集合中的每个值。我相信这个集合可以通过df.select('precision').distinct().collect()获得。

由于pyspark.sql.functions.whenColumn.when操作本身会返回Column个对象,因此您可以迭代集合中的项目(但是已获取)并保持“追加”{{1以编程方式相互操作,直到你用尽了集合:

when

答案 1 :(得分:0)

您可以使用python UDF执行此操作。它们可以获取尽可能多的输入值(来自行的列的值)并吐出单个输出值。它看起来像这样:

from pyspark.sql import types as T, functions as F
from pyspark.sql.function import udf, col

# Create example data frame
schema = T.StructType([
    T.StructField('precision', T.IntegerType(), False),
    T.StructField('value', T.FloatType(), False)
])

data = [
    (1, 0.123456),
    (2, 0.123456),
    (3, 0.123456)
]

rdd = sc.parallelize(data)
df = sqlContext.createDataFrame(rdd, schema)

# Define UDF and apply it
def format_func(precision, value):
    format_str = "{:." + str(precision) + "f}"
    return format_str.format(value)

format_udf = F.udf(format_func, T.StringType())

new_df = df.withColumn('formatted', format_udf('precision', 'value'))
new_df.show()

此外,如果您要使用全局值而不是列精度值,则可以在调用时使用lit(..)函数:

new_df = df.withColumn('formatted', format_udf(F.lit(2), 'value'))