Создание массива с отношениями между идентификаторами - PullRequest
1 голос
/ 14 октября 2019

Рассмотрим следующий игрушечный массив a:

a = np.array([[1074279, 937077, 1445858, 1679465], 
              [1074280, 1023600, 1679465, 937077],  
              [1074281, 908450, 1932761, 1100360],  
              [1074282, 1445858, 893656, 908183], 
              [1074283, 1958030, 1932761, 1445858]])

Первый столбец является идентификатором.

Как я могу преобразовать массив таким образом, который показывает, когда идентификатор связан с другим? Отношение существует, если два идентификатора имеют общее хотя бы одно значение в столбцах 2 - 4 из a.

Конечным результатом должен быть массив b ниже:

b = np.array([[1, 1, 0, 1, 1],
              [1, 1, 0, 0, 0],
              [0, 0, 1, 0, 1],
              [1, 0, 0, 1, 1],
              [1, 0, 1, 1, 1]])

Возможно, это можно лучше понять следующим образом:

         1074279 1074280 1074281 1074282 1074283
1074279     1       1       0       1       1
1074280     1       1       0       0       0
1074281     0       0       1       0       1
1074282     1       0       0       1       1
1074283     1       0       1       1       1

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

Ответы [ 2 ]

2 голосов
/ 14 октября 2019

Наружное равенство выполняет работу для векторизованного решения -

In [90]: np.equal.outer(a[:,1:],a[:,1:]).any(axis=(1,3)).view('i1')
Out[90]: 
array([[1, 1, 0, 1, 1],
       [1, 1, 0, 0, 0],
       [0, 0, 1, 0, 1],
       [1, 0, 0, 1, 1],
       [1, 0, 1, 1, 1]], dtype=int8)

Объяснение

По сути, мы выполняем сравнение парных равенств для всех строк и внутри каждогоСтрока парного сравнения на равенство с np.equal.outer(..). Сравнение на равенство представляет собой массив 4D. Таким образом, для среза a[:,1:], имеющего форму (m,n), мы получили бы массив сравнения равенств формы (m,n,m,n). Итак, затем мы ANY уменьшаем его по осям - 1 и 3, чтобы получить двумерный логический массив формы (m,m), и это наш окончательный результат после преобразования в массив int.

Альтернатива с явным расширением измерения была бы -

In [92]: (a[:,1:,None,None]==a[:,1:]).any(axis=(1,3)).view('i1')
Out[92]: 
array([[1, 1, 0, 1, 1],
       [1, 1, 0, 0, 0],
       [0, 0, 1, 0, 1],
       [1, 0, 0, 1, 1],
       [1, 0, 1, 1, 1]], dtype=int8)

Таким образом, единственное изменение заключается в том, что мы добавляем новые оси для первой версии среза с помощью None/np.newaxis для создания4D версия. Затем это сравнивается с исходной 2D-версией для получения логического массива по сравнению с 4D-равенством.

1 голос
/ 14 октября 2019

Более простое классическое решение, которое легко понять:

def has_in_common(a1, a2):
    """
    @param a1, a2: two input arrays
    @returns True if a1 and a2 has at least one value in common, otherwise False
    """
    for v1 in a1[1:]:
        for v2 in a2[1:]:
            if v1 == v2:
                return True
    return False

def relation_matrix(a):
    """
    @param a: an input array
    @returns m a matrix specifying the relationship between the rows of a
    ex: a = [[1074279, 937077, 1445858, 1679465], 
              [1074280, 1023600, 1679465, 937077],  
              [1074281, 908450, 1932761, 1100360],  
              [1074282, 1445858, 893656, 908183], 
              [1074283, 1958030, 1932761, 1445858]]
        m = [[1, 1, 0, 1, 1],
              [1, 1, 0, 0, 0],
              [0, 0, 1, 0, 1],
              [1, 0, 0, 1, 1],
              [1, 0, 1, 1, 1]]
        more precisely
        m =      1074279 1074280 1074281 1074282 1074283
        1074279     1       1       0       1       1
        1074280     1       1       0       0       0
        1074281     0       0       1       0       1
        1074282     1       0       0       1       1
        1074283     1       0       1       1       1
    """

    m = np.zeros((a.shape[0], a.shape[0]))
    for i in range(len(a)):
        for j in range(len(a)):
            if has_in_common(a[i], a[j]):
                m[i, j] = 1
    return m.astype('int')

Демонстрация:

In [1]:relation_matrix(a)
Out[1]: 
array([[1, 1, 0, 1, 1],
       [1, 1, 0, 0, 0],
       [0, 0, 1, 0, 1],
       [1, 0, 0, 1, 1],
       [1, 0, 1, 1, 1]])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...