Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/selenium/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用pyspark,如何将一列添加到数据帧中,作为同一数据帧中多个已知列(不包括null)的键值映射?_Pyspark_Apache Spark Sql_Pyspark Dataframes - Fatal编程技术网

使用pyspark,如何将一列添加到数据帧中,作为同一数据帧中多个已知列(不包括null)的键值映射?

使用pyspark,如何将一列添加到数据帧中,作为同一数据帧中多个已知列(不包括null)的键值映射?,pyspark,apache-spark-sql,pyspark-dataframes,Pyspark,Apache Spark Sql,Pyspark Dataframes,给出以下示例: d = [{'asset': '2', 'ts': 6, 'B':'123','C':'234'}, {'asset': '1', 'ts': 5, 'C.1':'999', 'B':'888','F':'999'}] df = spark.createDataFrame(d) df.show(truncate=False) +---+----+-----+---+----+----+ |B |C |asset|ts |C.1 |F | +---+---

给出以下示例:

d = [{'asset': '2', 'ts': 6,  'B':'123','C':'234'}, 
     {'asset': '1', 'ts': 5, 'C.1':'999', 'B':'888','F':'999'}]
df = spark.createDataFrame(d)
df.show(truncate=False)

+---+----+-----+---+----+----+
|B  |C   |asset|ts |C.1 |F   |
+---+----+-----+---+----+----+
|123|234 |2    |6  |null|null|
|888|null|1    |5  |999 |999 |
+---+----+-----+---+----+----+
我要创建以下输出:

+-----+---+--------------------------------+
|asset|ts |signals                         |
+-----+---+--------------------------------+
|2    |6  |[B -> 123, C -> 234]            |
|1    |5  |[B -> 888, C.1 -> 999, F -> 999]|
+-----+---+--------------------------------+
我尝试了以下方法:

from itertools import chain
from pyspark.sql.functions import *
all_signals=['B','C','C.1','F']
key_values = create_map(*(chain(*[(lit(name), col("`"+name+"`"))
                                  for name in all_signals])))

new_df = df.withColumn('signals',key_values).drop(*all_signals).show(truncate=False)

+-----+---+--------------------------------------+
|asset|ts |signals                               |
+-----+---+--------------------------------------+
|2    |6  |[B -> 123, C -> 234, C.1 ->, F ->]    |
|1    |5  |[B -> 888, C ->, C.1 -> 999, F -> 999]|
+-----+---+--------------------------------------+
但是我不想要带有空值的键。所以我尝试了很多方法来排除null或None。 我试过如果条件,当/否则,但似乎都不起作用。这里有一个尝试:

key_values = create_map(*(chain(*[(lit(name), col("`"+name+"`")) 
                                  for name in all_signals 
                                  if col("`"+name+"`").isNotNull()])))
new_df = df.withColumn('signals',key_values).drop(*all_signals).show(truncate=False)


ValueError: Cannot convert column into bool: please use '&' for 'and', '|' for 'or', '~' for 'not' when building DataFrame boolean expressions.

我用一种我不满意的循环方式让它工作:

new_df= df.withColumn("signals", from_json(
                       to_json(struct(["`"+x+"`" for x in all_signals])),"MAP<STRING,STRING>"))
                      
new_df = new_df.drop(*all_signals)
new_df.show(truncate=False)

+-----+---+--------------------------------+
|asset|ts |signals                         |
+-----+---+--------------------------------+
|2    |6  |[B -> 123, C -> 234]            |
|1    |5  |[B -> 888, C.1 -> 999, F -> 999]|
+-----+---+--------------------------------+

但是必须有一种排除null的方法,而不必来回访问json

我有另一个解决方案。首先使用空值构建映射,然后删除空值

从pyspark.sql.types导入映射类型,StringType 从pyspark.sql导入函数为F 原始数据帧 数据=[{'asset':'2','ts':6',B':'123',C':'234'}, {'asset':'1','ts':5,'C.1':'999','B':'888','F':'999'}] df=spark.createDataFramedata df.showtruncate=False 创建包含空值的映射 因为spark很奇怪,所以需要背景标记 https://stackoverflow.com/questions/44367019/column-name-with-dot-spark 名称=['B','C','C.1','F'] 键值列表=[] 对于名称中的名称: 键值列表+=[F.litname] 键值列表+=[df[`{}`.formatname]] 映射列=F.创建映射*键值列表 删除空值的UDF 删除\u null\u值\u udf=F.udf lambda d:{k:v代表k,d项中的v如果v不是None}, MapTypeStringType,StringType 应用以上两种方法 df=df.withColumn'map',删除\u null\u值\u udfmap\u column.drop*名称 df.show +---+--+----------+ |资产| ts |地图| +---+--+----------+ |2 | 6 |[B->123,C->234]| |1 | 5 |[B->888,F->9| +---+--+----------+
我有另一个解决方案。首先用空值构建映射,然后删除空值

从pyspark.sql.types导入映射类型,StringType 从pyspark.sql导入函数为F 原始数据帧 数据=[{'asset':'2','ts':6',B':'123',C':'234'}, {'asset':'1','ts':5,'C.1':'999','B':'888','F':'999'}] df=spark.createDataFramedata df.showtruncate=False 创建包含空值的映射 因为spark很奇怪,所以需要背景标记 https://stackoverflow.com/questions/44367019/column-name-with-dot-spark 名称=['B','C','C.1','F'] 键值列表=[] 对于名称中的名称: 键值列表+=[F.litname] 键值列表+=[df[`{}`.formatname]] 映射列=F.创建映射*键值列表 删除空值的UDF 删除\u null\u值\u udf=F.udf lambda d:{k:v代表k,d项中的v如果v不是None}, MapTypeStringType,StringType 应用以上两种方法 df=df.withColumn'map',删除\u null\u值\u udfmap\u column.drop*名称 df.show +---+--+----------+ |资产| ts |地图| +---+--+----------+ |2 | 6 |[B->123,C->234]| |1 | 5 |[B->888,F->9| +---+--+----------+ 不需要UDF,使用高阶函数过滤器,使用数组\u zip和映射\u from\u条目来获得所需的输出。spark2.4+

不需要UDF,使用高阶函数过滤器,使用数组\u zip和映射\u from\u条目来获得所需的输出。spark2.4+


这看起来棒极了。我会测试它的性能并让你知道。你太棒了。谢谢!这看起来棒极了。我会测试它的性能并让你知道。你太棒了。谢谢!我忍不住对你的解决方案微笑。这让我觉得很傻。令人印象深刻!出于某种原因,从_json到_json提供了更好的性能,但这确实回答了我的问题n、 我忍不住对你的解决方案笑了笑。这让我觉得很傻。令人印象深刻!出于某种原因,从_json和to_json提供了更好的性能,但这确实回答了我的问题。
from pyspark.sql import functions as F

all_singals=['B','C','C.1','F']

df.withColumn("all_one", F.array(*[F.lit(x) for x in all_signals]))\
  .withColumn("all_two", F.array(*["`"+x+"`" for x in all_signals]))\
  .withColumn("signals", F.expr("""map_from_entries(filter(arrays_zip(all_one,all_two),x-> x.all_two is not null))"""))\
  .drop("all_one","all_two").show(truncate=False)

#+---+----+-----+---+----+----+--------------------------------+
#|B  |C   |asset|ts |C.1 |F   |signals                         |
#+---+----+-----+---+----+----+--------------------------------+
#|123|234 |2    |6  |null|null|[B -> 123, C -> 234]            |
#|888|null|1    |5  |999 |999 |[B -> 888, C.1 -> 999, F -> 999]|
#+---+----+-----+---+----+----+--------------------------------+