从几年前的这个问题开始跟进,numpy中是否存在规范的"转变"功能?我没有看到文档中的任何内容.
这是我正在寻找的简单版本:
def shift(xs, n):
if n >= 0:
return np.r_[np.full(n, np.nan), xs[:-n]]
else:
return np.r_[xs[-n:], np.full(-n, np.nan)]
Run Code Online (Sandbox Code Playgroud)
使用它就像:
In [76]: xs
Out[76]: array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
In [77]: shift(xs, 3)
Out[77]: array([ nan, nan, nan, 0., 1., 2., 3., 4., 5., 6.])
In [78]: shift(xs, -3)
Out[78]: array([ 3., 4., 5., 6., 7., 8., 9., nan, nan, nan])
Run Code Online (Sandbox Code Playgroud)
这个问题来自于我昨天尝试写一个快速的rolling_product.我需要一种"转移"累积产品的方法,而我所能想到的只是复制逻辑np.roll()
.
所以np.concatenate()
要快得多np.r_[]
.此版本的功能执行得更好:
def shift(xs, n):
if n >= 0:
return np.concatenate((np.full(n, np.nan), xs[:-n]))
else:
return np.concatenate((xs[-n:], np.full(-n, np.nan)))
Run Code Online (Sandbox Code Playgroud)
更快的版本只需预先分配数组:
def shift(xs, n):
e = np.empty_like(xs)
if n >= 0:
e[:n] = np.nan
e[n:] = xs[:-n]
else:
e[n:] = np.nan
e[:n] = xs[-n:]
return e
Run Code Online (Sandbox Code Playgroud)
Ed *_*ith 72
不是numpy但scipy提供你想要的转换功能,
import numpy as np
from scipy.ndimage.interpolation import shift
xs = np.array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
shift(xs, 3, cval=np.NaN)
Run Code Online (Sandbox Code Playgroud)
其中default是从数组外部引入一个带值的常量值,在cval
此处设置为nan
.这给出了所需的输出,
array([ nan, nan, nan, 0., 1., 2., 3., 4., 5., 6.])
Run Code Online (Sandbox Code Playgroud)
负面转变同样有效,
shift(xs, -3, cval=np.NaN)
Run Code Online (Sandbox Code Playgroud)
提供输出
array([ 3., 4., 5., 6., 7., 8., 9., nan, nan, nan])
Run Code Online (Sandbox Code Playgroud)
gzc*_*gzc 44
对于那些只想复制和粘贴最快的shift实现的人来说,有一个基准和结论(见最后).另外,我介绍了fill_value参数并修复了一些bug.
import numpy as np
import timeit
# enhanced from IronManMark20 version
def shift1(arr, num, fill_value=np.nan):
arr = np.roll(arr,num)
if num < 0:
arr[num:] = fill_value
elif num > 0:
arr[:num] = fill_value
return arr
# use np.roll and np.put by IronManMark20
def shift2(arr,num):
arr=np.roll(arr,num)
if num<0:
np.put(arr,range(len(arr)+num,len(arr)),np.nan)
elif num > 0:
np.put(arr,range(num),np.nan)
return arr
# use np.pad and slice by me.
def shift3(arr, num, fill_value=np.nan):
l = len(arr)
if num < 0:
arr = np.pad(arr, (0, abs(num)), mode='constant', constant_values=(fill_value,))[:-num]
elif num > 0:
arr = np.pad(arr, (num, 0), mode='constant', constant_values=(fill_value,))[:-num]
return arr
# use np.concatenate and np.full by chrisaycock
def shift4(arr, num, fill_value=np.nan):
if num >= 0:
return np.concatenate((np.full(num, fill_value), arr[:-num]))
else:
return np.concatenate((arr[-num:], np.full(-num, fill_value)))
# preallocate empty array and assign slice by chrisaycock
def shift5(arr, num, fill_value=np.nan):
result = np.empty_like(arr)
if num > 0:
result[:num] = fill_value
result[num:] = arr[:-num]
elif num < 0:
result[num:] = fill_value
result[:num] = arr[-num:]
else:
result[:] = arr
return result
arr = np.arange(2000).astype(float)
def benchmark_shift1():
shift1(arr, 3)
def benchmark_shift2():
shift2(arr, 3)
def benchmark_shift3():
shift3(arr, 3)
def benchmark_shift4():
shift4(arr, 3)
def benchmark_shift5():
shift5(arr, 3)
benchmark_set = ['benchmark_shift1', 'benchmark_shift2', 'benchmark_shift3', 'benchmark_shift4', 'benchmark_shift5']
for x in benchmark_set:
number = 10000
t = timeit.timeit('%s()' % x, 'from __main__ import %s' % x, number=number)
print '%s time: %f' % (x, t)
Run Code Online (Sandbox Code Playgroud)
基准结果:
benchmark_shift1 time: 0.265238
benchmark_shift2 time: 0.285175
benchmark_shift3 time: 0.473890
benchmark_shift4 time: 0.099049
benchmark_shift5 time: 0.052836
Run Code Online (Sandbox Code Playgroud)
shift5是赢家!这是OP的第三个解决方案.
np8*_*np8 12
scipy.ndimage.interpolation.shift
) 是本页中列出的最慢的解决方案。shift4_numba
如果您想要优秀的全能选手,请选择(定义如下)shift4_numba
import numba
@numba.njit
def shift4_numba(arr, num, fill_value=np.nan):
if num >= 0:
return np.concatenate((np.full(num, fill_value), arr[:-num]))
else:
return np.concatenate((arr[-num:], np.full(-num, fill_value)))
Run Code Online (Sandbox Code Playgroud)
shift5_numba
import numba
@numba.njit
def shift5_numba(arr, num, fill_value=np.nan):
result = np.empty_like(arr)
if num > 0:
result[:num] = fill_value
result[num:] = arr[:-num]
elif num < 0:
result[num:] = fill_value
result[:num] = arr[-num:]
else:
result[:] = arr
return result
Run Code Online (Sandbox Code Playgroud)
shift5
shift5_numba
,只需删除@numba.njit 装饰器。shift_scipy
: scipy.ndimage.interpolation.shift
(scipy 1.4.1) - 接受答案中的选项,这显然是最慢的选择。shift1
:np.roll
和out[:num] xnp.nan
由IronManMark20&GZCshift2
:np.roll
和np.put
由IronManMark20shift3
:np.pad
和slice
由 GZCshift4
:np.concatenate
和np.full
由 chrisaycockshift5
:使用两次result[slice] = x
通过 chrisaycockshift#_numba
:@ numba .njit 以前的装饰版本。在shift2
和shift3
包含的功能是不是由当前numba(0.50.1)的支持。
没有一个功能可以满足您的需求.您对班次的定义与大多数人的做法略有不同.移动数组的方法通常是循环的:
>>>xs=np.array([1,2,3,4,5])
>>>shift(xs,3)
array([3,4,5,1,2])
Run Code Online (Sandbox Code Playgroud)
但是,您可以使用两个功能执行所需操作.
考虑a=np.array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
:
def shift2(arr,num):
arr=np.roll(arr,num)
if num<0:
np.put(arr,range(len(arr)+num,len(arr)),np.nan)
elif num > 0:
np.put(arr,range(num),np.nan)
return arr
>>>shift2(a,3)
[ nan nan nan 0. 1. 2. 3. 4. 5. 6.]
>>>shift2(a,-3)
[ 3. 4. 5. 6. 7. 8. 9. nan nan nan]
Run Code Online (Sandbox Code Playgroud)
在您给定的函数和上面提供的代码上运行cProfile之后,我发现您提供的代码进行了42次函数调用,而shift2
当arr为正时进行了14次调用,当为负时进行了16次调用.我将尝试计时,看看每个如何使用真实数据.
小智 6
您可以先转换ndarray
为Series
或DataFrame
使用pandas
,然后您可以shift
根据需要使用方法。
例子:
In [1]: from pandas import Series
In [2]: data = np.arange(10)
In [3]: data
Out[3]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [4]: data = Series(data)
In [5]: data
Out[5]:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
dtype: int64
In [6]: data = data.shift(3)
In [7]: data
Out[7]:
0 NaN
1 NaN
2 NaN
3 0.0
4 1.0
5 2.0
6 3.0
7 4.0
8 5.0
9 6.0
dtype: float64
In [8]: data = data.values
In [9]: data
Out[9]: array([ nan, nan, nan, 0., 1., 2., 3., 4., 5., 6.])
Run Code Online (Sandbox Code Playgroud)
您也可以使用 Pandas 执行此操作:
\n\n使用 2356 长的数组:
\n\nimport numpy as np\n\nxs = np.array([...])\n
Run Code Online (Sandbox Code Playgroud)\n\n使用 scipy:
\n\nfrom scipy.ndimage.interpolation import shift\n\n%timeit shift(xs, 1, cval=np.nan)\n# 956 \xc2\xb5s \xc2\xb1 77.9 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n使用熊猫:
\n\nimport pandas as pd\n\n%timeit pd.Series(xs).shift(1).values\n# 377 \xc2\xb5s \xc2\xb1 9.42 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n在此示例中,使用 Pandas 的速度大约是 Scipy 的 8 倍
\n 归档时间: |
|
查看次数: |
69997 次 |
最近记录: |