这是针对使用Spark 2.3.2的Python / PySpark。 我正在寻找最佳实践方法,使用Python / PySpark将一个数据框的列复制到另一个数据框,以处理10+十亿行(按年/月/日均匀划分)的非常大的数据集。每行有120列要转换/复制。输出数据帧将被写入日期分区,并写入另一个拼合的文件集中。
示例架构为: 输入DFinput(colA,colB,colC)和 输出DFoutput(X,Y,Z)
我要将DFInput复制到DFOutput,如下所示(colA => Z,colB => X,colC => Y)。
在Python Spark 2.3+中执行此操作的最佳实践是什么? 是否应该为每个列使用 DF.withColumn() 方法将源复制到目标列? 如果数十亿行每行有110列以上的列进行复制,这样的性能是否很好?
谢谢
答案 0 :(得分:1)
使用dataframe.withColumn()通过添加列或替换具有相同名称的现有列来返回新的DataFrame。
答案 1 :(得分:0)
就我所知,使用Apache Spark的方法是将输入DataFrame转换为所需的输出DataFrame。您只需在输入DataFrame上使用selectExpr
即可完成该任务:
outputDF = inputDF.selectExpr("colB as X", "colC as Y", "colA as Z")
此转换不会将数据从输入DataFrame“复制”到输出DataFrame。
答案 2 :(得分:0)
我遇到的这个有趣的示例显示了两种方法和更好的方法,并且同意其他答案。这是Scala,而不是pyspark,但适用原理相同,即使示例不同。
import org.apache.spark.sql.functions._
import spark.implicits._
val df = Seq(
("1","2", "3"),
("4", "5", "6"),
("100","101", "102")
).toDF("c1", "c2", "c3")
这很昂贵,因为withColumn会为每次迭代创建一个新的DF:
val df2 = df.columns.foldLeft(df) { case (df, col) =>
df.withColumn(col, df(col).cast("int"))
}
//df2.show(false)
这更快。
val df3 = df.select(df.columns.map { col =>
df(col).cast("int")
}: _*)
//df3.show(false)
答案 3 :(得分:0)
这个(python)上的菜鸟有点难,但是用SQL(或您拥有的任何原始资料)来做,然后将其读入新的/单独的数据帧中可能会更容易些?
答案 4 :(得分:0)
使用python处理列映射的另一个有用的结构是dictionary
。字典可帮助您使用key/value
结构将初始数据框的列映射到最终数据框的列,如下所示:
from pyspark.sql.functions import col
df = spark.createDataFrame([
[1, "John", "2019-12-01 10:00:00"],
[2, "Michael", "2019-12-01 11:00:00"],
[2, "Michael", "2019-12-01 11:01:00"],
[3, "Tom", "2019-11-13 20:00:00"],
[3, "Tom", "2019-11-14 00:00:00"],
[4, "Sofy", "2019-10-01 01:00:00"]
], ["A", "B", "C"])
col_map = {"A":"Z", "B":"X", "C":"Y"}
df.select(*[col(k).alias(col_map[k]) for k in col_map]).show()
# +---+-------+-------------------+
# | Z| X| Y|
# +---+-------+-------------------+
# | 1| John|2019-12-01 10:00:00|
# | 2|Michael|2019-12-01 11:00:00|
# | 2|Michael|2019-12-01 11:01:00|
# | 3| Tom|2019-11-13 20:00:00|
# | 3| Tom|2019-11-14 00:00:00|
# | 4| Sofy|2019-10-01 01:00:00|
# +---+-------+-------------------+
在这里,我们分别将A,B,C映射到Z,Y,X。
如果需要模块化解决方案,还可以将所有内容都放在函数中:
def tranform_cols(mappings, df):
return df.select(*[col(k).alias(mappings[k]) for k in mappings])
或者通过使用monkey patching来扩展DataFrame
类的现有功能,甚至进行模块化。将下一个代码放在其他任何东西之前的PySpark代码顶部:
from pyspark.sql import DataFrame
def transform_cols(self, mappings):
return self.select(*[col(k).alias(mappings[k]) for k in mappings])
DataFrame.transform = transform_cols
然后通过以下方式调用它:
df.tranform(col_map).show()
PS:这可能是通过创建自己的库并通过DataFrame和Monkey patching(熟悉C#的扩展方法)公开它们来扩展DataFrame功能的便捷方法。