Pandas DataFrame中基于键匹配与频率拆分数值的教程

花韻仙語
发布: 2025-10-10 09:33:00
原创
235人浏览过

Pandas DataFrame中基于键匹配与频率拆分数值的教程

本教程详细介绍了如何在Pandas DataFrame中,根据一个DataFrame(df1)中键的重复频率,将另一个DataFrame(df2)中的相关数值进行拆分并分配到df1的对应行中。核心方法是利用value_counts()计算键频率,然后通过div()进行标准化除法,最后使用merge()操作将处理后的数据合并,从而实现精确的数值分配。

1. 问题背景与目标

在数据处理中,我们经常会遇到需要将汇总数据(例如总销售额、总库存量)按某种比例或规则分配到其组成部分(例如单个销售记录、单个库存单位)的场景。本教程聚焦于一个具体问题:给定两个pandas dataframe,df1包含重复的键(例如产品id),df2包含每个唯一键对应的总数值。我们的目标是创建一个新的dataframe,其结构与df1相似,但df2中的数值已经被“拆分”并按键的出现频率分配到df1的对应行中。

例如,假设我们有以下两个DataFrame:

DataFrame 1 (df1): 包含重复的 id

id
A
B
A
C
A
A
C

DataFrame 2 (df2): 包含每个唯一 id 对应的总数值

id Col1 Col2 Col3
A 400 100 20
B 200 800
C 600 800

期望的输出结果:

id Col1 Col2 Col3
A 100 25 5
B 200 800
A 100 25 5
C 300 400
A 100 25 5
A 100 25 5
C 300 400

从期望结果可以看出,id为'A'的记录在df1中出现了4次,因此df2中'A'对应的Col1 (400) 被拆分为 400/4 = 100,Col2 (100) 被拆分为 100/4 = 25,Col3 (20) 被拆分为 20/4 = 5。同样,'C'出现了2次,其数值被拆分为一半。而'B'只出现1次,其数值保持不变。

2. 核心思路与实现步骤

要实现上述目标,我们需要执行以下几个关键步骤:

  1. 计算键频率: 统计df1中每个id出现的次数。
  2. 标准化 df2: 将df2中每个id对应的数值除以其在df1中的出现频率。
  3. 合并数据: 将标准化后的df2与原始df1进行合并。
  4. 恢复索引: 确保最终输出的DataFrame具有与原始df1相同的索引结构。

我们将使用Pandas库中的value_counts()、div()和merge()函数来高效完成这些操作。

3. 示例代码与详细解析

首先,我们创建示例数据:

import pandas as pd
import numpy as np

# 创建 DataFrame 1
data1 = {'id': ['A', 'B', 'A', 'C', 'A', 'A', 'C']}
df1 = pd.DataFrame(data1)

# 创建 DataFrame 2
data2 = {'id': ['A', 'B', 'C'],
         'Col1': [400, 200, 600],
         'Col2': [100, np.nan, 800],
         'Col3': [20, 800, np.nan]}
df2 = pd.DataFrame(data2)

print("原始 df1:")
print(df1)
print("\n原始 df2:")
print(df2)
登录后复制

原始 df1:

  id
0  A
1  B
2  A
3  C
4  A
5  A
6  C
登录后复制

原始 df2:

硅基智能
硅基智能

基于Web3.0的元宇宙,去中心化的互联网,高质量、沉浸式元宇宙直播平台,用数字化重新定义直播

硅基智能 62
查看详情 硅基智能
  id  Col1   Col2   Col3
0  A   400  100.0   20.0
1  B   200    NaN  800.0
2  C   600  800.0    NaN
登录后复制

现在,执行核心逻辑:

# 1. 计算 df1 中 'id' 列的频率
id_counts = df1['id'].value_counts()
print("\nid 频率:")
print(id_counts)

# 2. 标准化 df2: 将 df2 中的数值除以对应的 id 频率
#    - set_index('id') 将 'id' 设置为索引,以便与 id_counts 对齐
#    - div(id_counts, axis=0) 对齐索引并执行逐行除法
df2_standardized = df2.set_index('id').div(id_counts, axis=0)
print("\n标准化后的 df2:")
print(df2_standardized)

# 3. 合并数据
#    - df1.reset_index() 暂时将 df1 的原始索引保存为一列,以便后续恢复
#    - merge() 根据 'id' 列进行左连接 (how='left')
#    - set_index('index').reindex(df1.index) 恢复原始索引和行顺序
out = (df1.reset_index()
          .merge(df2_standardized, on='id', how='left')
          .set_index('index').reindex(df1.index)
      )

print("\n最终输出:")
print(out)
登录后复制

id 频率:

A    4
C    2
B    1
Name: id, dtype: int64
登录后复制

标准化后的 df2:

    Col1   Col2   Col3
id                     
A  100.0   25.0    5.0
B  200.0    NaN  800.0
C  300.0  400.0    NaN
登录后复制

最终输出:

  id   Col1   Col2   Col3
0  A  100.0   25.0    5.0
1  B  200.0    NaN  800.0
2  A  100.0   25.0    5.0
3  C  300.0  400.0    NaN
4  A  100.0   25.0    5.0
5  A  100.0   25.0    5.0
6  C  300.0  400.0    NaN
登录后复制

代码解析:

  1. id_counts = df1['id'].value_counts():

    • 这一步计算了df1中'id'列每个唯一值的出现频率。例如,'A'出现4次,'B'出现1次,'C'出现2次。结果是一个Pandas Series,索引是id值,值是频率。
  2. df2_standardized = df2.set_index('id').div(id_counts, axis=0):

    • df2.set_index('id'): 将df2的'id'列设置为其索引。这是为了让df2的行索引与id_counts的索引(即id值)对齐,以便进行正确的逐行除法。
    • .div(id_counts, axis=0): 对df2中除id列以外的所有数值列执行除法操作。axis=0表示按行进行操作,Pandas会自动根据索引(即id值)将df2的每一行与id_counts中对应的频率值进行匹配并相除。如果df2中的某个单元格为NaN,除法操作会保留NaN。
  3. out = (df1.reset_index().merge(df2_standardized, on='id', how='left').set_index('index').reindex(df1.index)):

    • df1.reset_index(): 在合并之前,df1的原始整数索引(0, 1, 2...)很重要,因为我们希望最终输出的DataFrame具有与df1相同的行顺序和索引。reset_index()将当前索引转换为一个名为'index'的普通列,并生成一个新的默认整数索引。
    • .merge(df2_standardized, on='id', how='left'):
      • 将df1(现在包含原始索引作为'index'列)与df2_standardized进行合并。
      • on='id' 指定了合并的键是'id'列。
      • how='left' 执行左连接。这意味着df1中的所有行都会被保留,如果df1中的某个id在df2_standardized中没有匹配项(虽然在这个特定问题中不太可能),则对应的Col1, Col2, Col3会填充NaN。
    • .set_index('index'): 合并完成后,我们将之前保存的'index'列重新设置回DataFrame的索引。
    • .reindex(df1.index): 这一步是可选但推荐的,它确保最终DataFrame的行顺序和索引类型与原始df1完全一致。reindex会根据df1.index的顺序重新排列行,如果原始索引中有重复值,也会正确处理。

4. 注意事项与最佳实践

  • 数据类型: 除法操作可能会导致数值列的数据类型从整数变为浮点数(例如int变为float),这是正常的。如果需要,可以使用astype()进行类型转换,但要注意NaN值可能导致无法转换为纯整数。
  • NaN 值处理: df2中的NaN值在除法和合并过程中会保持为NaN。如果需要,可以在合并前后使用fillna()进行填充。
  • 性能: 对于非常大的DataFrame,merge操作可能会比较耗时。然而,Pandas的底层实现通常是高度优化的。此方法在大多数情况下都是高效且简洁的。
  • 键的唯一性: 确保df2中的'id'列是唯一的,否则set_index('id')可能会引发错误或产生非预期的行为。如果df2中id不唯一,需要先对其进行聚合处理。
  • 索引管理: reset_index()和set_index().reindex()的组合是确保最终输出的索引和行顺序与原始df1保持一致的常用且稳健的方法。

5. 总结

本教程提供了一种高效且易于理解的Pandas解决方案,用于根据键的出现频率将一个DataFrame的数值拆分并分配到另一个DataFrame的对应行中。通过结合value_counts()计算频率、div()进行标准化以及merge()进行数据整合,我们能够精确地实现复杂的数值分配逻辑。掌握这种模式对于处理涉及数据聚合、拆分和重构的场景非常有用。

以上就是Pandas 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号