按Name分组校验Y/Z计数并计算时间差的数据清洗问题
结构化数据清洗Pandas实现方案
处理规则明细
- 数据筛选:以
Name列为分组维度,每个分组仅保留Country列取值为Y/Z的记录,其余取值行全部过滤 - 标记校验:逐组统计组内
Y、Z的记录数,二者计数完全相等时,该组所有保留记录的Flag字段赋值为1,否则赋值为0 - 时长计算:遵循业务规则「Y的发生时间早于Z」,仅对
Flag=1的分组做计算:- 提取组内时间最晚的Y记录、时间最早的Z记录,二者时间差值存入独立列
Exposure Time - 相同时间差值同步填写到对应分组Z记录的
Difference字段
- 提取组内时间最晚的Y记录、时间最早的Z记录,二者时间差值存入独立列
样例处理预期
原始数据自带Date、Time、Country、Name四个字段,处理后新增Flag、Difference字段,各分组结果符合如下预期:
- Ayesha分组:Y、Z各1条,
Flag=1,时间差计算结果为5小时 - Mirha分组:Y、Z各1条,
Flag=1,时间差计算结果为4分钟 - Ehsan分组:仅2条Y记录无对应Z记录,
Flag=0,不计算时间差
可直接运行的实现代码
import pandas as pd # 读取原始数据,将分离的日期、时间字段合并为可计算的时间戳 df = pd.read_csv("your_data_path.csv") df["ts"] = pd.to_datetime(df["Date"].astype(str) + " " + df["Time"].astype(str)) # 第一步:过滤非Y/Z的记录 df = df[df["Country"].isin(["Y", "Z"])].reset_index(drop=True) # 第二步:按Name分组统计Y/Z数量,生成Flag标记 count_res = df.groupby("Name")["Country"].value_counts().unstack(fill_value=0) # 兼容分组无Y或无Z的场景,补0避免报错 count_res["Y"] = count_res.get("Y", 0) count_res["Z"] = count_res.get("Z", 0) valid_name_list = count_res[count_res["Y"] == count_res["Z"]].index.to_list() df["Flag"] = df["Name"].apply(lambda x: 1 if x in valid_name_list else 0) # 第三步:初始化结果列,计算符合条件分组的时间差 df["Exposure Time"] = pd.NaT df["Difference"] = None for name in valid_name_list: cur_group = df[df["Name"] == name] # 取最晚的Y时间、最早的Z时间 y_latest_ts = cur_group[cur_group["Country"] == "Y"]["ts"].max() z_earliest_ts = cur_group[cur_group["Country"] == "Z"]["ts"].min() delta = z_earliest_ts - y_latest_ts # 写入Exposure Time列 df.loc[df["Name"] == name, "Exposure Time"] = delta # 写入对应Z记录的Difference字段 z_row_mask = (df["Name"] == name) & (df["Country"] == "Z") df.loc[z_row_mask, "Difference"] = delta # 如需输出可删除中间生成的ts列 df = df.drop(columns=["ts"])
代码中时间差默认保留pandas的timedelta格式,可直接参与后续数值计算;如果需要固定展示为X小时/X分钟的文本格式,可自行加格式化逻辑处理。
内容的提问来源于stack exchange,提问作者Filbadeha
相关产品推荐
相关产品推荐

