Допустим, у меня есть следующий 2D-массив:
import numpy as np
np.random.seed(123)
a = np.random.randint(1, 6, size=(5, 3))
, который выдает:
In [371]: a
Out[371]:
array([[3, 5, 3],
[2, 4, 3],
[4, 2, 2],
[1, 2, 2],
[1, 1, 2]])
есть ли более эффективный (Numpy, Pandas и т. Д.) Способ вычислениячастота всех пар чисел, отличных от следующего решения ?
from collections import Counter
from itertools import combinations
def pair_freq(a, sort=False, sort_axis=-1):
a = np.asarray(a)
if sort:
a = np.sort(a, axis=sort_axis)
res = Counter()
for row in a:
res.update(combinations(row, 2))
return res
res = pair_freq(a)
для получения чего-то подобного:
In [38]: res
Out[38]:
Counter({(3, 5): 1,
(3, 3): 1,
(5, 3): 1,
(2, 4): 1,
(2, 3): 1,
(4, 3): 1,
(4, 2): 2,
(2, 2): 2,
(1, 2): 4,
(1, 1): 1})
или:
In [39]: res.most_common()
Out[39]:
[((1, 2), 4),
((4, 2), 2),
((2, 2), 2),
((3, 5), 1),
((3, 3), 1),
((5, 3), 1),
((2, 4), 1),
((2, 3), 1),
((4, 3), 1),
((1, 1), 1)]
PS результирующий набор данных может выглядеть иначе - например, как многоиндексный Pandas DataFrame или что-то еще.
Я пытался увеличить размерность массива a
и использовать np.isin()
вместе ссписок комбинаций всех пар, но я все еще не мог избавиться от петли.
ОБНОВЛЕНИЕ:
(a) Вас интересует только частота комбинаций из 2 чисел (и не интересует частота комбинаций из 3 чисел)?
да, меня интересуют комбинации пар (2только цифры)
(b) Вы хотите считать (3,5) отличнымt из (5,3) или вы хотите рассматривать их как два вхождения одного и того же?
на самом деле оба подхода хороши - я всегда могу предварительно отсортировать свой массив, если мне нужно:
a = np.sort(a, axis=1)
ОБНОВЛЕНИЕ 2:
Хотите, чтобы различие между (a, b) и (b, a) происходило только из-за столбца источникаа и б или еще как?Поймите этот вопрос, рассмотрите три строки [[1,2,1], [3,1,2], [1,2,5]]
.Как вы думаете, что должно быть на выходе здесь?Какими должны быть отдельные 2-кортежи и какими должны быть их частоты?
In [40]: a = np.array([[1,2,1],[3,1,2],[1,2,5]])
In [41]: a
Out[41]:
array([[1, 2, 1],
[3, 1, 2],
[1, 2, 5]])
Я бы ожидал следующий результат:
In [42]: pair_freq(a).most_common()
Out[42]:
[((1, 2), 3),
((1, 1), 1),
((2, 1), 1),
((3, 1), 1),
((3, 2), 1),
((1, 5), 1),
((2, 5), 1)]
, потому что он более гибкий, поэтому яхочу сосчитать (a, b) и (b, a) как одну и ту же пару элементов, я мог бы сделать это:
In [43]: pair_freq(a, sort=True).most_common()
Out[43]: [((1, 2), 4), ((1, 1), 1), ((1, 3), 1), ((2, 3), 1), ((1, 5), 1), ((2, 5), 1)]