सुन्न स्लाइस का उपयोग करके इस जटिल अभिव्यक्ति को कैसे व्यक्त किया जाए


14

मैं पायथन में निम्नलिखित अभिव्यक्ति को लागू करना चाहता हूं: जहां और आकार , और संख्यात्मक सारणी हैं। आकार का एक अरै सरणी । आकार लगभग 10000 तक हो सकता है, और फ़ंक्शन एक आंतरिक लूप का हिस्सा है जिसका मूल्यांकन कई बार किया जाएगा, इसलिए गति महत्वपूर्ण है।x y n कश्मीर n × n n

xi=j=1i1kij,jaijaj,
xynkn×nn

आदर्श रूप से मैं लूप के लिए पूरी तरह से बचना चाहूंगा, हालांकि मुझे लगता है कि अगर यह एक है तो दुनिया का अंत नहीं है। समस्या यह है कि मुझे यह देखने में परेशानी हो रही है कि बिना जोड़े वाले छोरों के बिना यह कैसे करना है, और यह इसे धीमा करने की संभावना है।

क्या कोई देख सकता है कि कुशल के रूप में सुपीरियर का उपयोग करके उपरोक्त समीकरण को कैसे व्यक्त किया जाए, और अधिमानतः पठनीय भी? अधिक आम तौर पर, इस तरह की चीज के लिए सबसे अच्छा तरीका क्या है?


मैंने कुछ दिन पहले भी इसी तरह का सवाल किया था। मैं इसे stackoverflow पर पूछा। इस पोस्ट को देखें । मैं साइफन के बजाय scipy.weave का उपयोग करता हूं। क्या किसी को पता है कि यह किसी भी (काफी) प्रदर्शन अंतर बनाता है?
seb

जवाबों:


17

यहाँ Numba समाधान है। मेरी मशीन पर नुम्बा संस्करण डेकोरेटर (200x200 मैट्रिक्स, 'के' और 200-लंबाई वेक्टर 'ए') के बिना अजगर संस्करण की तुलना में 1000 गुना तेज है। आप @autojit डेकोरेटर का उपयोग भी कर सकते हैं जो प्रति कॉल में लगभग 10 माइक्रोसेकंड जोड़ता है ताकि एक ही कोड कई प्रकारों के साथ काम करेगा।

from numba import jit, autojit

@jit('f8[:](f8[:,:],f8[:])')
#@autojit
def looped_ver(k, a):
    x = np.empty_like(a)
    for i in range(x.size):
        sm = 0.0
        for j in range(0, i+1):
            sm += k[i-j,j] * a[i-j] * a[j]
        x[i] = sm
    return x

प्रकटीकरण: मैं नंबा डेवलपर्स में से एक हूं।


धन्यवाद, जो बहुत सीधा दिखता है। मुझे सुन्न के बारे में भी नहीं पता था! साइथन, PyPy, Numba ... यह एक भ्रामक दुनिया है।
नथानिएल

3
ट्रैविस, बहुत शांत, क्या आप अपने जवाब के नीचे एक खुलासा जोड़कर बुरा मानते हैं कि आप सुब्बा डेवलपर्स में से एक हैं?
एरन अहमदिया

1
साथ , Cython संस्करण भी बहुत तेजी से फंस अजगर के सापेक्ष (~ 700x, मेरे लिए) है। मुझे इस बात की उत्सुकता होगी कि बड़े प्रदर्शनों के साथ यह प्रदर्शन कैसे बदलता है, और क्या वे एक ही (मेमोरी?) बाधाओं का अनुभव करते हैं। n=200
नेट विल्सन

@ नटविल्सन - यदि आप इसे एक सवाल के रूप में पूछते हैं, तो मुझे आपके लिए कोशिश करने और उससे निपटने में खुशी होगी :)
एरन अहमदिया

4

यहाँ एक शुरुआत है। सबसे पहले, किसी भी गलतियों के लिए मेरी माफी।

मैंने कुछ अलग-अलग तरीकों से प्रयोग किया। ऊपरी सीमा होना चाहिए - मैं थोड़ा योग पर सीमा से उलझन में था , बजाय ?i - 1ii1

संपादित करें: नहीं, प्रश्न में प्रदान की गई ऊपरी सीमा सही थी। मैंने इसे यहां छोड़ दिया है क्योंकि एक अन्य उत्तर अब उसी कोड का उपयोग करता है, लेकिन फिक्स सरल है।

पहला लूप वाला संस्करण:

def looped_ver(k, a):
    x = np.empty_like(a)
    for i in range(x.size):
        sm = 0
        for j in range(0, i+1):
            sm += k[i-j,j] * a[i-j] * a[j]
        x[i] = sm
    return x

मैंने इसे खट्टे स्लाइस के साथ एक एकल लूप बनाया:

def vectorized_ver(k, a):
    ktr = zeros_like(k)
    ar = zeros_like(k)
    sz = len(a)
    for i in range(sz):
        ktr[i,:i+1] = k[::-1].diagonal(-sz+i+1)
        a_ = a[:i+1]
        ar[i,:i+1] = a_[::-1] * a_
    return np.sum(ktr * ar, 1)

एक स्पष्ट लूप के साथ खस्ता संस्करण होने पर मेरे कंप्यूटर पर लगभग 25x तेज होता है ।n=5000

फिर मैंने (अधिक-पठनीय) लूप कोड का साइथन संस्करण लिखा।

import numpy as np
import cython
cimport numpy as np

@cython.boundscheck(False)
@cython.wraparound(False)
def cyth_ver(double [:, ::1] k not None,
              double [:] a not None):
    cdef double[:] x = np.empty_like(a)
    cdef double sm
    cdef int i, j

    for i in range(len(a)):
        sm = 0.0
        for j in range(i+1):
            sm = sm + k[i-j,j] * a[i-j] * a[j]
        x[i] = sm
    return x

मेरे लैपटॉप पर, यह लूप किए गए संस्करण की तुलना में लगभग 200x तेज़ है (और 1-लूप वेक्टर किए गए संस्करण की तुलना में 8 गुना तेज़ है)। मुझे यकीन है कि दूसरे बेहतर कर सकते हैं।

मैं एक जूलिया संस्करण के साथ खेला था, और यह लग रहा था (अगर मैंने इसे ठीक से समय दिया है) साइथन कोड के बराबर है।


बहुत धन्यवाद। इसने मुझे आश्वस्त किया है कि मुझे सीखने के लिए प्रयास करने की आवश्यकता है :) मुझे उल्लेख करना चाहिए था कि हमेशा शून्य होना चाहिए, क्योंकि जाने वाले सूचकांक का अर्थ है कि योग करने के लिए कोई शब्द नहीं हैं - लेकिन यह एक मामूली विवरण है । i - 1x0i1
नथानिएल

ओह समझा। मैंने उसे मूल योग से इकट्ठा किया, लेकिन यह सुनिश्चित नहीं था कि वह इरादा था।
नैट विल्सन

1

आप जो चाहते हैं वह एक दृढ़ संकल्प प्रतीत होता है; मुझे लगता है कि इसे प्राप्त करने का सबसे तेज़ तरीका numpy.convolveकार्य होगा।

आपको अपनी आवश्यकताओं के अनुसार सूचकांकों को ठीक करना पड़ सकता है लेकिन मुझे लगता है कि आप कुछ इस तरह की कोशिश करना चाहेंगे:

import numpy as np
a = [1, 2, 3, 4, 5]
k = [2, 4, 6, 8, 10]

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