Как преобразовать список массивов numpy в один массив numpy?

111

Предположим, у меня есть;

LIST = [[array([1, 2, 3, 4, 5]), array([1, 2, 3, 4, 5],[1,2,3,4,5])] # inner lists are numpy arrays

Я пытаюсь преобразовать;

array([[1, 2, 3, 4, 5],
       [1, 2, 3, 4, 5],
       [1, 2, 3, 4, 5])

Я решаю это путем итерации на vstack прямо сейчас, но это очень медленно для особенно большого СПИСКА

Что вы предлагаете для наиболее эффективного способа?

эрогол
источник
5
LIST = [[array([1, 2, 3, 4, 5]), array([1, 2, 3, 4, 5],[1,2,3,4,5])]это неправильный синтаксис Python. Просьба уточнить.
Marcin

Ответы:

141

В общем, вы можете объединить целую последовательность массивов по любой оси:

numpy.concatenate( LIST, axis=0 )

но вы действительно должны беспокоиться о форме и размерность каждого массива в списке (для 2-мерного выхода 3х5, вам необходимо убедиться , что все они являются 2-мерные массивы п-по-5 уже). Если вы хотите объединить одномерные массивы как строки двухмерного вывода, вам необходимо расширить их размерность.

Как указывает ответ Хорхе, есть также функция stack, представленная в numpy 1.10:

numpy.stack( LIST, axis=0 )

При этом используется дополнительный подход: создается новое представление каждого входного массива и добавляется дополнительное измерение (в данном случае слева, поэтому каждый n-элементный 1D-массив становится 1- nмерным массивом) перед объединением. Это будет работать, только если все входные массивы имеют одинаковую форму - даже вдоль оси конкатенации.

vstack(или что то же самое row_stack) часто является более простым в использовании решением, потому что оно будет принимать последовательность 1- и / или 2-мерных массивов и автоматически расширять размерность там, где это необходимо, и только там, где это необходимо, прежде чем объединять весь список вместе. Если требуется новое измерение, оно добавляется слева. Опять же, вы можете объединить сразу весь список без необходимости повторять:

numpy.vstack( LIST )

Такое гибкое поведение также демонстрируется синтаксическим сокращением numpy.r_[ array1, ...., arrayN ](обратите внимание на квадратные скобки). Это хорошо для объединения нескольких массивов с явно указанными именами, но не подходит для вашей ситуации, потому что этот синтаксис не будет принимать последовательность массивов, таких как ваш LIST.

Существует также аналогичная функция column_stackи ярлык c_[...]для горизонтального (по столбцам) наложения, а также почти аналогичная функция - hstackхотя по какой-то причине последняя менее гибкая (более строгая в отношении размерности входных массивов и пытается объединить 1-мерные массивы сквозные, а не как столбцы).

Наконец, в конкретном случае вертикального наложения одномерных массивов также работает следующее:

numpy.array( LIST )

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

Jez
источник
5
Я думаю, он хотел получить на выходе 2d-массив.
Beefster
8

Начиная с версии 1.10 NumPy, у нас есть стек методов . Он может складывать массивы любого размера (все равны):

# List of arrays.
L = [np.random.randn(5,4,2,5,1,2) for i in range(10)]

# Stack them using axis=0.
M = np.stack(L)
M.shape # == (10,5,4,2,5,1,2)
np.all(M == L) # == True

M = np.stack(L, axis=1)
M.shape # == (5,10,4,2,5,1,2)
np.all(M == L) # == False (Don't Panic)

# This are all true    
np.all(M[:,0,:] == L[0]) # == True
all(np.all(M[:,i,:] == L[i]) for i in range(10)) # == True

Наслаждаться,

Хорхе Э. Кардона
источник
1

Я проверил некоторые методы на быстродействие и обнаружил, что разницы нет! Единственное отличие состоит в том, что при использовании некоторых методов необходимо тщательно проверять размер.

Время:

|------------|----------------|-------------------|
|            | shape (10000)  |  shape (1,10000)  |
|------------|----------------|-------------------|
| np.concat  |    0.18280     |      0.17960      |
|------------|----------------|-------------------|
|  np.stack  |    0.21501     |      0.16465      |
|------------|----------------|-------------------|
| np.vstack  |    0.21501     |      0.17181      |
|------------|----------------|-------------------|
|  np.array  |    0.21656     |      0.16833      |
|------------|----------------|-------------------|

Как вы можете видеть, я пробовал 2 эксперимента - с использованием np.random.rand(10000)и. np.random.rand(1, 10000) И если мы используем 2- мерные массивы, np.stackа затем и np.arrayсоздаем дополнительное измерение - result.shape равен (1,10000,10000) и (10000,1,10000), поэтому им нужны дополнительные действия, чтобы избежать этого. .

Код:

from time import perf_counter
from tqdm import tqdm_notebook
import numpy as np
l = []
for i in tqdm_notebook(range(10000)):
    new_np = np.random.rand(10000)
    l.append(new_np)



start = perf_counter()
stack = np.stack(l, axis=0 )
print(f'np.stack: {perf_counter() - start:.5f}')

start = perf_counter()
vstack = np.vstack(l)
print(f'np.vstack: {perf_counter() - start:.5f}')

start = perf_counter()
wrap = np.array(l)
print(f'np.array: {perf_counter() - start:.5f}')

start = perf_counter()
l = [el.reshape(1,-1) for el in l]
conc = np.concatenate(l, axis=0 )
print(f'np.concatenate: {perf_counter() - start:.5f}')
Михаил_Сам
источник