Es ist wichtig, Ästhetik von Leistung zu trennen. Manchmal ist der hässliche Code schnell. In der Tat ist das hier der Fall. Obwohl das Erstellen eines leeren Arrays und die anschließende Zuweisung von Werten zu Slices nicht schön aussehen, ist es schnell.
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)
Erträge, die folgenden timeit Ergebnisse auf meinem Rechner:
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
So using_empty
ist die schnellste (die Optionen tests
angewandt getestet).
Beachten Sie, dass np.stack
tut genau das, was Sie wollen, so
np.stack([x, np.log(x)], axis=x.ndim)
sieht recht hübsch, aber es ist auch die langsamste der drei Optionen geprüft.
Note, die zusammen mit viel langsamer zu sein, using_ufunc
ein Array von Objekt dtype zurückgibt:
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)
, die nicht das gleiche wie das gewünschte Ergebnis ist:
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)
Ich mag 'Stapel "Am besten eigentlich. Normalerweise optimiere ich meinen Python-Code nicht für Geschwindigkeit :) –
Würde es Ihnen etwas ausmachen, den '@ ufunc'-Dekorator als eine andere Möglichkeit hinzuzufügen, dies zu tun? –
Ich bin nicht vertraut mit dem '@ ufunc' Dekorateur. Beziehen Sie sich auf [diese] (https://mail.python.org/pipermail/python-dev/2013-June/126864.html)? – unutbu