首页 > 解决方案 > 测量 xy 点的时间序列之间的相关性 - python

问题描述

我的目标是返回一个描述 xy 点时间序列之间同步的连续测量。使用下面,有两个单独的点 ( A,B)。它们在前 3 个时间步长上朝着相似的方向移动,而在后 3 个时间步长上则朝着不同的方向移动。

本质上,它们在时间步长上遵循相同的方向1-3,然后在时间步长上分叉以完全不同的方向移动4-6

在单独测量单个时间序列(x 坐标或 y 坐标)之间的同步性时,有几个选项。但我找不到同时考虑两个轴(x 和 y)的函数或算法。

我可以使用pearsonror 一个crosscorr函数,但它必须独立测量 x 或 y 轴。不是xy坐标在一起。

我可以使用运动的角度吗?我希望可以将预期的输出附加到表示移动点同步的每个时间点的数据帧。

注意:我希望输出是连续的和数字的(浮点数最有意义)。我在下面插入了两个不同的选项。然而,点可以沿相似的方向(但不相同)或完全不同的路径移动。输出应该处理这个。

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

df = pd.DataFrame({      
    'Time' : [1,1,2,2,3,3,4,4,5,5,6,6],    
    'Label' : ['A','B','A','B','A','B','A','B','A','B','A','B'],
    'x' : [-2.0,-1.0,-1.0,0.0,0.0,1.0,0.0,1.0,0.0,1.0,0.0,1.0],
    'y' : [-2.0,-1.0,-2.0,-1.0,-2.0,-1.0,-3.0,0.0,-4.0,1.0,-5.0,2.0],              
   })

x = df.groupby('Label')['x'].diff().fillna(0).astype(float)
y = df.groupby('Label')['y'].diff().fillna(0).astype(float) 

# Return rotation of scalar difference and convert angle
df['Rotation'] = np.arctan2(x, y)
df['Angle'] = np.degrees(df['Rotation'])

df_A = df[df['Label'] == 'A'].reset_index(drop = True)
df_B = df[df['Label'] == 'B'].reset_index(drop = True)

#rolling_corr = df_A['Angle'].rolling(1).corr(df_B['Angle'])
#print(rolling_corr)

r, p = stats.pearsonr(df_A['Angle'], df_B['Angle'])
print(f"Scipy computed Pearson r: {r} and p-value: {p}")

预期输出:

    Time Label    x    y  Rotation  Angle Corr
0      1     A -2.0 -2.0  0.000000    0.0 1.0
1      1     B -1.0 -1.0  0.000000    0.0 1.0
2      2     A -1.0 -2.0  1.570796   90.0 1.0
3      2     B  0.0 -1.0  1.570796   90.0 1.0
4      3     A  0.0 -2.0  1.570796   90.0 1.0
5      3     B  1.0 -1.0  1.570796   90.0 1.0
6      4     A  0.0 -3.0  3.141593  180.0 0.0
7      4     B  1.0  0.0  0.000000    0.0 0.0
8      5     A  0.0 -4.0  3.141593  180.0 0.0
9      5     B  1.0  2.0  0.000000    0.0 0.0
10     6     A  0.0 -5.0  3.141593  180.0 0.0
11     6     B  1.0  1.0  3.141593  180.0 0.0

在此处输入图像描述

标签: pythonpandassynchronization

解决方案


我不完全确定我做对了。

如果我按照您的示例进行操作,那么如果步骤之间的轨迹相同,则您的点被认为是同步的。

如果是这样,我会这样做(请注意,您对arctan2函数犯了一个错误,它首先需要 Y args)。

df[['move_x', 'move_y']] = df.groupby('Label')[['x', 'y']].diff().fillna(0)
df['Rotation'] = np.arctan2(df['move_y'], df['move_x'])
df['Angle'] = np.degrees(df['Rotation'])

temp = df.pivot_table('Angle', index="Time", columns="Label")
temp['same_direction'] = temp.eq(temp.iloc[:, 0], axis=0).all(1)
temp.drop(['A', 'B'], axis=1, inplace=True)

df.set_index('Time', inplace=True)
df = df.join(temp)
df.reset_index(drop=False, inplace=True)
df.drop(['move_x', 'move_y'], axis=1, inplace=True)
print(df)

返回:

    Time Label    x    y  Rotation  Angle  same_direction
0      1     A -2.0 -2.0  0.000000    0.0            True
1      1     B -1.0 -1.0  0.000000    0.0            True
2      2     A -1.0 -2.0  0.000000    0.0            True
3      2     B  0.0 -1.0  0.000000    0.0            True
4      3     A  0.0 -2.0  0.000000    0.0            True
5      3     B  1.0 -1.0  0.000000    0.0            True
6      4     A  0.0 -3.0 -1.570796  -90.0           False
7      4     B  1.0  0.0  1.570796   90.0           False
8      5     A  0.0 -4.0 -1.570796  -90.0           False
9      5     B  1.0  1.0  1.570796   90.0           False
10     6     A  0.0 -5.0 -1.570796  -90.0           False
11     6     B  1.0  2.0  1.570796   90.0           False

编辑

正如我之前所说,我不会关注你的这些评论。但是,如果您想坚持 [0;pi[ 象限中的方向并添加一个度偏差的容差,我认为您可以通过这种方式更改过程:

df[['move_x', 'move_y']] = df.groupby('Label')[['x', 'y']].diff().fillna(0)
df['Rotation'] = np.arctan2(df['move_y'], df['move_x'])
df['Angle'] = np.degrees(df['Rotation'])


temp = df.pivot_table('Rotation', index="Time", columns="Label")

#get back in the [0;pi[ quadrant :
temp = np.abs(temp).replace(np.pi, 0)

temp['MeanAngle'] = np.arctan2(np.mean(np.sin(temp), axis=1), np.mean(np.cos(temp), axis=1)) #compute mean angle at each step
temp = np.degrees(temp) #convert to degrees

THRESHOLD = .5 #tolerance of 1 degree equals to a tolerance to .5 degree to the mean angle
temp['ALMOST_SYNC'] = False
ix = temp[
    (np.abs(temp.MeanAngle - temp.A < THRESHOLD))
    & (np.abs(temp.MeanAngle - temp.B < THRESHOLD))
    ].index
temp.loc[ix, 'ALMOST_SYNC'] = True

temp.drop(['A', 'B', 'MeanAngle'], axis=1, inplace=True)
df.set_index('Time', inplace=True)
df = df.join(temp)
df.reset_index(drop=False, inplace=True)
df.drop(['move_x', 'move_y'], axis=1, inplace=True)

print(df)

返回

    Time Label    x    y  Rotation  Angle  ALMOST_SYNC
0      1     A -2.0 -2.0  0.000000    0.0         True
1      1     B -1.0 -1.0  0.000000    0.0         True
2      2     A -1.0 -2.0  0.000000    0.0         True
3      2     B  0.0 -1.0  0.000000    0.0         True
4      3     A  0.0 -2.0  0.000000    0.0         True
5      3     B  1.0 -1.0  0.000000    0.0         True
6      4     A  0.0 -3.0 -1.570796  -90.0         True
7      4     B  1.0  0.0  1.570796   90.0         True
8      5     A  0.0 -4.0 -1.570796  -90.0         True
9      5     B  1.0  1.0  1.570796   90.0         True
10     6     A  0.0 -5.0 -1.570796  -90.0         True
11     6     B  1.0  2.0  1.570796   90.0         True

编辑2:

对于某种线性度量,您可以在所有角度和平均角度上使用最大增量(有两个点,这将等同于最小值,顺便说一句):

df[['move_x', 'move_y']] = df.groupby('Label')[['x', 'y']].diff().fillna(0)
df['Rotation'] = np.arctan2(df['move_y'], df['move_x'])
df['Angle'] = np.degrees(df['Rotation'])


temp = df.pivot_table('Rotation', index="Time", columns="Label")

#get back in the [0;pi[ quadrant :
temp = np.abs(temp).replace(np.pi, 0)

cols = temp.columns.tolist()

temp['MeanAngle'] = np.arctan2(np.mean(np.sin(temp), axis=1), np.mean(np.cos(temp), axis=1)) #compute mean angle at each step
temp = np.degrees(temp) #convert to degrees

temp['MAX_DELTA'] = np.max(
        (np.array([np.abs(temp[f] - temp['MeanAngle']) for f in cols]).T),
        axis=1)

temp.drop(['A', 'B', 'MeanAngle'], axis=1, inplace=True)

df.set_index('Time', inplace=True)
df = df.join(temp)
df.reset_index(drop=False, inplace=True)
df.drop(['move_x', 'move_y'], axis=1, inplace=True)

print(df)

返回:

    Time Label    x    y  Rotation  Angle  MAX_DELTA
0      1     A -2.0 -2.0  0.000000    0.0        0.0
1      1     B -1.0 -1.0  0.000000    0.0        0.0
2      2     A -1.0 -2.0  0.000000    0.0        0.0
3      2     B  0.0 -1.0  0.000000    0.0        0.0
4      3     A  0.0 -2.0  0.000000    0.0        0.0
5      3     B  1.0 -1.0  0.000000    0.0        0.0
6      4     A  0.0 -3.0 -1.570796  -90.0        0.0
7      4     B  1.0  0.0  1.570796   90.0        0.0
8      5     A  0.0 -4.0 -1.570796  -90.0        0.0
9      5     B  1.0  1.0  1.570796   90.0        0.0
10     6     A  0.0 -5.0 -1.570796  -90.0        0.0
11     6     B  1.0  2.0  1.570796   90.0        0.0

推荐阅读