Гетерогенизируйте массив NumPy так, чтобы не было двух соседних клеток - PullRequest
0 голосов
/ 12 октября 2018

У меня есть большой массив NumPy, который я хотел бы заполнить, используя следующие критерии:

  • использовать числа только из заданного диапазона (от 0 до 9), например
  • заполнить такиечто никакие соседние клетки не равны.Это означает, что каждая ячейка будет окружена значениями, которые будут отличаться от нее.Не допускаются никакие исключения.

В настоящее время я использую следующую функцию

def uniqify(in_array):
    #warning: array is mutable and gets modified outside this scope
    out_array = np.arange(in_array.size).reshape(in_array.shape)
    return out_array.astype(np.float32)

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

Существуют ли элегантные решения для достижения этой цели?

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

В настоящее время я смотрю на некоторые из рандомизирующих функций в numpy, такие как https://docs.scipy.org/doc/numpy/reference/generated/numpy.random.randn.html.

Вот пример, который я приготовил, используя np.random.choice

import numpy as np
data = np.array([[1,1,1], [1,1,1], [1,1,1]])
size = np.size(data)

for i in range(20):
    random_list = np.random.choice(size, size, replace= False)/(size-1)
    print(random_list)
print('\ndone')

При этом распечатываются различные списки с номерами в диапазоне от 0 до 1, что хорошо, однако для больших наборов данных я могу представить разницу между возможными выборками настолько малой, чтобы сделать их почти равными,Поэтому я не могу рандомизировать, но мне нужно управлять функцией с явной целью избежать равных соседних ячеек.Числа могут, я думаю, нарисовать от 1 до 9 ...

1 Ответ

0 голосов
/ 13 октября 2018

Как прокомментировал Пол Панцер, можно построить обычный шахматный шаблон:

def uniq(shape):
    f = lambda *idx: np.mod(np.sum(idx, axis=0), 10)
    return np.fromfunction(f, shape)

Например, uniq((5, 17)) равно

[[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9.  0.  1.  2.  3.  4.  5.  6.]
 [ 1.  2.  3.  4.  5.  6.  7.  8.  9.  0.  1.  2.  3.  4.  5.  6.  7.]
 [ 2.  3.  4.  5.  6.  7.  8.  9.  0.  1.  2.  3.  4.  5.  6.  7.  8.]
 [ 3.  4.  5.  6.  7.  8.  9.  0.  1.  2.  3.  4.  5.  6.  7.  8.  9.]
 [ 4.  5.  6.  7.  8.  9.  0.  1.  2.  3.  4.  5.  6.  7.  8.  9.  0.]]

Нет смежных элементов равных.По модулю может быть даже взят мод 2, в результате чего получается массив 0-1.

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

def uniq(shape):
    steps = 1 + np.mod(np.random.randint(1, 100, size=len(shape))*(np.sqrt(5)+1)/2, 8)
    f = lambda *idx: np.mod(np.floor(np.random.uniform(0, 10) + np.moveaxis(idx, 0, -1).dot(steps)), 10)
    return np.fromfunction(f, shape)

Теперь uniq((5, 17)) - это нечто случайное, похожее на

[[ 4.  8.  3.  7.  2.  7.  1.  6.  0.  5.  0.  4.  9.  3.  8.  3.  7.]
 [ 0.  4.  9.  4.  8.  3.  7.  2.  7.  1.  6.  0.  5.  0.  4.  9.  3.]
 [ 6.  1.  5.  0.  4.  9.  4.  8.  3.  7.  2.  7.  1.  6.  0.  5.  0.]
 [ 2.  7.  1.  6.  1.  5.  0.  4.  9.  4.  8.  3.  7.  2.  7.  1.  6.]
 [ 8.  3.  8.  2.  7.  1.  6.  1.  5.  0.  4.  9.  4.  8.  3.  7.  2.]]

В первой версии все шаги равны 1. Вычисление шагов основано на золотом сечении (np.sqrt(5)+1)/2 потому что его множители производят равномерно распределенные, но случайные числа.Шаги гарантированно будут между 1 и 9, поэтому с каждым шагом, после настила и принятия мода 10, мы уверены, что у нас будет другое число.

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