如何在Pandas中按机器分组,基于启停信号标记状态列?
多机器分组生成状态列的正确实现
问题背景
需要为包含多台机器的DataFrame生成独立的Status列:
- Signal=1时,Status设为1(开机),状态保持1直到收到Signal=2或3(关机),Status切换为0,直到再次收到Signal=1重复上述逻辑。
- 单机器逻辑已实现,但多机器分组处理时出现
KeyError,循环拼接代码逻辑混乱,无法得到正确结果。
错误代码问题分析
- 错误的列索引方式:
dfList = df[df['Machine']]会把Machine列的取值当作列名查找,导致KeyError,正确方式是直接获取唯一机器列表:unique_machines = df['Machine'].unique()。 - 函数逻辑混乱:
s_gen2函数参数未使用、循环嵌套错误、引用未定义变量,且未正确为每组机器生成状态序列,拼接DataFrame的方式也不符合要求。
正确实现方案
方案一:groupby + 自定义函数(推荐)
基于单机器逻辑修改函数,使其接收单组Signal序列,通过groupby对每台机器独立计算状态:
import numpy as np import pandas as pd # 定义状态生成函数,接收单台机器的Signal序列 def gen_status(signal_series): _status = 0 status_list = [] for sig in signal_series: if _status == 0: if sig == 1: _status = 1 else: if sig in (2, 3): _status = 0 status_list.append(_status) # 返回带索引的Series,确保合并时对应原行 return pd.Series(status_list, index=signal_series.index) # 构造多机器测试数据 df = pd.DataFrame([]) df['Date'] = ['2020-01-01','2020-01-02','2020-01-03','2020-01-04','2020-01-05', '2020-01-06','2020-01-07','2020-01-08','2020-01-09','2020-01-10', '2020-01-11','2020-01-12','2020-01-13','2020-01-14','2020-01-15', '2020-01-16','2020-01-17','2020-01-18','2020-01-19','2020-01-20', '2020-01-01','2020-01-02','2020-01-03','2020-01-04','2020-01-05', '2020-01-06','2020-01-07','2020-01-08','2020-01-09','2020-01-10', '2020-01-11','2020-01-12','2020-01-13','2020-01-14','2020-01-15', '2020-01-16','2020-01-17','2020-01-18','2020-01-19','2020-01-20'] df['Machine'] = ['A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A', 'B','B','B','B','B','B','B','B','B','B','B','B','B','B','B','B','B','B','B','B',] df['Signal'] = [0,1,2,0,1,3,0,0,0,3,0,1,0,0,3,0,1,0,0,1,0,1,2,0,1,3,0,0,0,3,0,1,0,0,3,0,1,0,0,1] # 为每台机器生成Status列 df['Status'] = df.groupby('Machine')['Signal'].apply(gen_status) print(df)
方案二:循环处理每个机器分组
如果偏好循环处理,可逐个筛选机器数据、生成状态后合并:
import numpy as np import pandas as pd # 构造多机器测试数据(同方案一) df = pd.DataFrame([]) df['Date'] = ['2020-01-01','2020-01-02','2020-01-03','2020-01-04','2020-01-05', '2020-01-06','2020-01-07','2020-01-08','2020-01-09','2020-01-10', '2020-01-11','2020-01-12','2020-01-13','2020-01-14','2020-01-15', '2020-01-16','2020-01-17','2020-01-18','2020-01-19','2020-01-20', '2020-01-01','2020-01-02','2020-01-03','2020-01-04','2020-01-05', '2020-01-06','2020-01-07','2020-01-08','2020-01-09','2020-01-10', '2020-01-11','2020-01-12','2020-01-13','2020-01-14','2020-01-15', '2020-01-16','2020-01-17','2020-01-18','2020-01-19','2020-01-20'] df['Machine'] = ['A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A', 'B','B','B','B','B','B','B','B','B','B','B','B','B','B','B','B','B','B','B','B',] df['Signal'] = [0,1,2,0,1,3,0,0,0,3,0,1,0,0,3,0,1,0,0,1,0,1,2,0,1,3,0,0,0,3,0,1,0,0,3,0,1,0,0,1] # 获取所有唯一机器 unique_machines = df['Machine'].unique() result_dfs = [] for machine in unique_machines: # 筛选当前机器的数据并复制,避免修改原DataFrame machine_df = df[df['Machine'] == machine].copy() # 生成状态序列 _status = 0 status_list = [] for sig in machine_df['Signal']: if _status == 0: if sig == 1: _status = 1 else: if sig in (2, 3): _status = 0 status_list.append(_status) machine_df['Status'] = status_list result_dfs.append(machine_df) # 合并所有机器的结果,保持原DataFrame的行顺序 final_df = pd.concat(result_dfs).loc[df.index] print(final_df)
结果验证
两种方案生成的Status列均与期望输出一致,每台机器的状态独立计算,不会互相干扰。
内容的提问来源于stack exchange,提问作者Flint
相关产品推荐
相关产品推荐

