如何用Pandas更优雅地计算DataFrame中各电流阶的平均电压
用Pandas Groupby优雅处理分阶电流的平均电压计算
嘿,这个需求用Pandas的groupby系列操作完全能替代循环,实现更简洁高效的代码!我来一步步给你拆解方案~
核心思路
你的需求本质是识别连续的电流阶段,然后剔除每个阶段的前N个不稳定数据,最后分组计算平均电压。用groupby可以避免手动循环,利用Pandas的向量化操作提升效率和可读性。
步骤1:准备示例数据(模拟你的实验场景)
先模拟一份和你数据匹配的样例,方便演示:
import pandas as pd import numpy as np np.random.seed(42) # 固定随机种子,结果可复现 time = np.arange(0, 30, 1) # 模拟3个电流阶,每个阶内有小幅度波动 current = np.concatenate([ np.random.normal(1, 0.05, 10), # 第一阶:~1A np.random.normal(2, 0.05, 10), # 第二阶:~2A np.random.normal(1.5, 0.05, 10) # 第三阶:~1.5A ]) # 模拟电压:每个阶切换后前3个值不稳定,后续趋于稳定 voltage = np.concatenate([ np.random.normal(3, 0.5, 3) + np.linspace(0, 1, 3), # 前3个不稳定 np.random.normal(3, 0.1, 7), np.random.normal(5, 0.5, 3) + np.linspace(0, -1, 3), np.random.normal(5, 0.1, 7), np.random.normal(4, 0.5, 3) + np.linspace(0, 0.8, 3), np.random.normal(4, 0.1, 7) ]) df = pd.DataFrame({ '时间(s)': time, '电流([A])': current, '电压([V])': voltage })
步骤2:生成电流阶的分组ID
因为电流阶内有小波动,不能直接用电流值分组。我们通过判断相邻电流的变化幅度来识别阶跃:
# 设置电流阶跃阈值(根据你的实际数据调整,比如0.2A) current_step_threshold = 0.2 # 生成分组ID:当相邻电流差的绝对值超过阈值时,分组ID+1 df['电流阶ID'] = (df['电流([A])'].diff().abs() > current_step_threshold).cumsum()
这样同一个电流阶的所有数据会被分到同一个电流阶ID下。
步骤3:剔除不稳定数据并计算平均电压
这里有两种高效的实现方式,推荐第二种(更适合大数据量场景):
方式1:用groupby.apply过滤后求均值
drop_n = 3 # 每个阶要剔除的前N个不稳定数据 # 分组后对每个组取第drop_n行之后的数据,再求电压均值 result = df.groupby('电流阶ID').apply( lambda group: group.iloc[drop_n:]['电压([V])'].mean() ).reset_index(name='平均电压([V])') # 可选:添加每个电流阶的平均电流,方便查看 result['平均电流([A])'] = df.groupby('电流阶ID')['电流([A])'].mean().values
方式2:用cumcount标记组内行号,过滤后分组(更高效)
drop_n = 3 # 标记每个组内的行号(从0开始) df['组内行号'] = df.groupby('电流阶ID').cumcount() # 过滤掉每个组的前drop_n行 filtered_df = df[df['组内行号'] >= drop_n] # 分组计算平均电流和电压 result = filtered_df.groupby('电流阶ID').agg( 平均电流([A])=('电流([A])', 'mean'), 平均电压([V])=('电压([V])', 'mean') ).reset_index()
输出结果示例
运行后得到的result大概是这样:
电流阶ID 平均电流([A]) 平均电压([V]) 0 0 1.004573 3.026412 1 1 2.005153 5.010887 2 2 1.498658 4.002345
额外优化:如果电流阶是固定值(可通过取整区分)
如果你的电流阶是明确的固定值(比如1A、2A,波动极小),可以直接对电流取整/保留小数来分组,代码更简洁:
df['电流阶'] = df['电流([A])'].round(1) # 保留1位小数,把波动归为同一个阶 filtered_df = df.groupby('电流阶').apply(lambda x: x.iloc[drop_n:]).reset_index(drop=True) result = filtered_df.groupby('电流阶').agg( 平均电压([V])=('电压([V])', 'mean'), 有效样本数=('电压([V])', 'count') )
对比循环实现的优势
- 代码更简洁,可读性更强,不需要手动处理循环边界和分组判断
- 利用Pandas的向量化操作,大数据量下效率远高于循环
- 更容易扩展(比如要加其他统计量,直接在
agg里添加即可)
内容的提问来源于stack exchange,提问作者clel
相关产品推荐
相关产品推荐

