Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/352.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的反比';s_-zip_Python_Apache Spark_Pyspark_Pyspark Dataframes - Fatal编程技术网

Python 寻找pyspark的反比';s_-zip

Python 寻找pyspark的反比';s_-zip,python,apache-spark,pyspark,pyspark-dataframes,Python,Apache Spark,Pyspark,Pyspark Dataframes,我有以下格式化的输入数据帧: 从pyspark.sql导入SparkSession 导入pyspark.sql.F函数 spark=SparkSession.builder.master(“本地”).getOrCreate() input_df=spark.createDataFrame( [ (‘爱丽丝;鲍勃;卡罗尔’,), ('12;13;14',), ('5;;7',), ('1;;3',), (';;3',) ], [“数据”] ) 输入_df.show() # +-----------

我有以下格式化的输入数据帧:

从pyspark.sql导入SparkSession
导入pyspark.sql.F函数
spark=SparkSession.builder.master(“本地”).getOrCreate()
input_df=spark.createDataFrame(
[
(‘爱丽丝;鲍勃;卡罗尔’,),
('12;13;14',),
('5;;7',),
('1;;3',),
(';;3',)
],
[“数据”]
)
输入_df.show()
# +---------------+
#|数据|
# +---------------+
#|爱丽丝;上下快速移动卡罗尔|
# |       12;13;14|
# |           5;;7|
# |           1;;3|
# |            ;;3|
# +---------------+
实际输入是一个分号分隔的CSV文件,其中一列包含一个人的值。每个人可以有不同数量的值。在这里,Alice有3个值,Bob只有一个值,Carol有4个值

我想将其在PySpark中转换为一个输出数据帧,该数据帧保存每个人一个数组,在本例中,输出为:

result=spark.createDataFrame(
[
(“爱丽丝”[12,5,1]),
(“Bob”[13,]),
(“卡罗尔”[14,7,3,3])
],
['name','values']
)
result.show()
# +-----+-------------+
#|名称|值|
# +-----+-------------+
#|爱丽丝|[12,5,1]|
#|鲍勃|[13]|
#|卡罗尔|[14,7,3,3]|
# +-----+-------------+
我该怎么做?我想它将是
F.arrays\u zip()
F.split()
和/或
F.explode()
的组合,但我想不出来

我现在被困在这里,这是我目前的尝试:

(输入
.withColumn('splits',F.split(F.col('data'),';'))
.drop('数据')
).show()
# +-------------------+
#|分裂|
# +-------------------+
#|[爱丽丝、鲍勃、卡罗尔]|
# |       [12, 13, 14]|
# |           [5, 7]|
# |           [1, 3]|
# |            [, 3]|
# +-------------------+

Spark-2.4+解决方案:

df.show()
#+---------------+
#|           data|
#+---------------+
#|Alice;Bob;Carol|
#|       12;13;14|
#|           5;;7|
#|           1;;3|
#|            ;;3|
#+---------------+
from pyspark.sql.functions import *

df.agg(split(concat_ws("|",collect_list(col("data"))),"\\|").alias("tmp")).\
withColumn("col1",split(element_at(col("tmp"),1),";")).\
withColumn("col2",split(element_at(col("tmp"),2),";")).\
withColumn("col3",split(element_at(col("tmp"),3),";")).\
withColumn("col4",split(element_at(col("tmp"),4),";")).\
withColumn("zip",arrays_zip(col("col1"),arrays_zip(col("col2"),col("col3"),col("col4")))).\
selectExpr("explode(zip)as tmp").\
selectExpr("tmp.*").\
toDF("name","values").\
show(10,False)

#+-----+----------+
#|name |values    |
#+-----+----------+
#|Alice|[12, 5, 1]|
#|Bob  |[13, , ]  |
#|Carol|[14, 7, 3]|
#+-----+----------+
使用
groupBy
使用
收集列表将所有行合并为一行,然后拆分以创建新列

  • 使用
    数组\u zip
    压缩数组并创建嵌套数组
    [键,[值]]
  • 最后,
    分解嵌套数组
示例:

df.show()
#+---------------+
#|           data|
#+---------------+
#|Alice;Bob;Carol|
#|       12;13;14|
#|           5;;7|
#|           1;;3|
#|            ;;3|
#+---------------+
from pyspark.sql.functions import *

df.agg(split(concat_ws("|",collect_list(col("data"))),"\\|").alias("tmp")).\
withColumn("col1",split(element_at(col("tmp"),1),";")).\
withColumn("col2",split(element_at(col("tmp"),2),";")).\
withColumn("col3",split(element_at(col("tmp"),3),";")).\
withColumn("col4",split(element_at(col("tmp"),4),";")).\
withColumn("zip",arrays_zip(col("col1"),arrays_zip(col("col2"),col("col3"),col("col4")))).\
selectExpr("explode(zip)as tmp").\
selectExpr("tmp.*").\
toDF("name","values").\
show(10,False)

#+-----+----------+
#|name |values    |
#+-----+----------+
#|Alice|[12, 5, 1]|
#|Bob  |[13, , ]  |
#|Carol|[14, 7, 3]|
#+-----+----------+


对于
spark<2.4
使用数组,使用
getItem()
而不是
函数中的
元素。

我建议将数据读取为
分离的csv,然后处理以获得
名称
列,如下所示-

请注意,这段代码是用scala编写的,但类似的代码可以在pyspark中实现,只需很少的更改

加载
分离csv
val数据=
"""
|爱丽丝;鲍勃;卡罗尔
|       12;13;14
|           5;;7
|           1;;3
|            ;;3
“.stripMargin”
val stringDS=data.split(System.lineSeparator())
.map(\\;).map(\.split(“\\\”).map(\.replaceAll(“^[\t]+\\t]+$”,”).mkString(“;”)
.toSeq.toDS()
val df=spark.read
.期权(“sep”、“;”)
.选项(“推断模式”、“真”)
.选项(“标题”、“正确”)
.选项(“空值”、“空值”)
.csv(stringDS)
df.printSchema()
df.show(假)
/**
*根
*|--Alice:integer(nullable=true)
*|--Bob:integer(nullable=true)
*|--Carol:integer(nullable=true)
*
* +-----+----+-----+
*|爱丽丝|鲍勃|卡罗尔|
* +-----+----+-----+
* |12   |13  |14   |
*| 5 |空| 7|
*| 1 |空| 3|
*|空|空| 3|
* +-----+----+-----+
*/
派生
名称

val columns=df.columns.map(c=>expr(s“named_struct('name','$c','values',collect_list($c)))
选择(数组(列:*).as(“数组”))
.selectExpr(“内联\外部(数组)”)
.show(假)
/**
* +-----+-------------+
*|名称|值|
* +-----+-------------+
*|爱丽丝|[12,5,1]|
*|鲍勃|[13]|
*|卡罗尔|[14,7,3,3]|
* +-----+-------------+
*/

一种方法是读取第一行作为标题,然后取消打印数据

df1 = spark.createDataFrame([(12,13,14),(5,None,7),(1,None,3),(None,None,3)], ['Alice','Bob','Carol'])

df1.show()
+-----+----+-----+
|Alice| Bob|Carol|
+-----+----+-----+
|   12|  13|   14|
|    5|null|    7|
|    1|null|    3|
| null|null|    3|
+-----+----+-----+

df1.select(f.expr('''stack(3,'Alice',Alice,'Bob',Bob,'Carol',Carol) as (Name,Value)'''))\
   .groupBy('Name').agg(f.collect_list('value').alias('Value')).orderBy('Name').show()

+-----+-------------+
| Name|        Value|
+-----+-------------+
|Alice|   [12, 5, 1]|
|  Bob|         [13]|
|Carol|[14, 7, 3, 3]|
+-----+-------------+

要动态传递列,请使用以下代码

cols = ','.join([f"'{i[0]}',{i[1]}" for i in zip(df1.columns,df1.columns)])
df1.select(f.expr(f'''stack(3,{cols}) as (Name,Value)''')).groupBy('Name').agg(f.collect_list('value').alias('Value')).orderBy('Name').show()

+-----+-------------+
| Name|        Value|
+-----+-------------+
|Alice|   [12, 5, 1]|
|  Bob|         [13]|
|Carol|[14, 7, 3, 3]|
+-----+-------------+

非常感谢!在我的原始数据集中,我有数百列,即数百个像Alice、Bob和Carol这样的名字。有没有办法在您的答案中循环所有创建“col1”、“col2”等的行?@AlexanderEngelhardt,对于在列中动态创建元素_,您可以使用这里提到的类似方法: