用0填充没有覆盖的箱子
我需要生成一个热图,显示每个区间内的平均覆盖情况。这个区间是根据我设定的数量来划分的,而不管每个区间内的转录组有多少个碱基。换句话说,如果我想要10个区间,一个转录组可能有1000个碱基要分配到这10个区间,而另一个转录组可能有2445个碱基也要分配到这10个区间。
问题是,在我的覆盖文件中,有些地方没有落入任何一个区间。比如说,如果我想在10个位置上划分成5个区间,我会得到:(0,2], (2,4], (4,6], (6,8], (8,10]。如果我的覆盖位置是1, 5, 5, 5, 7, 7, 10,那么区间“(2,4]”就会被忽略,因此在热图中不会出现。我希望这些没有覆盖的区间能用0填充,这样它们就能在热图中显示出来。
我正在使用Python,配合pandas、seaborn和matplotlib.pyplot库。
下面的图片中,第一行是我划分的区间边界,数据框显示了哪些区间有覆盖:
点击这里查看图片输入示例:
chr17 1 1
chr17 5 1
chr17 5 2
chr17 5 2
chr17 7 1
chr17 7 5
chr17 10 1
问题:
chr data_bin avg
chr17 (0,2] 1
chr17 (4,6] 1.66
chr17 (4,6] 1.66
chr17 (4,6] 1.66
chr17 (6,8] 3
chr17 (6,8] 3
chr17 (8,10] 1
期望结果:
chr data_bin avg
chr17 (0,2] 1
**chr17 (2,4] 0**
chr17 (4,6] 1.66
chr17 (4,6] 1.66
chr17 (4,6] 1.66
chr17 (6,8] 3
chr17 (6,8] 3
chr17 (8,10] 1
我使用的函数是:
def bins_calculator(path_txt:str, start:int,end:int):
column_names =["chr", "pos", "cov"]
data = pd.read_csv(path_txt, names = column_names, sep = '\t')
step = int((end - start) / 10)
n_bins = [start + i * step for i in range(11)]
n_bins[-1] = end
data["data_bin"] = pd.cut(data["pos"], bins = n_bins)
data["avg"] = data.groupby("data_bin", observed = False)["cov"].transform("mean")
filtered_data = data[["chr","data_bin","avg"]].drop_duplicates("data_bin")
return filtered_data
如果对这个问题有任何疑问,请在评论中告诉我 :)
1 个回答
1
如果我理解得没错,你可以使用 .merge
来合并缺失的类别,然后用你想要的值来填充任何 NaNs
(缺失值):
df["data_bin"] = pd.cut(df["pos"], range(0, 12, 2))
df = pd.merge(
df,
df["data_bin"].cat.categories.to_frame(),
left_on="data_bin",
right_on=0,
how="outer",
)[["chr", "data_bin", "cov"]]
df["chr"] = df["chr"].ffill().bfill()
df["cov"] = df["cov"].fillna(0)
df["avg"] = df.groupby("data_bin")["cov"].transform("mean")
print(df)
输出结果:
chr data_bin cov avg
0 chr17 (0.0, 2.0] 1.0 1.000000
1 chr17 (2.0, 4.0] 0.0 0.000000
2 chr17 (4.0, 6.0] 1.0 1.666667
3 chr17 (4.0, 6.0] 2.0 1.666667
4 chr17 (4.0, 6.0] 2.0 1.666667
5 chr17 (6.0, 8.0] 1.0 3.000000
6 chr17 (6.0, 8.0] 5.0 3.000000
7 chr17 (8.0, 10.0] 1.0 1.000000