Извлекайте уникальные пары минимального расстояния, используя каждый элемент только один раз - PullRequest
2 голосов
/ 26 февраля 2020

Из матрицы расстояний я сгенерировал кадр данных, состоящий из трех столбцов.

Столбец x и y содержит все уникальные комбинации идентификаторов: a, b, c и d. (Идентификаторы упрощены в целях иллюстрации, фактические данные состоят из цепочек цифр, то есть «1234», «2323», «2443»)

Тестовая матрица отсортирована по расстоянию, поскольку меня интересует все уникальные комбинации, содержащие измерения наименьшего расстояния.

Существует ли функция, способная извлекать уникальные пары из столбцов x и y, чтобы каждый элемент появлялся только один раз в любом из столбцов x и y?

В следующем сценарии меня интересует только одна пара, содержащая A, одна пара, содержащая B, и т. Д.

Пример:

Ввод:

test = pd.DataFrame(np.array([['a', 'b', 0.1], ['b', 'a', 0.1], 
                              ['c', 'a', 0.2], ['a', 'c', 0.2], 
                              ['b', 'd', 0.3], ['d', 'b', 0.3], 
                              ['c', 'd', 0.4], ['d', 'c', 0.4]]), columns=['x', 'y', 'distance'])  
test
   x  y distance
0  a  b      0.1
1  b  a      0.1
2  c  a      0.2
3  a  c      0.2
4  b  d      0.3
5  d  b      0.3
6  c  d      0.4
7  d  c      0.4

Желаемый вывод:

   x  y distance
0  a  b      0.1
1  c  d      0.4

Не важно, представляет ли вывод (a, b) или (b, a).

Обратите внимание, что удаление дубликатов в этом примере не является достаточно, поскольку пара (c, d) и (d, c) будет удалена.

РЕДАКТИРОВАТЬ:

Вот (грязный) в то время как l oop, которые обеспечивают правильный вывод, но я надеялся на менее сложное решение для ускорения для l oop, в котором эта функция будет вложенной.

i = 0

while i < len(test):

    comp_x = test.loc[i,'x']
    comp_y = test.loc[i,'y']

    test.loc[i+1:len(test),['x','y']] = test.loc[i+1:len(test),['x','y']][~test.loc[i+1:len(test),:][['x','y']].isin([comp_x])]
    test.loc[i+1:len(test),['x','y']] = test.loc[i+1:len(test),['x','y']][~test.loc[i+1:len(test),:][['x','y']].isin([comp_y])]

    test.dropna(inplace=True)
    test.reset_index(drop=True, inplace=True)

    i+=1

print(test)
   x  y distance
0  a  b      0.1
1  c  d      0.4

Ответы [ 3 ]

1 голос
/ 26 февраля 2020

Пожалуйста, проверьте, если вы ищете:

xy=set()
records=[]

for e in test.itertuples():
    if ((e[1] not in xy) and (e[2] not in xy)):
        records.append(e)
        xy.update(list(e[1:3]))

pd.DataFrame(records).set_index('Index').rename_axis('')

    x   y   distance        
0   a   b   0.1
6   c   d   0.4
0 голосов
/ 26 февраля 2020

Это должно сработать,

Идея состоит в том, чтобы создать новую серию и отсортировать значения вдоль их оси и использовать sort_by

s = test[["x", "y"]].sum(axis=1).apply(
    lambda x: sorted(x)
).explode().drop_duplicates().reset_index(drop=True)


s1 = (
    s.groupby(s.index // 2)
    .agg(",".join)
    .str.split(",", expand=True)
    .rename(columns={0: "x", 1: "y"})
)

test.sort_values("distance").loc[(test["x"].isin(s1["x"])) & (test["y"].isin(s1["y"]))]

out:

   x  y distance
0  a  b      0.1
6  c  d      0.4
0 голосов
/ 26 февраля 2020

Вы можете попробовать объединить столбцы 'x' & 'y' и удалить дубликаты из этого нового столбца


test['filter'] = test[['x', 'y']].apply(lambda row: '-'.join(sorted(row, key=lambda y: ord(y))), axis=1)

test = test.drop_duplicates(subset=['filter']).reset_index()[['x', 'y', 'distance']]

# solution
#    x  y distance
# 0  a  b      0.1
# 1  c  a      0.2
# 2  b  d      0.3
# 3  c  d      0.4

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...