Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.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
Python Pyspark从现有数组列创建特定长度的数组列_Python_Apache Spark_Pyspark_Apache Spark Sql - Fatal编程技术网

Python Pyspark从现有数组列创建特定长度的数组列

Python Pyspark从现有数组列创建特定长度的数组列,python,apache-spark,pyspark,apache-spark-sql,Python,Apache Spark,Pyspark,Apache Spark Sql,我有一个类似pyspark的数据帧 +-----+----+------------+------------+-------------+------------+ | Name| Age| P_Attribute|S_Attributes|P_Values |S_values | +-----+----+------------+------------+-------------+------------+ | Bob1| 16 | [x1,x2] | [x1

我有一个类似pyspark的数据帧

+-----+----+------------+------------+-------------+------------+
| Name| Age| P_Attribute|S_Attributes|P_Values     |S_values    | 
+-----+----+------------+------------+-------------+------------+
| Bob1| 16 |  [x1,x2]   |     [x1,x3]|["ab",1]     | [1,2]      |
| Bob2| 16 |[x1,x2,x3]  |     []     |["a","b","c"]| []         |
+-----+----+------------+------------+-------------+------------+
我想最终创建df,如下所示

+-----+----+------------+------------+
| Name| Age| Attribute  |      Values|
+-----+----+------------+------------+
| Bob1| 16 |  x1        |     ab     |
| Bob1| 16 |  x2        |     1      |
| Bob1| 16 |  x1        |     1      |
| Bob1| 16 |  x3        |     2      |
| Bob2| 16 |  x1        |     a      |
| Bob2| 16 |  x2        |     b      |
| Bob2| 16 |  x3        |     c      |
+-----+----+------------+------------+
基本上我想合并这两列并将它们分解成行。在pyspark数组函数的帮助下,我能够对数组进行concat和explode操作,但后来可以识别专业属性和运动属性之间的差异,因为它们可以有相同的名称。我还需要一个类型列

+-----+----+------------+------------+------------+
| Name| Age|   Attribute|       type |Value       |
+-----+----+------------+------------+------------+
| Bob1| 16 |  x1        |     1      | ab         |
| Bob1| 16 |  x2        |     1      | 1          |
| Bob1| 16 |  x1        |     2      | 1          |
| Bob1| 16 |  x3        |     2      | 2          |
| Bob2| 16 |  x1        |     1      | a          |
| Bob2| 16 |  x2        |     1      | b          |
| Bob2| 16 |  x3        |     1      | c          |
+-----+----+------------+------------+------------+  
所以我想先创建一个单独的数组列

+-----+----+------------+------------+------------+------------+
| Name| Age| P_Attribute|S_Attributes|P_type      |S_type      |
+-----+----+------------+------------+------------+------------+
| Bob1| 16 |  [x1,x2]   |     [x1,x3]|   [1,1]    | [2,2]      |
| Bob2| 16 |[x1,x2,x3]  |     []     |  [1,1,1]   |  []        |
+-----+----+------------+------------+------------+------------+
这样我就可以合并列并使用所需类型的列进行分解,如上面的df所示。 问题是我无法动态创建P_类型和S_类型列。 我试过下面的代码

new_df = df.withColumn("temp_P_type", F.lit(1))\
                .withColumn("P_type", F.array_repeat("temp_P_type",F.size("P_Attribute")))
这将抛出
TypeError:列不可编辑
错误。
若列的长度已经被提取为另一列,那个么它也不起作用。
有人能帮我吗?有没有更好的解决办法?作为df级别,不使用RDD和python函数(不使用UDF)是否可以做到这一点


另外,我正在使用spark 2.4,您可以执行以下操作。首先将
P\u属性
S\u属性
收集到一个
attributes
列中,然后在其上执行
posexplode
,这将根据需要给出引用属性源(
P
S
)的
类型
列。最后,
分解
属性
列以展平所有属性

import pyspark.sql.functions as f

df = spark.createDataFrame([
    ['Bob1', 16, ['x1', 'x2'], ['x1', 'x3']],
    ['Bob2', 16, ['x1', 'x2', 'x3'], []]],
    ['Name', 'Age', 'P_Attribute', 'S_Attributes'])

df.withColumn('Attributes', f.array('P_Attribute', 'S_Attributes'))\
  .select('Name', 'Age', f.posexplode('Attributes').alias('type', 'Attribute'))\
  .withColumn('Attribute', f.explode('Attribute'))\
  .show()

+----+---+----+---------+
|Name|Age|type|Attribute|
+----+---+----+---------+
|Bob1| 16|   0|       x1|
|Bob1| 16|   0|       x2|
|Bob1| 16|   1|       x1|
|Bob1| 16|   1|       x3|
|Bob2| 16|   0|       x1|
|Bob2| 16|   0|       x2|
|Bob2| 16|   0|       x3|
+----+---+----+---------+

我建议使用高阶函数
,使用
,然后
分解一次
,然后使用
*扩展选择两者。

df.show()
#+----+---+------------+------------+
#|Name|Age| P_Attribute|S_Attributes|
#+----+---+------------+------------+
#|Bob1| 16|    [x1, x2]|    [x1, x3]|
#|Bob2| 16|[x1, x2, x3]|          []|
#+----+---+------------+------------+

from pyspark.sql import functions as F
df.withColumn("Attributes", F.explode(F.array_union(F.expr("""transform(P_Attribute,x-> struct(x as Attribute,1 as Type))"""),\
              F.expr("""transform(S_Attributes,x-> struct(x as Attribute,2 as Type))"""))))\
   .select("Name", "Age", "Attributes.*").show()

#+----+---+---------+----+
#|Name|Age|Attribute|Type|
#+----+---+---------+----+
#|Bob1| 16|       x1|   1|
#|Bob1| 16|       x2|   1|
#|Bob1| 16|       x1|   2|
#|Bob1| 16|       x3|   2|
#|Bob2| 16|       x1|   1|
#|Bob2| 16|       x2|   1|
#|Bob2| 16|       x3|   1|
#+----+---+---------+----+
更新:

df.show()

#+----+---+------------+------------+---------+--------+
#|Name|Age| P_Attribute|S_Attributes| P_Values|S_values|
#+----+---+------------+------------+---------+--------+
#|Bob1| 16|    [x1, x2]|    [x1, x3]|  [ab, 1]|  [1, 2]|
#|Bob2| 16|[x1, x2, x3]|          []|[a, b, c]|      []|
#+----+---+------------+------------+---------+--------+

from pyspark.sql import functions as F
df.withColumn("Attributes", F.explode(F.array_union\
               (F.expr("""transform(arrays_zip(P_Attribute,P_Values),x->\
                          struct(x.P_Attribute as Attribute,1 as Type,string(x.P_Values) as Value))"""),\
                F.expr("""transform(arrays_zip(S_Attributes,S_Values),x->\
                          struct(x.S_Attributes as Attribute,2 as Type,string(x.S_Values) as Value))"""))))\
   .select("Name", "Age", "Attributes.*").show()

#+----+---+---------+----+-----+
#|Name|Age|Attribute|Type|Value|
#+----+---+---------+----+-----+
#|Bob1| 16|       x1|   1|   ab|
#|Bob1| 16|       x2|   1|    1|
#|Bob1| 16|       x1|   2|    1|
#|Bob1| 16|       x3|   2|    2|
#|Bob2| 16|       x1|   1|    a|
#|Bob2| 16|       x2|   1|    b|
#|Bob2| 16|       x3|   1|    c|
#+----+---+---------+----+-----+

我想如下创建df,这个预期结果(第二个表)非常混乱。您是否只需要一个属性列,如下表3?感谢@mohamand Murtaza Hashmi的回答。它解决了这个问题。是否可以向F.expr添加多个列,如F.expr(““”转换(S_属性,S_值,x,y->struct(x为属性,y为变量,2为类型))”),以便转换只能接受一个参数,或者(x,i),其中i是x的索引。因此,为了实现这一点,u必须组合
S_属性
S_值
,然后使用transform遍历它。如果
S_值
也是一个数组,那么u可以这样做
F.expr(““”转换(数组(S_属性,S_值),x->struct(x.S_属性作为属性,x.S_值作为值,2作为类型))”
如果您可以提供
S_值
列和
P_值
列,我很乐意与他们一起更新解决方案@NachiketKateThanks,以获得答案@Psidom。如果P_值和S_值列作为这些属性的值,是否可以使用f.array()呢?不完全确定您需要什么。但是可能
f.posexplode(f.explode(f.create_-map('P_-Attribute','P_-values')、f.create_-map('S_-Attributes','S_-values')))))。别名('type','Attribute')
如果属性列没有重复的元素。