Numpy append: автоматически приводит массив неправильного измерения - PullRequest
5 голосов
/ 20 апреля 2011

Есть ли способ сделать следующее без предложения if?

Я читаю набор файлов netcdf с pupynere и хочу создать массив с добавлением numpy.Иногда входные данные являются многомерными (см. Переменную «a» ниже), иногда одномерными («b»), но количество элементов в первом измерении всегда одинаково («9» в примере ниже).

> import numpy as np
> a = np.arange(27).reshape(3,9)
> b = np.arange(9)
> a.shape
(3, 9)
> b.shape
(9,)

это работает, как и ожидалось:

> np.append(a,a, axis=0)
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8],
   [ 9, 10, 11, 12, 13, 14, 15, 16, 17],
   [18, 19, 20, 21, 22, 23, 24, 25, 26],
   [ 0,  1,  2,  3,  4,  5,  6,  7,  8],
   [ 9, 10, 11, 12, 13, 14, 15, 16, 17],
   [18, 19, 20, 21, 22, 23, 24, 25, 26]])

, но добавление b не работает так элегантно:

> np.append(a,b, axis=0)
ValueError: arrays must have same number of dimensions

Проблема с добавлением (изсправочник numpy)

"Когда указана ось, значения должны иметь правильную форму."

Мне придется сначала привести в порядокчтобы получить правильный результат.

> np.append(a,b.reshape(1,9), axis=0)
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8],
   [ 9, 10, 11, 12, 13, 14, 15, 16, 17],
   [18, 19, 20, 21, 22, 23, 24, 25, 26],
   [ 0,  1,  2,  3,  4,  5,  6,  7,  8]])

Итак, в моем цикле чтения файлов я в настоящее время использую предложение if, подобное этому:

for i in [a, b]:
    if np.size(i.shape) == 2:
        result = np.append(result, i, axis=0)
    else:
        result = np.append(result, i.reshape(1,9), axis=0)

Есть ли способ добавить "a "и" b "без оператора if?

РЕДАКТИРОВАТЬ: Хотя @Sven отлично ответил на исходный вопрос (используя np.atleast_2d()), он (и другие) указал, что коднеэффективно.В ответе ниже я объединил их предложения и заменил мой оригинальный код.Это должно быть намного эффективнее сейчас.Спасибо.

Ответы [ 4 ]

3 голосов
/ 20 апреля 2011

Вы можете использовать numpy.atleast_2d():

result = np.append(result, np.atleast_2d(i), axis=0)

Тем не менее, обратите внимание, что повторное использование numpy.append() является очень неэффективным способом построения массива NumPy - его нужно перераспределять на каждом этапе. Если это вообще возможно, предварительно выделите массив с желаемым конечным размером и затем заполните его, используя нарезку.

2 голосов
/ 20 апреля 2011

Вы можете просто добавить все массивы в список, а затем использовать np.vstack(), чтобы объединить их все вместе в конце.Это позволяет избежать постоянного перераспределения растущего массива с каждым добавлением.

|1> a = np.arange(27).reshape(3,9)

|2> b = np.arange(9)

|3> np.vstack([a,b])
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8],
       [ 9, 10, 11, 12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23, 24, 25, 26],
       [ 0,  1,  2,  3,  4,  5,  6,  7,  8]])
1 голос
/ 21 апреля 2011

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

Это включает в себя использование списка Python, который позволяет добавлять с снижением производительности O (1), тогда как numpy.append () имеет снижение производительности O (N ** 2) . После этого список преобразуется в пустой массив:

Предположим, i имеет тип a или b:

> a = np.arange(27).reshape(3,9)
> b = np.arange(9)
> a.shape
(3, 9)
> b.shape
(9,)

Инициализировать список и добавить все прочитанные данные, например, если данные отображаются в порядке «aaba».

> mList = []
> for i in [a,a,b,a]:
     mList.append(i)

Ваш mList будет выглядеть так:

> mList
[array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8],
   [ 9, 10, 11, 12, 13, 14, 15, 16, 17],
   [18, 19, 20, 21, 22, 23, 24, 25, 26]]),
 array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8],
   [ 9, 10, 11, 12, 13, 14, 15, 16, 17],
   [18, 19, 20, 21, 22, 23, 24, 25, 26]]),
 array([0, 1, 2, 3, 4, 5, 6, 7, 8]),
 array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8],
   [ 9, 10, 11, 12, 13, 14, 15, 16, 17],
   [18, 19, 20, 21, 22, 23, 24, 25, 26]])]

наконец, vstack список, чтобы сформировать массив Numpy:

> result = np.vstack(mList[:])
> result.shape
(10, 9)

Еще раз спасибо за ценную помощь.

0 голосов
/ 20 апреля 2011

Как указано, append необходимо перераспределить каждый массив numpy. Альтернативное решение, которое выделяет один раз, будет примерно таким:

total_size = 0
for i in [a,b]:
    total_size += i.size

result = numpy.empty(total_size, dtype=a.dtype)
offset = 0
for i in [a,b]:
    # copy in the array
    result[offset:offset+i.size] = i.ravel()
    offset += i.size

# if you know its always divisible by 9:
result = result.reshape(result.size//9, 9)

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

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