PySpark更新某些列的值

时间:2017-05-10 15:57:20

标签: python pandas apache-spark pyspark

我正在努力确定更新多列值的最佳方法,但返回整个数据集 - 火花已迅速改变,许多答案似乎已过时。

我在一个小群集上运行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应用于多个列?由于我将在行上进行迭代,因此最好的查询设计似乎是应用我的映射函数一次到所有三列,但我不确定如何在我正在做的其他事情的背景下这样做。

如何进行此操作以便返回完整数据集,并更新这些值?我将要执行的所有聚合/操作都需要使用更新的列值。

非常感谢任何见解!

1 个答案:

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