Як перетворити список масивів numpy в один масив numpy?


103

Припустимо, що я маю;

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. Поясніть будь ласка.
Марцін

Відповіді:


131

Взагалі, ви можете об'єднати цілу послідовність масивів уздовж будь-якої осі:

numpy.concatenate( LIST, axis=0 )

але ви дійсно повинні турбуватися про форму і розмірність кожного масиву в списку (для 2-мірного виходу 3х5, вам необхідно переконатися , що всі вони є 2-мірні масиви п-по-5 вже). Якщо ви хочете об’єднати одновимірні масиви як рядки двовимірного виводу, вам потрібно розширити їх розмірність.

Як вказує відповідь Хорхе, існує також функція stack, введена в numpy 1.10:

numpy.stack( LIST, axis=0 )

Для цього застосовується додатковий підхід: він створює новий вигляд кожного вхідного масиву і додає додатковий вимір (у цьому випадку ліворуч, тому кожен n1-елементний масив стає 1-на- n2D масивом) перед об'єднанням. Це буде працювати лише в тому випадку, якщо всі вхідні масиви мають однакову форму - навіть вздовж осі об'єднання.

vstack(або еквівалентно row_stack) часто є більш простим у використанні рішенням, оскільки воно буде приймати послідовність 1- та / або двовимірних масивів і автоматично розширювати розмірність там, де це необхідно і лише там, де це необхідно, перш ніж об’єднати весь список разом. Там, де потрібен новий вимір, він додається зліва. Знову ж таки, ви можете об’єднати цілий список відразу, не потребуючи ітерації:

numpy.vstack( LIST )

Цю гнучку поведінку демонструє також синтаксичний ярлик numpy.r_[ array1, ...., arrayN ](зверніть увагу на квадратні дужки). Це добре для об'єднання декількох явно названих масивів, але не годиться для вашої ситуації, оскільки цей синтаксис не прийме послідовності масивів, як ваш LIST.

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

Нарешті, у конкретному випадку вертикального укладання одновимірних масивів також працює наступне:

numpy.array( LIST )

... тому що масиви можуть бути побудовані з послідовності інших масивів, додаючи новий вимір на початок.


5
Я думаю, що він хотів 2d-масив як результат.
Біфстер

7

Починаючи з NumPy версії 1.10, ми маємо стек методів . Він може складати масиви будь-якого виміру (всі рівні):

# 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) А якщо ми використовуємо 2d-масиви, 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}')
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.