कैसे एक संख्यात्मक सरणी से दूसरे में डेटा की प्रतिलिपि बनाएँ


86

सरणी ए के पते को संशोधित किए बिना सरणी बी से सरणी ए तक डेटा की नकल करने का सबसे तेज़ तरीका क्या है। मुझे इसकी आवश्यकता है क्योंकि एक बाहरी पुस्तकालय (PyFFTW) मेरे सरणी के लिए एक पॉइंटर का उपयोग करता है जो बदल नहीं सकता है।

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

a = numpy.empty(n, dtype=complex)
for i in xrange(a.size):
  a[i] = b[i]

यह एक लूप के बिना करना संभव है?

जवाबों:


86

मेरा मानना ​​है

a = numpy.empty_like (b)
a[:] = b

जल्दी से एक गहरी प्रतिलिपि बना देगा। जैसा कि फंसी का उल्लेख है, हाल ही के वर्जन के फंक्शन के भी copytoफंक्शन हैं।


4
+1। लेकिन नहीं होगा numpy.empty काफी हद तक की तुलना में तेजी से हो numpy.zeros ?
mg007

9
@ M.ElSaka a = bकेवल एक नया संदर्भ बनाता है ba[:] = bका अर्थ है "सभी तत्वों aको उन के बराबर सेट करें b"। अंतर महत्वपूर्ण है क्योंकि सुन्न सरणियाँ परस्पर प्रकार हैं।
ब्रायन हॉकिंस

14
@ mg007 मैंने कुछ परीक्षण चलाए, जो पता चला empty()कि लगभग 10% तेजी से है zeros()। आश्चर्यजनक रूप empty_like()से और भी तेज है। copyto(a,b)सरणी सिंटैक्स से अधिक तेज़ है a[:] = b। देखें gist.github.com/bhawkins/5095558
ब्रायन हॉकिन्स

2
@ ब्रायन हॉकिन्स सही हैं। गति में सुधार के लिए np.copyto(a, b)कब और कब उपयोग a = b.astype(b.dtype)करना है, इसका उत्तर नीचे देखें: stackoverflow.com/a/33672015/3703716
mab

1
@michael_n मुझे आश्चर्य था empty_likeकि बहुत तेजी से empty, खासकर जब zeros_likeसे धीमी है zeros। BTW मैं सिर्फ अपनी बेंचमार्क (अब अद्यतन) फिर से भाग गया, और बीच का अंतर copyto(a,b)और a[:] = bसुखाया गया लगता है। gist.github.com/bhawkins/5095558
ब्रायन हॉकिंस

26

NumPy संस्करण 1.7 में वह numpy.copytoकार्य है जो आप देख रहे हैं:

numpy.copyto (dst, src)

मूल्यों को एक सरणी से दूसरे में प्रसारित करता है, आवश्यकतानुसार प्रसारित करता है।

देखें: https://docs.scipy.org/doc/numpy/reference/generated/numpy.copy.html


यह मेरे लिए काम नहीं करता है। मुझे मिलता हैAttributeError: 'module' object has no attribute 'copyto'
कुल्लू १४'१४

19
a = numpy.array(b)

सुपीरियर v1.6 तक सुझाए गए समाधानों से भी तेज है और सरणी की एक प्रति भी बनाता है। हालाँकि, मैं इसे copyto (ए, बी) के खिलाफ परीक्षण नहीं कर सका, क्योंकि मेरे पास सबसे हाल का संस्करण नहीं है।


यह एक सरणी की प्रतिलिपि बनाने का एक शानदार तरीका है, लेकिन यह एक नई वस्तु बनाता है। ओपी को यह जानने की जरूरत है कि मूल्यों को कैसे पहले से बनाए गए सरणी में जल्दी से असाइन किया जाए।
ब्रायन हॉकिंस

15

आपके प्रश्न का उत्तर देने के लिए, मैंने कुछ वेरिएंट्स के साथ खेला और उन्हें प्रोफाइल किया।

निष्कर्ष: डेटा को कॉपी करने के लिए एक संख्यात्मक सरणी से दूसरे में से किसी एक का उपयोग करते हुए अंतर्निहित कार्य numpy.array(src)या numpy.copyto(dst, src)जहां भी संभव हो।

(लेकिन हमेशा बाद में चुनें अगर dstस्मृति पहले से ही आवंटित है, स्मृति का पुन: उपयोग करने के लिए। पोस्ट के अंत में प्रोफाइल देखें।)

प्रोफाइलिंग सेटअप

import timeit
import numpy as np
import pandas as pd
from IPython.display import display

def profile_this(methods, setup='', niter=10 ** 4, p_globals=None, **kwargs):
    if p_globals is not None:
        print('globals: {0}, tested {1:.0e} times'.format(p_globals, niter))
    timings = np.array([timeit.timeit(method, setup=setup, number=niter,
                                      globals=p_globals, **kwargs) for 
                        method in methods])
    ranking = np.argsort(timings)
    timings = np.array(timings)[ranking]
    methods = np.array(methods)[ranking]
    speedups = np.amax(timings) / timings

    pd.set_option('html', False)
    data = {'time (s)': timings,
            'speedup': ['{:.2f}x'.format(s) if 1 != s else '' for s in speedups],
            'methods': methods}
    data_frame = pd.DataFrame(data, columns=['time (s)', 'speedup', 'methods'])

    display(data_frame)
    print()

प्रोफाइलिंग कोड

setup = '''import numpy as np; x = np.random.random(n)'''
methods = (
    '''y = np.zeros(n, dtype=x.dtype); y[:] = x''',
    '''y = np.zeros_like(x); y[:] = x''',
    '''y = np.empty(n, dtype=x.dtype); y[:] = x''',
    '''y = np.empty_like(x); y[:] = x''',
    '''y = np.copy(x)''',
    '''y = x.astype(x.dtype)''',
    '''y = 1*x''',
    '''y = np.empty_like(x); np.copyto(y, x)''',
    '''y = np.empty_like(x); np.copyto(y, x, casting='no')''',
    '''y = np.empty(n)\nfor i in range(x.size):\n\ty[i] = x[i]'''
)

for n, it in ((2, 6), (3, 6), (3.8, 6), (4, 6), (5, 5), (6, 4.5)):
    profile_this(methods[:-1:] if n > 2 else methods, setup, 
                 niter=int(10 ** it), p_globals={'n': int(10 ** n)})

इंटेल i7 सीपीयू, सीपीथॉन v3.5.0, सुपीरियर v1.10.1 पर विंडोज 7 के लिए परिणाम


इसके अलावा, रूपरेखा के एक संस्करण के लिए परिणाम देखें, जहां गंतव्य की मेमोरी पहले से ही मूल्य प्रतिलिपि के दौरान पूर्व-आबंटित है , क्योंकि y = np.empty_like(x)सेटअप का हिस्सा है:


यह x.copy()भी उतना ही तेज है np.array(x)और मुझे वाक्य रचना बहुत पसंद है: $ python3 -m timeit -s "import numpy as np; x = np.random.random((100, 100))" "x.copy()"- 100000 loops, best of 3: 4.7 usec per loop। मेरे पास इसके समान परिणाम हैं np.array(x)। लिनक्स पर i5-4210U और सुपीरियर 1.10.4 के साथ परीक्षण किया गया
मार्को

हां मार्को, यह व्यक्तिगत स्वाद का मामला है। लेकिन ध्यान दें कि np.copyअधिक क्षमा: np.copy(False), np.copy(None)अभी भी काम करते हैं, जबकि a = None; a.copy()फेंकता है AttributeError: 'NoneType' object has no attribute 'copy'। इसके अलावा, हम विधि वाक्यविन्यास के बजाय फ़ंक्शन का उपयोग करके कोड की इस पंक्ति में क्या होना चाहते हैं, यह घोषित करने पर हम अधिक सटीक हैं।
माब

1
खैर, तथ्य np.copy(None)यह नहीं है कि एक त्रुटि है वास्तव में unpythonic फेंक नहीं है। उपयोग करने के लिए एक और कारण a.copy():)
मार्को सुल्ला

1
मैंने सिर्फ पायथन 2.7.12, NumPy 1.11.2 के साथ इन बेंचमार्क को चलाया और पाया कि y[:] = xयह अब की तुलना में मामूली रूप से तेज है copyto(y, x)Gist.github.com/bhawkins/7cdbd5b9372cb798e34e21f92279d2dc
ब्रायन हॉकिंस

10

आप आसानी से उपयोग कर सकते हैं:

b = 1*a

यह सबसे तेज़ तरीका है, लेकिन इसमें कुछ समस्याएं भी हैं। आप सीधे परिभाषित नहीं है, तो dtypeकी aहै और यह भी जांच नहीं करता है dtypeकी bआप मुसीबत में पड़ सकते हैं। उदाहरण के लिए:

a = np.arange(10)        # dtype = int64
b = 1*a                  # dtype = int64

a = np.arange(10.)       # dtype = float64
b = 1*a                  # dtype = float64

a = np.arange(10)        # dtype = int64
b = 1. * a               # dtype = float64

मुझे उम्मीद है, मैं बात को स्पष्ट कर सकता हूं। कभी-कभी आपके पास केवल एक छोटे से ऑपरेशन के साथ डेटा प्रकार परिवर्तन होगा।


1
नहीं, ऐसा करने से एक नई व्यूह रचना होती है। यह b = a.copy () के बराबर है।
चार्ल्स ब्रुनेट

क्षमा करें, लेकिन मैं आपसे नहीं मिलता। नए एरे बनाने के साथ आपका क्या मतलब है? अन्य सभी तरीके जो यहां प्रस्तुत किए गए हैं, उनके समान व्यवहार है। a = numpy.zeros(len(b))या a = numpy.empty(n,dtype=complex)एक नई सरणी भी बनाएगा।
इल्म

2
मान लीजिए कि आपके पास = numpy.empty (1000) है। अब, आपको मेमोरी में इसका पता बदले बिना, डेटा के साथ भरने की आवश्यकता है। यदि आप एक [0] = 1 करते हैं, तो आप किसी सरणी को फिर से नहीं बनाते हैं, आप सिर्फ सरणी की सामग्री को बदलते हैं।
चार्ल्स ब्रूनट

1
@CharlesBrunet सरणी को किसी बिंदु पर बनाना होगा। यह चतुर एक-लाइनर सिर्फ एक ऑपरेशन में यह सब करता है।
हेलटनबीकर

7

कई अलग-अलग चीजें हैं जो आप कर सकते हैं:

a=np.copy(b)
a=np.array(b) # Does exactly the same as np.copy
a[:]=b # a needs to be preallocated
a=b[np.arange(b.shape[0])]
a=copy.deepcopy(b)

चीजें जो काम नहीं करती हैं

a=b
a=b[:] # This have given my code bugs 

1

क्यों नहीं उपयोग करना है

a = 0 + b

मुझे लगता है कि यह पिछले गुणा के समान है लेकिन सरल हो सकता है।

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