2016-03-28 58 views
3

鑑於x,我想要生成x, log(x)作爲numpy陣列,其中x已形狀s,結果已形狀(*s, 2)。什麼是最好的方法來做到這一點? x可能只是一個浮點數,在這種情況下,我想要一個形狀爲(2,)的結果。有效的numpy陣列創建

醜陋的方式來做到這一點是:

import numpy as np 

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

回答

4

它從性能分離美學是很重要的。有時難看的代碼是快速的 。事實上,情況就是這樣。雖然創建一個空數組然後 爲切片分配值可能看起來不漂亮,但速度很快。

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) 

收益率,我的機器上以下timeit結果:

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 

所以using_empty是最快的(選項測試的應用tests)。

注意np.stack不正是你想要的東西,所以

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

看起來相當漂亮,但它也是最慢的測試了三個選項。


注意,與所要慢得多沿,using_ufunc返回對象D型細胞的數組:

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) 

這是不一樣的所期望的結果:

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

我喜歡'堆實際上最好的。我通常不優化我的Python代碼的速度:) –

+0

你介意添加'@ ufunc'裝飾器作爲另一種方式來做到這一點? –

+0

我不熟悉'@ ufunc'裝飾器。你是指[this](https://mail.python.org/pipermail/python-dev/2013-June/126864.html)? – unutbu