การลบแถวในอาร์เรย์ numpy


90

ฉันมีอาร์เรย์ที่อาจมีลักษณะดังนี้:

ANOVAInputMatrixValuesArray = [[ 0.96488889, 0.73641667, 0.67521429, 0.592875, 
0.53172222], [ 0.78008333, 0.5938125, 0.481, 0.39883333, 0.]]

สังเกตว่าแถวใดแถวหนึ่งมีค่าเป็นศูนย์ในตอนท้าย ฉันต้องการลบแถวใด ๆ ที่มีศูนย์ในขณะที่รักษาแถวที่มีค่าที่ไม่ใช่ศูนย์ในเซลล์ทั้งหมด

แต่อาร์เรย์จะมีจำนวนแถวต่างกันทุกครั้งที่มีการเติมข้อมูลและเลขศูนย์จะอยู่คนละแถวในแต่ละครั้ง

ฉันได้รับจำนวนองค์ประกอบที่ไม่ใช่ศูนย์ในแต่ละแถวด้วยโค้ดบรรทัดต่อไปนี้:

NumNonzeroElementsInRows    = (ANOVAInputMatrixValuesArray != 0).sum(1)

สำหรับอาร์เรย์ด้านบนNumNonzeroElementsInRowsประกอบด้วย: [5 4]

ค่าที่ 5 ระบุว่าค่าที่เป็นไปได้ทั้งหมดในแถว 0 ไม่เป็นศูนย์ในขณะที่ค่าสี่ระบุว่าค่าที่เป็นไปได้ค่าหนึ่งในแถว 1 เป็นศูนย์

ดังนั้นฉันจึงพยายามใช้โค้ดบรรทัดต่อไปนี้เพื่อค้นหาและลบแถวที่มีค่าเป็นศูนย์

for q in range(len(NumNonzeroElementsInRows)):
    if NumNonzeroElementsInRows[q] < NumNonzeroElementsInRows.max():
        p.delete(ANOVAInputMatrixValuesArray, q, axis=0)

แต่ด้วยเหตุผลบางประการรหัสนี้ดูเหมือนจะไม่ทำอะไรแม้ว่าการพิมพ์คำสั่งจำนวนมากจะบ่งชี้ว่าตัวแปรทั้งหมดดูเหมือนจะเติมข้อมูลอย่างถูกต้องซึ่งนำไปสู่รหัส

ต้องมีวิธีง่ายๆในการ "ลบแถวใดก็ได้ที่มีค่าเป็นศูนย์"

ใครช่วยแสดงรหัสที่จะเขียนเพื่อบรรลุเป้าหมายนี้ได้ไหม

คำตอบ:


166

วิธีที่ง่ายที่สุดในการลบแถวและคอลัมน์จากอาร์เรย์คือnumpy.deleteวิธีการ

สมมติว่าฉันมีอาร์เรย์ต่อไปนี้x:

x = array([[1,2,3],
        [4,5,6],
        [7,8,9]])

หากต้องการลบแถวแรกให้ดำเนินการดังนี้:

x = numpy.delete(x, (0), axis=0)

หากต้องการลบคอลัมน์ที่สามให้ดำเนินการดังนี้:

x = numpy.delete(x,(2), axis=1)

ดังนั้นคุณสามารถค้นหาดัชนีของแถวที่มี 0 อยู่ในนั้นใส่ไว้ในรายการหรือทูเพิลแล้วส่งค่านี้เป็นอาร์กิวเมนต์ที่สองของฟังก์ชัน


ขอบคุณ! ฉันมีปัญหาเดียวกันและฉันคิดไม่ออกว่าทำไมการโทรถึงใช้numpy.delete(x, index)ไม่ได้
Antimony

6
โปรดทราบว่าเอกสารnumpy delete ()ระบุว่า "มักจะนิยมใช้บูลีนมาสก์" เนื่องจากอาร์เรย์ใหม่จะถูกส่งคืนตัวอย่างมีให้ในลิงค์นั้น
arturomp

1
@arturomp แต่หน้ากากไม่ทำลาย การโทรเพื่อลบ () ใช้เวลา / หน่วยความจำหรือไม่
นาธาน

14

นี่คือซับเดียว (ใช่มันคล้ายกับ user333700 แต่ตรงไปตรงมากว่าเล็กน้อย):

>>> import numpy as np
>>> arr = np.array([[ 0.96488889, 0.73641667, 0.67521429, 0.592875, 0.53172222], 
                [ 0.78008333, 0.5938125, 0.481, 0.39883333, 0.]])
>>> print arr[arr.all(1)]
array([[ 0.96488889,  0.73641667,  0.67521429,  0.592875  ,  0.53172222]])

อย่างไรก็ตามวิธีนี้เร็วกว่าวิธีการมาสก์อาร์เรย์สำหรับเมทริกซ์ขนาดใหญ่มาก สำหรับเมทริกซ์ 2048 x 5 วิธีนี้เร็วกว่าประมาณ 1,000 เท่า

อย่างไรก็ตามวิธีการของ user333700 (จากความคิดเห็นของเขา) นั้นเร็วกว่าเล็กน้อยในการทดสอบของฉันแม้ว่ามันจะทำให้ฉันคิดว่าทำไม


3
"ใด ๆ " สามารถลัดวงจรได้ทันทีที่ตรวจพบกรณีแรกที่แท้จริงจะหยุดได้ขณะที่ "ทั้งหมด" ต้องตรวจสอบเงื่อนไขทั้งหมด ดังนั้นไม่ ("~" เป็นตัวเลข) ใด ๆ โดยทั่วไปควรเร็วกว่าทั้งหมด
Josef

4
@ user333700 ทั้งคู่สามารถลัดวงจรได้คนละอย่างกัน anyการลัดวงจรเป็นจริงในกรณีแรกที่ตรวจพบ allการลัดวงจรเป็นเท็จในกรณีแรกที่ตรวจพบเท็จ ในกรณีนี้การลัดวงจรควรเป็นการดึง แต่การทำพิเศษไม่ควรทำให้ช้าลงในความคิดของฉัน
Justin Peel

5

วิธีนี้คล้ายกับแนวทางเดิมของคุณและจะใช้พื้นที่น้อยกว่าคำตอบของ unutbuแต่ฉันสงสัยว่ามันจะช้ากว่า

>>> import numpy as np
>>> p = np.array([[1.5, 0], [1.4,1.5], [1.6, 0], [1.7, 1.8]])
>>> p
array([[ 1.5,  0. ],
       [ 1.4,  1.5],
       [ 1.6,  0. ],
       [ 1.7,  1.8]])
>>> nz = (p == 0).sum(1)
>>> q = p[nz == 0, :]
>>> q
array([[ 1.4,  1.5],
       [ 1.7,  1.8]])

ยังไงp.delete()ก็ตามสายงานของคุณใช้ไม่ได้สำหรับฉัน - ndarrayไม่มี.deleteแอตทริบิวต์


8
ง่ายกว่าเล็กน้อย: p [~ (p == 0) .any (1)] หรือมากกว่าอย่างชัดเจนสำหรับแถว: p [~ (p == 0) .any (1),:]
Josef

2

numpy มีฟังก์ชันง่ายๆในการทำสิ่งเดียวกัน: สมมติว่าคุณมีอาร์เรย์ที่มาสก์ 'a' การเรียก numpy.ma.compress_rows (a) จะลบแถวที่มีค่าที่ถูกปิดบัง ฉันเดาว่าวิธีนี้เร็วกว่ามาก ...


1
import numpy as np 
arr = np.array([[ 0.96488889, 0.73641667, 0.67521429, 0.592875, 0.53172222],[ 0.78008333, 0.5938125, 0.481, 0.39883333, 0.]])
print(arr[np.where(arr != 0.)])

-1

ฉันอาจจะสายเกินไปที่จะตอบคำถามนี้ แต่ต้องการแบ่งปันความคิดเห็นของฉันเพื่อประโยชน์ของชุมชน สำหรับตัวอย่างนี้ขอฉันเรียกเมทริกซ์ของคุณว่า 'ANOVA' และฉันสมมติว่าคุณแค่พยายามลบแถวออกจากเมทริกซ์นี้โดยมี 0 ในคอลัมน์ที่ 5 เท่านั้น

indx = []
for i in range(len(ANOVA)):
    if int(ANOVA[i,4]) == int(0):
        indx.append(i)

ANOVA = [x for x in ANOVA if not x in indx]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.