如何按递增染色体位置区间对DataFrame样本列分组求和及代码修正
基因组测序数据区间分组求和问题解决
问题背景
已有映射到基因组特定位点的DNA测序CSV数据,列定义:
- 列0:染色体名称
- 列1:核苷酸位置
- 列2:标识字段
- 列3-6:不同样本的序列映射次数
需求:按列1的**1-10000、10001-20000……**递增区间,分染色体、列2标识对样本列求和。
原尝试的pandas代码生成区间不符合预期,出现1-10000、10000-20000及错误大区间;用.loc[]循环处理多染色体区间时也遇到困难。
原代码:
MAX_SIZE = 10_000_000 # max chromosome size bins = list(range(0, MAX_SIZE, 10_000)) bins[0] = 1 labels = [f'{a}-{b}' for a,b in zip(bins, bins[1:])] group = pd.cut(data[1], bins, labels=labels).astype(str) out = (data.groupby([0, group, 2]) [[3, 4, 5]].sum().reset_index() )
问题原因
原代码的pd.cut默认采用左闭右开区间,手动修改bins[0]=1后,后续区间边界仍为10000、20000,导致第二个区间为[10000,20000),与第一个区间[1,10000)的边界重叠,标签文本和实际数值范围不匹配;同时超出MAX_SIZE的位置会被归到错误区间。
修正方案
方案一:数学计算生成区间标签(推荐)
直接通过整数运算定位区间,避免pd.cut的边界歧义:
BIN_SIZE = 10_000 # 计算每个核苷酸位置对应的区间起始值 data['interval'] = ((data[1] - 1) // BIN_SIZE) * BIN_SIZE + 1 # 生成符合要求的区间文本标签 data['interval'] = data['interval'].map(lambda x: f'{x}-{x + BIN_SIZE - 1}') # 按染色体、区间、标识字段分组,对样本列求和 out = data.groupby([0, 'interval', 2])[[3, 4, 5, 6]].sum().reset_index()
核心逻辑:(位置-1)//BIN_SIZE得到区间索引,反推起始值后生成x到x+BIN_SIZE-1的连续区间,确保无重叠、无遗漏。
方案二:调整pd.cut参数适配需求
若偏好使用pd.cut,需重新生成bins并设置区间规则:
BIN_SIZE = 10_000 MAX_SIZE = 10_000_000 # 生成左边界序列:1, 10001, 20001...,最后补充MAX_SIZE+1确保覆盖所有位置 bins = list(range(1, MAX_SIZE + BIN_SIZE, BIN_SIZE)) if bins[-1] <= MAX_SIZE: bins.append(MAX_SIZE + 1) # 生成对应区间标签 labels = [f'{a}-{a + BIN_SIZE - 1}' for a in bins[:-1]] # 使用right=False设置左闭右开区间,匹配标签范围 group = pd.cut(data[1], bins=bins, labels=labels, right=False) # 分组求和 out = data.groupby([0, group, 2])[[3, 4, 5, 6]].sum().reset_index()
这里的区间[1,10001)对应数值1-10000,[10001,20001)对应10001-20000,完美匹配需求标签。
内容的提问来源于stack exchange,提问作者timnick23
相关产品推荐
相关产品推荐

