从包含列表列的DataFrame中提取并聚合数据

碧海醫心
发布: 2025-09-26 08:30:02
原创
547人浏览过

从包含列表列的DataFrame中提取并聚合数据

本教程旨在解决如何从一个DataFrame中,根据另一个DataFrame中包含列表的列进行条件匹配,并提取符合条件的最小值。文章将详细介绍如何利用Pandas的explode、merge和groupby等功能,高效处理列表型数据匹配,并聚合出期望的最小值,最终生成一个结构清晰、易于理解的解决方案。

场景描述

在数据分析和处理中,我们经常会遇到需要从一个数据源(例如,包含详细交易记录的dataframe df1)中,根据另一个数据源(例如,包含分组或汇总信息,且其关键匹配列包含列表的dataframe df2)来提取或聚合数据的情况。具体来说,我们的目标是从 df1 中获取 value 值,并将其添加到 df2 中,匹配条件如下:

  1. df1 的 month 列必须与 df2 的 month 列匹配。
  2. df1 的 store 列的值必须包含在 df2 的 store 列(这是一个列表)中。
  3. 如果存在多个匹配项,我们需要获取所有匹配 value 中的最小值。

这带来了一个挑战,因为 df2 的 store 列是一个列表,无法直接进行标准的数据框合并操作。

数据准备

为了演示此过程,我们首先创建两个示例DataFrame:df1 包含商店、值和月份的详细记录,而 df2 包含商店列表和月份,我们希望向 df2 添加聚合后的 value 列。

import pandas as pd

# DataFrame 1: 详细数据
data1 = {'store': [1, 1, 2, 2], 'value': [24, 28, 29, 0], 'month': [1, 2, 1, 2]}
df1 = pd.DataFrame(data1)

# DataFrame 2: 包含列表的匹配数据
data2 = {'store': [[1, 2, 3], [2]], 'month': [1, 2]}
df2 = pd.DataFrame(data2)

print("df1:")
print(df1)
print("\ndf2:")
print(df2)
登录后复制

输出:

序列猴子开放平台
序列猴子开放平台

具有长序列、多模态、单模型、大数据等特点的超大规模语言模型

序列猴子开放平台 0
查看详情 序列猴子开放平台
df1:
   store  value  month
0      1     24      1
1      1     28      2
2      2     29      1
3      2      0      2

df2:
       store  month
0  [1, 2, 3]      1
1        [2]      2
登录后复制

我们期望的最终结果是 df2 添加一个 value 列,其中:

  • 对于 df2 的第一行 ([1, 2, 3], 1):
    • df1 中 (store=1, month=1) 对应的 value 是 24。
    • df1 中 (store=2, month=1) 对应的 value 是 29。
    • df1 中 (store=3, month=1) 没有匹配项。
    • 在 24 和 29 中取最小值,结果为 24。
  • 对于 df2 的第二行 ([2], 2):
    • df1 中 (store=2, month=2) 对应的 value 是 0。
    • 结果为 0。

核心挑战与解决方案

直接将 df2 与 df1 合并是不可行的,因为 df2['store'] 列包含的是列表,而不是单个值。解决此问题的关键在于使用 Pandas 的 explode() 方法。explode() 可以将列表或类列表的条目转换为单独的行,从而使我们能够进行标准化的合并操作。

具体步骤如下:

  1. 预处理 df1: 为了确保我们总是获取每个 (store, month) 组合的最小值,我们首先对 df1 进行分组并计算 value 的最小值。
  2. 展开 df2 的列表列: 使用 explode('store') 将 df2 的 store 列中的每个列表元素展开成单独的行。在展开过程中,我们需要保留原始行的索引,以便后续聚合。
  3. 合并数据: 将展开后的 df2 与预处理后的 df1 进行左连接合并。
  4. 聚合结果: 合并后,对于 df2 的每个原始行(通过保留的索引识别),我们需要再次聚合 value 列,以获取其所有匹配项中的最小值。
  5. 整合回 df2: 将最终聚合得到的最小值添加回原始的 df2。

详细实现步骤

1. 预处理 df1:计算每个 (store, month) 的最小值

这一步是为了确保 df1 中每个 (store, month) 组合只有一个 value,且是最小值。这在 df1 可能有重复 (store, month) 但 value 不同的情况下尤其重要。

df1_min_values = df1.groupby(['store', 'month'], as_index=False)['value'].min()
print("df1_min_values:")
print(df1_min_values)
登录后复制

输出:

df1_min_values:
   store  month  value
0      1      1     24
1      1      2     28
2      2      1     29
3      2      2      0
登录后复制

2. 展开 df2 的列表列

使用 explode('store') 将 df2 的 store 列中的列表展开。为了在后续步骤中能将结果正确地映射回原始 df2 的行,我们还需要使用 reset_index() 来获取原始的行索引。

exploded_df2 = df2.explode('store').reset_index()
print("\nexploded_df2:")
print(exploded_df2)
登录后复制

输出:

exploded_df2:
   index  store  month
0      0      1      1
1      0      2      1
2      0      3      1
3      1      2      2
登录后复制

可以看到,df2 的第一行(index=0)被展开成了三行,分别对应 store 列表中的 1, 2, 3,并且 month 和 index 列的值被复制。

3. 合并与聚合

现在,我们可以将 exploded_df2 与 df1_min_values 进行左连接合并。合并后,我们将得到一个包含所有可能匹配项的DataFrame。然后,我们按原始 df2 的索引 (index 列) 进行分组,并计算 value 的最小值。

merged_exploded = exploded_df2.merge(df1_min_values, on=['store', 'month'], how='left')
print("\nmerged_exploded after merge:")
print(merged_exploded)

final_min_values = merged_exploded.groupby('index')['value'].min()
print("\nfinal_min_values after groupby min:")
print(final_min_values)
登录后复制

输出:

merged_exploded after merge:
   index  store  month  value
0      0      1      1   24.0
1      0      2      1   29.0
2      0      0      3      1    NaN  # store 3, month 1 has no match in df1_min_values
3      1      2      2    0.0

final_min_values after groupby min:
index
0    24.0
1     0.0
Name: value, dtype: float64
登录后复制

注意,store=3, month=1 在 df1_min_values 中没有匹配项,因此其 value 为 NaN。groupby('index')['value'].min() 会自动忽略 NaN 值,只对有效数字进行最小值计算。

4. 整合回 df2

最后一步是将计算出的 final_min_values 赋值给原始的 df2。

df2_result = df2.assign(value=final_min_values)
print("\n最终结果 df2_result:")
print(df2_result)
登录后复制

输出:

最终结果 df2_result:
       store  month  value
0  [1, 2, 3]      1   24.0
1        [2]      2    0.0
登录后复制

这与我们期望的结果完全一致。

完整代码示例

import pandas as pd

# 原始数据
data1 = {'store': [1, 1, 2, 2], 'value': [24, 28, 29, 0], 'month': [1, 2, 1, 2]}
data2 = {'store': [[1, 2, 3], [2]], 'month': [1, 2]}
df1 = pd.DataFrame(data1)
df2 = pd.DataFrame(data2)

# 1. 预处理 df1,计算每个 (store, month) 的最小值
df1_min_values = df1.groupby(['store', 'month'], as_index=False)['value'].min()

# 2. 展开 df2 的 'store' 列,并保留原始索引
exploded_df2 = df2.explode('store').reset_index()

# 3. 合并展开后的 df2 与预处理的 df1,然后按原始索引聚合求最小值
s = exploded_df2.merge(df1_min_values, on=['store', 'month'], how='left') \
                .groupby('index')['value'].min()

# 4. 将结果赋值回原始 df2
df2_final = df2.assign(value=s)

print("最终的 df2:")
print(df2_final)
登录后复制

注意事项

  • 性能考量: explode() 操作会增加DataFrame的行数。如果原始DataFrame df2 很大,并且其列表列中的元素数量非常多,explode() 可能会导致内存消耗增加和性能下降。在这种情况下,可能需要考虑其他方法,例如使用 apply 函数结合列表推导或并行处理,但通常 explode 是更优的 Pandas 解决方案。
  • NaN 处理: 在合并过程中,如果 df2 展开后的行在 df1_min_values 中没有匹配项,则 value 列将包含 NaN。groupby().min() 方法会自动忽略 NaN 值。如果希望将未匹配项的 value 设为特定值(例如 0),可以在 assign 之前使用 fillna(0)。
  • 数据类型: value 列在合并后可能会因为包含 NaN 而转换为浮点类型。如果需要整数类型,可以在 fillna 后使用 astype(int)。

总结

本教程展示了如何利用 Pandas 强大的数据处理能力,通过 explode()、merge() 和 groupby() 等操作,有效地解决涉及列表列的复杂数据匹配和聚合问题。这种方法不仅能够处理一对多关系中的匹配,还能在匹配成功后进行灵活的聚合(如本例中的求最小值),是处理复杂数据结构时非常实用的技巧。掌握这些技术将大大提高你在数据清洗和特征工程中的效率。

以上就是从包含列表列的DataFrame中提取并聚合数据的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号