嵌套用于比较 2 个大型数据帧的循环性能

Nested for loop performance in comparing 2 large data frames

提问人:Michael_vn22 提问时间:7/10/2023 最后编辑:Michael_vn22 更新时间:7/10/2023 访问量:59

问:

我有 2 个数据框,请参阅下面的 2 个示例。第一个是大约 3 330 076 行,第二个是 400k。

如果第二个数据帧中的“项目代码”==第一个数据帧中的商品代码,并且数据帧 1 中的 salesdays 条目介于“开始”和“结束日期”条目之间或与“开始日期”和“结束日期”条目相符,则要求相当简单。然后向 dataframe 1 中的 promo count 列添加一个计数。下面是我尝试的嵌套 for 循环,但运行时间超过 2 小时而没有实际完成。任何帮助将不胜感激

for ind , row in SalesDF.iterrows():
    for j ,row2 in SfPromos.iterrows():
        if (row['article'] == row2['Item Code']) and (row2['Start date'] <= row['SalesDays'] <= row2['End date']):
            row['PromoCount'] += 1
print(SalesDF['PromoCount'] > 0)

如果第二个数据帧中的“项目代码”==第一个数据帧中的商品代码,并且数据帧 1 中的 salesdays 条目介于“开始”和“结束日期”条目之间或与“开始日期”和“结束日期”条目相符,则要求相当简单。然后向 dataframe 1 中的 promo count 列添加一个计数。我尝试过,但运行时间超过 2 小时而没有真正完成。

Python 数据帧 for 循环 嵌套

评论

1赞 julaine 7/10/2023
如果每次操作需要一微秒,则迭代 3Mio * 400k 行需要半年时间。如果您有这么大的数据,则需要摆脱二次缩放。尝试收集 ShopritePromos 上的统计数据(甚至不阅读 SalesDF),而不是将该信息集成回 SalesDF。
0赞 julaine 7/11/2023
“SalesDays”列中到底有什么?“s”表示它是天数或日期范围,但您将其与单个日期进行比较,这意味着 SalesDays 是一个日期。
0赞 Michael_vn22 7/11/2023
SalesDays ==( single date) 需要介于或等于开始日期和结束日期之间

答:

0赞 M_S 7/10/2023 #1

我不确定您想要什么作为输出,但我认为您可以尝试尝试加入 + 分组

下面我正在做左联接,它将把项目与促销活动结合起来,并创建一些统计信息,如评论中已经提到的那样

然后,您可以将它们连接回原始 df

import datetime
import pyspark.sql.functions as F

sales = [
    (datetime.date(2022, 7, 4), 10123762, 50, 0),
    (datetime.date(2022, 7, 1), 10123762, 50, 0),
]
promos = [
    (10123762, datetime.date(2022, 7, 3), datetime.date(2022, 7, 5)),
    (10123762, datetime.date(2022, 7, 4), datetime.date(2022, 7, 4)),
]

dfSales = spark.createDataFrame(
    sales, schema=["SalesDay", "article", "TotalSales", "PromoCount"]
)
dfPromos = spark.createDataFrame(promos, schema=["Item Code", "Start date", "End date"])

joinedDf = dfSales.join(
    dfPromos,
    (dfSales["article"] == dfPromos["Item Code"])
    & (
        (dfPromos["Start date"] <= dfSales["SalesDay"])
        & (dfSales["SalesDay"] <= dfPromos["End date"])
    ),
    "left",
)

joinedDfWithMatchFlag = joinedDf.filter(joinedDf["Item Code"].isNotNull()).withColumn(
    "Promo Matched",
    F.when(F.col("Item Code").isNotNull(), F.lit(1)).otherwise(F.lit(0)),
)
statistics = joinedDfWithMatchFlag.groupBy("article", "Item Code").agg(
    F.sum("Promo Matched")
)

statistics.show()

输出:

+--------+---------+------------------+
| article|Item Code|sum(Promo Matched)|
+--------+---------+------------------+
|10123762| 10123762|                 2|
+--------+---------+------------------+

评论

0赞 Michael_vn22 7/10/2023
这是一个非常有趣的方法,我会检查一下。目标是计算文章/项目代码每天的促销次数。数据帧的大小不同。生成以下错误 ValueError:只能比较标记相同的 Series 对象