我正在努力确定更新多列值的最佳方法,但返回整个数据集 - 火花已迅速改变,许多答案似乎已过时。
我在一个小群集上运行spark 2.1,创建一个数据帧,如下所示:
df = spark.read.options(header="true",sep = '|').csv(path = 'file:///usr//local//raw_data//somefile.txt')
print df.columns
['ID','field1','field2','field3','value'] #there are actually many more columns, this is just an example
我需要将下面的映射函数应用于field1,field2和field3,但保留整个数据集
def mappingFunction(val,dict):
if val in dict:
return dict(val)
else:
return val
非常简单,我可以在熊猫中这样做:
df['field1'] = df['field1'].map(mapDict)
df['field2'] = df['field2'].map(mapDict)
df['field3'] = df['field3'].map(mapDict)
在pyspark中,我看到有一个df.rdd.map()功能,但这看起来像是一种“过时”的方式来接近这个 - 而且我已经将基础数据集拆分为列,所以我不这样做我想我应该回到RDD。
我也看到了pyspark.sql.functions.udf(f,returnType = StringType),这似乎是我想要使用的内容。
我的问题是:
有人可以确认在此实例中定义UDF是正确的方法吗?
如果是这样,我如何一次将UDF应用于多个列?由于我将在行上进行迭代,因此最好的查询设计似乎是应用我的映射函数一次到所有三列,但我不确定如何在我正在做的其他事情的背景下这样做。
如何进行此操作以便返回完整数据集,并更新这些值?我将要执行的所有聚合/操作都需要使用更新的列值。
非常感谢任何见解!
答案 0 :(得分:2)
最好将字典转换为broadcast
变量,然后定义查找udf
并使用生成器表达式将其应用于所有相关列:
让我们先创建一个虚拟数据集和字典:
df = sc.parallelize([
("a",1,1,2,2),
("b",2,2,3,3),
("c",3,4,3,3)]).toDF(['ID','field1','field2','field3','value'])
myDict = {1: "y", 2: "x", 3: "z"}
现在我们将字典转换为broadcast
变量并定义查找udf
:
broadcastVar = sc.broadcast(myDict)
def lookup(x):
if broadcastVar.value.get(x) is None:
return x
else:
return broadcastVar.value.get(x)
lookup_udf = udf(lookup)
现在剩下的就是生成一个list
列名,我们将我们的函数应用于(包含"field"
的所有内容),并将它放在我们{{1}的生成器表达式中}:
udf