Pandas按User、MP分组提取指定占比前n行的实现方法
Pandas 按分组取前序固定占比行采样方案
需求说明
现有包含User、MP等共5列的DataFrame,需实现两层采样逻辑:
- 第一层按
User字段分组,为每个User提取占该User总条目数n%的前序行:例如某User共有1000条记录、n=5时,提取该User的前50条记录,所有采样结果最终合并为新DataFrame。 - 第二层为多MP值拆分逻辑:若同一User在
MP列存在多个不同取值,需按MP值进一步拆分采样占比:例如某User对应2个不同MP值时,每个MP值分组各提取2.5%的前序行。
原有代码问题
当前初步编写的代码未加入多MP拆分逻辑,且存在多处逻辑错误:
- User条目数统计逻辑错误:
df["User"].str.count(u).sum()是模糊匹配包含u字符串的User值,不是精确匹配当前遍历的User,统计结果偏差大。 - 存在无效嵌套循环:外层已经遍历所有唯一User值,内层再次遍历全量User列属于冗余逻辑,会导致重复采样。
- 取数范围错误:
df.head()是对全量数据表取头部行,不是对当前筛选的目标分组取前序行,取数结果完全不符合预期。 - 结果追加逻辑错误:pandas的
append()方法不会原地修改DataFrame,不重新赋值的话dfSample会始终为空表。
原有错误代码:
df = pd.read_excel("Results/fullData.xlsx") dfSample = pd.DataFrame() uniqueValues = df['User'].unique() print(uniqueValues) n = 5 for u in uniqueValues: sm = df["User"].str.count(u).sum() print(sm) for u in df['User']: sample = df.head(int(sm*(n/100))) #print(sample) dfSample.append(sample) print(dfSample) dfSample.to_excel('testFinal.xlsx')
修正后可直接运行的代码
直接按User+MP两级分组处理即可同时覆盖两个需求,无需多层嵌套判断,执行效率更高:
import pandas as pd df = pd.read_excel("Results/fullData.xlsx") n = 5 sample_fragments = [] # 按User、MP两级分组,sort=False保留原表行顺序 for (user_val, mp_val), group_df in df.groupby(['User', 'MP'], sort=False): # 计算当前User下不同MP的总数量,自动拆分每个MP分组的采样占比 mp_total = df[df['User'] == user_val]['MP'].nunique() per_mp_ratio = (n / 100) / mp_total # 计算当前分组需要提取的行数,兜底保证至少取1行,避免小分组漏采 sample_num = max(1, int(len(group_df) * per_mp_ratio)) # 取当前分组的前序行存入列表 sample_fragments.append(group_df.head(sample_num)) # 一次性合并所有采样片段,重置索引 dfSample = pd.concat(sample_fragments, ignore_index=True) print(dfSample) dfSample.to_excel('testFinal.xlsx', index=False)
实现逻辑说明
- 直接拆分到
User+MP最细粒度分组,自动适配单User下MP值数量不同的场景,不需要额外写分支判断MP个数。 - 每个MP分组的采样占比自动按「总采样占比n% / 当前User下去重MP数量」计算,完全匹配多MP拆分的要求。
- 用列表暂存所有采样片段、最后一次性合并,比循环中反复调用append的执行效率高很多,尤其适配大数据量场景。
- 增加
max(1, 采样数)兜底逻辑,避免某个MP分组条目数过少时,计算出的采样数为0导致漏采。
内容的提问来源于stack exchange,提问作者Pythonless
相关产品推荐
相关产品推荐

