วิธีคืนค่า 0 โดยหารด้วยศูนย์


106

ฉันกำลังพยายามหารองค์ประกอบอย่างชาญฉลาดใน python แต่ถ้าพบศูนย์ฉันต้องการให้ผลหารเป็นศูนย์

ตัวอย่างเช่น:

array1 = np.array([0, 1, 2])
array2 = np.array([0, 1, 1])

array1 / array2 # should be np.array([0, 1, 2])

ฉันสามารถใช้ for-loop ผ่านข้อมูลของฉันได้ตลอดเวลา แต่เพื่อใช้ประโยชน์จากการเพิ่มประสิทธิภาพของ numpy จริงๆฉันต้องการให้ฟังก์ชันการหารคืนค่า 0 เมื่อหารด้วยข้อผิดพลาดเป็นศูนย์แทนที่จะละเว้นข้อผิดพลาด

ดูเหมือนว่าnumpy.seterr ()ไม่สามารถคืนค่าได้หากไม่มีข้อผิดพลาด ใครมีข้อเสนอแนะอื่น ๆ เกี่ยวกับวิธีที่ฉันจะได้รับสิ่งที่ดีที่สุดในขณะที่ตั้งค่าการหารของตัวเองโดยการจัดการข้อผิดพลาดเป็นศูนย์?


ในเวอร์ชัน python ของฉัน (Python 2.7.11 | Continuum Analytics, Inc. ) นั่นคือผลลัพธ์ที่คุณได้รับ พร้อมคำเตือน.
Ramon Martinez

คำตอบที่ถูกต้องรวบรัดที่สุดคือstackoverflow.com/a/37977222/2116338
mrplants

คำตอบ:


197

ใน numpy v1.7 + คุณสามารถใช้ประโยชน์จากการ "ที่" ตัวเลือกสำหรับการufuncs คุณสามารถทำสิ่งต่างๆได้ในบรรทัดเดียวและไม่จำเป็นต้องจัดการกับตัวจัดการบริบทที่ผิดพลาด

>>> a = np.array([-1, 0, 1, 2, 3], dtype=float)
>>> b = np.array([ 0, 0, 0, 2, 2], dtype=float)

# If you don't pass `out` the indices where (b == 0) will be uninitialized!
>>> c = np.divide(a, b, out=np.zeros_like(a), where=b!=0)
>>> print(c)
[ 0.   0.   0.   1.   1.5]

ในกรณีนี้จะคำนวณหารที่ 'โดยที่' b ไม่เท่ากับศูนย์ เมื่อ b เท่ากับศูนย์มันจะยังคงไม่เปลี่ยนแปลงจากค่าที่คุณให้ไว้ในอาร์กิวเมนต์ 'out'


4
ถ้าaและ / หรือbอาจเป็นอาร์เรย์จำนวนเต็มแสดงว่าเป็นแนวคิดเดียวกันคุณเพียงแค่ต้องตั้งค่าประเภทเอาต์พุตที่ถูกต้องอย่างชัดเจน:c = np.divide(a, b, out=np.zeros(a.shape, dtype=float), where=b!=0)
DStauffman

out=np.zeros_like(a)มีความสำคัญตามที่ระบุไว้ในบรรทัดที่แสดงความคิดเห็น
Jonatan Öström

1
หากฉันใช้ฉันได้รับข้อผิดพลาดnp.divide(a, b, out=np.zeros_like(a), where=b!=0) Assigning to function call which doesn't returnสิ่งที่แปลกคือฉันใช้มันสองครั้งและข้อผิดพลาดปรากฏขึ้นเพียงครั้งเดียว
Jelmer Mulder

1
ในกรณีที่ใครสนใจวิธีที่เร็วที่สุดวิธีนี้เร็วกว่าคำตอบของ @ denis / @ Franck Dernoncourt โดยใช้หนึ่งล้านรอบฉันจะได้รับ 8 วินาทีสำหรับสิ่งนี้เทียบกับ 11 วินาทีสำหรับพวกเขา
kory

49

สร้างจากคำตอบของ @Franck Dernoncourt แก้ไข -1 / 0:

def div0( a, b ):
    """ ignore / 0, div0( [-1, 0, 1], 0 ) -> [0, 0, 0] """
    with np.errstate(divide='ignore', invalid='ignore'):
        c = np.true_divide( a, b )
        c[ ~ np.isfinite( c )] = 0  # -inf inf NaN
    return c

div0( [-1, 0, 1], 0 )
array([0, 0, 0])

ขอบคุณฉันไม่ได้จับจุดบกพร่องนั้นด้วยรหัสของ @Frank Dernoncourt
hlin117

สวัสดีฉันกำลังพยายามทำคณิตศาสตร์อาร์เรย์และฉันต้องการให้ 0/0 ได้ผลลัพธ์เป็น 0 แต่ฉันก็ไม่สนใจ np.NaN ในการคำนวณของฉันด้วย จะได้ผลหรือไม่ นอกจากนี้ฉันกำลังพยายามทำความเข้าใจ c [~ np.isfinite (c)] = 0 ทำอะไร? ฉันไม่เคยใช้ ~ ใน python มีไว้เพื่ออะไร? ขอบคุณ
user20408

@ user20408, ~ตีความTrueและFalseในอาร์เรย์ print ~ np.array([ True, False, False ])numpy: c[ ~ np.isfinite( c )] = 0หมายถึง: ค้นหาตำแหน่งที่cจำกัด สลับตำแหน่งที่ไม่ จำกัด ด้วย~และตั้งค่าไม่ จำกัด เป็น 0 ดูที่stackoverflow.com/search?q=[numpy]+"boolean+indexing "
denis

44

สร้างคำตอบอื่น ๆ และปรับปรุง:

รหัส:

import numpy as np

a = np.array([0,0,1,1,2], dtype='float')
b = np.array([0,1,0,1,3], dtype='float')

with np.errstate(divide='ignore', invalid='ignore'):
    c = np.true_divide(a,b)
    c[c == np.inf] = 0
    c = np.nan_to_num(c)

print('c: {0}'.format(c))

เอาท์พุต:

c: [ 0.          0.          0.          1.          0.66666667]

2
ดีสำหรับการตรวจสอบ0/0และ1/0ข้อผิดพลาด
hlin117

ฉันลองใช้วิธีของคุณด้วยอาร์เรย์ตัวอย่างที่ให้ไว้ในคำตอบของ DStauffmanและดูเหมือนว่าจะให้ผลเป็นตัวเลขที่สูงมากแทนที่จะเป็น np.inf ซึ่งยังคงอยู่ที่ผลลัพธ์สุดท้าย
Gal Avineri

ฉันจะกีดกันแนวทางนี้ หากมีอย่างใดอย่างหนึ่งaหรือbมีNaNโซลูชันของคุณก็ให้0ผลลัพธ์ทันที สิ่งนี้สามารถซ่อนข้อผิดพลาดในโค้ดของคุณได้อย่างง่ายดายและไม่คาดคิดอย่างยิ่ง
DerWeh

ตาม nan_to_num () manual numpy () ล่าสุดใช้ค่าเพื่อแทนที่ inf positive และ negative inf numpy.nan_to_num(x, copy=True, nan=0.0, posinf=None, neginf=None)เป็นลายเซ็น
Craig Hicks


13

ลองทำในสองขั้นตอน หารก่อนแล้วแทนที่

with numpy.errstate(divide='ignore'):
    result = numerator / denominator
    result[denominator == 0] = 0

numpy.errstateเส้นเป็นตัวเลือกและเพียงแค่ป้องกัน NumPy จากบอกคุณเกี่ยวกับ "ข้อผิดพลาด" ของการหารด้วยศูนย์ตั้งแต่คุณแล้วตั้งใจที่จะทำเช่นนั้นและการจัดการกรณีที่


5
คุณควรดำเนินการแบ่งตามบริบทnp.errstate(divide='ignore'):
Warren Weckesser

@WarrenWeckesser จุดยุติธรรม. ฉันได้แก้ไขคำตอบเพื่อรวมบริบท divide='warn'ยังอาจมีประโยชน์ถ้าเขา / เขาต้องการยังคงได้รับการแจ้งเตือน
Pi Marillion

2

นอกจากนี้คุณยังสามารถแทนที่ตามinfแต่ถ้าประเภทอาร์เรย์ลอยตามคำตอบนี้ :

>>> a = np.array([1,2,3], dtype='float')
>>> b = np.array([0,1,3], dtype='float')
>>> c = a / b
>>> c
array([ inf,   2.,   1.])
>>> c[c == np.inf] = 0
>>> c
array([ 0.,  2.,  1.])

0

คำตอบหนึ่งที่ฉันพบในการค้นหาคำถามที่เกี่ยวข้องคือการจัดการผลลัพธ์โดยพิจารณาว่าตัวส่วนเป็นศูนย์หรือไม่

สมมติว่าarrayAและarrayBได้รับการเริ่มต้น แต่arrayBมีบางศูนย์ เราสามารถทำสิ่งต่อไปนี้ได้หากต้องการคำนวณarrayC = arrayA / arrayBอย่างปลอดภัย

ในกรณีนี้เมื่อใดก็ตามที่ฉันมีการหารด้วยศูนย์ในเซลล์ใดเซลล์หนึ่งฉันจะตั้งค่าเซลล์ให้เท่ากับmyOwnValueซึ่งในกรณีนี้จะเป็นศูนย์

myOwnValue = 0
arrayC = np.zeros(arrayA.shape())
indNonZeros = np.where(arrayB != 0)
indZeros = np.where(arrayB = 0)

# division in two steps: first with nonzero cells, and then zero cells
arrayC[indNonZeros] = arrayA[indNonZeros] / arrayB[indNonZeros]
arrayC[indZeros] = myOwnValue # Look at footnote

เชิงอรรถ: ในการมองย้อนกลับบรรทัดนี้ไม่จำเป็นอีกต่อไปเนื่องจากarrayC[i]ถูกสร้างอินสแตนซ์เป็นศูนย์ แต่ถ้าเป็นเช่นนั้นmyOwnValue != 0การดำเนินการนี้จะทำอะไรบางอย่าง


0

ทางออกอื่นที่ควรค่าแก่การกล่าวถึง:

>>> a = np.array([1,2,3], dtype='float')
>>> b = np.array([0,1,3], dtype='float')
>>> b_inv = np.array([1/i if i!=0 else 0 for i in b])
>>> a*b_inv
array([0., 2., 1.])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.