首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Python 3:删除表中的重叠

Python 3:删除表中的重叠
EN

Stack Overflow用户
提问于 2019-03-03 13:01:10
回答 5查看 1.3K关注 0票数 2

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

代码语言:javascript
运行
复制
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进行排序,如果有重叠的点击,则保持较低的value

到目前为止,这是我的代码,它首先由from启动,然后由value启动

代码语言:javascript
运行
复制
import pandas
df = pandas.read_csv("table", sep='\s+', names=["id", "hit", "from", "to", "value"])
df.sort_values(['from', "value"]).groupby('id')

但是,如何检查重叠(fromto) &删除得分较高的重叠?

这是我的预期输出:

代码语言:javascript
运行
复制
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有两个相同值的重叠命中,因此这两个条目都将被踢出。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2019-04-20 09:53:52

首先,我们介绍了一个惟一的ID并使用了pd.Interval

代码语言:javascript
运行
复制
df['ID'] = range(df.shape[0])
df['Interval'] = df.apply(lambda x: pd.Interval(x['from'], x['to'], closed='both'), axis=1)

在此之后,我们将自己加入df并计算重叠部分:

代码语言:javascript
运行
复制
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_x']).agg(list)

并通过深度优先搜索计算连接部件。

代码语言:javascript
运行
复制
def connections(graph, id):
    def dict_to_df(d):
        df = pd.DataFrame(data=[d.keys(), d.values()], index=['ID', 'Subgraph']).T
        df['id'] = id
        return df[['id', 'Subgraph', 'ID']]

    def dfs(node, num):
        visited[node] = num
        for _node in graph.loc[node].iloc[0]:
            if _node not in visited:
                dfs(_node, num)

    visited = {}
    graph = graph.loc[id]
    for (num, node) in enumerate(graph.index):
        if node not in visited:
            dfs(node, num)

    return dict_to_df(visited)

dfs = []
for id in graph.index.get_level_values(0).unique():
    dfs.append(connections(graph, id))

conns = pd.concat(dfs)

conns持有连接的组件,我们可以将它们放在一起:

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

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

代码语言:javascript
运行
复制
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]

现在我们结束了:

代码语言:javascript
运行
复制
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
票数 1
EN

Stack Overflow用户

发布于 2019-04-16 11:17:12

如果您不介意代码中的多行代码,那么这样的代码应该可以工作,我想.(这里是python新手.) 来源

代码语言:javascript
运行
复制
df.sort_values(['from', "value"]).groupby('id')
df.drop_duplicates(subset=['id', 'value'], keep=False, inplace=True)

参数设置为false,因为您根本不想要重复的行。

,其结果是:

代码语言:javascript
运行
复制
  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

和要摆脱混乱的索引列:

代码语言:javascript
运行
复制
df.reset_index(drop=True, inplace=True)

,其结果是:

代码语言:javascript
运行
复制
  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:这是我第一次给出答案,所以请温柔一点。而且我还在学英语。

票数 2
EN

Stack Overflow用户

发布于 2019-04-16 20:53:05

代码语言:javascript
运行
复制
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

因此,我的解决方案使用掩码检查重叠。通过对“from”值进行排序,并检查next“from”值是否小于“to”值。np.inf只需确保第一个值在分组中始终为0。

然后,我们在df中将掩码设置为自己的列。然后,我们按所需的一切进行分组,删除任何副本,重新设置索引,然后最后删除掩码。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54969074

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档