如何在Python中对齐两个不同长度的数组(在没有匹配元素的情况下使用NaNs)

2024-10-06 06:45:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个数组y,它包含在每个月的某一天观察到的值。月份的日期在数组x中

我需要用三次样条插值这些值,这样我就可以得到一个月里每一天的值。为了考虑每月的每一天,我创建了一个数组xd。在

如果我想绘制原始y和插值y(即yd),我需要它们在同一个轴上对齐。这个轴是一个考虑到一个月的一天,xd。在

有没有一种有效的方法可以快速创建一个新的y数组,在新的x轴的正确位置精确地包含原始的y元素,所有其他元素都填充零或NaN(最好)?在

例如,我的第一个y只在第2天可用,所以在新的y数组中,我需要第一个元素来显示0/NaN。然后第二个元素将显示原始y=11,第三个元素将显示NaN,依此类推

我已经写了这段代码,上面我提到了,但我不知道是否有更好/更快的方法来实现这一点。在许多情况下,数组比我在下面的例子中展示的要大得多,所以有一些有效的算法会有所帮助。非常感谢。在

import numpy as np
import scipy.interpolate as sp

x = [2, 5, 7, 11, 13, 16, 19, 23, 25, 30]
y = [11, 10, 12, 14, 16, 19, 17, 14, 18, 17]

xd = np.linspace(0, max(x), int(max(x))+1) # create the new x axis
ipo = sp.splrep(x, y, k=3) # cubic spline
yd = sp.splev(xd, ipo) # interpolated y values

newY = np.zeros((1, len(yd)), dtype=float) # preallocate for the filled y values

for i in x: 
    if(i in xd): 
        idx, = np.where(xd == i) # find where the original x value is in the new x axis
        idx2, = np.where(np.array(x) == i)
        newY[0, int(idx)] = y[int(idx2)] # replace the y value of the new vector with the y value from original set

编辑:

为了澄清一下,需要一组对齐的数组(两个数组共享同一个轴)是因为当我绘制两个数组(newY和yd)时,我还添加了一些子图,其中我取绝对值和相对值的差异,以查看适合性有多好。在

我知道在这种情况下,样条曲线将始终通过我作为输入的所有点,因此差值将为零,但下面的绘图函数应该适用于任何类型的比较(即任何类型的插值与实际输入)。我使用的绘图功能如下:

^{pr2}$

编辑2:

添加到目前为止提案的绩效指标。循环的速度比我的循环快得多,因为循环的速度比循环快得多。在我的例子中,x有23个元素,而xd有3655个元素。在

def A():
    for i in x: 
        if(i in xd): 
            idx, = np.where(xd == i) # find where the original x value is in the new x axis
            idx2, = np.where(np.array(x) == i)
            newY[int(idx)] = y[int(idx2)] # replace the y value of the new vector with the y value from original set 

def B():
    for i, date in enumerate(xd):
        if date in x:
            new_y[i] = date

def C(): 
    known_values = dict(zip(x, y))

    for i,u in enumerate(xd):
        if u in known_values:
            newY[i] = known_values[u]

%timeit A() 每个回路219µs±8.8µs(平均值±标准偏差,7次运行,每个回路1000次)

%timeit B() 每个回路8.87 ms±95.3µs(7次运行的平均值±标准偏差,每个回路100次)

%timeit C() 每个回路408µs±11.3µs(平均值±标准偏差,7次运行,每个回路1000次)

我还尝试将A()函数传递给Numba进行JIT编译:

A_nb = numba.jit(A)

获取:

%timeit A_nb() 每个回路226µs±610 ns(平均值±标准偏差,7次运行,每个回路1000次)


Tags: thein元素newforifvaluenp
2条回答

抱歉,如果我完全误解了您的代码,但是np.linspace(0, max(x), int(max(x))+1)不是一种简单的np.array(range(1+max(x)))的迂回方式吗?看起来好像您只是在0max(x)之间的范围内(包括1+max(x))进行线性间隔采样,这与只获取0和max(x)之间的整数相同。在

在这种情况下,有必要这样做吗?在

if(i in xd): 
    idx, = np.where(xd == i) # find where the original x value is in the new x axis

如果xd真的只是一个从0到max(x)的整数列表,那么x中的所有元素都将在xd中,并且{}应该始终等于i。在

(当然,这假设x只包含非负整数值。)

^{pr2}$

编辑:在更一般的情况下,新的轴不仅仅是整数范围0..max(x),我建议在将已知值转换为字典之后,在数组上迭代。这将更有效,因为线性搜索被字典查找所取代。在

known_values = dict(zip(x, y))

xd = [... your new axis ...]
newY = np.zeros(len(xd))

for i,x in enumerate(xd):
    if x in known_values:
        newY[i] = known_values[x]

编辑:有趣的是,性能要差得多——如果已知值太少(那么在大数组中循环开销要大得多),显然会发生这种情况,但我认为这在实践中不会是一个问题。在

还有另一种循环方式,它利用了这两种顺序,但它替代了np.哪里如果不是显式的,那就取决于MPI的显式循环有多高效:

^{4}$

我明白这一切的目的是在同一个图上绘制y值,为什么不直接做呢? 轴可以轻松处理同一绘图上的不同x轴,如下所示:

import numpy as np
import scipy.interpolate as sp
import matplotlib.pyplot as plt

x = [2, 5, 7, 11, 13, 16, 19, 23, 25, 30]
y = [11, 10, 12, 14, 16, 19, 17, 14, 18, 17]

xd = np.linspace(0, max(x), int(max(x)) + 1)  # create the new x axis
ipo = sp.splrep(x, y, k=3)  # cubic spline
yd = sp.splev(xd, ipo)  # interpolated y values

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y, label='Original')
ax.plot(xd, yd, label='Interpolated')
plt.legend()
plt.grid()

plt.show()

如您所愿,每个“y”数据都与它自己的x轴对齐,而无需进行任何预处理。这里所做的唯一插值是Matplotlib用于显示的插值。在

由于您确实需要用Nan填充数组,下面是一种有效的方法:

^{pr2}$

也许可以用一些华丽的单行代码来减少

相关问题 更多 >