
在处理大规模数据集时,我们经常需要根据多个条件对数据进行筛选、组合,并执行各种计算。传统的做法可能涉及多次使用dataframe.loc进行条件筛选,创建多个中间dataframe,然后通过pd.merge将它们合并,最后进行列之间的算术运算。这种方法虽然能够得到正确结果,但存在以下显著缺点:
以下是一个典型场景的示例代码,展示了这种重复性操作:
import io
import pandas as pd
TESTDATA="""
enzyme regions N length
AaaI all 10 238045
AaaI all 20 170393
AaaI all 30 131782
AaaI all 40 103790
AaaI all 50 81246
AaaI all 60 62469
AaaI all 70 46080
AaaI all 80 31340
AaaI all 90 17188
AaaI captured 10 292735
AaaI captured 20 229824
AaaI captured 30 193605
AaaI captured 40 163710
AaaI captured 50 138271
AaaI captured 60 116122
AaaI captured 70 95615
AaaI captured 80 73317
AaaI captured 90 50316
AagI all 10 88337
AagI all 20 19144
AagI all 30 11030
AagI all 40 8093
AagI all 50 6394
AagI all 60 4991
AagI all 70 3813
AagI all 80 2759
AagI all 90 1666
AagI captured 10 34463
AagI captured 20 19220
AagI captured 30 15389
AagI captured 40 12818
AagI captured 50 10923
AagI captured 60 9261
AagI captured 70 7753
AagI captured 80 6201
AagI captured 90 4495
"""
df_stats = pd.read_csv(io.StringIO(TESTDATA), sep='\s+')
# 原始的重复性操作示例
df_cap_N90 = df_stats[(df_stats['N'] == 90) & (df_stats['regions'] == 'captured')].drop(columns=['regions', 'N'])
df_cap_N50 = df_stats[(df_stats['N'] == 50) & (df_stats['regions'] == 'captured')].drop(columns=['regions', 'N'])
df_all_N50 = df_stats[(df_stats['N'] == 50) & (df_stats['regions'] == 'all')].drop(columns=['regions', 'N'])
df_summ_cap_N50_all_N50 = pd.merge(df_cap_N50, df_all_N50, on='enzyme', how='inner', suffixes=('_cap_N50', '_all_N50'))
df_summ_cap_N50_all_N50['cap_N50_all_N50'] = (df_summ_cap_N50_all_N50['length_cap_N50'] -
df_summ_cap_N50_all_N50['length_all_N50'])
df_summ_cap_N90_all_N50 = pd.merge(df_cap_N90, df_all_N50, on='enzyme', how='inner', suffixes=('_cap_N90', '_all_N50'))
df_summ_cap_N90_all_N50['cap_N90_all_N50'] = df_summ_cap_N90_all_N90['length_cap_N90'] - df_summ_cap_N90_all_N90['length_all_N50']
df_summ = pd.merge(df_summ_cap_N50_all_N50.drop(columns=['length_cap_N50', 'length_all_N50']),
df_summ_cap_N90_all_N50.drop(columns=['length_cap_N90', 'length_all_N50']),
on='enzyme', how='inner')
print("原始方法计算结果:")
print(df_summ)为了克服上述问题,我们可以利用Pandas的pivot函数和其强大的向量化操作能力。pivot函数能够将DataFrame从“长格式”转换为“宽格式”,将指定列的唯一值转换为新的列,从而大大简化后续的计算。结合向量化操作,我们可以避免显式的循环和多次合并,直接对整个列或DataFrame进行高效运算。
核心思想是:
我们将使用df_stats数据集,目标是计算cap_N50_all_N50 (captured N50 - all N50) 和 cap_N90_all_N50 (captured N90 - all N50)。
# 1. 筛选相关数据
# 仅保留N为50或90的行,因为只有这些N值参与最终计算
filtered_df = df_stats.loc[df_stats["N"].isin([50, 90])]
# 2. 使用pivot进行数据透视
# index='enzyme':以enzyme作为新的行索引
# columns=['regions', 'N']:将regions和N的组合作为新的列索引(多级列索引)
# values='length':透视后单元格的值取自length列
pivoted_df = filtered_df.pivot(index="enzyme", columns=["regions", "N"], values="length")
print("\n透视后的DataFrame (pivoted_df):")
print(pivoted_df)
# 3. 执行向量化计算
# 提取'captured'区域的N50和N90长度
captured_lengths = pivoted_df["captured"]
# 提取'all'区域的N50长度
all_N50_length = pivoted_df[("all", 50)]
# 计算 (captured N50 - all N50) 和 (captured N90 - all N50)
# captured_lengths.sub(all_N50_length, axis=0)
# axis=0 表示按行进行广播,即captured_lengths的每一行都减去all_N50_length的对应行值
result_df = captured_lengths.sub(all_N50_length, axis=0)
# 4. 调整列名并重置索引
# 为结果列添加前缀和后缀,使其符合目标输出格式
# add_prefix("cap_N"):为'captured'下的N值(50, 90)添加前缀'cap_N'
# add_suffix("_all_N50"):为所有结果列添加后缀'_all_N50'
final_output = result_df.add_prefix("cap_N").add_suffix("_all_N50").reset_index()
print("\n最终优化后的计算结果 (final_output):")
print(final_output)代码解析:
通过本教程,我们深入探讨了如何利用Pandas的pivot函数和向量化操作来优化数据聚合与转换过程。这种方法不仅显著提升了代码的简洁性、可读性和可维护性,还在处理大规模数据集时展现出卓越的性能优势。掌握pivot和向量化计算是成为高效Pandas用户的关键一步,能够帮助开发者摆脱冗余的select和merge操作,编写出更加优雅和高效的数据处理代码。在面对复杂的数据转换需求时,始终优先考虑Pandas提供的内置高效函数,以充分发挥其强大功能。
以上就是Pandas数据透视与向量化操作:高效聚合复杂数据集的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号