จากอาร์เรย์ ND ถึง 1D


150

สมมติว่าฉันมีอาร์เรย์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 โดยพลการหรือไม่?

คำตอบ:


289

ใช้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()จะคืนค่า a viewของaเมื่อเป็นไปได้ ดังนั้นการปรับเปลี่ยนยังปรับเปลี่ยนb ส่งคืนค่าเมื่อองค์ประกอบ 1D อยู่ติดกันในหน่วยความจำ แต่จะส่งคืนif ตัวอย่างเช่นสร้างจากการแบ่งอาร์เรย์อื่นโดยใช้ขนาดขั้นตอนที่ไม่ใช่หน่วย (เช่น)aravel()viewcopyaa = 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>
Warren Weckesser

3
a.ravel()a.reshape(-1)ลักษณะที่จะเป็นรอบสามครั้งเป็นอย่างรวดเร็ว a.flatten()เป็นวิธีที่ช้ากว่าเนื่องจากต้องทำสำเนา
BallpointBen

26
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])

12
อาจใช้b = a.reshape(-1)สั้น ๆ ในตัวอย่างแรก
Syrtis Major

7

ฉันอยากจะเห็นผลมาตรฐานของฟังก์ชั่นที่กล่าวถึงในคำตอบรวมทั้งของ unutbu

นอกจากนี้ยังต้องการชี้ให้เห็นว่าควรใช้numpy docarr.reshape(-1)ใน case view (แม้ว่า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)

1
คุณระบุว่าอาจมีบางกรณีที่reshapeส่งคืนมุมมองและravelไม่แสดงผล y=x[::2]หนึ่งในกรณีดังกล่าวคือเมื่อ เนื่องจากyไม่ติดกันจึงต้องคัดลอก ravel แม้ว่าจะเป็นอาร์เรย์ 1D อยู่แล้วก็ตาม คุณสามารถใช้สิ่งนี้เพื่อประดิษฐ์กรณีที่ ravel ช้าลง
user3281410

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 '(?,)' 

5

สำหรับรายการอาร์เรย์ที่มีขนาดแตกต่างกันให้ใช้ดังต่อไปนี้:

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
Bikram

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.