От ND до 1D массивов


141

Скажем, у меня есть массив a:

a = np.array([[1,2,3], [4,5,6]])

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

Я хотел бы преобразовать его в одномерный массив (т.е. вектор-столбец):

b = np.reshape(a, (1,np.product(a.shape)))

но это возвращается

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

что не то же самое, что:

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

Я могу взять первый элемент этого массива, чтобы вручную преобразовать его в одномерный массив:

b = np.reshape(a, (1,np.product(a.shape)))[0]

но это требует от меня знать, сколько измерений имеет исходный массив (и объединять [0] при работе с более высокими измерениями)

Есть ли независимый от размеров способ получения вектора столбца / строки из произвольного массива?

Ответы:


277

Используйте np.ravel (для одномерного представления) или np.ndarray.flatten (для одномерной копии) или np.ndarray.flat (для одномерного итератора):

In [12]: a = np.array([[1,2,3], [4,5,6]])

In [13]: b = a.ravel()

In [14]: b
Out[14]: array([1, 2, 3, 4, 5, 6])

Обратите внимание , что ravel()возвращает viewиз aкогда это возможно. Таким образом, модификация bтакже модифицирует a. ravel()возвращает a, viewкогда элементы 1D являются смежными в памяти, но возвращает a, copyесли, например, они aбыли сделаны из нарезки другого массива с использованием шага, не равного единице (например a = x[::2]).

Если вы хотите получить копию, а не представление, используйте

In [15]: c = a.flatten()

Если вы просто хотите использовать итератор, используйте np.ndarray.flat:

In [20]: d = a.flat

In [21]: d
Out[21]: <numpy.flatiter object at 0x8ec2068>

In [22]: list(d)
Out[22]: [1, 2, 3, 4, 5, 6]

4
<pedantic> В этом примере ravel()возвращает представление, но это не всегда так. Есть случаи, когда ravel()возвращается копия. </
Pedantic

3
a.ravel()выглядит примерно в три раза быстрее a.reshape(-1). a.flatten()это намного медленнее, так как он должен сделать копию.
BallpointBen

25
In [14]: b = np.reshape(a, (np.product(a.shape),))

In [15]: b
Out[15]: array([1, 2, 3, 4, 5, 6])

или просто:

In [16]: a.flatten()
Out[16]: array([1, 2, 3, 4, 5, 6])

11
Можно использовать b = a.reshape(-1)для краткости в первом примере.
Syrtis Major

5

Один из самых простых способов - использовать flatten(), как в следующем примере:

 import numpy as np

 batch_y =train_output.iloc[sample, :]
 batch_y = np.array(batch_y).flatten()

Мой массив это было так:

    0
0   6
1   6
2   5
3   4
4   3
.
.
.

После использования flatten():

array([6, 6, 5, ..., 5, 3, 6])

Это также решение ошибок этого типа:

Cannot feed value of shape (100, 1) for Tensor 'input/Y:0', which has shape '(?,)' 

4

Для списка массивов с разным размером используйте следующее:

import numpy as np

# ND array list with different size
a = [[1],[2,3,4,5],[6,7,8]]

# stack them
b = np.hstack(a)

print(b)

Вывод:

[1 2 3 4 5 6 7 8]


как бы вы получили форму aспины b?
dvdblk

Если вы хотите разделить 1D на куски. Посмотреть это stackoverflow.com/a/8495740/6117565
Бикрам

4

Я хотел увидеть результаты теста функций, упомянутых в ответах, включая unutbu .

Также хочу отметить, что NumPyDOC рекомендует использовать arr.reshape(-1)в случае, если представление является предпочтительным. (хотя ravelэто немного быстрее в следующем результате)


TL; DR : np.ravelнаиболее производительный (по очень небольшому количеству).

эталонный тест

Функции:

numpy версия: '1.18.0'

Время исполнения на разные ndarrayразмеры

+-------------+----------+-----------+-----------+-------------+
|  function   |   10x10  |  100x100  | 1000x1000 | 10000x10000 |
+-------------+----------+-----------+-----------+-------------+
| ravel       | 0.002073 |  0.002123 |  0.002153 |    0.002077 |
| reshape(-1) | 0.002612 |  0.002635 |  0.002674 |    0.002701 |
| flatten     | 0.000810 |  0.007467 |  0.587538 |  107.321913 |
| flat        | 0.000337 |  0.000255 |  0.000227 |    0.000216 |
+-------------+----------+-----------+-----------+-------------+

Вывод

ravelи reshape(-1)время выполнения было согласованным и независимым от размера массива. Тем не менее, ravelэто немного быстрее, но reshapeобеспечивает гибкость в изменении размера. (может быть, поэтому numpy doc рекомендует использовать его вместо этого. Или могут быть случаи, когда reshapeвозвращается view и ravelнет).
Если вы имеете дело с ndarray большого размера, использование flattenможет вызвать проблемы с производительностью. Рекомендую не использовать его. Если вам не нужна копия данных, чтобы сделать что-то еще.

Используемый код

import timeit
setup = '''
import numpy as np
nd = np.random.randint(10, size=(10, 10))
'''

timeit.timeit('nd = np.reshape(nd, -1)', setup=setup, number=1000)
timeit.timeit('nd = np.ravel(nd)', setup=setup, number=1000)
timeit.timeit('nd = nd.flatten()', setup=setup, number=1000)
timeit.timeit('nd.flat', setup=setup, number=1000)

0

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

def getVector(data_array,col):
    vector = []
    imax = len(data_array)
    for i in range(imax):
        vector.append(data_array[i][col])
    return ( vector )
a = ([1,2,3], [4,5,6])
b = getVector(a,1)
print(b)

Out>[2,5]

Так что если вам нужно транспонировать, вы можете сделать что-то вроде этого:

def transposeArray(data_array):
    # need to test if this is a 1D array 
    # can't do a len(data_array[0]) if it's 1D
    two_d = True
    if isinstance(data_array[0], list):
        dimx = len(data_array[0])
    else:
        dimx = 1
        two_d = False
    dimy = len(data_array)
    # init output transposed array
    data_array_t = [[0 for row in range(dimx)] for col in range(dimy)]
    # fill output transposed array
    for i in range(dimx):
        for j in range(dimy):
            if two_d:
                data_array_t[j][i] = data_array[i][j]
            else:
                data_array_t[j][i] = data_array[j]
    return data_array_t
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.