Insulation score(IS),俗称绝缘分数,用于计算识别三维基因组中的拓扑关联结构域TAD。

首次提出是在:

1,概念

为染色体上的基因组区间分配‘绝缘评分’的方法。该评分用于衡量跨越每个区间的所有相互作用的总和。绝缘曲线的最低点代表高绝缘区域,我们将其定义为TAD边界。

关键点来了,很多人一开始看这个定义的时候很容易忽略一个词——across,

指的是跨过这个bin的互作的总和,什么意思呢?

我可以滑动窗口(在hic矩阵的对角线上),我窗口有大有小不是关键,包含某个bin,但是我计算的却是across/或者说是跳过这个bin的互作总和。

是不是很难理解?

我举个例子就很好懂了,

如果这个bin是一个边界(boundary),那么互作能不能跨过这个边界传递给远方,理论上是不能的,所以across跨越边界的互作总和是很小的;

反之,如果某个bin不是边界,就是正常的在TAD内部的一个区域,那么跨越这个bin的互作之和,和正常的TAD内的互作之和有什么区别吗,其实差别不会很大。

所以这个值,insulation score,顾名思义,我们把它当作是一个类似于CNN中局部local receptor field的话,那么它关注的其实就是局部的互作信息,而且这个局部感受野还挖掉了中心的eye。

这个信息只有在遇到边界的时候才能够体现出互作的显著差异,

即边界所分隔开的区域,互作之和,肯定显著低于没有被隔开的、同样大小的区域的互作之和。

绝缘分数本质——量化基因组位点对交互的阻碍强度。

2,识别算法

首先我先举一个常见的理解错误,也不能说是错误,应该是误区(实际上insulation score在2015年这篇nature文献发表之后有很多改版和变种,所以也不乏有些文献可能就是我下面的这种想法);

Warning:下面这个是我刚开始的想法以及伪代码实现,并不是我按照2015年这篇算法开发文献的原汁原味的理解(要看对应的伪代码的直接跳过这里,看我后面第2块伪代码)!!!!!!!!!!!!!!

  TAD边界检测算法 (Hi-C数据分析)                         
───────────────────────────────────────────────────────输入:                                                 • hic_matrix: ICE校正矩阵(10kb/50kb bins)            • window_size=500kb (绝缘分析窗口)                   输出:                                                 • boundaries: [[start,end],...] (边界区域列表)        
───────────────────────────────────────────────────────1. 初始化参数                                          bin_size ← 10kb                                    window_bins ← window_size/bin_size                 insulation_scores ← array[n]                      2. 计算绝缘分数 (∀ i ∈ [0,n-1]):                       if i∉[window_bins, n-window_bins-1]:                scores[i] ← NaN                                else:                                             ▸ 方块区域: rows/cols ∈ [i±window_bins]         ▸ score = (∑方块 - M[i,i]) / (有效bins数)        3. 归一化:                                           avg ← mean(scores[有效区域])                        scores ← log₂(scores/avg)                         
───────────────────────────────────────────────────────4. 边界检测:                                           a) 计算delta导数(100kb窗口):                        δ[i] = mean(left_diff) - mean(right_diff)       b) 候选边界:                                        ∀i where δ[i]>0 ∧ δ[i+1]<0                      c) 强度过滤:                                        strength = (left_peak - score) + (score - right_valley)keep if strength ≥ 0.1                          
───────────────────────────────────────────────────────                                                        
5. 输出边界区域:                                       ∀boundary → [boundary±3 bins] (±30kb)              

这里我们要区分几个概念

  • bin_size:这个很简单,就是hic分析中的分辨率,简单来说就是将一条染色体分成以多少kb为单位的区域,比如说10kb为单位的区域,划分出来了上万个bin,那么bin_size就是10kb,不熟悉的可以查看我之前hic分析pipeline系列的文章。
  • matrix_size:其实严格来说没有这个概念,只不过是我在这里为了分析透彻才提出的,其实就是hic互作矩阵的大小。举例来说,chr1我们有1个互作矩阵图谱,假设是1Mb(假设),那么1Mb就是这个矩阵的size,我们所有要识别的TAD等分析手段,都是在这个大背景下的matrix中实现的。我们的矩阵是1Mb x 1Mb,如果考虑分成bin的话,比如说bin_size还是10kb,那么这个matrix就是100bin x 100bin。
  • window_size:这个没什么好说的了,就是窗口的大小,但是我上面这里写的window其实不是我们常规意义理解中的滑动窗口,按照我的理解,这里改成flank_region其实更合理,就是侧翼区域,其实就是将每个bin为中心,上下游各自延伸出来window_size,比如说window_size是5个bin的话,那么就是以当前bin为中心,在hic矩阵的对角线上上下各自延伸5个bin,那么这个square其实就是5x2+1=11个bins了。
  • square(diamond window):square其实才是我们在宏观角度上看来的,真实在hic矩阵对角线上滑动的那个窗口。

(1)绘制insulation score-bin index曲线

首先我们肯定有一个全长范围的matrix,比如说chr1,我们假设是1Mb x 1Mb的窗口大小,这个是我们要研究的全景范围。

然后比如说我们的hic矩阵的分辨率也就是bin_size是10kb大小,

那么这个全景窗口也就是matrix,我们实际上就有100bin x 100bin划分的网格区域——》这个时候只是有了分bin的大小,也就是这个网格划分出了大小;

然后我们在有了这个窗口也就是田字格之后,我们再引入观察的窗口window(这里观察的窗口实际上是为了我们上面提到的square所服务的),所以我们还是直接提square为主,这里的square,比如说我们使用1个长度为500kb的square的矩形窗口去滑动,那么实际上这个square就是一个50bin x 50bin大小的窗口。

也就是说1个50bin x 50bin大小的正方形,在1个100bin x 100bin大小的背景窗口下沿着对角线滑动,那么可以获得多少个滑动子序列呢? 100-50+1个,其实对角线上就是1D序列,我们还是称这些子序列为square。

总之每一个square,因为里面都是50bin x 50bin,就算是1bin x 1bin,我们也可以计算出或者是统计出contact数来,所以我们可以获取该square中的contact总和,每一个square都可以做到。

然后对于每一个square,因为是有50bin x 50bin,理论上是可以计算出对每一个1bin x 1bin的均值(也就是将这个square的contact总和/单位bin分箱的总个数),也就是10kb的1bin,问题是这个均值,到底给square里的谁呢?毕竟这个square里有50个bin的对角线,难道这50个对角线上的bin都分配到这个square里平均的contact吗?

答案是否定的,这个平均下来的contact实际上就是score,score是与bin一一对应的,所以这个score实际上是分配给对应的bin?

那这个bin到底是谁呢?

从直接上讲,我们肯定是下意识地觉得这个bin就是中心化的bin,这是符合直觉的。

并且,method里提到了在matrix首尾超过500kb的bin,实际上就不分配score,这不是正好意味着我们的score分配原则是依据square定的吗!

这里的square,如果沿着hic矩阵的对角线滑动,正好在左上角以及右下角划出了square size的范围之外,实际上就相当于是没有这个square,那么square就没有对应的bin了,那自然就也没有对应的score了。

所以,从理论上讲,其实这里的score是和square对应的,也就是和bin对应的,

所以逻辑上bin-square-score一一对应,可以绘制出score-bin index曲线,那么如何做到这一点,对于一个就有很多个bin在对角线上的square,符合直觉的方式也就只有分配给中心的bin了。

边界处理:对于距离矩阵起点或终点500 kb以内的分箱,不分配绝缘分数,因为500 kb × 500 kb的窗口会超出矩阵范围。

这个其实就很好理解了,大背景窗口window,在对角线上左上角以及右下角,分别划出来1个square作为边界,我们的square滑动的范围界限就是这两个边界square之间;

所以我们的问题,其实是要解决每个对角线上的bin如何计算出insulation score的问题————》

一旦计算出来了,每个bin都有1个对应的insulation score,那么我们就可以做归一化,就是对角线上所有的bin的score求和,然后分子是某个bin的score,分母是所有bin求和的score,然后比值可以log2对数化。

这个时候其实对于每一个bin,如果x轴是bin index,y轴是score的话,其实就已经可以画出来1个score曲线了;

然后这个score曲线的谷底,也就是min,可以看作是hic互作急剧下降的位点,这些bin其实就被解释为TAD边界。

所以这里的理解关键就是,如何将滑动的square与bin一一对应上?

还是使用文献中的方法,其实这里的描述已经很清晰了:

across each bin (up to a specified distance up- and downstream of the bin)

我们的bin(被across的),是如何被组织成需要聚合的square的contact,其实就是在这个bin上下游划分或者说是各自延伸一定distance,这里的distance其实就是我上面提到的window_size的概念,

然后我们每一个bin,有了上下游的window_size,也就是bin±window_size,才组织成了square这个概念。

而且这里其实也说明了,我们的window_size也就是侧翼flank的区域大小,其实是自定义的(相当于是1个超参数)。

当然,实际上这个算法有很多变种版本,主要是关于其中的square的定义部分,

不同的变种版本,具体设置的[Xstart,Xend]x[Ystart,Yend]实际上是不一样的;

在我上面理解的版本中,由[Xstart,Xend]x[Ystart,Yend]构成的square(也就是diamond window),实际上采用的是是在中心化的bin的左右两侧都flank一个window出来;

有的版本中,比如说下面的:

这也和我们前面的伪代码中减去中心的这个bin的contact的某种思想是对应的。

好了,以上就是我提到的第一个误区,也就是我一开始的想法!!!!!!!!

那么,真实原文实现的细节是怎么样的呢?

参考具体原始实现细节:

https://github.com/dekkerlab/crane-nature-2015

原始脚本是使用perl写的,详细细节可以参考,

我们需要重点关注的细节是这个square方块如何选取的,原始使用的脚本中对于这个square的坐标的设计:

如果我们还是使用500kb的square_size来举例的话,那么这一个square选取的其实不是一个对称矩阵:

其实结合这个图形,就更容易理解了,我们这会正经看一下这个图:

所谓的across其实和“do not include the diagonal”是一致的,

我们仔细看这个热图,发现了什么没有(一般越是CNS主刊的图越是不可能随意画的,所以这就算是一个简单的算法示意图,还是有细节可以考究的)。

我们注意看这个热图中滑动的square的起点以及终点,

我们可以发现,左上角的第一个square,实际上只和标记mark为3的那个bin有接触

从这个图里,我们就很容易发现并理解,为什么bin1和2就没有对应的square,因为这个square再接着按照图中的轨迹向左上方移动就会超出边界线。

再仔细看一下,很明显这个square的window_size就有2个bin大小,当然这个不是问题的关键,可能有的人会有疑问,如果我把这个square放在对角线上,不也同样是能够获取mark 2的bin的信息的吗?

那按理来说我不应该是从index为2的bin开始就有1个score吗?

但实际上这个示意图中只有从index 3开始的score信息!

所以,这其实就是理解算法中across的关键,我们恰恰可以从这一个问题出发:为什么这个square不放在对角线上,看形式上,它是放在对角线的上方的,只能说是沿着along对角线,不能说是on对角线。

我们再看一下这种square放置方法的效果是什么:

我们可以仔细看这个和index为3的bin有接触的square,

我们可以把对角线上的坐标映射到x轴以及y轴上

我们可以发现什么,这个square包含的是不是mark1、2的bin和mark4、5的bin之间的互作contact之和!

少了什么?

就是bin3内部的contact!

而1、2和4、5不就是bin3的上下游吗,所以就是来统计评估在bin3上下游的互作情况,而且是指定上游和下游互作强度如何。

我们很容易就可以推论,如果bin3是一个边界的话,那么bin3上游的bin1、2和下游的bin4、5不就正好被绝缘了吗,相当于是正好对应上游的TAD以及下游的TAD,

所以这个时候两个TAD之间的互作绝缘的话,那么bin1、2和bin4、5统计出来的contact应该会很低,所以我们说bin3也就是绝缘边界的话insulation score会很低。

反之,如果bin3不是TAD边界,而是在某一个TAD的内部,那么在一个window_size范围内,其实邻居bin还是在TAD内的,那么依据TAD的定义,内部互作依然是频繁的,所以这个时候bin1、2和bin4、5统计出来的contact应该会很高。

那么两个比较之下,很显然,我们就能够依据insulation score的高低来区分这个bin是在边界上还是在TAD domain内部。

上面都是定性的表述,下面我们来定量描述一下:

我们可以看到这里的bin index为3,也就是我们假设i=3,对于目前要处理的bin;

那么依据我们前面对于bin-square-score一一对应的理论,这里的square应该如何组织呢?

square无非是由4个坐标决定,也就是[Xstart,Xend]x[Ystart,Yend]。

很明显,这里i=3的bin对应的square是[4,5]x[1,2]。

我们可以用一种更加容易理解的方式来重写这个square的坐标:
[3+1,3+2]x[3-2,3-1],

这里其实就可以联系我们的square_size了,

对标index=i的bin,其实用于收集其对应across的square坐标是[i+1,i+square_size]x[i-square_size,i-1]。

然后因为是对称矩阵,所以square放在对角线右上角还是左下角其实是没有区别的,都可以收集到across这个bin的互作contact。

简单来理解就是bin i右上方邻接的square_size x square_size的正方形。

从这个角度来讲,其实就很好理解我下面这里所写出来的insulation score的伪代码了:

  TAD边界检测算法 (Hi-C数据分析)                         
───────────────────────────────────────────────────────输入:                                                 • hic_matrix: ICE校正矩阵(10kb bins)            • window_size=500kb (绝缘分析窗口)                   输出:                                                 • boundaries: [[start,end],...] (边界区域列表)        
───────────────────────────────────────────────────────1. 初始化参数                                          bin_size ← 10kb                                    window_bins ← window_size/bin_size                 insulation_scores ← array[n]                      2. 计算绝缘分数 (∀ i ∈ [0,n-1]):                       if i∉[window_bins, n-window_bins-1]:                scores[i] ← NaN                                else:                                             ▸ 方块区域square: rows ∈ [i-window_bins, i-1]cols ∈ [i+1, i+window_bins]      ▸ score = (∑方块) / (有效bins数)        3. 归一化:                                           avg ← mean(scores[有效区域])                        scores ← log₂(scores/avg)                         
───────────────────────────────────────────────────────4. 边界检测:                                           a) 计算delta差分(上下游各100kb窗口):                        δ[i] = mean(left_diff) - mean(right_diff)       b) 候选边界:                                        ∀i where δ[i]>0 ∧ δ[i+1]<0                      c) 强度过滤:                                        strength = (left_peak - right_valley)keep if strength ≥ 0.1                          
───────────────────────────────────────────────────────                                                        
5. 输出边界区域:                                       ∀boundary → [boundary±3 bins] (±30kb)              

注意:实际坐标或者说bin的index会因为0、1-indexed的差异,或者在实际hic矩阵中bin是作为一个区间还是一个起点——导致上面的具体实现细节有点差异,但是大致算法上的逻辑,基本上应该是和我上面这个理解兼容的。

(2)有了这个曲线之后我们再讨论如何寻找min,也就是谷底

这个时候其实就很简单了,如果我们按照(1)中的方法,已经绘制出了一条insulation score-bin index的曲线,我们其实只需要找这个极小值点就行了(按照我们对TAD边界在insulation score中的表现和定义)。

求极值点其实很简单,学过微积分的都知道,如果是连续函数,就求导,一阶导=0的点,也就是极值点。当然这里我们要注意一下,极值点对应的不一定是valley谷底,也可能是peak山峰,也就是极小值还是极大值。

如果是离散的话,就差分,微分方程对应差分方程,其实就是数值分析那一块的内容。

所以delta法其实就是差分法,同样的,delta=0的地方可能是极大值也可能是极小值,比如说上面图a红线跨0点的地方,对应的黑线部分,可能是insulation score max或min的,其中min的坐标是我们需要的。

然后,注意到我们在计算insulation score的时候,是针对每一个bin进行计算的,所以是bin和score一一对应的;

现在,我们在这里同样计算delta,也是围绕每一个参考bin进行的,所以也是bin和delta一一对应的。

然后这个delta计算其实就很简单了,就是(左侧互作-参考bin)的均值-(右侧互作-参考bin)的均值,至于左侧和右侧到底size多大,还是要定义1个window,相当于还是有一个超参数

当然,还是那个边界的问题,对于delta,我们还是要考虑在参考bin上游的窗口能否取到,理论上delta因为要计算前向值,那么前面没有score的bin,在计算delta向量的时候是否会有边界问题?

当然注意一下,这里的差分delta,其实和我们正常理解的差分不一样,我们正常理解的差分,是用当前bin的score-之前bin的score,但是这里指的是上游bin的score相对参考点的score,所以这里理解的delta的值和我们常规理解的差分其实就差了个方向

那么我们要从-delta的角度来类比微分,然后理解极小值点和极大值点是什么,

-delta[i]<0,-delta[i+1]>0,valley,对应就是谷底,也就是边界

当然理想情况下是delta=0,

我们还是对照前面官方原始的perl脚本

for(my $y=0;$y<$numHeaders;$y++) {# 获取当前bin的头部信息my $yHead=$inc2header->{ y }->{$y};my $insulation="NA";$insulation=$matrixInsulation->{$yHead} if(exists($matrixInsulation->{$yHead}));# 计算左右边界my $leftBound=($y-$halfInsulationDeltaBinSize);$leftBound=0 if($leftBound < 0);my $rightBound=($y+$halfInsulationDeltaBinSize);$rightBound=$numHeaders-1 if($rightBound >= $numHeaders);# 计算左侧delta值my @leftDelta=();for(my $ly=$leftBound;$ly<$y;$ly++) {my $leftHead=$inc2header->{ y }->{$ly};my $leftInsulation="NA";$leftInsulation=$matrixInsulation->{$leftHead} if(exists($matrixInsulation->{$leftHead}));my $delta="NA";$delta=($leftInsulation-$insulation) if(($insulation ne "NA") and ($leftInsulation ne "NA"));push(@leftDelta,$delta) if($delta ne "NA");}my $leftDeltaAggregrate="NA";if(@leftDelta > 0) {my $leftDeltaStats=listStats(\@leftDelta);$leftDeltaAggregrate=$leftDeltaStats->{ mean };}# 计算右侧delta值my @rightDelta=();for(my $ry=$y+1;$ry<=$rightBound;$ry++) {my $rightHead=$inc2header->{ y }->{$ry};my $rightInsulation="NA";$rightInsulation=$matrixInsulation->{$rightHead} if(exists($matrixInsulation->{$rightHead}));my $delta="NA";$delta=($rightInsulation-$insulation) if(($insulation ne "NA") and ($rightInsulation ne "NA"));push(@rightDelta,$delta) if($delta ne "NA");}my $rightDeltaAggregrate="NA";if(@rightDelta > 0) {my $rightDeltaStats=listStats(\@rightDelta);$rightDeltaAggregrate=$rightDeltaStats->{ mean };}# 计算deltaDelta值my $deltaDelta="NA";$deltaDelta=($leftDeltaAggregrate-$rightDeltaAggregrate) if(($leftDeltaAggregrate ne "NA") and ($rightDeltaAggregrate ne "NA"));$matrixDelta->{$yHead}=$deltaDelta;
}

其实代码逻辑很简单,实现的是同样的原理:

  1. 遍历每个bin:
    • 使用for(my y = 0 ; y=0; y=0;y< n u m H e a d e r s ; numHeaders; numHeaders;y++)循环遍历矩阵中的每个bin。
  2. 获取当前bin的绝缘指数:
    • m a t r i x I n s u l a t i o n 哈希中获取当前 b i n 的绝缘指数( matrixInsulation哈希中获取当前bin的绝缘指数( matrixInsulation哈希中获取当前bin的绝缘指数(insulation)。
    • 如果当前bin的绝缘指数不存在,则设置为"NA"。
  3. 计算左右边界:
    • 计算当前bin的左边界( l e f t B o u n d )和右边界( leftBound)和右边界( leftBound)和右边界(rightBound)。
    • 确保边界不会超出矩阵的范围。
  4. 计算左侧delta值:
    • 遍历当前bin左侧的bin,计算每个左侧bin的绝缘指数与当前bin的绝缘指数的差值($delta)。
    • 将有效的delta值存储在@leftDelta数组中。
    • 如果@leftDelta数组中有数据,计算其平均值($leftDeltaAggregrate)。
  5. 计算右侧delta值:
    • 遍历当前bin右侧的bin,计算每个右侧bin的绝缘指数与当前bin的绝缘指数的差值($delta)。
    • 将有效的delta值存储在@rightDelta数组中。
    • 如果@rightDelta数组中有数据,计算其平均值($rightDeltaAggregrate)。
  6. 计算deltaDelta值:
    • 计算左侧delta平均值与右侧delta平均值的差值($deltaDelta)。
    • 将计算结果存储在$matrixDelta哈希中。

当然使用极小值法找出来边界之后,我们还有一个叫做boundary strength的指标来过滤,

当前bin左侧的局部极大值-右侧的局部极小值

然后计算这个边界的话,其实也很简单,因为我们知道找到的每一个候选的boundary,实际上都是insulation的局部极小值点,按照delta的逻辑和方向的定义,又是delta的右半侧下降曲线交叉零点的地方,

既然是右半侧下降曲线,那么这个下降曲线,向左的边界是局部极大值(delta的局部极大值,不是insulation的),向右的边界是局部极小值。

所以原脚本中的逻辑就是:
通过向左和向右搜索,找到当前点两侧的“delta”值变化趋势的边界,并计算这两个边界之间的差值作为边界强度。如果计算出的边界强度小于噪声阈值,则认为这个边界是无效的,从而跳过它。

对照原始脚本,就是:

$leftSearchIndex = $yIndex - 1;
while( ($leftSearchIndex > 0) and ($matrixDelta->{$inc2header->{ y }->{$leftSearchIndex}} ne "NA") and ($matrixDelta->{$inc2header->{ y }->{$leftSearchIndex-1}} ne "NA") and ($matrixDelta->{$inc2header->{ y }->{$leftSearchIndex-1}} >= $matrixDelta->{$inc2header->{ y }->{$leftSearchIndex}}) 
) {$leftSearchIndex--;  # 向左移动直到Delta不再递增
}
my $leftDeltaBound = $matrixDelta->{$inc2header->{ y }->{$leftSearchIndex}};

向左搜索局部极大值(Peak):

  • 搜索逻辑:
    从候选边界向左移动,找到Delta值的局部最大值(即曲线上升的终点)
    终止条件:Delta开始下降(前一个Delta < 当前Delta)或遇到数据缺失
  • 生物学意义:左侧区域的最高绝缘分数变化率

向右搜索局部极小值(Trough)

$rightSearchIndex = $yIndex + 1;
while(($rightSearchIndex < ($numHeaders-2)) and ($matrixDelta->{$inc2header->{ y }->{$rightSearchIndex}} ne "NA") and ($matrixDelta->{$inc2header->{ y }->{$rightSearchIndex+1}} ne "NA") and ($matrixDelta->{$inc2header->{ y }->{$rightSearchIndex+1}} <= $matrixDelta->{$inc2header->{ y }->{$rightSearchIndex}})
) {$rightSearchIndex++;  # 向右移动直到Delta不再递减
}
my $rightDeltaBound = $matrixDelta->{$inc2header->{ y }->{$rightSearchIndex}};
  • 搜索逻辑:
    从候选边界向右移动,找到Delta值的局部最小值(即曲线下降的终点)
    终止条件:Delta开始上升(后一个Delta > 当前Delta)或遇到数据缺失
  • 生物学意义:右侧区域的最低绝缘分数变化率

然后就是这个边界强度

my $valleyDeltaStrength = "NA";
$valleyDeltaStrength = ($leftDeltaBound - $rightDeltaBound) if(($leftDeltaBound ne "NA") and ($rightDeltaBound ne "NA"));

计算公式:
Strength=LeftPeakDelta−RightTroughDeltaStrength=LeftPeakDelta−RightTroughDelta

综上,再次重申我理解的伪代码:

  TAD边界检测算法 (Hi-C数据分析)                         
───────────────────────────────────────────────────────输入:                                                 • hic_matrix: ICE校正矩阵(10kb bins)            • window_size=500kb (绝缘分析窗口)                   输出:                                                 • boundaries: [[start,end],...] (边界区域列表)        
───────────────────────────────────────────────────────1. 初始化参数                                          bin_size ← 10kb                                    window_bins ← window_size/bin_size                 insulation_scores ← array[n]                      2. 计算绝缘分数 (∀ i ∈ [0,n-1]):                       if i∉[window_bins, n-window_bins-1]:                scores[i] ← NaN                                else:                                             ▸ 方块区域square: rows ∈ [i-window_bins, i-1]cols ∈ [i+1, i+window_bins]      ▸ score = (∑方块) / (有效bins数)        3. 归一化:                                           avg ← mean(scores[有效区域])                        scores ← log₂(scores/avg)                         
───────────────────────────────────────────────────────4. 边界检测:                                           a) 计算delta差分(上下游各100kb窗口):                        δ[i] = mean(left_diff) - mean(right_diff)       b) 候选边界:                                        ∀i where δ[i]>0 ∧ δ[i+1]<0                      c) 强度过滤:                                        strength = (left_peak - right_valley)keep if strength ≥ 0.1                          
───────────────────────────────────────────────────────                                                        
5. 输出边界区域:                                       ∀boundary → [boundary±3 bins] (±30kb)              

此处原文获取了对应作为边界的bin之后,再用了上下游30kb,也就是3个bin来延伸对应效果最好的的边界。

如果要严谨对应源代码perl脚本一点,就是

TAD边界检测算法 (Hi-C数据分析)
───────────────────────────────────────────────────────
输入:• hic_matrix: 对称的ICE校正矩阵(等距bin)• window_size=500kb (默认绝缘窗口)• delta_span=window_size/2 (默认差分窗口)
输出:*.boundaries (边界区域bed)
───────────────────────────────────────────────────────
1. 初始化参数bin_size ← headerSpacing (从矩阵元数据获取)window_bins ← ceil((window_size - bin_size)/bin_size) +1delta_bins ← ceil(delta_span/bin_size)if delta_bins是偶数: delta_bins +=1 (确保奇数窗口)2. 绝缘分数计算:for y in [window_bins, n-window_bins-1]:startY = y - window_binsendY = ystartX = y + 1endX = y + window_bins +1boxData = []for y2 in [startY, endY):for x2 in [startX, endX):if matrix[y2][x2] == -7337: 跳过缺失值if ignoreZero and matrix[y2][x2] == 0: 跳过零值boxData.append(matrix[y2][x2])if 有效数据点 < 总数据点/2: 跳过该binscore = 根据insulationMode计算(boxData) # mean/sum/median3. 归一化处理:valid_scores = 过滤NaN值(scores)avg = mean(valid_scores)for score in scores:if score和avg都不为0:score = log2(score/avg)  # Perl实际使用自然对数换算else:score = score - avg  # 简单中心化4. 边界检测:a) 计算delta差分:for y in [0, numHeaders):left_mean = mean( insulation[y-delta_bins...y] - insulation[y] )right_mean = mean( insulation[y...y+delta_bins] - insulation[y] )delta[y] = left_mean - right_meanb) 候选边界检测:- 遍历delta符号变化点(正→负)- 用matrixDeltaSquare标记(+1表示正delta,-1表示负delta)c) 强度过滤:for 每个候选边界y:left_peak = 向左搜索直到delta不再增加right_valley = 向右搜索直到delta不再减少strength = delta[left_peak] - delta[right_valley]if strength < noiseThreshold(默认0.1): 剔除5. 输出结果:- 原始边界坐标 ± (boundaryMarginOfError * bin_size)

3,Implementation实现

(1)cooltools:

https://cooltools.readthedocs.io/en/latest/notebooks/insulation_and_boundaries.html

contact frequencies between upstream and downstream loci——》其实这个说法和我们对across绝缘的理解是一致的

from cooltools import insulation

其实从API中我们已经很清楚了diamond window这个概念,其实就是我上面提到的square概念,diamond window to calculate the insulation score

(2)GENOVA:

https://rdrr.io/github/robinweide/GENOVA/man/insulation_score.html

TAD boundaries can be identified as local minima in the insulation score

因为GENOVA是用R写的,所以我们可以看一下call_TAD_insulation以及tornado_insulation这两个函数的具体实现细节。

(3)FAN-C

https://vaquerizaslab.github.io/fanc/fanc-executable/fanc-analyse-hic/domains.html

Use fanc insulation to calculate the insulation score from the command line:usage: fanc insulation [-h] [-o OUTPUT_FORMAT][-w WINDOW_SIZES [WINDOW_SIZES ...]] [-r REGION] [-i][--offset OFFSET] [-L] [-N][--normalisation-window NORMALISATION_WINDOW] [-s] [-g][--trim-mean TRIM_MEAN] [-tmp]input [output]

我们不用看其他的参数,其实关键的都是window这个参数,也就是square,而且我们可以发现,Window size must be multiple of binsize(也就是侧翼flank区域得是bin size的倍数,那么square自然也就是bin size的倍数了)

同时这里也提到了由于单个窗口的大小可能容易出现局部矩阵差异,所以建议是同时计算多个window_size的IS score

4,识别TAD的另外一种常见算法:directionality index

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/87268.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/87268.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/87268.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电脑系统重装有什么用?

一、解决系统软件问题 1、修复系统崩溃与错误 系统出现频繁蓝屏、死机、启动失败或程序运行异常&#xff08;如驱动冲突、系统文件损坏&#xff09; 2、清除恶意软件与病毒 电脑中病毒或恶意软件难以通过杀毒软件彻底清除 二、优化系统性能 1、清理冗余文件与设置 长时间…

js随机生成一个颜色

在 JavaScript 中&#xff0c;随机生成颜色有多种方式&#xff0c;以下是最常见的几种实现方法&#xff1a; 方法1&#xff1a;生成随机十六进制颜色&#xff08;如 #FFFFFF&#xff09; 这是最常见的方式&#xff0c;生成格式为 #RRGGBB 的颜色字符串&#xff1a; function…

运维打铁: 服务器防火墙策略配置与管理

文章目录 思维导图一、防火墙基础1. 防火墙概念2. 常见防火墙类型3. 防火墙工作原理 二、策略配置1. 规则制定原则2. 端口与服务开放Linux 系统&#xff08;以 iptables 为例&#xff09;Windows 系统&#xff08;以 Windows 防火墙为例&#xff09; 3. IP 地址过滤允许特定 IP…

locate 命令更新机制详解

文章目录 **一、定时更新的实现载体&#xff1a;crontab 任务****二、定时任务的配置逻辑****三、更新触发的额外机制****四、更新流程的性能优化****五、常见问题与解决方案****总结** 一、定时更新的实现载体&#xff1a;crontab 任务 Linux 系统通常通过 crontab 定时任务 …

docker部署nacos【单机模式使用mysql,使用.env配置】(更新:2025/7/1~)

视频 我的个人视频&#xff0c;有详细步骤 使用docker部署nacos_哔哩哔哩_bilibili 环境 虚拟机&#xff1a;VM&#xff0c;CentOS7 远程连接工具&#xff1a;MobaXterm 使用工具 随机生成字符串&#xff1a; 随机字符串生成器 | 菜鸟工具 Base64编码&#xff1a; B…

如何安全地清除笔式驱动器

您是否正在寻找安全清除笔式驱动器的方法&#xff1f;如果是的话&#xff0c;您可以从本文中得到4个有效的解决方案。无论您准备出售还是捐赠您的笔式驱动器&#xff0c;您都可以轻松清空笔式驱动器。虽然简单的删除似乎就足够了&#xff0c;但残留的数据通常可以恢复。因此&am…

信息新技术

目录 分布式处理基础 一、基础概念 二、通信与网络 三、分布式协调与一致性 四、分布式存储与数据库 五、分布式计算框架 六、容错与高可用 七、负载均衡与调度 八、安全与监控 九、常见分布式系统设计模式 十、典型系统与工具学习 区块链 区块链的核心技术 物联…

创客匠人解析创始人 IP 定位:从专业度到用户心智的占领之道

在知识付费领域&#xff0c;创始人 IP 的定位往往决定了商业变现的天花板。创客匠人通过服务 5 万 知识博主的实践经验&#xff0c;揭示了一个核心逻辑&#xff1a;定位的本质不是简单的标签设定&#xff0c;而是通过持续提升专业度&#xff0c;以实际成果占领用户心智。这一过…

详解Kafka如何保证消息可靠性

Kafka 通过多个环节的精心设计和配置&#xff0c;能够提供高可靠的消息传递保证&#xff0c;最大限度地减少消息丢失的可能性。这需要生产者、Broker 和消费者三方的协同配置才能实现端到端的不丢失。以下是关键机制&#xff1a; 一、核心原则&#xff1a;副本机制 (Replicati…

华为云Flexus+DeepSeek征文 | Word办公软件接入华为云ModelArts Studio大模型,实现AI智能办公

前言 在数字化办公时代&#xff0c;人工智能技术正深刻改变着传统办公软件的使用体验和功能边界。将 Word 办公软件与华为云 ModelArts Studio 大模型进行深度融合&#xff0c;借助 AI 的强大能力实现智能化优化&#xff0c;不仅能大幅提升办公效率&#xff0c;还能为用户带来…

基于开源AI大模型AI智能名片S2B2C商城小程序的流量转化与价值沉淀研究

摘要&#xff1a;在数字化商业生态中&#xff0c;公域流量转化已成为企业竞争的核心战场。本文以开源AI大模型AI智能名片S2B2C商城小程序为研究对象&#xff0c;结合服装、健康食品、快时尚等行业的实践案例&#xff0c;系统分析其通过技术赋能实现精准获客、用户留存与商业闭环…

创客匠人拆解知识变现困局:创始人 IP 打造的底层逻辑与实践路径

在知识付费行业竞争愈发激烈的当下&#xff0c;许多内容创作者面临 “流量增长停滞、变现效率低下” 的困境。创客匠人通过对 5 万 知识博主的服务经验&#xff0c;总结出创始人 IP 打造与知识变现的底层逻辑 —— 其核心在于将 “个人影响力” 转化为 “商业闭环”&#xff0…

LabVIEW远程面板交互控制

基于LabVIEW 远程面板&#xff08;Remote Panel&#xff09;技术&#xff0c;实现服务器端 VI 与客户端的远程交互控制&#xff0c;涵盖服务器配置、客户端连接请求、VI 执行状态监测及控制权交接等流程&#xff0c;支持跨 LabVIEW 实例&#xff08;可跨设备&#xff09;的远程…

S7-1200 CPU 与 CP343-1 S7 通信(S7-1200 作为服务器)

S7-1200 CPU 与 CP343-1 S7 通信&#xff08;S7-1200 作为服务器&#xff09; S7-1200 CPU 与 CP343-1 之间的以太网通信通过 S7 通信来实现。当 CP343-1&#xff08;至少标准版&#xff09;作为客户端&#xff0c;S7-1200 作为服务器&#xff0c;需在客户端单边组态连接和编程…

旋转不变子空间( ESPRIT) 算法

旋转不变子空间( ESPRIT) 算法 1.1 ESPRIT 算法模型 以均匀线阵为研究背景&#xff0c;假设有阵元数为&#xff0c;阵元间距为的平面等间距线性天线阵列。设窄带远场信号的 DOA 估计的数学模型为 (1) 式中&#xff0c;为阵列流型阵( 导向矢量阵) 。 1.2 ESPRIT 算法原理 …

HarmonyOS学习记录1

HarmonyOS学习记录1 本文为个人学习记录&#xff0c;仅供参考&#xff0c;如有错误请指出。本文主要记录HarmonyOS基础概念合核心技术理念。 核心技术理念&#xff1a; 一次开发&#xff0c;多端部署&#xff1a; 其含义是一套代码工程&#xff0c;一次开发上架&#xff0c;…

C++特殊类设计 单例模式

在C编程中&#xff0c;特殊类设计和单例模式是两个非常重要的高级主题。特殊类设计涉及到一些特定功能类的实现&#xff0c;如不可拷贝类、不可移动类等。而单例模式是一种创建型设计模式&#xff0c;保证一个类只有一个实例&#xff0c;并提供全局访问点。本文将详细介绍这两个…

springboot集成达梦数据库,取消MySQL数据库,解决问题和冲突

一、驱动与连接配置 更换JDBC驱动 在pom.xml中移除MySQL驱动&#xff0c;添加达梦驱动&#xff08;版本根据DM数据库选择&#xff09;&#xff1a; <dependency><groupId>com.dameng</groupId><artifactId>DmJdbcDriver</artifactId><versi…

Git 使用快速入门:从基础命令到仓库管理全解析

Git 使用快速入门&#xff1a;从基础命令到仓库管理全解析 在软件开发和团队协作的世界里&#xff0c;版本控制系统是不可或缺的工具。而 Git&#xff0c;凭借其强大的功能、高效的性能以及分布式的特性&#xff0c;已然成为当下最受欢迎的版本控制系统。无论是个人开发者管理项…

Go语言项目工程化 —— 日志、配置、错误处理规范

在Go语言中&#xff0c;项目工程化的日志、配置、错误处理规范是保障项目可维护性、可观测性与健壮性的核心实践之一。本章将从三个方面进行详解&#xff1a; 一、日志规范 1. 日志的重要性 • 问题排查的唯一“现场还原”• 性能瓶颈的定位手段• 安全审计的依据 2. 日志库…