Від масивів ND до 1D


141

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

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

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

Я хотів би перетворити його в 1D масив (тобто вектор стовпця):

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

але це повертається

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

що не те саме, що:

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

Я можу взяти перший елемент цього масиву, щоб вручну перетворити його в 1D масив:

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

але це вимагає від мене знати, скільки розмірів має оригінальний масив (і об'єднувати [0] при роботі з більшими розмірами)

Чи існує незалежний від розмірів спосіб отримання вектора стовпця / рядків від довільної ndarray?

Відповіді:


277

Використовуйте np.ravel (для 1D перегляду) або np.ndarray.flatten (для 1D копії) або np.ndarray.flat (для 1D ітератора):

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)У першому прикладі можна використовувати коротко.
Майор

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 .

Також хочу зазначити, що numpy doc рекомендують використовувати 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)час виконання був послідовним і незалежним від розміру ndarray. Однак, ravelце швидше, але reshapeзабезпечує гнучкість у переформуванні розміру. (можливо, саме тому numpy doc рекомендують використовувати його замість цього. Або можуть бути випадки, коли reshapeповертається перегляд, а 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.