Подсчитать значение столбцов в соответствии со значением в конкретной строке в матрице питона - PullRequest
3 голосов
/ 12 марта 2019
mat = [ [1,3,5,7], [1,2,5,7], [8,2,3,4] ]

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

Массив результатов для каждой строки будет

row0 = [2,1,2,2]
row1 = [2,2,2,2]
row3 = [1,2,1,1]

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

Я пытаюсь использовать функцию numpy count_nonzero, но для этого требуется условие, которое я не смогу распространить на всесправочная строка

Ответы [ 3 ]

1 голос
/ 12 марта 2019

Простое векторизованное решение заключается в использовании

mat = np.array([
    [1,3,5,7],
    [1,2,5,7],
    [8,2,3,4]
])

tmp = mat + np.arange(mat.shape[1]) * np.max(mat)
np.bincount(tmp.ravel())[tmp]
# array([[2, 1, 2, 2],
#        [2, 2, 2, 2],
#        [1, 2, 1, 1]])

Время для матрицы 64x8640:

# 4 ms ± 300 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1 голос
/ 12 марта 2019

Вот решение numpy с использованием `argsort.Это может обрабатывать нецелые записи:

import numpy as np

def count_per_col(a):
    o = np.argsort(a, 0)
    ao = np.take_along_axis(a, o, 0)
    padded = np.ones((ao.shape[1], ao.shape[0]+1), int)
    padded[:, 1:-1] = np.diff(ao, axis=0).T
    i, j = np.where(padded)
    j = np.maximum(np.diff(j), 0)
    J = j.repeat(j)
    out = np.empty(a.shape, int)
    np.put_along_axis(out, o, J.reshape(out.shape[::-1]).T, 0)
    return out

mat = np.array([[1,3,5,7], [1,2,5,7], [8,2,3,4]])

count_per_col(mat)
# array([[2, 1, 2, 2],
#        [2, 2, 2, 2],
#        [1, 2, 1, 1]])

Как быстро?

from timeit import timeit

large = np.random.randint(0, 100, (100, 10000))
large = np.random.random(100)[large]

timeit(lambda: count_per_col(large), number=10)/10
# 0.1332556433044374
0 голосов
/ 12 марта 2019

Существует простое решение: 1) подсчитать количество элементов в каждом столбце, 2) использовать это количество для построения другого списка.

from collections import Counter

mat = [[1,3,5,7], [1,2,5,7], [8,2,3,4]]
col_counts = [Counter(col) for col in zip(*mat)]
results = [[count[cell] for cell, count in zip(row, col_counts)] for row in mat]

Результат:

[[2, 1, 2, 2], [2, 2, 2, 2], [1, 2, 1, 1]]

Обратите внимание, что в первой строке [1,3,5,7] элемент 3 соответствует 1, а не нулю, поскольку у вас ровно один3 во втором столбце [3, 2, 2].

Немного более легкое решение (используется только один счетчик за раз), я также детализировал построчное преобразование, чтобы его было легче понять:

def row_count(mat):
    def row_transform(row):
        count = Counter(row)
        return [count[e] for e in row]

    matT = zip(*mat)
    matT_count = map(row_transform, matT)
    return zip(*matT_count)

Если вам нужен список, то вы можете вызвать list(row_count(mat)), если вам нужно только перебрать строки, вы можете сделать for row in row_count(mat):, и это сэкономит вам немного памяти (создание только одной строки за раз).

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