3 डी आयाम, एन बार (पायथन) में 2 डी सरणी की प्रतिलिपि बनाएँ


106

मैं एक तीसरे आयाम में एक सुस्पष्ट 2D सरणी की नकल करना चाहता हूं। उदाहरण के लिए, दी गई (2 डी) संख्या:

import numpy as np
arr = np.array([[1,2],[1,2]])
# arr.shape = (2, 2)

एक नए आयाम में एन ऐसी प्रतियों के साथ 3 डी मैट्रिक्स में परिवर्तित करें। arrN = 3 के साथ अभिनय करना, आउटपुट होना चाहिए:

new_arr = np.array([[[1,2],[1,2]],[[1,2],[1,2]],[[1,2],[1,2]]])
# new_arr.shape = (3, 2, 2)

जवाबों:


146

संभवतः सबसे साफ तरीका उपयोग करना है np.repeat:

a = np.array([[1, 2], [1, 2]])
print(a.shape)
# (2,  2)

# indexing with np.newaxis inserts a new 3rd dimension, which we then repeat the
# array along, (you can achieve the same effect by indexing with None, see below)
b = np.repeat(a[:, :, np.newaxis], 3, axis=2)

print(b.shape)
# (2, 2, 3)

print(b[:, :, 0])
# [[1 2]
#  [1 2]]

print(b[:, :, 1])
# [[1 2]
#  [1 2]]

print(b[:, :, 2])
# [[1 2]
#  [1 2]]

कहा कि, आप अक्सर प्रसारण का उपयोग करके अपने सरणियों को पूरी तरह से दोहराने से बच सकते हैं । उदाहरण के लिए, मान लें कि मैं एक (3,)वेक्टर जोड़ना चाहता था :

c = np.array([1, 2, 3])

को a। मैं aतीसरे आयाम में 3 बार की सामग्री को कॉपी कर सकता हूं , फिर cपहले और दूसरे दोनों आयामों में दो बार की सामग्री को कॉपी कर सकता हूं , ताकि मेरे दोनों (2, 2, 3)सरणियां फिर उनकी राशि की गणना करें। हालाँकि, यह करने के लिए बहुत सरल और तेज है:

d = a[..., None] + c[None, None, :]

यहाँ, a[..., None]आकार है (2, 2, 1)और c[None, None, :]आकार है (1, 1, 3)*। जब मैं योग की गणना करता हूं, तो परिणाम आकार 1 के आयामों के साथ 'प्रसारित' हो जाता है, जिससे मुझे आकार मिलता है (2, 2, 3):

print(d.shape)
# (2,  2, 3)

print(d[..., 0])    # a + c[0]
# [[2 3]
#  [2 3]]

print(d[..., 1])    # a + c[1]
# [[3 4]
#  [3 4]]

print(d[..., 2])    # a + c[2]
# [[4 5]
#  [4 5]]

ब्रॉडकास्टिंग एक बहुत शक्तिशाली तकनीक है क्योंकि यह मेमोरी में आपके इनपुट सरणियों की बार-बार प्रतियां बनाने में शामिल अतिरिक्त ओवरहेड से बचा जाता है।


* हालांकि मैंने उन्हें स्पष्टता के लिए शामिल किया, लेकिन Noneसूचकांकों को cवास्तव में आवश्यक नहीं है - आप भी कर सकते हैं a[..., None] + c, यानी एक (2, 2, 1)सरणी के खिलाफ एक (3,)सरणी प्रसारित कर सकते हैं । ऐसा इसलिए है क्योंकि यदि किसी एक सरणियों में दूसरे की तुलना में कम आयाम हैं तो केवल दो सरणियों के अनुगामी आयामों को संगत करने की आवश्यकता है। अधिक जटिल उदाहरण देने के लिए:

a = np.ones((6, 1, 4, 3, 1))  # 6 x 1 x 4 x 3 x 1
b = np.ones((5, 1, 3, 2))     #     5 x 1 x 3 x 2
result = a + b                # 6 x 5 x 4 x 3 x 2

कि यह वास्तव में सही परिणाम देता है सत्यापित करने के लिए, आप भी प्रिंट कर सकते हैं b[:,:,0], b[:,:,1]और b[:,:,2]। प्रत्येक तीसरे आयाम का टुकड़ा मूल 2D सरणी की एक प्रति है। यह केवल देखने में उतना स्पष्ट नहीं है print(b)
ely

कोई नहीं और np.newaxis के बीच अंतर क्या है? जब मैंने उसका परीक्षण किया, तो उसने वही परिणाम दिया।
मोनोलिथ

1
@wedran वे बिलकुल एक जैसे हैं - np.newaxisसिर्फ None
ali_m

27

दूसरा तरीका उपयोग करना है numpy.dstack। यह सोचते हुए कि आप मैट्रिक्स a num_repeatsबार दोहराना चाहते हैं :

import numpy as np
b = np.dstack([a]*num_repeats)

चाल को aएक एकल तत्व की सूची में मैट्रिक्स को लपेटना है , फिर *इस सूची के num_repeatsसमय में तत्वों की नकल करने के लिए ऑपरेटर का उपयोग करना है ।

उदाहरण के लिए, यदि:

a = np.array([[1, 2], [1, 2]])
num_repeats = 5

यह [1 2; 1 2]तीसरे आयाम में 5 बार के सरणी को दोहराता है । सत्यापित करने के लिए (IPython में):

In [110]: import numpy as np

In [111]: num_repeats = 5

In [112]: a = np.array([[1, 2], [1, 2]])

In [113]: b = np.dstack([a]*num_repeats)

In [114]: b[:,:,0]
Out[114]: 
array([[1, 2],
       [1, 2]])

In [115]: b[:,:,1]
Out[115]: 
array([[1, 2],
       [1, 2]])

In [116]: b[:,:,2]
Out[116]: 
array([[1, 2],
       [1, 2]])

In [117]: b[:,:,3]
Out[117]: 
array([[1, 2],
       [1, 2]])

In [118]: b[:,:,4]
Out[118]: 
array([[1, 2],
       [1, 2]])

In [119]: b.shape
Out[119]: (2, 2, 5)

अंत में हम देख सकते हैं कि मैट्रिक्स का आकार 2 x 2तीसरे आयाम में 5 स्लाइस के साथ है।


यह कैसे तुलना करता है reshape? और तेज? एक ही संरचना देता है? इसका निश्चित रूप से neater।
एंडर बिगुरी जूल

@AnderBiguri मैंने कभी भी बेंचमार्क नहीं किया है ... मैंने इसे यहाँ मुख्य रूप से पूर्णता के लिए रखा है। यह समय के साथ दिलचस्प होगा और अंतर देखेगा।
रेयरेंग जूल

1
मैंने अभी img = np.dstack ([arr] * 3) किया और ठीक काम किया! धन्यवाद
thanos.a

1
लगा कि मैं दक्षता के लिए देखे गए आउटपुट का प्रस्ताव कर सकता हूं। एक पुरानी पोस्ट होने के कारण, लोगों को वह याद आ गया होगा। इस प्रश्नोत्तर पर एक समाधान जोड़ा गया।
दिवाकर

1
IMHO सबसे पठनीय समाधान है, लेकिन यह तुलना के लिए अन्य तरीकों के खिलाफ बेंचमार्क करने के लिए बहुत अच्छा होगा।
मर्ग्लोम

16

एक दृश्य का उपयोग करें और मुफ्त रनटाइम प्राप्त करें! जेनेरिक बढ़ाएँn-dimकरने के लिए सरणियाँn+1-dim

NumPy1.10.0 में प्रस्तुत , हम इनपुट ऐरे में numpy.broadcast_toकेवल एक 3Dदृश्य उत्पन्न करने के लिए लाभ उठा सकते हैं 2D। लाभ कोई अतिरिक्त मेमोरी ओवरहेड और वस्तुतः मुक्त रनटाइम होगा। यह उन मामलों में आवश्यक होगा जहां सरणियाँ बड़ी हैं और हम विचारों के साथ काम करने के लिए ठीक हैं। इसके अलावा, यह सामान्य n-dimमामलों के साथ काम करेगा ।

मैं शब्द का प्रयोग करेंगे stackके स्थान परcopy , क्योंकि पाठक इसे मेमोरी कॉपी बनाने वाले सरणियों की नकल के साथ भ्रमित कर सकते हैं।

पहली धुरी के साथ ढेर

यदि हम arrपहले अक्ष के साथ इनपुट को स्टैक करना चाहते हैं , तो दृश्य np.broadcast_toबनाने के लिए समाधान 3Dहोगा -

np.broadcast_to(arr,(3,)+arr.shape) # N = 3 here

तीसरी / अंतिम धुरी के साथ ढेर

arrतीसरे अक्ष के साथ इनपुट को ढेर करने के लिए, 3Dदृश्य बनाने का समाधान होगा -

np.broadcast_to(arr[...,None],arr.shape+(3,))

अगर हमें वास्तव में मेमोरी कॉपी की आवश्यकता होती है, तो हम हमेशा .copy()वहां अपील कर सकते हैं । इसलिए, समाधान होगा -

np.broadcast_to(arr,(3,)+arr.shape).copy()
np.broadcast_to(arr[...,None],arr.shape+(3,)).copy()

यहाँ बताया गया है कि कैसे दो मामलों के लिए स्टैकिंग काम करता है, एक नमूना मामले के लिए उनके आकार की जानकारी के साथ दिखाया गया है -

# Create a sample input array of shape (4,5)
In [55]: arr = np.random.rand(4,5)

# Stack along first axis
In [56]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[56]: (3, 4, 5)

# Stack along third axis
In [57]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[57]: (4, 5, 3)

समान समाधान (एस) पहली और आखिरी कुल्हाड़ियों के साथ आउटपुट देखने के लिए एक n-dimइनपुट का विस्तार करने के लिए काम करेगा n+1-dim। आइए कुछ उच्च मंद मामलों की पड़ताल करें -

3 डी इनपुट मामला:

In [58]: arr = np.random.rand(4,5,6)

# Stack along first axis
In [59]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[59]: (3, 4, 5, 6)

# Stack along last axis
In [60]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[60]: (4, 5, 6, 3)

4D इनपुट मामला:

In [61]: arr = np.random.rand(4,5,6,7)

# Stack along first axis
In [62]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[62]: (3, 4, 5, 6, 7)

# Stack along last axis
In [63]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[63]: (4, 5, 6, 7, 3)

और इसी तरह।

समय

आइए एक बड़े नमूना 2Dमामले का उपयोग करें और समय प्राप्त करें और आउटपुट को सत्यापित करें view

# Sample input array
In [19]: arr = np.random.rand(1000,1000)

आइए साबित करें कि प्रस्तावित समाधान वास्तव में एक दृश्य है। हम पहले अक्ष के साथ स्टैकिंग का उपयोग करेंगे (परिणाम तीसरी अक्ष के साथ स्टैकिंग के लिए समान होगा) -

In [22]: np.shares_memory(arr, np.broadcast_to(arr,(3,)+arr.shape))
Out[22]: True

चलो यह दिखाने के लिए कि यह वस्तुतः मुफ्त है -

In [20]: %timeit np.broadcast_to(arr,(3,)+arr.shape)
100000 loops, best of 3: 3.56 µs per loop

In [21]: %timeit np.broadcast_to(arr,(3000,)+arr.shape)
100000 loops, best of 3: 3.51 µs per loop

, एक दृश्य होने के नाते में वृद्धि Nसे 3करने के लिए 3000समय पर बदल कुछ भी नहीं है और दोनों समय इकाइयों पर नगण्य हैं। इसलिए, स्मृति और प्रदर्शन दोनों पर कुशल!


3
A=np.array([[1,2],[3,4]])
B=np.asarray([A]*N)

आयाम क्रम को संरक्षित करने के लिए @ Mr.F को संपादित करें:

B=B.T

यह मेरे लिए एक N x 2 x 2 सरणी में परिणाम करता है, उदाहरण के लिए जो कुछ भी B.shapeप्रिंट करता (N, 2, 2)है N। यदि आप इसके Bसाथ स्थानांतरण करते हैं B.Tतो यह अपेक्षित आउटपुट से मेल खाता है।
ely

@ Mr.F - आप सही हैं। यह पहले आयाम के साथ प्रसारित होगा, और ऐसा करने B[0], B[1],...से आपको सही टुकड़ा मिलेगा, जिसका मैं तर्क देता हूं और कहता हूं कि इसका उपयोग करने के बजाय टाइप करना अधिक आसान है B[:,:,0], B[:,:,1], आदि
किरण

यह टाइप करना आसान हो सकता है, लेकिन उदाहरण के लिए यदि आप छवि डेटा के साथ ऐसा कर रहे हैं तो यह काफी हद तक गलत होगा, क्योंकि लगभग सभी एल्गोरिदम पिक्सेल चैनलों के 2 डी स्लाइस के लिए रैखिक बीजगणित के सम्मेलनों का उपयोग करने की उम्मीद करेंगे। उन अनुप्रयोगों की कल्पना करना कठिन है जहां आप एक 2 डी सरणी के साथ शुरू करते हैं, एक निश्चित सम्मेलन के साथ पंक्तियों और स्तंभों का इलाज करते हैं, और फिर आप उसी चीज की कई प्रतियां चाहते हैं जो एक नई अक्ष में फैली हुई है, लेकिन अचानक आप चाहते हैं कि पहली धुरी का अर्थ बदलना नई धुरी
बनें

@ Mr.F - ओह निश्चित रूप से। मैं अनुमान नहीं लगा सकता कि आप भविष्य में 3D मैट्रिक्स का उपयोग किन अनुप्रयोगों के लिए करना चाहते हैं। यह कहा जा रहा है, यह सब आवेदन पर निर्भर करता है। एफडब्ल्यूआईडब्ल्यू, मैं उसी B[:,:,i]तरह से पसंद करता हूं जैसा कि मैं आदी हूं।
२३:१५ को रेय्यरेंग

2

यहां एक प्रसारण उदाहरण है जो वास्तव में अनुरोध किया गया था।

a = np.array([[1, 2], [1, 2]])
a=a[:,:,None]
b=np.array([1]*5)[None,None,:]

फिर b*aवांछित परिणाम और (b*a)[:,:,0]उत्पादन है array([[1, 2],[1, 2]]), जो मूल है a, जैसा कि करता है (b*a)[:,:,1], आदि।


2

इसे अब np.tile का उपयोग करके भी प्राप्त किया जा सकता है:

import numpy as np

a = np.array([[1,2],[1,2]])
b = np.tile(a,(3, 1,1))

b.shape
(3,2,2)

b
array([[[1, 2],
        [1, 2]],

       [[1, 2],
        [1, 2]],

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