这里有一个 PySpark 中的常见任务:如何在一个数据帧列中筛选另一个数据帧的唯一值?
方法 1
假设我们有两个数据帧 df1 和 df2,我们想要通过名为“id”的列来筛选 df1,其值需要来自 df2 中的“id”列。如果 df2 的“id”列的唯一值不太大,我们可以这样做:
python
Copy code
from pyspark.sql.functions import col
# Create the first DataFrame
df1 = spark.createDataFrame([(1, "a"), (2, "b"), (3, "c"), (4, "d")], ["id", "value"])
# Create the second DataFrame
df2 = spark.createDataFrame([(1, "x"), (2, "y")], ["id", "other_value"])
# Get the unique values of the second DataFrame's column
unique_values = df2.select("id").distinct().rdd.flatMap(lambda x: x).collect()
# Filter the first DataFrame's column based on the unique values
filtered_df1 = df1.filter(col("id").isin(unique_values))
在上面的示例中,filtered_df1 将只包含 df1 中 id 列在 df2 id 列中唯一值列表中的行。
方法 2
然而,上面使用 collect 的示例对于大型数据量可能不是最优的。在示例中,使用 .collect() 方法收集了第二个数据帧的唯一值。这是必要的,因为用于筛选第一个数据帧列的 .isin() 函数需要可迭代的值(例如列表,集合或元组)来检查。
但值得提醒的是,如果第二个 DataFrame 非常大并且唯一值很多,则使用 .collect() 方法可能会导致性能问题,在这种情况下,最好使用 join 或 subquery 方法来过滤第一个 DataFrame,而不是收集唯一值。
例如,如果要根据第二个 DataFrame 的 id 列过滤第一个 DataFrame:
filtered_df1 = df1.join(df2, df1.id == df2.id, 'inner').select(df1.columns)
这将给出与先前示例相同的结果,但不需要收集唯一值。
那么如果 df1 和 df2 有相同的列名呢?那么使用上面的代码就会出错。
但是不要担心,解决方法很简单。我们只需要重命名其中一个列的名称即可。
如果两个 DataFrame 都有相同名称的列,则需要在执行 join 之前使用 alias() 函数为其中一列分配一个新名称。
例如,如果两个 DataFrame 都有一列名为 “id”:
from pyspark.sql.functions import col
# Create the first DataFrame
df1 = spark.createDataFrame([(1, "a"), (2, "b"), (3, "c"), (4, "d")], ["id", "value"])
# Create the second DataFrame
df2 = spark.createDataFrame([(1, "x"), (2, "y")], ["id", "other_value"])
# Assign a new name to the second DataFrame's 'id' column
df2 = df2.selectExpr("id as df2_id", "other_value")
# Perform the join
filtered_df1 = df1.join(df2, df1.id == df2.df2_id, 'inner').select(df1.columns)
另一个可能更快的方法是一次性替换所有列。
因此,在 PySpark 中如何通过添加前缀来重命名所有数据框列?
在 PySpark 中,您可以使用 selectExpr() 函数和一个字符串表达式列表来重命名 DataFrame 的所有列,并在其中添加前缀。
下面是一个示例,它演示了如何在 DataFrame 的所有列中添加前缀 “prefix_”:
from pyspark.sql.functions import col
# 创建一个 DataFrame
df = spark.createDataFrame([(1, "a"), (2, "b"), (3, "c"), (4, "d")], ["id", "value"])
# 获取当前列名
old_columns = df.columns
# 创建一个字符串表达式列表来重命名列
new_columns = ["prefix_" + col for col in old_columns]
# 使用 selectExpr() 函数重命名列
df = df.selectExpr(*[f"{old} as {new}" for old, new in zip(old_columns, new_columns)])
在这个示例中,selectExpr() 函数被用来通过在原始列名上添加前缀 “prefix_” 来重命名所有列。这是通过使用列表推导来创建一个包含原始列名和新列名 “prefix_” 的字符串表达式列表来完成的。
此外,您还可以使用 withColumnRenamed() 方法一个一个重命名所有列。
for col in old_columns:
df = df.withColumnRenamed(col, f"prefix_{col}")
如果我们想操作一个原始数据帧的副本上。
在 PySpark 中,您可以使用 .copy() 方法或通过从原始 DataFrame 的数据创建新 DataFrame 来创建 DataFrame 的深层副本。
这是如何使用 .copy() 方法创建 DataFrame 的深层副本的示例:
# 创建原始 DataFrame
df = spark.createDataFrame([(1, "a"), (2, "b"), (3, "c"), (4, "d")], ["id", "value"])
# 创建原始 DataFrame 的深层副本
df_copy = df.copy()
在这个示例中,df_copy 变量将包含原始 DataFrame 的深层副本,它与原始 DataFrame 独立,对其进行的任何修改都不会影响原始 DataFrame。
请注意,.copy() 方法在所有版本的 PySpark 中都不可用,因此您可以使用第二种方法创建 DataFrame 的深层副本。
所以另一种创建 DataFrame 的深层副本的方法是通过从原始 DataFrame 的数据创建新 DataFrame。
# 从原始 DataFrame 的数据创建新 DataFrame
df_copy = spark.createDataFrame(df.rdd, df.schema)
英文链接
AI日新月异,但是万丈高楼拔地起,离不开良好的基础。您是否有兴趣了解人工智能的原理和实践? 不要再观望! 我们关于 AI 原则和实践的书是任何想要深入了解 AI 世界的人的完美资源。 由该领域的领先专家撰写,这本综合指南涵盖了从机器学习的基础知识到构建智能系统的高级技术的所有内容。 无论您是初学者还是经验丰富的 AI 从业者,本书都能满足您的需求。 那为什么还要等? 立即下单,开始以一种易于访问、引人入胜且实用的方式学习 AI。
人工智能原理与实践 全面涵盖人工智能和数据科学各个重要体系经典
北大出版社,人工智能原理与实践 人工智能和数据科学从入门到精通 详解机器学习深度学习算法原理