一文让你记住Pyspark下DataFrame的7种的Join 效果

Pyspark Join类型详解:实战演示与应用场景

最近看到了一片好文,虽然很简单,但是配上的插图可以让人很好的记住Pyspark 中的多种Join 类型和实际的效果。原英文链接 Introduction to Pyspark join types - Blog | luminousmen

假设使用如下的两个DataFrame 来进行展示

heroes_data = [
    ('Deadpool', 3), 
    ('Iron man', 1),
    ('Groot', 7),
]
race_data = [
    ('Kryptonian', 5), 
    ('Mutant', 3), 
    ('Human', 1), 
]
heroes = spark.createDataFrame(heroes_data, ['name', 'id'])
races = spark.createDataFrame(race_data, ['race', 'id'])

实际的上的数据展示效果如下:

+--------+---+           +----------+---+
|    name| id|           |      race| id|
+--------+---+           +----------+---+
|Deadpool|  3|           |Kryptonian|  5|
|Iron man|  1|           |    Mutant|  3|
|   Groot|  7|           |     Human|  1|
+--------+---+           +----------+---+

下面的展示图片中,其中相同的颜色表示的是能够Join匹配上的数据。下面的Join都是通过ID的方式来进行关联。

下面除了 Cross Join 之间,其它的都是通过如下说明

heroes.join(races, on='id', how='left').show()

说明在不同的 Join 的方式下不同效果。

Cross join 笛卡尔积

这个比较好理解,就是heroes表的数据和races表的数据进行Join,就是将heroes表的每一行数据都同races表的每一行数据进行联合。数据的数量级就是 m*n。不考虑Join的主键。

>>> heroes.crossJoin(races).show()
+--------+---+----------+---+  
|    name| id|      race| id|
+--------+---+----------+---+
|Deadpool|  3|Kryptonian|  5|
|Deadpool|  3|    Mutant|  3|
|Deadpool|  3|     Human|  1|
|Iron man|  1|Kryptonian|  5|
|Iron man|  1|    Mutant|  3|
|Iron man|  1|     Human|  1|
|   Groot|  7|Kryptonian|  5|
|   Groot|  7|    Mutant|  3|
|   Groot|  7|     Human|  1|
+--------+---+----------+---+

Inner join 内联合

只生成同时匹配表heroes和表races的记录集

Inner join

>>> heroes.join(races, on='id', how='inner').show()
+---+--------+------+ 
| id|    name|  race|
+---+--------+------+
|  1|Iron man| Human|
|  3|Deadpool|Mutant|
+---+--------+------+

Left join / Left outer join 左外联合

leftleft outer 是一个别名的关系。生成表heroes的所有记录,包括在表races里匹配的记录。如果没有匹配的,右边将是null。就是inner Join 的结果,再加上左边的表未匹配的所有的结果。

Left join

>>> heroes.join(races, on='id', how='left').show()
>>> heroes.join(races, on='id', how='leftouter').show()
+---+--------+------+
| id|    name|  race|
+---+--------+------+
|  7|   Groot|  null|
|  1|Iron man| Human|
|  3|Deadpool|Mutant|
+---+--------+------+

Right join / Right outer join 右外联合

同上左外联合类似。

Right join

>>> heroes.join(races, on='id', how='right').show()
>>> heroes.join(races, on='id, how='rightouter').show()
+---+--------+----------+ 
| id|    name|      race|
+---+--------+----------+
|  5|    null|Kryptonian|
|  1|Iron man|     Human|
|  3|Deadpool|    Mutant|
+---+--------+----------+

Full outer join 全外联合

outer和full 也是别名关系。生成表heroes和表races里的记录全集,包括两边都匹配的记录。如果有一边没有匹配的,缺失的这一边为null。

Full outer join

>>> heroes.join(races, on='id', how='outer').show()
>>> heroes.join(races, on='id', how='full').show()
+---+--------+----------+
| id|    name|      race|
+---+--------+----------+
|  7|   Groot|      null|
|  5|    null|Kryptonian|
|  1|Iron man|     Human|
|  3|Deadpool|    Mutant|
+---+--------+----------+

Left semi-join 左半连接

可以简单的看成是,inner join 之后,只保留能够Join上的左边表数据。

Left semi-join

>>> heroes.join(races, on='id', how='leftsemi').show()
+---+--------+
| id|    name|
+---+--------+
|  1|Iron man|
|  3|Deadpool|
+---+--------+

Left anti join

看成是Left semi-join 的取反操作,将左边中,没有匹配上的数据给取出。

Left anti join

>>> heroes.join(races, on='id', how='leftanti').show()
+---+-----+
| id| name|
+---+-----+
|  7|Groot|
+---+-----+

其它的补充

在Join的过程中,左边和右边都不能为None,可以是空数据的表但是需要带Schema,且Schema中有指定的关联主键(on)。

使用Pyspark 中创建空的DataFrame

  1. 创建空Schema的空DataFrame
  2. 创建带Schema的空DataFrame
def create_empty_df_without_schema():
    # Create an empty RDD
    emp_RDD = spark.sparkContext.emptyRDD()
    # Create empty schema
    columns = StructType([])
    return spark.createDataFrame(data=emp_RDD,
                                 schema=columns)

def create_empty_df_with_schema():
    columns = StructType([
        StructField('name', StringType(), True),
        StructField('id', IntegerType(), True),
    ])
    # emp_RDD = spark.sparkContext.emptyRDD()
    return spark.createDataFrame(data=[],
                                 schema=columns)

喜欢点个赞再走吧~

<think>好的,我现在需要帮助用户了解如何使用PySpark创建和操作DataFrame。首先,我得回忆一下PySpark的基本知识。用户可能已经知道PySparkPythonSpark接口,但可能需要从基础开始讲解。 根据用户的问题,他们想了解如何创建和操作DataFrame。根据引用中的信息,比如引用3提到了从CSV文件、pandas DataFrame以及Spark表创建DataFrame的方法,这些应该是重点。首先,我需要分步骤说明不同的创建方式,比如从CSV、现有RDD、pandas DataFrame等。 接下来是操作DataFrame的部分。用户可能需要进行数据筛选、聚合、添加列等操作。引用1中提到DataFrame适合处理结构化数据,所以示例应包括常见的SQL-like操作,比如select、filter、groupBy等。此外,引用4提到转换为pandas DataFrame的注意事项,这里需要提醒用户小心内存问题。 然后,性能优化部分也很重要。引用2提到PySpark支持多种功能,比如Spark SQL,可以结合这些特性来展示优化技巧,比如缓存、避免shuffle等。同时,引用1中的性能优化可能涉及分区或执行计划调整,需要简单提及。 用户可能对实际代码示例感兴趣,所以每个步骤都需要提供代码片段。例如,创建DataFrame的不同方法,展示如何读取CSV,转换pandas DataFrame,以及执行操作后的输出。同时,需要注意代码格式是否正确,如使用正确的SparkSession初始化。 还需要考虑用户可能的后续问题,比如数据写入、处理大型数据集时的注意事项,或者与RDD的区别。但根据当前问题,重点放在创建和基本操作上。 最后,确保回答结构清晰,分点说明,并附上相关问题。检查是否有遗漏的创建方式或常见操作,确保覆盖主要的使用场景。同时,引用相关的引用来源,比如引用3中的示例代码,引用4的转换注意事项,以增强可信度。</think>### 使用 PySpark 创建和操作 DataFrame 的步骤 #### 一、创建 DataFrame 的常用方法 1. **从结构化文件(CSV/JSON/Parquet)读取** 使用`spark.read`模块加载结构化数据文件,支持自动推断数据类型(需谨慎使用`inferSchema`): ```python from pyspark.sql import SparkSession spark = SparkSession.builder.appName("DataFrame Demo").getOrCreate() # 从 CSV 文件创建(引用[3]) df_csv = spark.read.csv("path/to/file.csv", header=True, inferSchema=True) # 从 Parquet 文件创建 df_parquet = spark.read.parquet("path/to/file.parquet") ``` 2. **通过 Python 集合或 Pandas DataFrame 转换** 若数据量较小,可直接从列表或 Pandas DataFrame 转换: ```python import pandas as pd data = [("Alice", 34), ("Bob", 45)] # 从列表创建(需指定列名) df_spark = spark.createDataFrame(data, ["Name", "Age"]) # 从 Pandas DataFrame 转换(引用[4]) pd_df = pd.DataFrame(data, columns=["Name", "Age"]) spark_df = spark.createDataFrame(pd_df) ``` 3. **通过 SQL 查询生成** 将临时表注册到 Spark 元数据目录后,可通过 SQL 操作: ```python df_csv.createOrReplaceTempView("people") df_sql = spark.sql("SELECT Name, Age FROM people WHERE Age > 30") # 引用[3] ``` --- #### 二、DataFrame 核心操作 1. **数据查看与结构分析** ```python df_csv.show(5) # 显示前5行 df_csv.printSchema() # 打印表结构 df_csv.describe().show()# 统计摘要 ``` 2. **列操作与条件过滤** ```python from pyspark.sql.functions import col # 选择特定列 df_select = df_csv.select("Name", "Age") # 添加新列 df_with_column = df_csv.withColumn("AgePlus10", col("Age") + 10) # 条件过滤 df_filtered = df_csv.filter(col("Age") > 30) ``` 3. **聚合与分组** ```python from pyspark.sql.functions import avg df_grouped = df_csv.groupBy("Department").agg(avg("Salary").alias("AvgSalary")) ``` 4. **数据类型转换** ```python from pyspark.sql.types import IntegerType df_converted = df_csv.withColumn("AgeInt", col("Age").cast(IntegerType())) ``` --- #### 三、性能优化技巧(引用[1][2]) 1. **避免`inferSchema`开销** 对大型 CSV 文件手动指定 Schema 可提升读取速度: ```python from pyspark.sql.types import StructType, StructField, StringType, IntegerType schema = StructType([ StructField("Name", StringType(), True), StructField("Age", IntegerType(), True) ]) df = spark.read.csv("data.csv", header=True, schema=schema) ``` 2. **缓存高频访问数据** ```python df.cache() # 将 DataFrame 缓存到内存 ``` 3. **控制分区数** 通过`repartition`优化数据分布: ```python df = df.repartition(4) # 按指定分区数重新分布 ``` --- #### 四、与其他数据格式交互 1. **写入外部存储** ```python df.write.parquet("output.parquet", mode="overwrite") df.write.csv("output.csv", header=True) ``` 2. **与 Pandas 互转的注意事项(引用[4])** ```python # Spark -> Pandas(小数据集适用) pd_df = df.toPandas() # Pandas -> Spark(需注意Driver内存限制) spark_df = spark.createDataFrame(pd_df) ``` --- ### 示例完整代码 ```python # 初始化 Spark 会话 from pyspark.sql import SparkSession spark = SparkSession.builder.appName("DataFrame Tutorial").getOrCreate() # 创建 DataFrame data = [("Sales", 50000), ("Engineering", 80000)] columns = ["Department", "Budget"] df = spark.createDataFrame(data, columns) # 执行操作 df_filtered = df.filter(col("Budget") > 60000) df_filtered.show() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值