You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为NumPy二维散点图拟合直线并筛选离群点?

问题:二维MaskedArray数据拟合直线及异常点检测

问题重现

用户尝试对二维网格上的两类观测数据(TIR1和TIR2亮温)拟合直线,使用numpy.polyfit时触发类型错误,核心报错为:

TypeError: expected 1D vector for x

用户代码如下:

import h5py
import sys
import numpy as np
import matplotlib.pyplot as plt

# First get data from HDF5 file with h5py:
fn = '/home/swadhin/project/insat/data/3RIMG_30MAR2018_0014_L1B_STD_V01R00.h5'
x = np.load('/home/swadhin/project/insat/land_mask.npy')

#Reading the L2 SST data
with np.load('sst.npz') as npz:
    arr_sst = np.ma.MaskedArray(**npz)

with h5py.File(fn) as f:
    print(list(f.keys()))
    # retrieve image data:
    image = 'IMG_TIR1'
    image2 = 'IMG_TIR2'
    lon = f['Longitude'][:]*0.01
    lat = f['Latitude'][:]*0.01
    img_arr = f[image][0, :, :]
    img_arr2 = f[image2][0, :, :]
    
    # get _FillValue for data masking
    img_arr_fill = f[image].attrs['_FillValue'][0]
    img_arr_fill2 = f[image2].attrs['_FillValue'][0]

    #LUT 
    radiance_lut_tir1 = np.array(f[image+str('_RADIANCE')])
    radiance_lut_tir2 = np.array(f[image2+str('_RADIANCE')])
    bt_lut_tir1 = np.array(f[image+str('_TEMP')])
    bt_lut_tir2 = np.array(f[image2+str('_TEMP')])
    
# retrieve the extent of the plot from file attributes:
    left_lon = f.attrs['left_longitude'][0]
    right_lon = f.attrs['right_longitude'][0]
    lower_lat = f.attrs['lower_latitude'][0]
    upper_lat = f.attrs['upper_latitude'][0]
    sat_long = f.attrs['Nominal_Central_Point_Coordinates(degrees)_Latitude_Longitude'][1]
    sat_hght = f.attrs['Nominal_Altitude(km)'][0] * 1000.0  # (for meters)
print('Done reading HDF5 file')

# Use np.ma.masked_equal with integer values to
# mask '_FillValue' data in corners:
img_arr_m = np.ma.masked_equal(img_arr, img_arr_fill)
img_arr_m2 = np.ma.masked_equal(img_arr2, img_arr_fill2)

lon_m = np.ma.masked_equal(lon, 327.67)
lat_m = np.ma.masked_equal(lat, 327.67)
#########BT from LUT

def count2bt_lut_tir1(count):
    return bt_lut_tir1[count]
def count2bt_lut_tir2(count):
    return bt_lut_tir2[count]


bt_tir1_lut = count2bt_lut_tir1(img_arr_m)
bt_tir2_lut = count2bt_lut_tir2(img_arr_m2)

bt_tir1_lut_m = np.ma.array(bt_tir1_lut, mask=x, dtype=np.float64)
bt_tir2_lut_m = np.ma.array(bt_tir2_lut, mask=x, dtype=np.float64)

################# Creating a Scatter Plot of Bts from TIR1 and TIR2

plt.scatter(bt_tir1_lut_m,bt_tir2_lut_m,s = 10)
np.shape(bt_tir1_lut_m)
m, b = np.polyfit(bt_tir1_lut_m, bt_tir2_lut_m, 1)
plt.plot(bt_tir1_lut_m, m*bt_lut_tir1 + b,color='k')


plt.xlabel("Brightness Temperature(K) in TIR1 (10.8 micron)")
plt.ylabel("Brightness Temperature(K) in TIR2 (12 micron)")

完整报错栈:

TypeError                                 Traceback (most recent call last)
/home/swadhin/project/insat/bt_comparison.py in <cell line: 156>()
    154 plt.scatter(bt_tir1_lut_m,bt_tir2_lut_m,s = 10)
    155 np.shape(bt_tir1_lut_m)
--> 156 m, b = np.polyfit(bt_tir1_lut_m, bt_tir2_lut_m, 1)
    157 plt.plot(bt_tir1_lut_m, m*bt_lut_tir1 + b,color='k')
    160 plt.xlabel("Brightness Temperature(K) in TIR1 (10.8 micron)")

File <__array_function__ internals>:180, in polyfit(*args, **kwargs)

File ~/anaconda3/envs/rttov/lib/python3.9/site-packages/numpy/lib/polynomial.py:636, in polyfit(x, y, deg, rcond, full, w, cov)
    634     raise ValueError("expected deg >= 0")
    635 if x.ndim != 1:
--> 636     raise TypeError("expected 1D vector for x")
    637 if x.size == 0:
    638     raise TypeError("expected non-empty vector for x")

TypeError: expected 1D vector for x

解决方案

1. 拟合直线:将二维MaskedArray转为一维有效数据

np.polyfit要求输入为一维数组,而bt_tir1_lut_m和bt_tir2_lut_m是二维MaskedArray。需要先提取其中非掩码的有效数据并展平为一维:

# 提取非掩码的一维有效数据
x_data = bt_tir1_lut_m.compressed()
y_data = bt_tir2_lut_m.compressed()

# 拟合直线(一阶多项式)
m, b = np.polyfit(x_data, y_data, 1)

修正拟合线绘制

原代码中plt.plot(bt_tir1_lut_m, m*bt_lut_tir1 + b)存在错误:bt_lut_tir1是LUT数组,不是当前的亮温数据。正确做法是基于x数据的范围生成拟合线的点:

# 生成拟合线的x轴范围(覆盖所有有效数据)
x_fit = np.linspace(x_data.min(), x_data.max(), 100)
y_fit = m * x_fit + b

# 绘制拟合线
plt.plot(x_fit, y_fit, color='k', label=f'Fit: y = {m:.2f}x + {b:.2f}')
plt.legend()

2. 获取远离拟合线的点(异常点)

通过计算残差(实际值与拟合值的差),设定阈值筛选异常点:

# 计算所有有效点的拟合值与残差
y_pred = m * x_data + b
residuals = y_data - y_pred

# 设定异常点阈值(示例:残差绝对值超过2倍标准差)
threshold = 2 * np.std(residuals)
outlier_mask = np.abs(residuals) > threshold

# 提取异常点
x_outliers = x_data[outlier_mask]
y_outliers = y_data[outlier_mask]

# 在散点图中标记异常点
plt.scatter(x_outliers, y_outliers, s=15, color='r', label='Outliers')
plt.legend()

完整修正后的代码片段

################# Creating a Scatter Plot of Bts from TIR1 and TIR2

plt.scatter(bt_tir1_lut_m, bt_tir2_lut_m, s=10, alpha=0.5)

# 提取有效数据并拟合直线
x_data = bt_tir1_lut_m.compressed()
y_data = bt_tir2_lut_m.compressed()
m, b = np.polyfit(x_data, y_data, 1)

# 绘制拟合线
x_fit = np.linspace(x_data.min(), x_data.max(), 100)
y_fit = m * x_fit + b
plt.plot(x_fit, y_fit, color='k', label=f'Fit: y = {m:.2f}x + {b:.2f}')

# 检测并绘制异常点
y_pred = m * x_data + b
residuals = y_data - y_pred
threshold = 2 * np.std(residuals)
outlier_mask = np.abs(residuals) > threshold
plt.scatter(x_data[outlier_mask], y_data[outlier_mask], s=15, color='r', label='Outliers')

plt.xlabel("Brightness Temperature(K) in TIR1 (10.8 micron)")
plt.ylabel("Brightness Temperature(K) in TIR2 (12 micron)")
plt.legend()
plt.show()

内容的提问来源于stack exchange,提问作者The Emerging Star

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 12:15:37