在numpy中快速找到对称对


15
from itertools import product
import pandas as pd

df = pd.DataFrame.from_records(product(range(10), range(10)))
df = df.sample(90)
df.columns = "c1 c2".split()
df = df.sort_values(df.columns.tolist()).reset_index(drop=True)
#     c1  c2
# 0    0   0
# 1    0   1
# 2    0   2
# 3    0   3
# 4    0   4
# ..  ..  ..
# 85   9   4
# 86   9   5
# 87   9   7
# 88   9   8
# 89   9   9
# 
# [90 rows x 2 columns]

如何快速查找,识别和删除此数据帧中所有对称对的最后一个重复项?

对称对的一个示例是“(0,1)”等于“(1,0)”。后者应删除。

该算法必须快速,因此建议使用numpy。不允许转换为python对象。


1
你能举一个你所理解的例子symmetric pairs吗?
yatu

(0,1)==(1,0)为True
该Unfun猫

1
(0,1)==(0,1)是否也成立?
wundermahn

@JerryM。是的,但使用df.drop_duplicates()

2
@ molybdenum42我使用itertools产品创建示例,数据本身不是使用itertools产品创建的。
Unfun Cat,

Answers:


13

您可以对值进行排序,然后groupby

a= np.sort(df.to_numpy(), axis=1)
df.groupby([a[:,0], a[:,1]], as_index=False, sort=False).first()

选项2:如果您有很多双c1, c2groupby可能会很慢。在这种情况下,我们可以分配新值并按以下条件过滤drop_duplicates

a= np.sort(df.to_numpy(), axis=1) 

(df.assign(one=a[:,0], two=a[:,1])   # one and two can be changed
   .drop_duplicates(['one','two'])   # taken from above
   .reindex(df.columns, axis=1)
)

7

一种方法是使用np.uniquewith return_index=True并使用结果来索引数据帧:

a = np.sort(df.values)
_, ix = np.unique(a, return_index=True, axis=0)

print(df.iloc[ix, :])

    c1  c2
0    0   0
1    0   1
20   2   0
3    0   3
40   4   0
50   5   0
6    0   6
70   7   0
8    0   8
9    0   9
11   1   1
21   2   1
13   1   3
41   4   1
51   5   1
16   1   6
71   7   1
...

1
是的,否则唯一的无法检测到对称对@DanielMesejo
yatu

好的,我知道了,您正在对
货币

是的,但我的意思是您将[1,0]转换为[0,1]对吗?
Dani Mesejo,

6

frozenset

mask = pd.Series(map(frozenset, zip(df.c1, df.c2))).duplicated()

df[~mask]

1
您不是在这里遍历每个列中的元组吗?不过,请投票。
Unfun Cat,

是的,我正在迭代。不,它没有您想的那么慢。
piRSquared,

5

我会做

df[~pd.DataFrame(np.sort(df.values,1)).duplicated().values]

从熊猫和numpy tri

s=pd.crosstab(df.c1,df.c2)
s=s.mask(np.triu(np.ones(s.shape)).astype(np.bool) & s==0).stack().reset_index()

5

这是一个基于NumPy的整数-

def remove_symm_pairs(df):
    a = df.to_numpy(copy=False)
    b = np.sort(a,axis=1)
    idx = np.ravel_multi_index(b.T,(b.max(0)+1))
    sidx = idx.argsort(kind='mergesort')
    p = idx[sidx]
    m = np.r_[True,p[:-1]!=p[1:]]
    a_out = a[np.sort(sidx[m])]
    df_out = pd.DataFrame(a_out)
    return df_out

如果要保留索引数据不变,请使用return df.iloc[np.sort(sidx[m])]

对于通用数字(整数/浮点数等),我们将使用view-based一个-

# https://stackoverflow.com/a/44999009/ @Divakar
def view1D(a): # a is array
    a = np.ascontiguousarray(a)
    void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
    return a.view(void_dt).ravel()

而只需更换步骤来获得idxidx = view1D(b)remove_symm_pairs


1

如果这需要快速,如果你的变量是整数,那么下面的技巧可以帮助:让v,w是你的矢量的列; 构造[v+w, np.abs(v-w)] =: [x, y]; 然后按字典顺序排序此矩阵,删除重复项,最后将其映射回[v, w] = [(x+y), (x-y)]/2

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.