Python 2.7 使用柱替换柱上的PySPARK UDF

Python 2.7 使用柱替换柱上的PySPARK UDF,python-2.7,pyspark,pyspark-dataframes,Python 2.7,Pyspark,Pyspark Dataframes,写入此UDF是为了用变量替换列的值。Python 2.7;Spark 2.2.0 import pyspark.sql.functions as func def updateCol(col, st): return func.expr(col).replace(func.expr(col), func.expr(st)) updateColUDF = func.udf(updateCol, StringType()) 变量L_1到L_3为每行更新了列。 我这样称

写入此UDF是为了用变量替换列的值。Python 2.7;Spark 2.2.0

import pyspark.sql.functions as func

    def updateCol(col, st):
       return func.expr(col).replace(func.expr(col), func.expr(st))

  updateColUDF = func.udf(updateCol, StringType())
变量L_1到L_3为每行更新了列。 我这样称呼它:

updatedDF = orig_df.withColumn("L1", updateColUDF("L1", func.format_string(L_1))). \
                withColumn("L2", updateColUDF("L2", func.format_string(L_2))). \
                withColumn("L3", updateColUDF("L3", 
                withColumn("NAME", func.format_string(name)). \
                withColumn("AGE", func.format_string(age)). \
                select("id", "ts", "L1", "L2", "L3",
                     "NAME", "AGE")
错误是:

return Column(sc._jvm.functions.expr(str))
AttributeError: 'NoneType' object has no attribute '_jvm'

尝试创建一个示例数据帧,然后使用PySpark中的
lit
函数

似乎工作正常,这是使用Databricks笔记本


错误是因为您正在udf中使用pyspark函数。了解母语、二语的内容也会很有帮助。。变量

但是,如果我正确理解了您想要做的事情,那么您不需要自定义项。我假设L1,L2等都是常数,对吗?如果没有,请让我知道相应地调整代码。下面是一个例子:

from pyspark import SparkConf
from pyspark.sql import SparkSession, functions as F


conf = SparkConf()
spark_session = SparkSession.builder \
    .config(conf=conf) \
    .appName('test') \
    .getOrCreate()

data = [{'L1': "test", 'L2': "data"}, {'L1': "other test", 'L2': "other data"}]
df = spark_session.createDataFrame(data)
df.show()

# +----------+----------+
# |        L1|        L2|
# +----------+----------+
# |      test|      data|
# |other test|other data|
# +----------+----------+

L1 = 'some other data'
updatedDF = df.withColumn(
    "L1",
    F.lit(L1)
)
updatedDF.show()
# +---------------+----------+
# |             L1|        L2|
# +---------------+----------+
# |some other data|      data|
# |some other data|other data|
# +---------------+----------+


# or if you need to replace the value in a more complex way
pattern = '\w+'
updatedDF = updatedDF.withColumn(
    "L1",
    F.regexp_replace(F.col("L1"), pattern, "testing replace")
)

updatedDF.show()
# +--------------------+----------+
# |                  L1|        L2|
# +--------------------+----------+
# |testing replace t...|      data|
# |testing replace t...|other data|
# +--------------------+----------+

# or even something more complicated:
# set L1 value to L2 column when L2 column equals to data, otherwise, just leave L2 as it is
updatedDF = df.withColumn(
    "L2",
    F.when(F.col('L2') == 'data', L1).otherwise(F.col('L2'))
)
updatedDF.show()

# +----------+---------------+
# |        L1|             L2|
# +----------+---------------+
# |      test|some other data|
# |other test|     other data|
# +----------+---------------+
你的例子是:

DF = orig_df.withColumn("L1", pyspark_func.lit(L_1))
...
此外,请确保在这一点之前有一个活动的spark会话

我希望这有帮助

编辑:如果L1、L2等是列表,那么一个选项是使用它们创建一个数据帧并连接到初始df。不幸的是,我们需要索引进行连接,因为您的数据帧非常大,我认为这不是一个非常有效的解决方案。我们也可以使用广播和udf,或者广播和加入

下面是一个(我认为是次优的)如何进行连接的示例:

L1 = ['row 1 L1', 'row 2 L1']
L2 = ['row 1 L2', 'row 2 L2']

# create a df with indexes    
to_update_df = spark_session.createDataFrame([{"row_index": i, "L1": row[0], "L2": row[1]} for i, row in enumerate(zip(L1, L2))])

# add indexes to the initial df 
indexed_df = updatedDF.rdd.zipWithIndex().toDF()
indexed_df.show()
# +--------------------+---+
# | _1 | _2 |
# +--------------------+---+
# | [test, some other... | 0 |
# | [other test, othe... | 1 |
# +--------------------+---+

# bring the df back to its initial form
indexed_df = indexed_df.withColumn('row_number', F.col("_2"))\
    .withColumn('L1', F.col("_1").getItem('L1'))\
    .withColumn('L2', F.col("_1").getItem('L2')).\
    select('row_number', 'L1', 'L2')

indexed_df.show()
# +----------+----------+---------------+
# |row_number|        L1|             L2|
# +----------+----------+---------------+
# |         0|      test|some other data|
# |         1|other test|     other data|
# +----------+----------+---------------+

# join with your results and keep the updated columns
final_df = indexed_df.alias('initial_data').join(to_update_df.alias('other_data'), F.col('row_index')==F.col('row_number'), how='left')
final_df = final_df.select('initial_data.row_number', 'other_data.L1', 'other_data.L2')
final_df.show()

# +----------+--------+--------+
# |row_number|      L1|      L2|
# +----------+--------+--------+
# |         0|row 1 L1|row 1 L2|
# |         1|row 2 L1|row 2 L2|
# +----------+--------+--------+

这在性能方面肯定会更好。

Pypark确实支持lit,我想请不要使用Python 2.7。给定无法引用functions.py中的“lit”。您可以从pyspark.sql.functions import*执行此操作,而不是像pyspark_func一样尝试导入pyspark.sql.functions。它给出了未解析的引用“lit”,因为不允许在UDF中使用dataframe API函数。先把这个修好,我试试看。L1到L6是通过从SOAP API响应XML中提取标记来设置的变量。每一张唱片都会不断变化。这使得我的实现变得有点棘手和困难。哦,如果它们对每一条记录都不断变化,那么它就是一个列表,对吗?希望与您的数据帧大小相同?是的。我正在以列表的形式填充每个数据帧行的这些字段。我将尝试一下,并让您知道。Cheesdone在源API本身使用了一些更改。感谢您在命令提示下在pyspark终端上选择inputslit。但是pycharmCool上没有,所以这是一些JIRA门票中存在的问题,让我看看是否可以为您获取这些门票。只有几个链接似乎显示了类似的问题。是的,我至少修复了pycharm上的lit问题。但我用相应的问题替换列的主要问题仍然很大,只是为了弄清楚,您提到的使用lit now as lit的scala代码在Pyspark中可用并不能解决这个问题。您是否也在尝试将字符串变量“one”转换为int变量1,假设从第一行获取L1值。。。?