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

Scipy linregress回归线与散点图拟合不准 相关系数异常问题

降雨率与行星边界层高度线性回归异常问题

我尝试对数据集ocean_rr_1d和ocean_PBLH_1d(各含330万个数据点)绘制线性回归线,但生成的回归线完全不符合数据分布。两组数据分别是行星边界层高度(PBLH,单位米)和降雨率(单位mm/hr)的日度测量值,PBLH原始为小时级数据,我将逐小时数据拼接为完整日度数组,处理逻辑见下方代码。

带回归线的散点图

我同时测试了两组数据的相关性,使用np.corrcoef(ocean_rr_1d, ocean_PBLH_1d)计算得到的相关系数为0.9998,接近完全相关,但绘图结果显然不符合完全相关的特征,理想的R=1相关数据集分布见下图:

R=1相关数据分布图

我使用的是掩膜数据,数据处理和绘图代码如下。我已经尝试掩膜np.nan值但问题未解决,也通过print('Daily minimum PBLH:' + ' ' + str(np.min(ocean_PBLH_1d)))检查PBLH最小值为253,和图中最小PBLH点一致,不存在异常值拉偏回归线的情况。

import os
import subprocess, shlex
import conda
import datetime as dt
import numpy as np
import matplotlib.pyplot as plt
import glob
import pandas as pd
import netCDF4
import sys
from global_land_mask import globe
from netCDF4 import Dataset
from scipy import stats

# Fixes KeyError: "PROJ_LIB" issue
conda_file_dir         = conda.__file__
conda_dir              = conda_file_dir.split('lib')[0]
proj_lib               = os.path.join(os.path.join(conda_dir, 'share'), 'proj')
os.environ["PROJ_LIB"] = proj_lib
from mpl_toolkits.basemap import Basemap, cm

curDT = dt.datetime(2020, 7, 20, 0) # Start time 
endDT = dt.datetime(2020, 7, 20, 23) # End time

directory        = '/uufs/chpc.utah.edu/common/home/zpu-group10/pu03/mpletch/thesis/IMERG/July/gpm1.gesdisc.eosdis.nasa.gov/opendap/GPM_L3/GPM_3IMERGHH.06/2020/202/*.nc4' # Directory for IMERG data
regridded_merra2 = Dataset('/uufs/chpc.utah.edu/common/home/zpu-group10/pu03/mpletch/thesis/regridded_MERRA2_pblh/07' + curDT.strftime("%d") + '_new_regridded_MERRA2.nc4.nc4')
hourly           = ("00.V06B.HDF5.nc4", "20.V06B.HDF5.nc4", "40.V06B.HDF5.nc4", "60.V06B.HDF5.nc4", "80.V06B.HDF5.nc4") # Strings that represent tshe pattern of hourly rain-rate data since 30-minute data is included in the IMERG data.

rain_rate_all      = []
regridded_pblh_all = []
lat_regridded_all  = []
lon_regridded_all  = []

while curDT < endDT: # Loops through each hourly IMERG case by adding an hour to the current time (curDT). 
  for filepath in glob.iglob(directory): # Navigates to the IMERG data directory
    if filepath.endswith(hourly): # Ensures that only hourly and not half-hourly data is used
      
      imerg_data    = Dataset(filepath, 'r')
      imerg_data.variables.keys()
      rain_rate     = np.array(imerg_data.variables['precipitationCal'][0,100:650,0:250]*1).T # Reads in IMERG rain rate data
      lat_imerg     = np.array(imerg_data.variables['lat'][0:250]*1)
      lon_imerg     = np.array(imerg_data.variables['lon'][100:650]*1)
      levels_imerg  = [2 + 2*n for n in range(25)] # Defines contours for rain rate plots
 
      regridded_pblh = np.array(regridded_merra2.variables['PBLH'][curDT.strftime("%-H"),0:250,100:650])
      regridded_lat  = regridded_merra2.variables['lat'][0:250]
      regridded_lon  = regridded_merra2.variables['lon'][100:650]
      regridded_lat  = np.tile(regridded_lat,(len(regridded_lon),1)).T
      regridded_lon  = np.tile(regridded_lon,(len(regridded_lat),1))

      rain_rate_all.append(rain_rate)
      pblh_all.append(pblh)
      regridded_pblh_all.append(regridded_pblh)
      lat_regridded_all.append(regridded_lat)
      lon_regridded_all.append(regridded_lon)
   
    curDT = curDT + dt.timedelta(hours = 0.5) # Loops through hourly PBLH data instead of every two hours

# Converts all arrays to np.arrays.
regridded_pblh_all = np.array(regridded_pblh_all)
rain_rate_all      = np.array(rain_rate_all)
lat_regridded_all  = np.array(lat_regridded_all)
lon_regridded_all  = np.array(lon_regridded_all)

masked_rr        = np.where(rain_rate_all >=10, rain_rate_all, -1) # Masks any rain rate that is less than or equal to 10 mm/hr and replaces them with -1
masked_rr        = np.ma.masked_where(masked_rr == -1, masked_rr) # Masks -1 PBLH values.
onedim_masked_rr = masked_rr.flatten()
PBLH_col         = np.where(rain_rate_all > 10, regridded_pblh_all, -1) # Locates the PBLH where the rainfall rate is 10 mm/hr and greater
PBLH_col         = np.ma.masked_where(PBLH_col == -1, PBLH_col) # Masks the -1 fill values
PBLH_col         = np.ma.masked_where(PBLH_col == 1000000000000000.0, PBLH_col) # Masks the 1E15 values

on_land = globe.is_land(lat_regridded_all, lon_regridded_all) # Determines if a point is on land

ocean_PBLH    = np.where(on_land == False, PBLH_col, -9999) # Finds the PBLH over ocean instead of land.
ocean_PBLH    = np.ma.masked_where(ocean_PBLH < 0, ocean_PBLH) # Masks any PBLH below 0
ocean_PBLH    = np.ma.masked_where(ocean_PBLH == 1000000000000000.0, ocean_PBLH) # Masks 1E15 PBLH values that are for some reason in the data
ocean_PBLH_1d = ocean_PBLH.flatten() # Creates a 1-D array to use for correlation test

ocean_rr      = np.where(on_land == False, masked_rr, -9999) # Masks all data over land.
ocean_rr      = np.ma.masked_where(ocean_rr < 0, ocean_rr) # Masks out any negative values.
ocean_rr_1d   = ocean_rr.flatten() # Creates a 1-D array to use for the correlation test.

corr = np.corrcoef(ocean_rr_1d, ocean_PBLH_1d) # Runs correlation between the two data sets.

regression_mask = ~np.isnan(ocean_rr_1d) & ~np.isnan(ocean_PBLH_1d)
slope, intercept, r_value, p_value, std_err = stats.linregress(ocean_rr_1d[regression_mask], ocean_PBLH_1d[regression_mask]) # Masks any NaN values to be used in the correlation
plt.scatter(ocean_rr_1d, ocean_PBLH_1d, s = 2, c = 'blue')
plt.plot(ocean_rr_1d, intercept + slope*ocean_rr_1d, 'r')
plt.title('Scatter plot of rain rate (10+ mm/hr) and PBLH (m)\n 07-04-2020')
plt.xlabel('Rain rate (mm/hr)')
plt.ylabel('PBLH (m)')
plt.show()

以下是两个数据集的样本输出,由于掩膜值较多,我选取了一小段非掩膜数据展示格式:

PBLH数据

3235075          NaN
3235076          NaN
3235077   605.557373
3235078   545.571350
3235079   485.585358
3235080   425.599365
3235081          NaN
3235082          NaN

降雨率数据

3235075        NaN
3235076        NaN
3235077  26.847431
3235078  27.215666
3235079  14.650899
3235080  32.269173
3235081        NaN
3235082        NaN

内容的提问来源于stack exchange,提问作者mpletch1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 06:18:02