Python 3:删除表中的重叠

Python 3:删除表中的重叠,python,pandas,sorting,filtering,Python,Pandas,Sorting,Filtering,我有一个表(程序的简化输出),需要过滤: id hit from to value A hit1 56 102 0.00085 B hit2 89 275 0.00034 B hit3 240 349 0.00034 C hit4 332 480 3.40E-15 D hit5 291 512 3.80E-24 D hit6 287 313 0.00098 D hit7 381 426 0.00098 D hi

我有一个表(程序的简化输出),需要过滤:

id   hit from   to value
A   hit1    56  102 0.00085
B   hit2    89  275 0.00034
B   hit3    240 349 0.00034
C   hit4    332 480 3.40E-15
D   hit5    291 512 3.80E-24
D   hit6    287 313 0.00098
D   hit7    381 426 0.00098
D   hit8    287 316 0.0029
D   hit9    373 422 0.0029
D   hit10   514 600 0.0021
对于每个id,
df
应按
from
排序,如果有重叠点击,则保留
值较低的点击

到目前为止,这是我的代码,它首先从
开始,然后从
值开始:

import pandas
df = pandas.read_csv("table", sep='\s+', names=["id", "hit", "from", "to", "value"])
df.sort_values(['from', "value"]).groupby('id')
但是我如何检查重叠(从
)并删除分数较高的重叠

这是我的预期输出:

id   hit from   to valu
A   hit1    56  102 0.00085
C   hit4    332 480 3.40E-15
D   hit5    291 512 3.80E-24
D   hit10   514 600 0.0021
请注意,
id B
有两个相同值的重叠点击,因此这两个条目都将被踢出。

如果您对id='D'进行排序

    id  hit from    to  value
5   D   hit6    287 313 9.800000e-04
7   D   hit8    287 316 2.900000e-03
4   D   hit5    291 512 3.800000e-24
8   D   hit9    373 422 2.900000e-03
6   D   hit7    381 426 9.800000e-04
9   D   hit10   514 600 2.100000e-03
重叠将是:

  • 命中6、8和5=保持5 bc的最小值

  • 命中9和7=kepp 7

  • hit 10是一个人留下的吗


如果您不介意代码中有多行,我想这样应该可以。。。(这里是python新手…)

“keep”参数被设置为false,因为您根本不需要重复的行

结果是:

  id    hit from   to     value
0  A   hit1   56  102   0.00085
3  C   hit4  332  480  3.40E-15
4  D   hit5  291  512  3.80E-24
9  D  hit10  514  600    0.0021
df.reset_index(drop=True, inplace=True)
并且为了摆脱混乱的索引列:

  id    hit from   to     value
0  A   hit1   56  102   0.00085
3  C   hit4  332  480  3.40E-15
4  D   hit5  291  512  3.80E-24
9  D  hit10  514  600    0.0021
df.reset_index(drop=True, inplace=True)
结果是:

  id    hit from   to     value
0  A   hit1   56  102   0.00085
1  C   hit4  332  480  3.40E-15
2  D   hit5  291  512  3.80E-24
3  D  hit10  514  600    0.0021
PS:这是我第一次给出答案,所以请温柔一点。而且,我还在学习英语。

df=pd.DataFrame({'id':['A','B','B','C','D','D','D','D','D'],
df = pd.DataFrame({'id': ['A', 'B', 'B', 'C', 'D', 'D' ,'D', 'D', 'D', 'D', 'D'],
                  'hit': ['hit1', 'hit2', 'hit3','hit4', 'hit5','hit6', 'hit7','hit8', 'hit9','hit10', 'hit11'],
                  'from': [56,89,240,332,291,287,381,287,373,514, 599],
                  'to':[102,275,349,480,512,313,426,316,422,600, 602],
                  'value': [0.00085,0.00034,0.00034,3.40E-15,3.80E-24,0.00098,0.00098,0.0029,0.0029,0.0021, 0.002]})

overlapMask =  df.sort_values(by = 'from')\
                 .groupby('id')\
                 .apply(lambda x: np.where(x['from'] < x['to'].shift(), 0 , 1).cumsum())\
                 .reset_index()

df['Mask'] = np.concatenate((overlapMask[0].values))


df.drop_duplicates(subset = ['id','value'], keep = False, inplace = True)


df.sort_values(by = 'value')\
  .groupby(['id', 'Mask'])\
  .head(1)\
  .reset_index()\
  .drop(['Mask', 'index'],axis = 1)\
  .sort_values(by = 'id')


    id  hit    from  to    value
2   A   hit1    56  102 8.500000e-04
1   C   hit4    332 480 3.400000e-15
0   D   hit5    291 512 3.800000e-24
3   D   hit11   599 602 2.000000e-03
“hit”:[“hit1”、“hit2”、“hit3”、“hit4”、“hit5”、“hit6”、“hit7”、“hit8”、“hit9”、“hit10”、“hit11]”, ‘from’:[56,89240332291287381287373514599], ‘收件人’:[102275349480512313426316422600602], “值”:[0.00085,0.00034,0.00034,3.40E-15,3.80E-24,0.00098,0.00098,0.0029,0.0029,0.0021,0.002]) 重叠掩码=df.sort_值(by='from')\ .groupby('id'))\ .apply(lambda x:np.where(x['from']
因此,我的解决方案使用遮罩来检查重叠。通过对“from”值进行排序,并检查下一个“from”值是否小于上一个“to”值。inf只是确保分组中的第一个值始终为0


然后,我们在df中将掩码设置为自己的列。然后,我们根据需要进行分组,删除所有重复项,重置索引,最后删除掩码。

首先,我们引入一个唯一的
ID
,并使用:

在此之后,我们将df自身连接起来,并计算重叠部分:

columns = ['id', 'Interval', 'ID']
connected = df[columns].merge(df[columns], on='id')
connected['Overlap'] = connected.apply(lambda x: x['Interval_x'].overlaps(x['Interval_y']), axis=1) 
connected = connected.loc[connected['Overlap'] == True, ['id', 'ID_x', 'ID_y']]
现在我们知道哪些ID重叠,但我们不知道哪些ID构建了一个连接的组件。一般来说,这不能通过像重新排序这样的简单算法来完成,但有一点帮助。所以我们建立了一个图

graph=connected.groupby(['id','id\ux']).agg(list)

并通过

conns
保存连接的组件,我们可以将它们组合在一起:

data=df.merge(conns[['Subgraph','ID']],on=['ID'])

最后一项任务是选择要保留的行:

def select_min(x):
    m = x['value'].min()
    if len(x) > 1 and (x['value'] == m).all():
        return -1
    else:
        return x['value'].idxmin()

selected = data.groupby(['id', 'Subgraph'])['value', 'ID'].apply(select_min)
selected = selected[selected >= 0]
现在我们完成了:

print(df.loc[df.ID.isin(selected), :].drop(columns=['ID', 'Interval']))
  id    hit  from   to         value
0  A   hit1    56  102  8.500000e-04
3  C   hit4   332  480  3.400000e-15
4  D   hit5   291  512  3.800000e-24
9  D  hit10   514  600  2.100000e-03

如果你一组一组地执行,那么一行一行地执行就相当简单了。在pandas中似乎没有一种方法可以有效地编写一个同时对多行和多列进行操作的函数

def strip(group):
    non_overlapping=[]
    overlapping = [list(group.itertuples())[0]]
    end = list(group.itertuples())[0].to
    for row in list(group.itertuples())[1:]:
        if row[3]<=end:
            overlapping.append(row)
            if row.to > end:
                end = row.to
        else:
            non_overlapping.append(reduce_overlap(overlapping))
            overlapping=[row]
    non_overlapping.append(reduce_overlap(overlapping))
    return non_overlapping
为了找到要返回的值,我们按值排序,如果两个值碰巧相同,则不返回任何值

编辑: 这是一个将其应用于我尚未测试的整个数据帧的函数

def nonoverlapping(df):
  return df.Dataframe.from_records([strip(group) for name,group in df.sort_values(['from', "value"]).groupby('id')])

你能在测试数据中加入一些重叠值吗?你能解释一下重叠吗?如果不清楚的话,很抱歉。从和<代码>到作为坐标考虑<代码>。因此,
A
没有任何重叠命中,因为它是唯一的命中,而
B
在坐标240到275处有重叠。而
D
有5个重叠的点击,其中1个必须根据最低的
值选择,但最后的
hit10
D
的其他点击没有重叠。在您的逻辑下,id“D”,hit5应该被删除,但在您的示例中有。我读对你的逻辑了吗?值较低的命中应该不太正确。如你所说,命中6,8,5重叠,但命中9与命中5重叠,命中7与命中9重叠。在这里,从5个选项中选择一个值最低的选项。Hit 10没有重叠,所以请继续。逻辑相当复杂,我本周没有时间复习。抱歉。解决方案不好,没有删除的重叠,不幸的是,数据不是MCVE,因此获取输出,如需要OP。但另一个数据解决方案失败。我同意,此解决方案只是删除重复值,很遗憾……那么可能会有帮助吗@SarahaI收到一个
TypeError:shift()收到一个意外的关键字参数“fill\u value”
这在pandas 0.24.0中似乎是新的,请检查您的pandas版本。我也刚刚检查过,你似乎不需要fill_值,所以你可以删除它。发生的情况是,所有内容的第一个值都是1,而不是0,但这不会影响掩码的分组。@Saraha,您重试了吗?我尝试在表中添加另一行(
D hit1599602 0.0002
)。不幸的是,代码没有考虑到这一点,因为我得到了一个错误的输出…你说的对,我错过了一个bug,我修复了代码,它现在应该可以正常工作了。很抱歉,谢谢你简洁的解释
def reduce_overlap(overlapping):
    overlapping= sorted(overlapping,key=lambda x: x.value)
    if len(overlapping)==1 or overlapping[0].value != overlapping[1].value:
        return overlapping[0]
    else:
        return []
def nonoverlapping(df):
  return df.Dataframe.from_records([strip(group) for name,group in df.sort_values(['from', "value"]).groupby('id')])