python - 如何向 pandas dataframe 滚动窗口添加步骤

标签 python pandas

我有一个数据帧,其中包含来自陀螺仪的时间序列数据,以 20 Hz(每 50 毫秒)采样一次。我需要使用 4 秒的移动窗口来计算来自引用 4 秒信号的 DTW 距离。

我正在使用此代码:

df['Gyro_Z_DTW']=df['Gyro_Z'].rolling(window='4s',min_periods=80).apply(DTWDistanceWindowed,raw=False)

其中函数DTWDistanceWindowed()如下:

def DTWDistanceWindowed(entry):
    w=10
    s1=entry
    s2=reference

    DTW={}

    w = max(w, abs(len(s1)-len(s2)))
    print('window = ',w)

    for i in range(-1,len(s1)):
        for j in range(-1,len(s2)):
            DTW[(i, j)] = float('inf') 


    DTW[(-1, -1)] = 0

    for i in range(len(s1)):
        for j in range(max(0, i-w), min(len(s2), i+w)):
            dist= (s1[i]-s2[j])**2
            DTW[(i, j)] = dist + min(DTW[(i-1, j)],DTW[(i, j-1)], DTW[(i-1, j-1)])

    return math.sqrt(DTW[len(s1)-1, len(s2)-1])

# adapted method from #http://alexminnaar.com/2014/04/16/Time-Series-Classification-and-Clustering-with-Python.html

它可以工作,但是如果移动窗口每次可以滑动 500 毫秒(而不是 50 毫秒),我可以节省一些时间。

有办法做到这一点吗?

如果您知道更好的方法,我愿意接受其他建议,而不是滚动。

最佳答案

一种方法是检查 entry 的第一个(或任何索引)是否是 500ms 的倍数,如果不是,则返回 np.nan。那么“复杂”的计算只会每 500ms 发生一次。所以函数是

def DTWDistanceWindowed(entry):
    if bool(entry.index[0].microsecond%500000):
        return np.nan
    w=10
    s1=entry
    ....# same as your function after

有趣的是,pd.Timestamp (entry.index[0]的类型)具有微秒属性,但没有毫秒属性,因此使用%500000

编辑:现在如果你想加速该功能,你可以使用 numpy 数组,如下所示:

#sample data
np.random.seed(6)
nb = 200
df = pd.DataFrame({'Gyro_Z':np.random.random(nb)}, 
                  index=pd.date_range('2020-05-15', freq='50ms', periods=nb))
reference = np.random.random(10)

# create a for reference with your function
a = df['Gyro_Z'].rolling(window='4s',min_periods=80).apply(DTWDistanceWindowed,raw=False)

使用 numpy 定义函数

def DTWDistanceWindowed_np(entry):
    if bool(entry.index[0].microsecond%500000):
        return np.nan
    w=10
    s1=entry.to_numpy()
    l1 = len(s1) # calcualte once the len of s1
    # definition of s2 and its length
    s2 = np.array(reference) 
    l2 = len(s2)

    w = max(w, abs(l1-l2))

    # create an array of inf and initialise
    DTW=np.full((l1+1,l2+1), np.inf)
    DTW[0, 0] = 0

    # avoid calculate some difference several times
    s1ms2 = (s1[:,None]-s2)**2
    # do the loop same way, note the small change in bounds
    for i in range(1,l1+1):
        for j in range(max(1, i-w), min(l2+1, i+w)):
            DTW[i, j] = s1ms2[i-1,j-1] + min(DTW[i-1, j],DTW[i, j-1], DTW[i-1, j-1])

    return math.sqrt(DTW[l1, l2])

# use it to create b
b = df['Gyro_Z'].rolling(window='4s',min_periods=80).apply(DTWDistanceWindowed_np,raw=False)

# compare a every 10 rows and b and mot the nan rows
print ((b.dropna() == a.dropna()[::10]).all())
# True

时间安排:

#original solution
%timeit df['Gyro_Z'].rolling(window='4s',min_periods=80).apply(DTWDistanceWindowed,raw=False)
3.31 s ± 422 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# with numpy and 1 out of 10 rows
%timeit df['Gyro_Z'].rolling(window='4s',min_periods=80).apply(DTWDistanceWindowed_np,raw=False)
41.7 ms ± 9.42 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

这样做 if bool(... 已经快了近 10 倍,但使用 numpy 又快了 9 倍。速度可能取决于关于引用尺寸,我还没有真正检查过。

关于python - 如何向 pandas dataframe 滚动窗口添加步骤,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61830275/

相关文章:

python - 分类变量 pandas 总结

python - 将 PySerial Readline 从字符串转换为二进制

python - 如何合并或连接两个数据帧,但保留两者的某些列

java - 用于 Java 的 Unirest

python - 无需凭据即可使用 Python Google Storage 客户端

python - 具有特定值的 DataFrame 回填

python - 在 pandas 中,有没有办法将行旋转到其他行的末尾?

python - Python中的文字可以被覆盖吗?

pandas - 在多个 DataFrame Pandas 的每个单元格中查找最大值

python - 从 pd.df.ix[] View 中按行选择?