如何在 pyspark 中创建数据框的副本?
Posted
技术标签:
【中文标题】如何在 pyspark 中创建数据框的副本?【英文标题】:How to create a copy of a dataframe in pyspark? 【发布时间】:2018-09-12 04:35:09 【问题描述】:我有一个数据框,我需要通过执行以下操作来创建一个新的数据框,并在架构中进行少量更改。
>>> X = spark.createDataFrame([[1,2], [3,4]], ['a', 'b'])
>>> schema_new = X.schema.add('id_col', LongType(), False)
>>> _X = X.rdd.zipWithIndex().map(lambda l: list(l[0]) + [l[1]]).toDF(schema_new)
问题是在上述操作中,X
的架构被原地改变了。所以当我打印 X.columns
我得到 p>
>>> X.columns
['a', 'b', 'id_col']
但X
中的值仍然相同
>>> X.show()
+---+---+
| a| b|
+---+---+
| 1| 2|
| 3| 4|
+---+---+
为避免更改X
的架构,我尝试使用三种方式创建X
的副本
- 使用来自copy
模块的copy
和deepcopy
方法
- 只需使用_X = X
copy
方法失败并返回一个
RecursionError: maximum recursion depth exceeded
赋值方法也不行
>>> _X = X
>>> id(_X) == id(X)
True
由于他们的id
是相同的,因此在这里创建一个重复的数据框并没有真正的帮助,并且在_X
上完成的操作反映在X
中。
所以我的问题确实是两个方面
如何更改架构替代位置(即不对X
进行任何更改)?
更重要的是,如何创建 pyspark 数据帧的副本?
注意:
这个问题是这个post的后续问题
【问题讨论】:
我想到的最简单的解决方案是使用df_copy = original_df.select("*")
的解决方法,并且可能添加一些 .cache() 。有意义吗?
【参考方案1】:
.alias()
常用于重命名列,但它也是a DataFrame method,它会给你你想要的:
df2 = df.alias('df2')
id(df2) == id(df) # False
【讨论】:
@GuillaumeLabs 你能告诉你的火花版本和你得到了什么错误。 我正在使用 azure databricks 6.4 。数据帧的 ID 不同,但因为初始数据帧是一个增量表的选择,所以这个数据帧的副本和你的技巧仍然是这个增量表的一个选择;-)。【参考方案2】:如另一个问题的答案中所述,您可以对初始架构进行深度复制。然后我们可以修改该副本并使用它来初始化新的DataFrame
_X
:
import pyspark.sql.functions as F
from pyspark.sql.types import LongType
import copy
X = spark.createDataFrame([[1,2], [3,4]], ['a', 'b'])
_schema = copy.deepcopy(X.schema)
_schema.add('id_col', LongType(), False) # modified inplace
_X = X.rdd.zipWithIndex().map(lambda l: list(l[0]) + [l[1]]).toDF(_schema)
现在让我们检查一下:
print('Schema of X: ' + str(X.schema))
print('Schema of _X: ' + str(_X.schema))
输出:
Schema of X: StructType(List(StructField(a,LongType,true),StructField(b,LongType,true)))
Schema of _X: StructType(List(StructField(a,LongType,true),
StructField(b,LongType,true),StructField(id_col,LongType,false)))
请注意,要复制DataFrame
,您只需使用_X = X
。每当您添加新列时,例如withColumn
,对象并没有就地改变,而是返回了一个新的副本。
希望这会有所帮助!
【讨论】:
【参考方案3】:如果您需要创建 pyspark 数据帧的副本,您可以使用 Pandas。
schema = X.schema
X_pd = X.toPandas()
_X = spark.createDataFrame(X_pd,schema=schema)
del X_pd
【讨论】:
【参考方案4】:在 Scala 中:
-
使用“X.schema.copy”创建新架构实例,而无需修改旧架构;
在每个返回 Dataframe(“select”、“where”等)的 Dataframe 操作中,都会创建新的 Dataframe,而无需修改原始数据框。原件可以反复使用。猜猜,您的情况不需要重复。性能是单独的问题,可以使用“persist”。
【讨论】:
【参考方案5】:df2 = df.select("*")
id(df2) = id(df) # False
这与@SantiagoRodriguez 给出的答案相同,同样代表了与@tozCSS 共享的类似方法。我相信@tozCSS 建议使用.alias()
代替.select()
可能确实是最有效的。
【讨论】:
以上是关于如何在 pyspark 中创建数据框的副本?的主要内容,如果未能解决你的问题,请参考以下文章
从列表中创建一个 pyspark 数据框列,其中列表的长度与数据框的行数相同
如何在 PySpark ML 中创建自定义 SQLTransformer 以透视数据
如何在 Databricks 的 PySpark 中使用在 Scala 中创建的 DataFrame
如何在 Pyspark Dataframe 中创建多列的所有成对组合?