时间戳不匹配的眼动追踪数据相关性计算方法咨询
嘿,这个问题我之前处理过类似的生理时序信号对齐场景,确实直接用df.corr()行不通——时间戳不匹配的话,样本点对应关系就乱了,计算出来的相关性完全没意义。下面给你几个更靠谱的方案,比单纯填充NaN要贴合你的数据特性:
1. 时间对齐重采样(最推荐)
因为瞳孔大小、注视速度都是连续变化的生理指标,先把两组数据对齐到统一的时间轴上是最合理的思路。你可以用重采样+插值的方式,把不同时间戳的数据映射到相同的采样频率上:
# 假设df1、df2分别是两名受试者的数据集,包含timestamp、pupil_size、gaze_velocity列 # 先把时间戳设为索引并排序 df1 = df1.set_index('timestamp').sort_index() df2 = df2.set_index('timestamp').sort_index() # 取两组数据的共同时间范围,避免超出某一方的数据区间 common_start = max(df1.index.min(), df2.index.min()) common_end = min(df1.index.max(), df2.index.max()) # 重采样到统一频率(比如10ms,根据你的原始数据采样率调整),用线性插值补全缺失值 resampled_sub1 = df1.loc[common_start:common_end].resample('10ms').interpolate(method='linear') resampled_sub2 = df2.loc[common_start:common_end].resample('10ms').interpolate(method='linear') # 现在时间戳完全一致,直接计算相关性 pupil_corr = resampled_sub1['pupil_size'].corr(resampled_sub2['pupil_size']) gaze_corr = resampled_sub1['gaze_velocity'].corr(resampled_sub2['gaze_velocity'])
这个方法的优势是保留了数据的时序连续性,线性插值也符合生理信号的渐变规律,不会像盲目填充NaN那样引入噪声。如果你的数据波动较大,还可以换成spline(样条插值)来更平滑地拟合。
2. 基于时间窗口的统计匹配
如果原始数据采样率极不均匀,或者你想观察不同时间尺度下的相关性,可以把时间划分为固定窗口(比如500ms/1s),计算每个窗口内的统计量(均值、中位数等),再用这些统计量来计算相关性:
# 定义一个计算窗口统计量的函数 def get_window_metrics(df, window='500ms'): return df.resample(window).agg({ 'pupil_size': 'mean', 'gaze_velocity': 'median' # 注视速度用中位数更抗噪 }) # 对两组数据分别计算窗口指标 windowed_sub1 = get_window_metrics(df1.set_index('timestamp').sort_index()) windowed_sub2 = get_window_metrics(df2.set_index('timestamp').sort_index()) # 对齐窗口索引,只保留双方都有数据的窗口 aligned_windows = windowed_sub1.join(windowed_sub2, lsuffix='_sub1', rsuffix='_sub2', how='inner') # 计算相关性 pupil_window_corr = aligned_windows['pupil_size_sub1'].corr(aligned_windows['pupil_size_sub2'])
这种方法适合分析“宏观趋势”的相关性,比如两名受试者在相同任务阶段的瞳孔变化是否同步。
3. 谨慎使用NaN填充(仅短时间缺失适用)
如果你坚持想用填充NaN的思路,别直接填0或者均值——这会严重扭曲数据。建议只对短时间间隔的缺失值做前向/后向填充,同时过滤掉时间间隔过大的无效样本:
# 合并两组数据,保留所有时间戳 merged_df = df1.set_index('timestamp').join( df2.set_index('timestamp'), lsuffix='_sub1', rsuffix='_sub2', how='outer' ).sort_index() # 计算相邻时间戳的间隔,只填充间隔小于100ms的缺失值(阈值根据你的数据调整) time_diff = merged_df.index.to_series().diff().dt.total_seconds() merged_df['pupil_size_sub1'] = merged_df['pupil_size_sub1'].where( time_diff > 0.1, merged_df['pupil_size_sub1'].ffill() ) merged_df['pupil_size_sub2'] = merged_df['pupil_size_sub2'].where( time_diff > 0.1, merged_df['pupil_size_sub2'].ffill() ) # 删除仍有NaN的行,再计算相关性 clean_df = merged_df.dropna() if not clean_df.empty: pupil_corr = clean_df['pupil_size_sub1'].corr(clean_df['pupil_size_sub2']) else: print("有效样本不足,无法计算相关性")
这个方法只适合数据缺失是偶然的、短时间的情况,比如某几帧采样丢失,否则还是会引入虚假的相关性。
内容的提问来源于stack exchange,提问作者Tank




