测量 xy 点时间序列之间的相关性 - python

Measure correlation between a time series of xy points - python

我的目标是 return 单个 连续 测量来描述 xy 点时间序列之间的同步性。使用下面,有两个独立的点(A,B)。它们在前 3 个时间步中朝相似的方向移动,在后 3 个时间步中朝不同的方向移动。

本质上,它们在时间步长 1-3 中遵循相同的方向,然后在时间步长 4-6

中向完全不同的方向移动

孤立地测量单个时间序列之间的同步性(x 坐标或 y 坐标)时,有几个选项。但是我找不到一个函数或算法来解释两个轴(x 和 y)。

我可以使用 pearsonrcrosscorr 函数,但它必须独立测量 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

我不太确定我做对了。

如果我按照你的例子,如果你的点在步骤之间的轨迹相同,那么你的点被认为是同步的。

如果是这样,我会这样做(请注意,您在 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)

Returns :

    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)

returns

    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)

Returns :

    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

如果要测量两组点之间的方向相关性,最好使用点积。你可以看到更多here。例如,尝试:

# Example Values
A_prime = [0, 0]
A = [1, 2]
B_prime = [3, 7]
B = [2, 9]

delta_A = [A[0] - A_prime[0], A[1] - A_prime[1]]
delta_B = [B[0] - B_prime[0], B[1] - B_prime[1]]

similarity = delta_A[0] * delta_B[0] + delta_A[1] * delta_B[1]  
# dot product similarity measure
print(similarity)

Pandas 可能还有一种内置方法可以更快地实现点积。理想情况下,您应该能够计算每对 A、B 值的点积,并获得示例中的 table。