为何两个Pandas Series相除结果全为NaN?
我有两个Pandas DataFrame,想要将第一个DataFrame的列与第二个DataFrame的对应列按分钟级数据计算小时区间的比值。第一个DataFrame的规模略大于第二个,我尝试通过匹配索引执行除法,随后将第一个DataFrame列的起止索引各偏移1位重复执行除法,循环此操作30次。
示例代码如下:
keys = ['BX_GSE', 'BY_GSE', 'BZ_GSE', 'Vx', 'Vy', 'Vz', 'proton_density', 'T'] max_avg = [] timeshift_offset = [] for k in keys: averages_storage_array = [] for n in range(30): # 计算30分钟窗口内的点比值 # 注:原代码存在语法错误,应为fixed[k][j:j+60] ratio_of_points = sliding[k][sliding_start-n:sliding_stop-n] / fixed[k [j:j+60]) averaged_ratio_1hr = np.average(ratio_of_points) averages_storage_array.append(averaged_ratio_1hr) max_avg.append(max(averages_storage_array)) timeshift_offset.append(averages_storage_array.index(max(averages_storage_array)))
运行后发现ratio_of_points数组全部为NaN值!加载的数据类型为<class 'pandas.core.series.Series'>,单个元素类型为<class 'numpy.float64'>,且所有元素均非零。
示例Series数据:
第一个Series的前10个元素:
print(sliding[k][sliding_start:sliding_start+10]) 30 -1.284938 31 -1.219414 32 -0.936132 33 -0.801830 34 -0.848222 35 -1.291175 36 -1.470336 37 -1.428876 38 -1.318022 39 -1.303974
第二个Series的前10个元素:
print(fixed[k][j:j+10]) 0 -3.22 1 -3.58 2 -3.51 3 -1.62 4 -1.78 5 -1.40 6 -1.19 7 -1.50 8 -1.58 9 -1.09
使用/运算符、np.divide()和pandas.Series.divide都会出现相同问题。猜测是DataFrame索引不匹配导致的错误,想知道有没有办法强制两个Series忽略索引执行除法,目前想到的方法是转换为常规数组或numpy数组。
问题根源
Pandas中Series的算术运算默认会按索引对齐,你的两个Series索引完全不重叠(一个是30-39,一个是0-9),对齐后没有匹配的元素,因此运算结果全为NaN。
强制按位置运算的方法
方法1:转换为NumPy数组
直接提取Series的数值部分,用to_numpy()(Pandas 0.24+推荐)或.values,这样会完全忽略索引,按位置逐元素计算:
ratio_of_points = sliding[k][sliding_start-n:sliding_stop-n].to_numpy() / fixed[k][j:j+60].to_numpy()
方法2:重置索引
用reset_index(drop=True)将两个Series的索引重置为从0开始的连续整数,让索引对齐逻辑按位置匹配:
sliding_subset = sliding[k][sliding_start-n:sliding_stop-n].reset_index(drop=True) fixed_subset = fixed[k][j:j+60].reset_index(drop=True) ratio_of_points = sliding_subset / fixed_subset
代码优化建议
循环30次时可以提前缓存fixed的切片,避免重复索引查找,提升运行效率:
keys = ['BX_GSE', 'BY_GSE', 'BZ_GSE', 'Vx', 'Vy', 'Vz', 'proton_density', 'T'] max_avg = [] timeshift_offset = [] for k in keys: averages_storage_array = [] # 提前缓存fixed的60分钟切片的NumPy数组 fixed_np = fixed[k][j:j+60].to_numpy() for n in range(30): sliding_np = sliding[k][sliding_start-n:sliding_stop-n].to_numpy() ratio_of_points = sliding_np / fixed_np averaged_ratio_1hr = np.average(ratio_of_points) averages_storage_array.append(averaged_ratio_1hr) max_avg.append(max(averages_storage_array)) timeshift_offset.append(averages_storage_array.index(max(averages_storage_array)))
内容的提问来源于stack exchange,提问作者Kajmunso

