2015-11-11 3 views
1

У меня есть список, состоящий из нескольких массивов numpy с разными формами. Я хочу изменить этот список массивов на числовой вектор, а затем изменить каждый элемент в векторе, а затем переформатировать его обратно в исходный список массивов.Измените список массивов numpy, а затем измените форму обратно

Например:

входного

[numpy.zeros((2,2)), numpy.ones((3,3))] 
  • Первый

к векторным

[0,0,0,0,1,1,1,1,1,1,1,1,1] 
  • Второй

каждый раз изменение только один элемент. например, изменить первый элемент 0 до 2

[0,2,0,0,1,1,1,1,1,1,1,1,1] 
  • Последний

преобразовать его обратно в

[array([[0,2],[0,0]]),array([[1,1,1],[1,1,1],[1,1,1]])] 

Есть ли быстрая реализация? Огромное спасибо.

ответ

1

Кажется, что преобразование в список и обратно будет неэффективным. Вместо этого, почему бы не выяснить, какой массив индексировать (и где), а затем просто обновлять этот индекс? например

def change_element(arr1, arr2, ix, value): 
    which = ix >= arr1.size 
    arr = [arr1, arr2][which] 
    ix = ix - arr1.size if which else ix 
    arr.ravel()[ix] = value 

И вот несколько примеров использования:

>>> arr1 = np.zeros((2, 2)) 
>>> arr2 = np.ones((3, 3)) 
>>> change_element(arr1, arr2, 1, 2) 
>>> change_element(arr1, arr2, 6, 3.14) 
>>> arr1 
array([[ 0., 2.], 
     [ 0., 0.]]) 
>>> arr2 
array([[ 1. , 1. , 3.14], 
     [ 1. , 1. , 1. ], 
     [ 1. , 1. , 1. ]]) 
>>> change_element(arr1, arr2, 7, 3.14) 
>>> arr1 
array([[ 0., 2.], 
     [ 0., 0.]]) 
>>> arr2 
array([[ 1. , 1. , 3.14], 
     [ 3.14, 1. , 1. ], 
     [ 1. , 1. , 1. ]]) 

Несколько заметок - Это обновляет массивы на месте. Он не создает новые массивы. Если вам действительно нужно создавать новые массивы, я полагаю, вы могли бы np.copy их и вернуться. Кроме того, это зависит от памяти обмена массивами до и после ravel. Я не помню точных обстоятельств, когда ravel вернул новый массив, а не представление в исходный массив. , ,


Обобщение на большее количество массивов на самом деле довольно просто. Нам просто нужно спуститься по списку массивов и посмотреть, меньше ли размер ix. Если это так, мы нашли наш массив.Если это не так, мы должны вычесть размер массива из ix для представления числа элементов, мы пересекали до сих пор:

def change_element(arrays, ix, value): 
    for arr in arrays: 
     if ix < arr.size: 
      arr.ravel()[ix] = value 
      return 
     ix -= arr.size 

И вы можете назвать это похоже на перед:

change_element([arr1, arr2], 6, 3.14159) 
+0

Nice. Но это решение ограничено ровно двумя массивами. Было бы интересно обобщить его на список массивов с неопределенным количеством массивов. –

+0

@ MikeMüller - Конечно. Обобщение довольно просто (достаточно просто, чтобы добавить его в качестве дополнения к решению). – mgilson

+0

@mgilson Большое спасибо. Я думаю, что это решение может решить мою проблему. – tuming1990

0

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

lst = [numpy.zeros((2,4)), numpy.ones((3,3))] 
tlist = [e for a in lst for e in a.ravel()] 
tlist[1] = 2 
i = 0 
lst2 = [] 
dims = [a.shape for a in lst] 
for n, m in dims: 
    lst2.append(np.array(tlist[i:i+n*m]).reshape(n,m)) 
    i += n*m 
lst2 

[array([[ 0., 2.], 
    [ 0., 0.]]), array([[ 1., 1., 1.], 
    [ 1., 1., 1.], 
    [ 1., 1., 1.]])] 

Конечно, вы теряете информацию о размерах вашего массива, когда вы сглаживаете, поэтому вам нужно их где-то хранить (здесь, в dims).

+0

Это решение довольно элегантно. Спасибо. – tuming1990

Смежные вопросы