使用 Pyspark 比较数据帧的架构

Avi*_*Avi 10 python apache-spark apache-spark-sql pyspark

我有一个数据框(df)。为了显示其架构,我使用:

from pyspark.sql.functions import *
df1.printSchema()
Run Code Online (Sandbox Code Playgroud)

我得到以下结果:

#root
# |-- name: string (nullable = true)
# |-- age: long (nullable = true)
Run Code Online (Sandbox Code Playgroud)

有时架构会发生变化(列类型或名称):

df2.printSchema()


 #root
        # |-- name: array (nullable = true)
        # |-- gender: integer (nullable = true)
        # |-- age: long (nullable = true)
Run Code Online (Sandbox Code Playgroud)

我想比较两个模式(df1df2)并仅获取类型和列名称的差异(有时列可以移动到另一个位置)。结果应该是一个类似这样的表格(或数据框):

   column                df1          df2     diff                       
    name:               string       array     type                             
    gender:              N/A         integer   new column 
Run Code Online (Sandbox Code Playgroud)

age列是相同的并且没有改变。如果省略列,将会有指示'omitted')如果每个列中有很多列,我该如何有效地做到这一点?

Sai*_*ish 12

无需任何外部库,我们可以使用以下方式找到模式差异

from pyspark.sql.session import SparkSession
from pyspark.sql import DataFrame

def schema_diff(spark: SparkSession, df_1: DataFrame, df_2: DataFrame):
    s1 = spark.createDataFrame(df_1.dtypes, ["d1_name", "d1_type"])
    s2 = spark.createDataFrame(df_2.dtypes, ["d2_name", "d2_type"])
    difference = (
        s1.join(s2, s1.d1_name == s2.d2_name, how="outer")
        .where(s1.d1_type.isNull() | s2.d2_type.isNull())
        .select(s1.d1_name, s1.d1_type, s2.d2_name, s2.d2_type)
        .fillna("")
    )
    return difference

Run Code Online (Sandbox Code Playgroud)
  • fillna 是可选的。我更喜欢将它们视为空字符串。
  • 在 where 子句中,我们使用类型,因为这将帮助我们显示即使列存在于两个数据帧中但它们具有不同的架构。
  • 这还将显示第二个数据帧中但不在第一个数据帧中的所有列

用法:

diff = schema_diff(spark, df_1, df_2)
diff.show(diff.count(), truncate=False)
Run Code Online (Sandbox Code Playgroud)

  • 好的,在这种情况下,您应该删除 where 子句,否则它不会返回具有相同名称但不同类型的列。只需使用这些数据帧尝试一下: `df1 = Spark.createDataFrame([("a", (1, 2))], "a: string, b struct<x:int,y:int>")`, `df2 = Spark.createDataFrame([("a", (1, 2))], "a: 字符串, b struct<z:int,t:int>")` (3认同)
  • 仅突出显示不同列的正确子句应该是: `.where(s1.d1_type.isNull() | s2.d2_type.isNull() | (s1.d1_type != s2.d2_type))` 另外,合并列名将让结果更清晰 (2认同)

小智 3

您可以尝试使用 DF1 和 DF2 的元数据创建两个 pandas 数据框,如下所示

pd_df1=pd.DataFrame(df1.dtypes,columns=['column','data_type'])
pd_df2=pd.DataFrame(df2.dtypes,columns=['column','data_type'])
Run Code Online (Sandbox Code Playgroud)

然后通过“外部”连接连接这两个熊猫数据框?