【问题标题】:Reshape numpy array with minimum rate以最小速率重塑 numpy 数组
【发布时间】:2018-11-15 08:58:13
【问题描述】:

我有一个不是单调递增的数组。我想在数组减小时应用恒定速率使其单调增加。

我在这里创建了一个比率为 0.2 的小示例:

# Rate
rate = 0.2

# Array to interpolate
arr1 = np.array([0,1,2,3,4,4,4,3,2,2.5,3.5,5.2,7,10,9.5,np.nan,np.nan,np.nan,11.2, 11.4, 12,10,9,9.5,10.2,10.5,10.8,12,12.5,15],dtype=float)

# Line with constant rate at first monotonic decrease (index 6)
xx1 = 6
xr1 = np.array(np.arange(0,arr1.shape[0]+1),dtype=float)
yr1 = rate*xr1 + (arr1[xx1]-rate*xx1)

# Line with constant rate at second monotonic decrease [index 14]
xx2 = 13
xr2 = np.array(np.arange(0,arr1.shape[0]+1),dtype=float)
yr2 = rate*xr2 + (arr1[xx2]-rate*xx2)

# Line with constant rate at second monotonic decrease [index 14]
xx3 = 20
xr3 = np.array(np.arange(0,arr1.shape[0]+1),dtype=float)
yr3 = rate*xr3 + (arr1[xx3]-rate*xx3)

plt.figure()
plt.plot(arr1,'.-',label='Original')
plt.plot(xr1,yr1,label='Const Rate line 1')
plt.plot(xr2,yr2,label='Const Rate line 2')
plt.plot(xr3,yr3,label='Const Rate line 2')
plt.legend()
plt.grid()

“原始”数组是我的数据集。 我想要的最终结果是蓝色+红色虚线。在图中,我还突出显示了“恒定速率曲线”。

由于我有非常大的数组(数百万条记录),我想避免整个数组的 for 循环。

非常感谢大家的帮助!

【问题讨论】:

  • 将数组的副本移动一个样本,然后从原始样本中减去该样本,以找到一个样本小于下一个样本的位置。
  • 您应该将“reshape”更改为“interpolate”,因为“reshaping”与此完全无关
  • 如果 rate = 0.3 会怎样?然后arr2 = np.array([0, 1, 2, 3, 4, 4, 4, 4.3, 4.6, 4.9, 5.2, 5, ...])。如您所见,它不是单调递增的。所以你需要检查一下......为什么不跳过不需要的点并将连续增加的点用一条线连接起来,例如arr1[6] = 4arr1[11] = 5arr1[13] = 10arr1[18] = 11.2?
  • @AndyK 我按照你的建议连接这些点,但我需要找到一个连接点位于从第一个点开始的直线上方并且以恒定速率(我将问题更新为更清楚)。
  • x[26] = x[20]x[27] > x[20] 时,为什么您的预期输出会在x[20]x[29] 之间进行插值?你期待x[n] > x[n-1] + 0.2吗?

标签: python arrays numpy reshape rate


【解决方案1】:

这是一个不同的选择:如果您有兴趣从数据中绘制单调递增曲线,那么您可以简单地跳过两个连续递增点之间不需要的点,例如在arr1[6] = 4arr1[11] = 5 之间,用一条线连接它们。

import numpy as np
import matplotlib.pyplot as plt

arr1 = np.array([0,1,2,3,4,4,4,3,2,2.5,3.5,5.2,7,10,9.5,np.nan,np.nan,np.nan,11.2, 11.4, 12,10,9,9.5,10.2,10.5,10.8,12,12.5,15],dtype=float)

mask = (arr1 == np.maximum.accumulate(np.nan_to_num(arr1)))

x = np.arange(len(arr1))

plt.figure()
plt.plot(x, arr1,'.-',label='Original')
plt.plot(x[mask], arr1[mask], 'r-', label='Interp.')    
plt.legend()
plt.grid()

【讨论】:

    【解决方案2】:
    arr2 = arr1[1:] - arr1[:-1]
    ind = numpy.where(arr2 < 0)[0]
    for i in ind:
        arr1[i] = arr1[i - 1] + rate
    

    您可能需要先将任何 numpy.nan 替换为值,例如 numpy.amin(arr1)

    【讨论】:

      【解决方案3】:

      我想避免整个数组的 for 循环。

      坦率地说,在 numpy 中很难实现没有 for 循环,因为 numpy 作为 C-made-library 使用在 C / C++ 中实现的 for 循环。并且所有排序算法(如 np.argwhere、np.all 等)都需要比较,因此也需要迭代。

      相反,我建议至少使用一个用 Python 制作的显式循环(迭代只进行一次):

      arr0 = np.zeros_like(arr1)
      num = 1
      rate = .2
      while(num < len(arr1)):
          if arr1[num] < arr1[num-1] or np.isnan(arr1[num]):
              start = arr1[num-1]
              while(start > arr1[num] or np.isnan(arr1[num])):
                  print(arr1[num])
                  arr0[num] = arr0[num-1] + rate
                  num+=1
              continue
          arr0[num] = arr1[num]
          num +=1
      

      【讨论】:

        【解决方案4】:

        您的问题可以用一个简单的递归差分方程表示:

        y[n] = max(y[n-1] + 0.2, x[n])
        

        所以直接的 Python 形式是

        def func(a):
            out = np.zeros_like(a)
            out[0] = a[0]
            for i in range(1, len(a)):
                out[i] = max(out[i-1] + 0.2, a[i])
        
            return out
        

        不幸的是,这个方程是递归的和非线性的,所以找到一个矢量化算法可能很困难。

        但是,使用 Numba,我们可以将这种基于循环的算法提高 300 倍:

        fastfunc = numba.jit(func)
        
        arr1 = np.random.rand(1000000)
        
        %timeit func(arr1)
        # 599 ms ± 13.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
        %timeit fastfunc(arr1)
        # 2.22 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
        

        【讨论】:

        • 我认为 OP 想要10.0, 10.2, 10.4, 10.6, 10.8, 11.2,而不是10. , 10.24, 10.48, 10.72, 10.96, 11.2
        【解决方案5】:

        我终于设法用 while 循环做我想做的事。

        # data['myvar'] is the original dataset I want to reshape
        data['myvar_corrected'] = data['myvar'].values
        temp_d = data['myvar'].fillna(0).values*1.0
        dtc = np.maximum.accumulate(temp_d)
        data.loc[temp_d < np.maximum.accumulate(dtc),'myvar_corrected'] = float('nan')
        stay_in_while = True
        min_rate = 5/200000/(24*60)
        idx_next = 0
        while stay_in_while:
            df_temp = data.iloc[idx_next:]
            if df_tem['myvar'].isnull().sum()>0:
                idx_first_nan = df_temp.reset_index().['myvar_corrected'].isnull().argmax()
        
                idx_nan_or = (data_new.index.values==df_temp.index.values[idx_first_nan]).argmax()
        
                x = np.arange(idx_first_nan-1,df_temp.shape[0])
                y0 = df_temp.iloc[idx_first_nan-1]['myvar_corrected']
                rate_curve = min_rate*x + (y0 - min_rate*(idx_first_nan-1))
        
                damage_m_rate = df_temp.iloc[idx_first_nan-1:]['myvar_corrected']-rate_curve
        
                try:
                    idx_intercept = (data_new.index.values==damage_m_rate[damage_m_rate>0].index.values[0]).argmax()
                    data_new.iloc[idx_nan_or:idx_intercept]['myvar'] = rate_curve[0:(damage_m_rate.index.values==damage_m_rate[damage_m_rate>0].index.values[0]).argmax()-1]
                    idx_next = idx_intercept + 1
                except:
                    stay_in_while = False
            else:
                stay_in_while = False
        # Finally I have my result stored in data_new['myvar']
        

        结果如下图。

        感谢大家的贡献!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-02-10
          • 2020-07-11
          • 1970-01-01
          • 2020-12-05
          • 2013-12-13
          • 2020-10-25
          • 2021-03-03
          相关资源
          最近更新 更多