有趣的 Pandas 数据框问题:如何在两列上删除重复项(反向) - 对于具有共同属性的每一行?
Interesting Pandas dataframe problem: how to drop duplicates (inverse) over two columns - for each row with a common attribute?
过滤掉反向重复项后,我必须计算实际有多少个重复项。这是我的(工作示例)代码,但它太慢了,对于 90 000 多行.. 使用 iterrows:
import pandas as pd
data = {'id_x':[1,2,3,4,5,6],
'ADDICTOID_x':['BFO:0000023', 'MF:0000016', 'BFO:0000023', 'MF:0000016', 'MF:0000016', 'ADDICTO:0000872'],
'PMID':[34116904, 34116904, 34112174, 34112174, 34112174, 22429780],
'LABEL_x':['role', 'human being', 'role', 'human being', 'human being', 'FDA'],
'id_y':[11,12,13,14,15,16],
'ADDICTOID_y':['MF:0000016', 'BFO:0000023', 'MF:0000016', 'BFO:0000023', 'BFO:0000023', 'ADDICTO:0000904'],
'LABEL_y':['human being', 'role', 'human being', 'role', 'role', '']}
dcp = pd.DataFrame(data)
dcp = dcp.drop(dcp[dcp.LABEL_x == dcp.LABEL_y].index)
for index, row in dcp.iterrows(): # THIS IS SLOW
if ((dcp['ADDICTOID_x'] == row['ADDICTOID_y'])
& (dcp['ADDICTOID_y'] == row['ADDICTOID_x'])
& (dcp['PMID'] == row['PMID'])).any(): # Does the inverse of this row exist in the table?
dcp.drop(index, inplace=True)
print("dcp after drop: ")
print(dcp)
我不能只使用 dcp.duplicated(subset=['ADDICTOID_x', 'ADDICTOID_y'], keep='first')
因为它会删除所有重复项(有很多),我只想一个一个地做,而且 'PMID' 也需要匹配.同样,(dcp.ADDICTOID_x + dcp.ADDICTOID_y).isin(dcp.ADDICTOID_y + dcp.ADDICTOID_x) & (dcp.PMID == dcp.PMID)
查找到处都有重复项的行。 Iterrows 并逐一测试是我发现的唯一有效方法,但它太慢了。有人知道解决这个问题的方法吗?
过滤反向重复项后,我是这样计算的:
data_chord_plot = dcp.groupby(['LABEL_x', 'LABEL_y'], as_index=False)[['PMID']].count() data_chord_plot.columns = ['source','target','value']
编辑:在这个简单的例子中,第 1 行和第 3 行被删除,因为它们是第 2 行和第 4 行的反向副本。
编辑:我需要消除在两列上具有反向重复项的行的“镜像”图像,但每行只有一个具有重复项。有些行没有镜像。
(慢)示例的正确输出:
id_x ADDICTOID_x PMID LABEL_x id_y ADDICTOID_y LABEL_y
1 2 MF:0000016 34116904 人类 12 BFO:0000023 角色
3 4 MF:0000016 34112174 人 14 BFO:0000023 角色
4 5 MF:0000016 34112174 人 15 BFO:0000023 角色
5 6 ADDICTO:0000872 22429780 FDA 16 ADDICTO:0000904
也许有更短的方法,但我可以考虑将 df
与其反向自身合并,然后只留下没有先前匹配的行。所以不是你的循环做:
dcp = dcp.merge(dcp[['id_x', 'PMID', 'ADDICTOID_x', 'ADDICTOID_y']].rename({'id_x': 'inv_id', 'ADDICTOID_x': 'inv_y', 'ADDICTOID_y': 'inv_x'}, axis=1), how='left')
dcp['was'] = (dcp['ADDICTOID_x'] == dcp['inv_x']) & (dcp['ADDICTOID_y'] == dcp['inv_y']) & (dcp['id_x'] > dcp['inv_id'])
dcp = dcp.sort_values(['id_x', 'was']).drop_duplicates('id_x', keep='last')
dcp = dcp.loc[~dcp['was'], 'id_x': 'LABEL_y']
创建 ADDICTOID_xy
的排序元组并使用 drop_duplicates
和正确的子集:
dcp['ADDICTOID'] = dcp[['ADDICTOID_x', 'ADDICTOID_y']].apply(sorted, axis=1) \
.apply(tuple)
out = dcp.drop_duplicates(subset=['ADDICTOID', 'PMID'], keep='first')
>>> out
id_x ADDICTOID_x PMID LABEL_x id_y ADDICTOID_y LABEL_y ADDICTOID
0 1 BFO:0000023 34116904 role 11 MF:0000016 human being (BFO:0000023, MF:0000016)
2 3 BFO:0000023 34112174 role 13 MF:0000016 human being (BFO:0000023, MF:0000016)
5 6 ADDICTO:0000872 22429780 FDA 16 ADDICTO:0000904 (ADDICTO:0000872, ADDICTO:0000904)
过滤掉反向重复项后,我必须计算实际有多少个重复项。这是我的(工作示例)代码,但它太慢了,对于 90 000 多行.. 使用 iterrows:
import pandas as pd
data = {'id_x':[1,2,3,4,5,6],
'ADDICTOID_x':['BFO:0000023', 'MF:0000016', 'BFO:0000023', 'MF:0000016', 'MF:0000016', 'ADDICTO:0000872'],
'PMID':[34116904, 34116904, 34112174, 34112174, 34112174, 22429780],
'LABEL_x':['role', 'human being', 'role', 'human being', 'human being', 'FDA'],
'id_y':[11,12,13,14,15,16],
'ADDICTOID_y':['MF:0000016', 'BFO:0000023', 'MF:0000016', 'BFO:0000023', 'BFO:0000023', 'ADDICTO:0000904'],
'LABEL_y':['human being', 'role', 'human being', 'role', 'role', '']}
dcp = pd.DataFrame(data)
dcp = dcp.drop(dcp[dcp.LABEL_x == dcp.LABEL_y].index)
for index, row in dcp.iterrows(): # THIS IS SLOW
if ((dcp['ADDICTOID_x'] == row['ADDICTOID_y'])
& (dcp['ADDICTOID_y'] == row['ADDICTOID_x'])
& (dcp['PMID'] == row['PMID'])).any(): # Does the inverse of this row exist in the table?
dcp.drop(index, inplace=True)
print("dcp after drop: ")
print(dcp)
我不能只使用 dcp.duplicated(subset=['ADDICTOID_x', 'ADDICTOID_y'], keep='first')
因为它会删除所有重复项(有很多),我只想一个一个地做,而且 'PMID' 也需要匹配.同样,(dcp.ADDICTOID_x + dcp.ADDICTOID_y).isin(dcp.ADDICTOID_y + dcp.ADDICTOID_x) & (dcp.PMID == dcp.PMID)
查找到处都有重复项的行。 Iterrows 并逐一测试是我发现的唯一有效方法,但它太慢了。有人知道解决这个问题的方法吗?
过滤反向重复项后,我是这样计算的:
data_chord_plot = dcp.groupby(['LABEL_x', 'LABEL_y'], as_index=False)[['PMID']].count() data_chord_plot.columns = ['source','target','value']
编辑:在这个简单的例子中,第 1 行和第 3 行被删除,因为它们是第 2 行和第 4 行的反向副本。
编辑:我需要消除在两列上具有反向重复项的行的“镜像”图像,但每行只有一个具有重复项。有些行没有镜像。
(慢)示例的正确输出:
id_x ADDICTOID_x PMID LABEL_x id_y ADDICTOID_y LABEL_y
1 2 MF:0000016 34116904 人类 12 BFO:0000023 角色
3 4 MF:0000016 34112174 人 14 BFO:0000023 角色
4 5 MF:0000016 34112174 人 15 BFO:0000023 角色
5 6 ADDICTO:0000872 22429780 FDA 16 ADDICTO:0000904
也许有更短的方法,但我可以考虑将 df
与其反向自身合并,然后只留下没有先前匹配的行。所以不是你的循环做:
dcp = dcp.merge(dcp[['id_x', 'PMID', 'ADDICTOID_x', 'ADDICTOID_y']].rename({'id_x': 'inv_id', 'ADDICTOID_x': 'inv_y', 'ADDICTOID_y': 'inv_x'}, axis=1), how='left')
dcp['was'] = (dcp['ADDICTOID_x'] == dcp['inv_x']) & (dcp['ADDICTOID_y'] == dcp['inv_y']) & (dcp['id_x'] > dcp['inv_id'])
dcp = dcp.sort_values(['id_x', 'was']).drop_duplicates('id_x', keep='last')
dcp = dcp.loc[~dcp['was'], 'id_x': 'LABEL_y']
创建 ADDICTOID_xy
的排序元组并使用 drop_duplicates
和正确的子集:
dcp['ADDICTOID'] = dcp[['ADDICTOID_x', 'ADDICTOID_y']].apply(sorted, axis=1) \
.apply(tuple)
out = dcp.drop_duplicates(subset=['ADDICTOID', 'PMID'], keep='first')
>>> out
id_x ADDICTOID_x PMID LABEL_x id_y ADDICTOID_y LABEL_y ADDICTOID
0 1 BFO:0000023 34116904 role 11 MF:0000016 human being (BFO:0000023, MF:0000016)
2 3 BFO:0000023 34112174 role 13 MF:0000016 human being (BFO:0000023, MF:0000016)
5 6 ADDICTO:0000872 22429780 FDA 16 ADDICTO:0000904 (ADDICTO:0000872, ADDICTO:0000904)