2017-05-31 11 views
5

क्याफास्ट तरीका सशर्त समारोह की गणना करने के

# here x is just a number 
def f(x): 
    if x >= 0: 
     return np.log(x+1) 
    else: 
     return -np.log(-x+1) 

एक संभव तरीका की तरह समारोह की गणना करने के लिए सबसे तेज़ तरीका है है:

# here x is an array 
def loga(x) 
    cond = [x >= 0, x < 0] 
    choice = [np.log(x+1), -np.log(-x+1) 
    return np.select(cond, choice) 

लेकिन लगता है numpy तत्व द्वारा सरणी तत्व के माध्यम से चला जाता है। क्या बेहतर प्रदर्शन प्राप्त करने के लिए np.exp (x) के समान कुछ वैचारिक रूप से समान उपयोग करने का कोई तरीका है?

+0

क्या पोस्ट किए गए समाधान आपके लिए काम करते हैं? – Divakar

+0

@ दिवाकर क्षमा करें, मुझे अभी तक जांच करने की संभावना नहीं है। मैं निकटतम समय में कोशिश करूंगा और एक उत्तर – ichernob

उत्तर

6
def f(x): 
     return (x/abs(x)) * np.log(1+abs(x)) 
+0

अच्छा लगा! यह काम। गणित पर अच्छा काम। 'Numexpr' और/या' abs (x) 'का पुनः उपयोग करने के साथ विजेता होना चाहिए। – Divakar

+2

मैं शून्य द्वारा संभावित विभाजन से बचने के लिए 'x/abs (x)' की बजाय 'numpy.sign (x)' का उपयोग करने का सुझाव देता हूं। 'np.copysign (np.log (1 + abs (x)), x) 'एक और तरीका होगा। –

+0

यह सब बहुत अच्छा है। लेकिन abs(), np.sign() जैसे फ़ंक्शन 0 लौट सकते हैं। मार्क समाधान वास्तव में अच्छा है, हालांकि, मैं np.tanh (x) से अधिक समाधान ढूंढना चाहता हूं। क्या यह संभव है? – ichernob

3

इस तरह के मामलों में, masking में मदद करता है -

def mask_vectorized_app(x): 
    out = np.empty_like(x) 
    mask = x>=0 
    mask_rev = ~mask 
    out[mask] = np.log(x[mask]+1) 
    out[mask_rev] = -np.log(-x[mask_rev]+1) 
    return out 

परिचय numexpr module हमें आगे मदद करता है।

import numexpr as ne 

def mask_vectorized_numexpr_app(x): 
    out = np.empty_like(x) 
    mask = x>=0 
    mask_rev = ~mask 

    x_masked = x[mask] 
    x_rev_masked = x[mask_rev] 
    out[mask] = ne.evaluate('log(x_masked+1)') 
    out[mask_rev] = ne.evaluate('-log(-x_rev_masked+1)') 
    return out 

@user2685079's post से प्रेरित होकर और फिर logarithmetic संपत्ति का उपयोग कर: log(A**B) = B*log(A), हम लॉग संगणना में संकेत में धक्का कर सकते हैं और यह हमें numexpr के साथ और अधिक काम करने के लिए अनुमति देता है अभिव्यक्ति का मूल्यांकन, इसलिए जैसे -

s = (-2*(x<0))+1 # np.sign(x) 
out = ne.evaluate('log((abs(x)+1)**s)') 

कम्प्यूटिंग sign तुलना का उपयोग कर किसी अन्य तरीके से हमें s देता है -

s = (-2*(x<0))+1 
def loopy_app(x): 
    out = np.empty_like(x) 
    for i in range(len(out)): 
     out[i] = f(x[i]) 
    return out 

समय और सत्यापन - -

In [141]: x = np.random.randn(100000) 
    ...: print np.allclose(loopy_app(x), mask_vectorized_app(x)) 
    ...: print np.allclose(loopy_app(x), mask_vectorized_numexpr_app(x)) 
    ...: print np.allclose(loopy_app(x), mask_vectorized_numexpr_app2(x)) 
    ...: 
True 
True 
True 

In [142]: %timeit loopy_app(x) 
    ...: %timeit mask_vectorized_numexpr_app(x) 
    ...: %timeit mask_vectorized_numexpr_app2(x) 
    ...: 
10 loops, best of 3: 108 ms per loop 
100 loops, best of 3: 3.6 ms per loop 
1000 loops, best of 3: 942 µs per loop 
तुलना के लिए

def mask_vectorized_numexpr_app2(x): 
    return ne.evaluate('log((abs(x)+1)**((-2*(x<0))+1))') 

रनटाइम परीक्षण

दीवाना दृष्टिकोण -अंत में, हम इस numexpr में धक्का कर सकते हैं अभिव्यक्ति का मूल्यांकन

के साथ या बिना numexpr मूल्यांकन @user2685079's solution का उपयोग करना np.sign का उपयोग कर पहले भाग को बदलने के लिए और उसके बाद -

In [143]: %timeit np.sign(x) * np.log(1+abs(x)) 
100 loops, best of 3: 3.26 ms per loop 

In [144]: %timeit np.sign(x) * ne.evaluate('log(1+abs(x))') 
1000 loops, best of 3: 1.66 ms per loop 
+0

क्या आप अपना समय अपने समय में जोड़ सकते हैं? – piRSquared

+1

@piRSquared मेरे पास 'numba' नहीं है। मेरा अपना जोड़ जोड़ना? – Divakar

+0

नवीनतम 'एप 2' – piRSquared

1

आप थोड़ा np.where बजाय np.select का उपयोग करके अपने दूसरा समाधान की गति में सुधार कर सकते हैं:

def loga(x): 
    cond = [x >= 0, x < 0] 
    choice = [np.log(x+1), -np.log(-x+1)] 
    return np.select(cond, choice) 

def logb(x): 
    return np.where(x>=0, np.log(x+1), -np.log(-x+1)) 

In [16]: %timeit loga(arange(-1000,1000)) 
10000 loops, best of 3: 169 µs per loop 

In [17]: %timeit logb(arange(-1000,1000)) 
10000 loops, best of 3: 98.3 µs per loop 

In [18]: np.all(loga(arange(-1000,1000)) == logb(arange(-1000,1000))) 
Out[18]: True 
2

Using numba

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

नुंबा आयात समय, रनटाइम, या स्थैतिक रूप से एलएलवीएम कंपाइलर आधारभूत संरचना का उपयोग करके अनुकूलित मशीन कोड उत्पन्न करके काम करता है (शामिल पीईसीसी उपकरण का उपयोग करके)।Numba या तो CPU या GPU हार्डवेयर पर चलाने के लिए पाइथन के संकलन का समर्थन करता है, और इसे पायथन वैज्ञानिक सॉफ़्टवेयर स्टैक के साथ एकीकृत करने के लिए डिज़ाइन किया गया है।

नुंबा परियोजना को कॉन्टिन्यूम Analytics और द गॉर्डन और बेट्टी मूर फाउंडेशन (ग्रांट जीबीएमएफ 5423) द्वारा समर्थित है।

from numba import njit 
import numpy as np 

@njit 
def pir(x): 
    a = np.empty_like(x) 
    for i in range(a.size): 
     x_ = x[i] 
     _x = abs(x_) 
     a[i] = np.sign(x_) * np.log(1 + _x) 
    return a 

शुद्धता

np.isclose(pir(x), f(x)).all() 

True 

समय

x = np.random.randn(100000) 

# My proposal 
%timeit pir(x) 
1000 loops, best of 3: 881 µs per loop 

# OP test 
%timeit f(x) 
1000 loops, best of 3: 1.26 ms per loop 

# Divakar-1 
%timeit mask_vectorized_numexpr_app(x) 
100 loops, best of 3: 2.97 ms per loop 

# Divakar-2 
%timeit mask_vectorized_numexpr_app2(x) 
1000 loops, best of 3: 621 µs per loop 

कार्यशील परिभाषाएँ

from numba import njit 
import numpy as np 

@njit 
def pir(x): 
    a = np.empty_like(x) 
    for i in range(a.size): 
     x_ = x[i] 
     _x = abs(x_) 
     a[i] = np.sign(x_) * np.log(1 + _x) 
    return a 

import numexpr as ne 

def mask_vectorized_numexpr_app(x): 
    out = np.empty_like(x) 
    mask = x>=0 
    mask_rev = ~mask 

    x_masked = x[mask] 
    x_rev_masked = x[mask_rev] 
    out[mask] = ne.evaluate('log(x_masked+1)') 
    out[mask_rev] = ne.evaluate('-log(-x_rev_masked+1)') 
    return out 

def mask_vectorized_numexpr_app2(x): 
    return ne.evaluate('log((abs(x)+1)**((-2*(x<0))+1))') 


def f(x): 
    return (x/abs(x)) * np.log(1+abs(x)) 
+0

मेरा नवीनतम ऐप 2 थोड़ा अलग है :) मुसीबत के लिए खेद है। क्या आप अपडेट कर सकते हैं? ऐसा मत सोचो कि आपको उनको फिर से सूचीबद्ध करने की आवश्यकता है। – Divakar

+1

@ दिवाकर कोई परेशानी नहीं :-)। वह नवीनतम वास्तव में तेज़ है। – piRSquared

संबंधित मुद्दे