Numpy изменяет матрицу 1d на 2d с 1 столбцом

В numpy размеры результирующего массива меняются во время выполнения. Часто возникает путаница между массивом 1d и массивом 2d с 1 столбцом. В одном случае я могу перебирать столбцы, в другом случае я не могу.

Как вы решительно решаете эту проблему? Чтобы избежать засорения моего кода инструкциями if, проверяющими размерность, я использую эту функцию:

def reshape_to_vect(ar):
    if len(ar.shape) == 1:
      return ar.reshape(ar.shape[0],1)
    return ar

Однако это чувствует себя неэлегантным и дорогостоящим. Есть ли лучшее решение?

Ответ 1

Самый простой способ:

ar.reshape(-1, 1)

Ответ 2

Вы можете сделать -

ar.reshape(ar.shape[0],-1)

Второй вход в reshape: -1 заботится о числе элементов для второй оси. Таким образом, для случая ввода 2D он не изменяется. Для случая ввода 1D он создает массив 2D со всеми элементами, которые "толкаются" на первую ось из-за ar.shape[0], что является общим числом элементов.

Примеры прогонов

1D Случай:

In [87]: ar
Out[87]: array([ 0.80203158,  0.25762844,  0.67039516,  0.31021513,  0.80701097])

In [88]: ar.reshape(ar.shape[0],-1)
Out[88]: 
array([[ 0.80203158],
       [ 0.25762844],
       [ 0.67039516],
       [ 0.31021513],
       [ 0.80701097]])

2D-пример:

In [82]: ar
Out[82]: 
array([[ 0.37684126,  0.16973899,  0.82157815,  0.38958523],
       [ 0.39728524,  0.03952238,  0.04153052,  0.82009233],
       [ 0.38748174,  0.51377738,  0.40365096,  0.74823535]])

In [83]: ar.reshape(ar.shape[0],-1)
Out[83]: 
array([[ 0.37684126,  0.16973899,  0.82157815,  0.38958523],
       [ 0.39728524,  0.03952238,  0.04153052,  0.82009233],
       [ 0.38748174,  0.51377738,  0.40365096,  0.74823535]])

Ответ 3

Вариант ответа divakar: x = np.reshape(x, (len(x),-1)), который также касается случая, когда вход представляет собой список 1d или 2d.

Ответ 4

Я спросил о dtype, потому что ваш пример озадачен.

Я могу создать структурированный массив с 3 элементами (1d) и тремя полями:

In [1]: A = np.ones((3,), dtype='i,i,i')
In [2]: A
Out[2]: 
array([(1, 1, 1), (1, 1, 1), (1, 1, 1)], 
      dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')])

Я могу получить доступ к одному полю по имени (добавление скобок не меняет вещи)

In [3]: A['f0'].shape
Out[3]: (3,)

но если я получаю 2 поля, я все равно получаю 1d-массив

In [4]: A[['f0','f1']].shape
Out[4]: (3,)
In [5]: A[['f0','f1']]
Out[5]: 
array([(1, 1), (1, 1), (1, 1)], 
      dtype=[('f0', '<i4'), ('f1', '<i4')])

На самом деле эти дополнительные скобки имеют значение, если я смотрю на значения

In [22]: A['f0']
Out[22]: array([1, 1, 1], dtype=int32)
In [23]: A[['f0']]
Out[23]: 
array([(1,), (1,), (1,)], 
      dtype=[('f0', '<i4')])

Если массив является простым 2d, я до сих пор не получаю ваши фигуры

In [24]: A=np.ones((3,3),int)
In [25]: A[0].shape
Out[25]: (3,)
In [26]: A[[0]].shape
Out[26]: (1, 3)
In [27]: A[[0,1]].shape
Out[27]: (2, 3)

Но что касается вопроса о том, что массив равен 2d, независимо от того, возвращает ли индексирование 1d или 2, ваша функция в основном в порядке

def reshape_to_vect(ar):
    if len(ar.shape) == 1:
      return ar.reshape(ar.shape[0],1)
    return ar

Вы можете проверить ar.ndim вместо len(ar.shape). Но в любом случае это не дорого - то есть время выполнения минимально - никаких больших операций массива. reshape не копирует данные (если ваши шаги не странны), поэтому это просто затраты на создание нового объекта массива с помощью общего указателя данных.

Посмотрите код для np.atleast_2d; он тестирует 0d и 1d. В 1-м случае он возвращает result = ary[newaxis,:]. Он добавляет дополнительную ось сначала, более естественное расположение numpy для добавления оси. Вы добавите его в конце.

ar.reshape(ar.shape[0],-1) - это умный способ обхода теста if. В небольших временных тестах это происходит быстрее, но мы говорим о микросекундах, о влиянии слоя вызова функции.

np.column_stack - это еще одна функция, которая при необходимости создает столбчатые массивы. Он использует:

 if arr.ndim < 2:
        arr = array(arr, copy=False, subok=True, ndmin=2).T

Ответ 5

Чтобы избежать необходимости перестановки в первую очередь, если вы нарезаете строку/столбец со списком или "бегущим" срезом, вы получите 2D-массив с одной строкой/столбцом

import numpy as np
x = np.array(np.random.normal(size=(4,4)))
print x, '\n'

Result:
[[ 0.01360395  1.12130368  0.95429414  0.56827029]
 [-0.66592215  1.04852182  0.20588886  0.37623406]
 [ 0.9440652   0.69157556  0.8252977  -0.53993904]
 [ 0.6437994   0.32704783  0.52523173  0.8320762 ]] 

y = x[:,[0]]
print y, 'col vector \n'
Result:
[[ 0.01360395]
 [-0.66592215]
 [ 0.9440652 ]
 [ 0.6437994 ]] col vector 


y = x[[0],:]
print y, 'row vector \n'

Result:
[[ 0.01360395  1.12130368  0.95429414  0.56827029]] row vector 

# Slice with "running" index on a column
y = x[:,0:1]
print y, '\n'

Result:
[[ 0.01360395]
 [-0.66592215]
 [ 0.9440652 ]
 [ 0.6437994 ]] 

Вместо этого, если вы используете один номер для выбора строки/столбца, это приведет к 1D-массиву, который является основной причиной вашей проблемы:

y = x[:,0]
print y, '\n'

Result:
[ 0.01360395 -0.66592215  0.9440652   0.6437994 ] 

Ответ 6

y = np.array(12)
y = y.reshape(-1,1)
print(y.shape)

O/P:- (1, 1)