【问题标题】:efficient way to generate 2 dimensional array of multiple shifts of a 1 dimensional array [duplicate]生成一维数组的多个移位的二维数组的有效方法[重复]
【发布时间】:2017-01-07 09:16:57
【问题描述】:

考虑数组a

import numpy as np
import pandas as pd

np.random.seed([3,1415])
a = np.random.randint(100, size=10)
print(a)

[11 98 74 90 15 55 13 11 13 26]

我想构建一个数组,该数组是这个数组的不断变化的版本,看起来像这样。我想要一种通用的方法来对小于原始数组长度的任意数量的移位执行此操作。在这种情况下,班次数n等于5

[[ 11.  nan  nan  nan  nan]
 [ 98.  11.  nan  nan  nan]
 [ 74.  98.  11.  nan  nan]
 [ 90.  74.  98.  11.  nan]
 [ 15.  90.  74.  98.  11.]
 [ 55.  15.  90.  74.  98.]
 [ 13.  55.  15.  90.  74.]
 [ 11.  13.  55.  15.  90.]
 [ 13.  11.  13.  55.  15.]
 [ 26.  13.  11.  13.  55.]]

【问题讨论】:

  • @WarrenWeckesser 实际上,我忘了把它放在我的问题中。我想问这是不是抄袭,请标记一下。我不知道要搜索什么。我很高兴你这样做了,谢谢。
  • 另一个:stackoverflow.com/questions/18026541/…。一旦你知道名字toeplitz,就很容易搜索相关问题。在不知道名称的情况下,很难找到能够产生相关结果的正确搜索词。
  • 我正在编译这些以符合我的确切标准并将它们添加到我的测试中。更多的是出于我的好奇心。
  • @WarrenWeckesser 你认为np.nan 和性能方面证明这不是一个骗局吗?无论哪种方式,我都很好。

标签: python pandas numpy


【解决方案1】:

我想到了两种方法来做到这一点

使用生成器

def multi_shift(a, n):
    yield a
    while n > 1:
        a = np.append(np.nan, a[:-1])
        yield a
        n -= 1

np.stack(multi_shift(a, 5)).T

使用广播构建切片

rng = np.arange(len(a))
slc = rng[:, None] - rng[:5]

np.where(slc >= 0, a[slc], np.nan)

[[ 11.  nan  nan  nan  nan]
 [ 98.  11.  nan  nan  nan]
 [ 74.  98.  11.  nan  nan]
 [ 90.  74.  98.  11.  nan]
 [ 15.  90.  74.  98.  11.]
 [ 55.  15.  90.  74.  98.]
 [ 13.  55.  15.  90.  74.]
 [ 11.  13.  55.  15.  90.]
 [ 13.  11.  13.  55.  15.]
 [ 26.  13.  11.  13.  55.]]

时间测试
代码
Divakar's stride functions from this post

from scipy.linalg import toeplitz
from numpy.lib.stride_tricks import as_strided as strided 

def pir1(a, n):
    return np.stack(multi_shift(a, n)).T

def pir2(a, n):
    rng = np.arange(len(a))
    slc = rng[:, None] - rng[:5]

    return np.where(slc >= 0, a[slc], np.nan)

# Suggested by @WarrenWeckesser
def toeplitz1(a, n):
    return toeplitz(a, np.array([np.nan] * n))

# from @Divakar
def strided_nan_filled(a, W):
    a_ext = np.concatenate((np.full(W-1, np.nan), a))
    n = a_ext.strides[0]
    out = strided(a_ext, shape=(a.size, W), strides=(n, n))[:,::-1]
    return out

def strided_nan_filled_v2(a, W):
    a_ext = np.concatenate(( np.full(W-1,np.nan) ,a))
    n = a_ext.strides[0]
    return strided(a_ext[W-1:], shape=(a.size,W), strides=(n,-n))

试验

from timeit import timeit

cols = pd.MultiIndex.from_product(
    [['pir1', 'pir2', 'toeplitz1', 'stride'], [10, 100]])
results = pd.DataFrame(index=[100, 1000], columns=cols)

np.random.seed([3,1415])
for i in results.index:
    a = np.random.rand(i)
    for j in results.columns:
        stmt = '{}(a, {})'.format(*j)
        iprt = 'from __main__ import a, {}'.format(j[0])
        results.set_value(i, j, timeit(stmt, iprt, number=100))

results.stack().plot.barh()


删除 pri1toeplitz
显然那些需要太长时间
毫无疑问,这种外观stride 是要走的路。

from timeit import timeit

cols = pd.MultiIndex.from_product(
    [['pir2', 'strided_nan_filled', 'strided_nan_filled_v2'], [10, 100]])
results = pd.DataFrame(index=[100, 1000, 10000], columns=cols)

np.random.seed([3,1415])
for i in results.index:
    a = np.random.rand(i)
    for j in results.columns:
        stmt = '{}(a, {})'.format(*j)
        iprt = 'from __main__ import a, {}'.format(j[0])
        results.set_value(i, j, timeit(stmt, iprt, number=100))

results.stack().plot.barh()

【讨论】:

  • 已更新。随意编辑。
猜你喜欢
  • 2016-06-25
  • 1970-01-01
  • 2011-10-18
  • 2013-05-28
  • 2020-10-25
  • 2020-06-29
  • 1970-01-01
  • 1970-01-01
  • 2019-10-27
相关资源
最近更新 更多