2016-03-28 22 views
3

x göz önüne alındığında, xs şekil alır, böylece bir numpy dizi olarak x, log(x) üretmek istediği, sonuç (*s, 2) şekil alır. Bunu yapmanın en iyi yolu nedir? x sadece bir kayan nokta olabilir, bu durumda (2,) biçiminde bir sonuç istiyorum.etkin numpy dizi oluşturma

Bunu yapmanın çirkin yoludur:

import numpy as np 

x = np.asarray(x) 
result = np.empty((*x.shape, 2)) 
result[..., 0] = x 
result[..., 1] = np.log(x) 

cevap

4

Bu performanstan estetiğini ayırmak önemlidir. Bazen çirkin kod hızlıdır. Aslında, buradaki durum budur. Boş bir dizi oluştururken ve daha sonra dilimlere değerler atamak güzel görünmese de, hızlıdır.

import numpy as np 
import timeit 
import itertools as IT 
import pandas as pd 

def using_empty(x): 
    x = np.asarray(x) 
    result = np.empty(x.shape + (2,)) 
    result[..., 0] = x 
    result[..., 1] = np.log(x) 
    return result 

def using_concat(x): 
    x = np.asarray(x) 
    return np.concatenate([x, np.log(x)], axis=-1).reshape(x.shape+(2,), order='F') 

def using_stack(x): 
    x = np.asarray(x) 
    return np.stack([x, np.log(x)], axis=x.ndim) 

def using_ufunc(x): 
    return np.array([x, np.log(x)]) 
using_ufunc = np.vectorize(using_ufunc, otypes=[np.ndarray]) 

tests = [np.arange(600), 
     np.arange(600).reshape(20,30), 
     np.arange(960).reshape(8,15,8)] 

# check that all implementations return the same result 
for x in tests: 
    assert np.allclose(using_empty(x), using_concat(x)) 
    assert np.allclose(using_empty(x), using_stack(x)) 


timing = [] 
funcs = ['using_empty', 'using_concat', 'using_stack', 'using_ufunc'] 
for test, func in IT.product(tests, funcs): 
    timing.append(timeit.timeit(
     '{}(test)'.format(func), 
     setup='from __main__ import test, {}'.format(func), number=1000)) 

timing = pd.DataFrame(np.array(timing).reshape(-1, len(funcs)), columns=funcs) 
print(timing) 

verimleri, benim makinede aşağıdaki sürümüyle gelen timeit sonuçları:

using_empty using_concat using_stack using_ufunc 
0  0.024754  0.025182  0.030244  2.414580 
1  0.025766  0.027692  0.031970  2.408344 
2  0.037502  0.039644  0.044032  3.907487 

Yani using_empty (seçenekler tests uygulanan Test edilen) en hızlı olduğunu. np.stack böylece

np.stack([x, np.log(x)], axis=x.ndim) 

, ne istediğinizi tam olarak yaptığı

Not makul güzel görünüyor, ama aynı zamanda test edilen üç seçenekten en yavaş olduğunu.

In [236]: x = np.arange(6) 

In [237]: using_ufunc(x) 
Out[237]: 
array([array([ 0., -inf]), array([ 1., 0.]), 
     array([ 2.  , 0.69314718]), 
     array([ 3.  , 1.09861229]), 
     array([ 4.  , 1.38629436]), array([ 5.  , 1.60943791])], dtype=object) 

arzu edilen sonuç ile aynı değildir:

ben gibi
In [240]: using_empty(x) 
Out[240]: 
array([[ 0.  ,  -inf], 
     [ 1.  , 0.  ], 
     [ 2.  , 0.69314718], 
     [ 3.  , 1.09861229], 
     [ 4.  , 1.38629436], 
     [ 5.  , 1.60943791]]) 

In [238]: using_ufunc(x).shape 
Out[238]: (6,) 

In [239]: using_empty(x).shape 
Out[239]: (6, 2) 
+0

'yığın boyunca daha yavaş olmak üzere using_ufunc nesne d_type bir dizi döner


Not 'aslında en iyi. Genellikle hızım için Python kodumu optimize etmiyorum :) –

+0

Bunu yapmak için başka bir yol olarak '@ ufunc' dekoratörünü ekleyebilir misiniz? –

+0

'@ ufunc' dekoratörüne aşina değilim. [Bu] 'a atıfta bulunuyorsunuz (https://mail.python.org/pipermail/python-dev/2013-June/126864.html)? – unutbu

İlgili konular