Python PySpark更新某些列的值

Python PySpark更新某些列的值,python,pandas,apache-spark,pyspark,Python,Pandas,Apache Spark,Pyspark,我正在努力找出更新多列中的值的最佳方法,但返回整个数据集-spark变化很快,许多答案似乎已经过时 我正在一个小型集群上运行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

我正在努力找出更新多列中的值的最佳方法,但返回整个数据集-spark变化很快,许多答案似乎已经过时

我正在一个小型集群上运行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
,并使用生成器表达式将其应用于所有相关列:

让我们先创建一个虚拟数据集和字典:

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"}
现在,我们将字典转换为
广播
变量,并定义查找
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)
from pyspark.sql.functions import col

cols = [s for s in df.columns if "field" in s]
df.select(*(lookup_udf(col(c)).alias(c) if c in cols else c for c in df.columns)).show()
+---+------+------+------+-----+
| ID|field1|field2|field3|value|
+---+------+------+------+-----+
|  a|     y|     y|     x|    2|
|  b|     x|     x|     z|    3|
|  c|     z|     4|     z|    3|
+---+------+------+------+-----+
现在剩下的是生成我们将应用函数的列名的
列表
(包含
“field”
)并将其放入带有
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)
from pyspark.sql.functions import col

cols = [s for s in df.columns if "field" in s]
df.select(*(lookup_udf(col(c)).alias(c) if c in cols else c for c in df.columns)).show()
+---+------+------+------+-----+
| ID|field1|field2|field3|value|
+---+------+------+------+-----+
|  a|     y|     y|     x|    2|
|  b|     x|     x|     z|    3|
|  c|     z|     4|     z|    3|
+---+------+------+------+-----+

您最好将字典转换为
广播
变量,然后定义查找
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"}
现在,我们将字典转换为
广播
变量,并定义查找
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)
from pyspark.sql.functions import col

cols = [s for s in df.columns if "field" in s]
df.select(*(lookup_udf(col(c)).alias(c) if c in cols else c for c in df.columns)).show()
+---+------+------+------+-----+
| ID|field1|field2|field3|value|
+---+------+------+------+-----+
|  a|     y|     y|     x|    2|
|  b|     x|     x|     z|    3|
|  c|     z|     4|     z|    3|
+---+------+------+------+-----+
现在剩下的是生成我们将应用函数的列名的
列表
(包含
“field”
)并将其放入带有
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)
from pyspark.sql.functions import col

cols = [s for s in df.columns if "field" in s]
df.select(*(lookup_udf(col(c)).alias(c) if c in cols else c for c in df.columns)).show()
+---+------+------+------+-----+
| ID|field1|field2|field3|value|
+---+------+------+------+-----+
|  a|     y|     y|     x|    2|
|  b|     x|     x|     z|    3|
|  c|     z|     4|     z|    3|
+---+------+------+------+-----+

谢谢非常有帮助!最后一个问题——我希望这些更新是“永久性的”——我可以在这些更新上运行其他聚合/计算。现在,您的最后一个输出只是一个.show()函数。我是否可以将最后一行替换为:df=df.select(*(lookup_udf(col(c)).alias(c)if c in cols else c for c in df.columns)).collect()您可以只分配输出,而不必
.show()
,例如
df1=df.select(..
,我以
.show()结束)
打印转换后数据的外观。不要在最后使用
collect()
,这样会将数据带到驱动程序节点。Duh-我知道这个。谢谢!谢谢!非常有用!最后一个问题-我希望这些更新是“永久的”-然后我可以对其运行其他聚合/计算。现在,您的最后一个输出只是一个.show()函数。我是否可以将最后一行替换为:df=df.select(*(lookup_udf(col(c)).alias(c)if c in cols else c for c in df.columns)).collect()您可以只分配输出而不必
.show()
在最后,例如
df1=df。选择(…
,我以
.show()
结束,以打印转换后数据的外观。不要在最后使用
collect()
,这会将数据带到驱动程序节点。Duh-我知道这一点。谢谢!