Двумерные массивы, заменяющие значения в соответствии с вхождением - PullRequest
0 голосов
/ 21 октября 2019

У меня много 2D массивов 1161 x 1161, состоящих из 0,1,2,3 чисел. например, один из них составлен следующим образом:

521859 нулей, 288972 единиц, 481471 двойок, 55619 тройок.

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

55619 нулей, 288972 единиц, 481471 двойок, 521859 трёх

Если есть очень питонический способ, это было бы здорово, конечно

Заранее спасибо за любую помощь!

1 Ответ

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

Вы можете использовать np.unique , чтобы получить уникальные элементы и счетчики, а затем создать словарь, в котором ключи - это старые значения, а значения - новые. Наконец, примените его ко всему массиву, используя np.vectorize :

import numpy as np
from operator import itemgetter

arr = np.array([2, 2, 0, 0, 0, 1, 3, 3, 3, 3])

# get unique elements and counts
counts = zip(*np.unique(arr, return_counts=True))

# create a lookup dictionary value -> i where values are sorted according to frequency
mapping = {value: i for i, (value, _) in enumerate(sorted(counts, key=itemgetter(1)))}

# apply the dictionary in a vectorized way
result = np.vectorize(mapping.get)(arr)

print(result)

Выход

[1 1 2 2 2 0 3 3 3 3]

A, возможно, чище, альтернативаиспользовать collection.Counter , для подсчета и создания словаря сопоставления:

# get unique elements and counts
counts = Counter(arr)

# create a lookup dictionary value -> i where values are sorted according to frequency
mapping = {value: i for i, value in enumerate(sorted(counts, key=counts.get))}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...