
本教程详细介绍了如何在pandas数据框中,针对特定分组(如g1和g2)内的变量(如tpe列中的'ts'与'td')计算比率,并将结果作为新行添加回原数据框。文章通过一个实际案例,展示了如何利用`set_index`、`unstack`和向量化操作,以高效且优雅的方式处理数据重塑、比率计算以及缺失值(nan)的填充,避免了传统`groupby().apply()`方法可能存在的性能瓶颈和复杂性。
在数据分析中,我们经常需要根据数据框中的某些列进行分组,然后计算组内特定变量之间的比率。例如,在一个包含交易类型(TPE)和数量(QC)的数据框中,我们可能需要计算每组(G1, G2)中'ts'类型数量与'td'类型数量的比率(ts/td)。此外,还需要将计算出的比率作为新行添加到原始数据框中,并且要妥善处理那些不包含完整'ts'和'td'值的组。
假设我们有以下Pandas DataFrame df_in:
import pandas as pd
import numpy as np
data = {
'G1': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'D'],
'G2': ['S1', 'S1', 'S2', 'S2', 'S1', 'S1', 'S2', 'S2', 'S1', 'S2'],
'TPE': ['td', 'ts', 'td', 'ts', 'td', 'ts', 'td', 'ts', 'td', 'ts'],
'QC': [2, 4, 6, 3, 20, 40, 60, 30, 90, 7]
}
df_in = pd.DataFrame(data)
# 模拟原始数据中可能存在的缺失类型
df_in.loc[8, 'TPE'] = 'td' # C S1 只有 td
df_in.loc[9, 'TPE'] = 'ts' # D S2 只有 ts
df_in = df_in.drop(index=[8,9]).append(pd.DataFrame([['C', 'S1', 'td', 90], ['D', 'S2', 'ts', 7]], columns=df_in.columns), ignore_index=True)
print("原始数据框 df_in:")
print(df_in)输出 df_in 如下:
G1 G2 TPE QC 0 A S1 td 2 1 A S1 ts 4 2 A S2 td 6 3 A S2 ts 3 4 B S1 td 20 5 B S1 ts 40 6 B S2 td 60 7 B S2 ts 30 8 C S1 td 90 9 D S2 ts 7
我们的目标是生成一个包含原始数据和计算出的比率的新数据框 df_out。对于每个 (G1, G2) 组,如果同时存在 'td' 和 'ts' 类型的 QC 值,则计算 ts_QC / td_QC 作为比率,并将新行的 TPE 列标记为 'ratio'。如果缺少 'td' 或 'ts',则比率应为空(NaN)。
期望的 df_out 结构如下:
G1 G2 TPE QC 0 A S1 td 2.0 1 A S1 ts 4.0 2 A S2 td 6.0 3 A S2 ts 3.0 4 B S1 td 20.0 5 B S1 ts 40.0 6 B S2 td 60.0 7 B S2 ts 30.0 8 C S1 td 90.0 9 D S2 ts 7.0 10 A S1 ratio 2.0 11 A S2 ratio 0.5 12 B S1 ratio 2.0 13 B S2 ratio 0.5 14 C S1 ratio NaN 15 D S2 ratio NaN
一种常见的思路是使用 groupby().apply() 方法,为每个组编写一个自定义函数来计算比率。
def calculate_ratio_apply(group):
td_row = group[group['TPE'] == 'td']
ts_row = group[group['TPE'] == 'ts']
if not td_row.empty and not ts_row.empty:
ratio = ts_row['QC'].values[0] / td_row['QC'].values[0]
return pd.DataFrame({'G1': [group['G1'].iloc[0]],
'G2': [group['G2'].iloc[0]],
'TPE': ['ratio'],
'QC': [ratio]})
# 如果缺少td或ts,返回一个空的DataFrame,这会导致这些组的比率行被省略
return pd.DataFrame()
# 这种方法会忽略没有完整td和ts值的组
# grouped = df_in.groupby(['G1', 'G2']).apply(calculate_ratio_apply).reset_index(drop=True)
# df_out_apply = pd.concat([df_in, grouped], ignore_index=True)
# print("\n使用 apply 方法(可能遗漏空比率):")
# print(df_out_apply)上述 apply 方法虽然能计算比率,但如果某个组没有同时包含 'td' 和 'ts' 值,它会返回一个空的DataFrame,导致这些组的比率行被完全省略,而不是填充 NaN。对于大型数据集,apply 方法也可能因为循环迭代而导致性能问题。
更高效和优雅的解决方案是利用 Pandas 的数据重塑功能,将 'TPE' 列中的 'td' 和 'ts' 值转化为独立的列,然后进行向量化计算。
# 1. 重塑数据:将 'TPE' 列中的 'td' 和 'ts' 值转换为独立的列
# - set_index(['G1', 'G2', 'TPE']): 将这三列设为索引
# - unstack()['QC']: 将 TPE 索引层的数据(QC值)unstack(逆透视)成列
# 结果是一个多级索引的 DataFrame,列为 TPE 的不同值(td, ts)
tmp = df_in.set_index(['G1', 'G2', 'TPE']).unstack()['QC']
print("\n中间结果 tmp (重塑后的数据):")
print(tmp)中间结果 tmp 的结构如下,我们可以清晰地看到每个 (G1, G2) 组对应的 'td' 和 'ts' 值,以及缺失值(NaN):
TPE td ts G1 G2 A S1 2.0 4.0 S2 6.0 3.0 B S1 20.0 40.0 S2 60.0 30.0 C S1 90.0 NaN D S2 NaN 7.0
# 2. 计算比率:直接对重塑后的列进行向量化除法
# - tmp['ts'].div(tmp['td']): 计算 'ts' 列与 'td' 列的比率
# - reset_index(name='QC'): 将多级索引重置为列,并将比率结果命名为 'QC'
# - assign(TPE='ratio'): 添加一个新列 'TPE',其值为 'ratio'
ratio_df = tmp['ts'].div(tmp['td']).reset_index(name='QC').assign(TPE='ratio')
print("\n计算出的比率数据框 ratio_df:")
print(ratio_df)计算出的比率数据框 ratio_df 如下:
G1 G2 QC TPE 0 A S1 2.0 ratio 1 A S2 0.5 ratio 2 B S1 2.0 ratio 3 B S2 0.5 ratio 4 C S1 NaN ratio 5 D S2 NaN ratio
# 3. 合并数据:将原始数据框和计算出的比率数据框进行纵向合并
df_out = pd.concat([df_in, ratio_df], ignore_index=True)
print("\n最终输出数据框 df_out:")
print(df_out)最终的 df_out 完美符合我们的要求:
G1 G2 TPE QC 0 A S1 td 2.0 1 A S1 ts 4.0 2 A S2 td 6.0 3 A S2 ts 3.0 4 B S1 td 20.0 5 B S1 ts 40.0 6 B S2 td 60.0 7 B S2 ts 30.0 8 C S1 td 90.0 9 D S2 ts 7.0 10 A S1 ratio 2.0 11 A S2 ratio 0.5 12 B S1 ratio 2.0 13 B S2 ratio 0.5 14 C S1 ratio NaN 15 D S2 ratio NaN
import pandas as pd
import numpy as np
# 原始数据框
data = {
'G1': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'D'],
'G2': ['S1', 'S1', 'S2', 'S2', 'S1', 'S1', 'S2', 'S2', 'S1', 'S2'],
'TPE': ['td', 'ts', 'td', 'ts', 'td', 'ts', 'td', 'ts', 'td', 'ts'],
'QC': [2, 4, 6, 3, 20, 40, 60, 30, 90, 7]
}
df_in = pd.DataFrame(data)
# 模拟原始数据中可能存在的缺失类型,确保 C S1 只有 td,D S2 只有 ts
df_in = df_in.drop(index=[8,9]).append(pd.DataFrame([['C', 'S1', 'td', 90], ['D', 'S2', 'ts', 7]], columns=df_in.columns), ignore_index=True)
# 1. 重塑数据:将 'TPE' 列中的 'td' 和 'ts' 值转换为独立的列
# 通过 set_index 和 unstack,将数据从长格式转换为宽格式,便于计算
tmp = df_in.set_index(['G1', 'G2', 'TPE']).unstack()['QC']
# 2. 计算比率并格式化结果
# - tmp['ts'].div(tmp['td']): 执行向量化除法,自动处理缺失值(NaN)
# - reset_index(name='QC'): 将多级索引重置为常规列,并将比率结果列命名为 'QC'
# - assign(TPE='ratio'): 添加一个新列 'TPE',其值为 'ratio'
ratio_df = tmp['ts'].div(tmp['td']).reset_index(name='QC').assign(TPE='ratio')
# 3. 合并数据:将原始数据框和计算出的比率数据框进行纵向合并
df_out = pd.concat([df_in, ratio_df], ignore_index=True)
print("最终输出数据框 df_out:")
print(df_out)通过本教程,您应该能够高效且优雅地在 Pandas 数据框中处理分组比率计算问题,即使面对复杂的数据结构和缺失值情况也能游刃有余。
以上就是在Pandas中高效计算分组堆叠数据框中的变量比率的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号