使用Pandas将数据集过滤为retention1、retention2及混合留存数据框的方案
前置数据预处理
先统一清洗数据,生成后续要用的判断标记:
import pandas as pd # 统一替换字符串None为真实空值 df = df.replace({'None': None}) # 生成每行的r1/r2非空标记 df['has_r1'] = df['retention1'].notna() df['has_r2'] = df['retention2'].notna()
分类逻辑实现
先按name分组判断每个name所属的留存类型:
# 分组聚合判断每个name的类型标记 name_type = df.groupby('name').agg( has_any_r1=('has_r1', 'any'), has_any_r2=('has_r2', 'any') ).reset_index() # 打类型标签 name_type['retention_type'] = '混合留存' name_type.loc[(name_type['has_any_r1']==True) & (name_type['has_any_r2']==False), 'retention_type'] = 'retention1' name_type.loc[(name_type['has_any_r1']==False) & (name_type['has_any_r2']==True), 'retention_type'] = 'retention2' # 把类型标签合并回原表 df = df.merge(name_type[['name', 'retention_type']], on='name', how='left')
有效值提取通用逻辑
先写工具函数处理AZ_URL判断和retention值提取:
def get_element_index(cluster_id, az_url): # 按实际AZ_URL分隔符调整,这里默认用/或:拆分,取前两部分判断 az_parts = az_url.replace(':', '/').split('/')[:2] if cluster_id in az_parts[1]: return 0 # 第二部分,取第一个元素 elif cluster_id in az_parts[0]: return 1 # 第一部分,取第二个元素 # 匹配不到的情况可根据业务补默认值 return 0 def extract_retention_value(retention_str, idx): if pd.isna(retention_str): return None # 去除括号,按分号拆分 parts = retention_str.strip('[]').split(';') return parts[idx].strip() if len(parts) > idx else None
分类型计算最终值
1. retention1类型计算
r1_df = df[df['retention_type'] == 'retention1'].copy() # 计算取值索引 r1_df['elem_idx'] = r1_df.apply(lambda x: get_element_index(x['ClusterID'], x['Az_URL']), axis=1) # 提取retention1有效值 r1_df['final_retention'] = r1_df.apply(lambda x: extract_retention_value(x['retention1'], x['elem_idx']), axis=1)
2. retention2类型计算
r2_df = df[df['retention_type'] == 'retention2'].copy() # 计算取值索引 r2_df['elem_idx'] = r2_df.apply(lambda x: get_element_index(x['ClusterID'], x['Az_URL']), axis=1) # 分别提取retention2数值和快照留存类型 r2_df['final_retention'] = r2_df.apply(lambda x: extract_retention_value(x['retention2'], x['elem_idx']), axis=1) r2_df['final_snapshot'] = r2_df.apply(lambda x: extract_retention_value(x['retention snapshot'], x['elem_idx']), axis=1)
3. 混合留存类型计算
混合留存可直接保留分组内的所有有效记录,或按业务需要聚合输出:
mix_df = df[df['retention_type'] == '混合留存'].copy() # 同样按规则提取每条有效记录的对应值即可 mix_df['elem_idx'] = mix_df.apply(lambda x: get_element_index(x['ClusterID'], x['Az_URL']), axis=1) mix_df['final_r1'] = mix_df.apply(lambda x: extract_retention_value(x['retention1'], x['elem_idx']) if x['has_r1'] else None, axis=1) mix_df['final_r2'] = mix_df.apply(lambda x: extract_retention_value(x['retention2'], x['elem_idx']) if x['has_r2'] else None, axis=1) mix_df['final_snapshot'] = mix_df.apply(lambda x: extract_retention_value(x['retention snapshot'], x['elem_idx']) if x['has_r2'] else None, axis=1)
原有代码问题说明
- retention2计算的两行
str.extract逻辑错误,第一行提取数字后第二行又提取字母会直接覆盖原有结果,需要分开存储数值和快照类型 - 混合留存的
groupby.agg写法语法错误,lambda参数不能直接写x['retention1'],需要先按分组判断类型再处理对应字段
内容的提问来源于stack exchange,提问作者coolguy2024
相关产品推荐
相关产品推荐

