Python NumPy Array के सभी तत्वों को बदलें जो कुछ मान से अधिक हैं


188

मैं एक 2 डी NumPy सरणी है और सभी मूल्यों 255.0 के साथ एक सीमा टी के बराबर या उससे अधिक उस में बदलने के लिए चाहते हैं। मेरे ज्ञान के लिए, सबसे मौलिक तरीका होगा:

shape = arr.shape
result = np.zeros(shape)
for x in range(0, shape[0]):
    for y in range(0, shape[1]):
        if arr[x, y] >= T:
            result[x, y] = 255
  1. ऐसा करने के लिए सबसे संक्षिप्त और पाइथोनिक तरीका क्या है?

  2. क्या ऐसा करने का एक तेज़ (संभवतः कम संक्षिप्त और / या कम पायथोनिक) तरीका है?

यह मानव सिर के एमआरआई स्कैन के लिए एक खिड़की / स्तर समायोजन उप-भाग का हिस्सा होगा। 2 डी संख्यात्मक सरणी छवि पिक्सेल डेटा है।


अधिक जानकारी के लिए, इस परिचय पर नज़र डालें अनुक्रमण के लिए
Askewchan

जवाबों:


330

मुझे लगता है कि ऐसा करने के लिए सबसे तेज़ और सबसे संक्षिप्त दोनों तरीके हैं, NumPy के अंतर्निहित फैंसी इंडेक्सिंग का उपयोग करना। यदि आपके पास एक ndarrayनाम है arr, तो आप सभी तत्वों >255को एक मूल्य के साथ बदल सकते xहैं:

arr[arr > 255] = x

मैंने 500 x 500 यादृच्छिक मैट्रिक्स के साथ अपनी मशीन पर इसे चलाया, सभी मानों को प्रतिस्थापित करते हुए> 5 के साथ 0.5, और इसमें 7.59ms का औसत लिया।

In [1]: import numpy as np
In [2]: A = np.random.rand(500, 500)
In [3]: timeit A[A > 0.5] = 5
100 loops, best of 3: 7.59 ms per loop

3
ध्यान दें कि यह ओपी की तरह arrएक resultसरणी बनाने के बजाय मौजूदा सरणी को संशोधित करता है ।
askewchan

1
क्या ऐसा करने का कोई तरीका नहीं है, Aबल्कि संशोधित करके एक नई सरणी बनाई जाए?
sodiumnitrate

हम क्या करते हैं, अगर हम अनुक्रमित जो एन को देखते हुए की तरह एक [2] के कई हैं, एक [4], एक [6], एक [8] ..... के लिए n = 2 में परिवर्तन मूल्यों करना चाहते थे?
lavee_singh

100 लूप्स, सर्वश्रेष्ठ 3: 2.22 एमएस प्रति लूप
dreab

5
नोट: यदि डेटा एक अजगर सूची में है, तो यह काम नहीं करता है, यह एक संख्यात्मक सरणी ( np.array([1,2,3]) में होना है
mjp

46

चूंकि आप वास्तव में एक अलग सरणी चाहते हैं जो कि arrकहां है arr < 255, और 255अन्यथा, यह बस किया जा सकता है:

result = np.minimum(arr, 255)

अधिक सामान्यतः, कम और / या ऊपरी बाउंड के लिए:

result = np.clip(arr, 0, 255)

यदि आप केवल 255 से अधिक मूल्यों का उपयोग करना चाहते हैं, या कुछ अधिक जटिल है, तो @ mtitan8 का उत्तर अधिक सामान्य है, लेकिन np.clipऔर np.minimum(या np.maximum) आपके मामले के लिए अच्छे हैं और बहुत तेज़ हैं:

In [292]: timeit np.minimum(a, 255)
100000 loops, best of 3: 19.6 µs per loop

In [293]: %%timeit
   .....: c = np.copy(a)
   .....: c[a>255] = 255
   .....: 
10000 loops, best of 3: 86.6 µs per loop

यदि आप इसे इन-प्लेस करना चाहते हैं (यानी, arrबनाने के बजाय संशोधित करें result) तो आप निम्न outपैरामीटर का उपयोग कर सकते हैं np.minimum:

np.minimum(arr, 255, out=arr)

या

np.clip(arr, 0, 255, arr)

( out=नाम समारोह की परिभाषा के रूप में एक ही क्रम में बहस के बाद से वैकल्पिक है।)

यथा-स्थान संशोधन के लिए, बूलियन अनुक्रमण (बनाने के लिए और फिर अलग से प्रतिलिपि को संशोधित किए बिना) एक बहुत गति, लेकिन अभी भी जितनी जल्दी नहीं है minimum:

In [328]: %%timeit
   .....: a = np.random.randint(0, 300, (100,100))
   .....: np.minimum(a, 255, a)
   .....: 
100000 loops, best of 3: 303 µs per loop

In [329]: %%timeit
   .....: a = np.random.randint(0, 300, (100,100))
   .....: a[a>255] = 255
   .....: 
100000 loops, best of 3: 356 µs per loop

तुलना के लिए, यदि आप अपने मूल्यों को न्यूनतम के साथ-साथ अधिकतम तक सीमित करना चाहते थे, तो बिना clipकुछ किए दो बार ऐसा करना होगा।

np.minimum(a, 255, a)
np.maximum(a, 0, a)

या,

a[a>255] = 255
a[a<0] = 0

1
आपकी पूरी टिप्पणी के लिए बहुत-बहुत धन्यवाद, हालाँकि np.clip और np.minimum को ऐसा नहीं लगता कि मुझे इस मामले में क्या चाहिए, ओपी में आप देखते हैं कि सीमा टी और प्रतिस्थापन मूल्य (255) आवश्यक नहीं हैं नंबर। हालाँकि मैंने फिर भी आपको पूरी तरह से वोट दिया। एक बार फिर धन्यवाद।
एनएलआई

हम क्या करते हैं, अगर हम अनुक्रमित जो एन को देखते हुए की तरह एक [2] के कई हैं, एक [4], एक [6], एक [8] ..... के लिए n = 2 में परिवर्तन मूल्यों करना चाहते थे?
lavee_singh

@lavee_singh, ऐसा करने के लिए, आप स्लाइस के तीसरे भाग का उपयोग कर सकते हैं, जो आमतौर पर उपेक्षित होता है: a[start:stop:step]आपको ऐरे से तत्वों को देता startहै stop, लेकिन हर तत्व के बजाय, यह केवल हर लेता है step(यदि उपेक्षित है, तो यह 1डिफ़ॉल्ट रूप से है) )। इसलिए सभी a[::2] = 0
बुराइयों

धन्यवाद मुझे कुछ चाहिए, इस तरह, भले ही मैं इसे सरल सूचियों के लिए जानता था, लेकिन मुझे नहीं पता था कि यह numpy.array के लिए काम करता है या नहीं।
लावे_सिंह

14

मुझे लगता है कि आप whereफ़ंक्शन का उपयोग करके इसे सबसे तेज प्राप्त कर सकते हैं :

उदाहरण के लिए 0.2 से आइटम अधिक से अधिक की तलाश में एक numpy सरणी में और 0 के साथ उन की जगह:

import numpy as np

nums = np.random.rand(4,3)

print np.where(nums > 0.2, 0, nums)

10

आप numpy.putmask का उपयोग करने पर विचार कर सकते हैं :

np.putmask(arr, arr>=T, 255.0)

यहाँ Numpy के बिलिन इंडेक्सिंग के साथ एक प्रदर्शन तुलना है:

In [1]: import numpy as np
In [2]: A = np.random.rand(500, 500)

In [3]: timeit np.putmask(A, A>0.5, 5)
1000 loops, best of 3: 1.34 ms per loop

In [4]: timeit A[A > 0.5] = 5
1000 loops, best of 3: 1.82 ms per loop

8

एक और तरीका है उपयोग करने के लिए है np.place, जिसमें जगह प्रतिस्थापन करता है और multidimentional सरणियों के साथ काम करता है:

import numpy as np

# create 2x3 array with numbers 0..5
arr = np.arange(6).reshape(2, 3)

# replace 0 with -10
np.place(arr, arr == 0, -10)

यह वह समाधान है जिसका मैंने उपयोग किया क्योंकि यह पहली बार था जब मैं आया था। मुझे आश्चर्य है कि अगर इसके और ऊपर चयनित उत्तर के बीच कोई बड़ा अंतर है। तुम क्या सोचते हो?
jonathanking

बहुत सीमित परीक्षणों में, np.place के साथ मेरा उपरोक्त कोड प्रत्यक्ष अनुक्रमण की स्वीकृत विधि की तुलना में 2X धीमा चल रहा है। यह आश्चर्यजनक है क्योंकि मैंने सोचा होगा कि np.place अधिक अनुकूलित होगा, लेकिन मुझे लगता है कि उन्होंने प्रत्यक्ष अनुक्रमण पर अधिक काम किया है।
शीतल शाह

मेरे मामले np.placeमें भी अंतर्निहित विधि की तुलना में धीमी थी, हालांकि इस टिप्पणी में विपरीत का दावा किया गया है ।
riyansh.legend

3

तुम भी उपयोग कर सकते हैं &, |अधिक लचीलेपन के लिए (और / या):

5 और 10 के बीच का मान: A[(A>5)&(A<10)]

मान 10 से अधिक या 5 से छोटा: A[(A<5)|(A>10)]

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.