SolarData:统一封装公开太阳能数据源,实现高效下载与清洗 简介这是面向太阳能领域数据分析的R语言工具包聚焦下载并处理NREL、NOAA、NASA等公开太阳能数据集涵盖栅格化卫星辐照度、密集传感器网络、地面辐照度、数字高程与林克浊度等多种数据便于科研与工程用户快速获取标准化数据。压缩包共34个文件包括R脚本、Rd帮助文档、RData示例数据以及项目配置和说明文档整体仅168KB轻量且目录清晰适合快速部署与二次开发。目前已有1839人学习下载适合气象、能源方向的科研人员及R开发者学习参考包内函数与示例覆盖PSM、SURFRAD、BSRN等常用数据源可显著缩短数据采集与预处理时间。对于光伏电站选址、太阳能资源评估、气候建模等任务这套工具能减少自行查找数据源与解析格式的麻烦是开展相关研究的实用基础。 前两天有个做光伏电站选址的朋友跟我抱怨说找太阳能数据比找对象还难官方数据源分散在好几个网站有的要填申请表单有的返回格式乱七八糟下载回来还得自己一个个清洗。我听完直接把这几年攒的下载处理公开太阳能数据集的脚本整理了一下就是现在的SolarData项目。这玩意解决的核心问题很简单把散落在NREL、Solcast、Open-Meteo等平台的公开太阳能数据源用统一的方式拉下来、洗干净、转成标准格式再落成CSV或者直接画成图。适合做光伏资源评估、发电量预测、科研建模或者单纯想盘一盘自家屋顶光伏能发多少电的朋友参考。这活儿听起来像个跑腿脚本但真做起来全是细节。数据源格式不统一只是第一道坎后面还有时区错位、单位混用、缺失值伪装成0、API限流这些坑等着你稍不留神你辛辛苦苦拉下来的数据就是一张废表。这篇我把整个项目的设计思路、核心字段、实测代码和踩坑记录都摊开讲你照着抄就能用。1. 整体设计思路与数据源选型1.1 为什么需要统一封装太阳能数据集本身的“下载”动作并不难难点在于每个平台的访问方式、返回格式和更新策略都不一样。比如NREL的NSRDB走的是RESTful API返回JSON格式但每个请求有严格的经纬度参数和年份限制Solcast提供批量CSV导出但历史数据有次数配额Open-Meteo则是完全开源的接口返回结构简单但数据口径偏再分析产品和实测站数据有误差。这种情况下如果每次做项目都重新写一遍请求、解析、清洗代码时间成本完全不可控。SolarData的定位就是把这些差异吸收掉对外暴露三个统一能力按指定经纬度或点集批量拉数据、自动对齐时间轴和物理单位、一键输出标准DataFrame或CSV。这不只是省几行代码而是把数据获取从“手工作坊”变成了“流水线”。1.2 公开数据源盘点与选择逻辑选数据源不能只看哪个顺手要看项目场景。国内项目我一般不推荐直接用海外再分析数据除非是做预研对比原因后面说。下表是我实测过的几个公开数据源各自的定位和限制列得很清楚数据源数据类型时间分辨率覆盖范围访问限制适用场景NREL NSRDB卫星反演GHI/DNI/DHI等5分钟/小时美国、部分全球区域需注册API Key逐年按经纬度拉取光伏资源详评、系统设计NREL PVWatts估算发电量小时全球API无严格配额快速估算电站发电量Open-Meteo再分析气象含太阳辐射小时/15分钟全球免费、无需Key大范围粗略扫描、补充数据Solcast卫星模型融合5分钟/30分钟全球免费版有日请求配额短期功率预测、动态分析EMHIRES再分析气象小时欧洲为主免费下载欧洲区域研究选型逻辑很直白如果你要的是“能直接拿去算发电量”的高质量数据优先NSRDB如果你只想在草图阶段估算一下项目潜力Open-Meteo够用了如果你做的是欧洲项目EMHIRES口径更友好。至于那些需要签协议才能拿的数据源我一般先PASS掉公开数据能做到的事情没必要卡在流程上。2. 核心细节解析太阳能数据里的关键字段与单位陷阱2.1 必须搞懂的五个辐射字段很多人拿到数据之后直接读GHI列就开始算发电量这是很危险的习惯。太阳能数据里有几个概念看着像、用起来完全不同GHI是水平面总辐射DHI是水平面散射辐射DNI是法向直射辐射。光伏组件朝向固定时真正落到倾斜面上的辐射是要靠这三者通过空间几何关系折算出来的直接拿GHI粗算会明显低估或高估。还要注意“晴空辐射”这个概念。NSRDB会提供一个Clear Sky GHI字段这个值是理论上无云情况下的辐射上限。实际业务里拿实际GHI除以晴空GHI能快速判断云遮挡强度这也是很多光伏功率预测算法的输入特征之一。数据里如果缺了这类派生特征建模效果会差不少。2.2 单位换算和时区对齐不能想当然NSRDB的GHI单位是瓦每平方米W/m²但部分历史汇总数据会给出焦耳或千瓦时每平方米PVWatts则直接给出交流发电量。如果在同一套代码里混用多个数据源第一步就要把单位全部归一化我习惯统一换算成kWh/m²计算发电量时再乘以面积和效率系数。时区问题更隐蔽。NSRDB的时间戳是UTCOpen-Meteo默认返回本地时间Solcast又是UTC。很多人下载完直接按时间序列画图结果太阳辐射峰值出现在“晚上”就是因为没对齐时区。SolarData里我用pandas的tz_convert统一转成目标时区并且把本地太阳时也计算出来做日照时段筛选时非常有用。2.3 缺失值与无效值要分开处理公开数据集的另一个共性是数据缺得各有特色。NSRDB用-99999表示无效值Open-Meteo直接给null翻车现场则经常出现在SolarData的早期版本里我把这些占位符和真实0值混在一起处理统计日均值时结果被拉低了一大截。正确的做法是先把无效值重新映射成NaN再按业务规则做填充。如果是5分钟粒度的短时缺失线性插值够用如果是连续几小时缺失且出现在晴天可以考虑用晴空辐射模型补如果缺失比例超过5%这个站点干脆弃用不然下游分析全是噪声。3. 实操过程从零下载一份NSRDB数据并进行清洗可视化3.1 环境准备与依赖安装实战阶段我以NSRDB为例讲因为它的字段最全、文档最规范非常适合当模板。先把环境装好Python 3.9以上版本配置国内镜像源几秒钟就完成pip install pandas numpy requests matplotlib plotly -i https://pypi.tuna.tsinghua.edu.cn/simple这套依赖里pandas和numpy是数据清洗的地基requests负责调APImatplotlib和plotly一个管静态图一个管交互图。我建议再加一个python-dateutil处理ISO时间字符串时能少踩很多坑。3.2 配置API Key与请求参数NSRDB要求先到官网注册获取API Key然后把Key写进环境变量不要硬编码在脚本里免得脚本传出去把Key也泄露了。配置好之后核心逻辑是先构造请求URL# 设置环境变量Linux/Mac直接exportWindows用set export NSRDB_API_KEY你的Key构造请求时NSRDB要求三个必填参数经纬度、年份、数据集名称。还有一个容易漏掉的参数是interval它决定返回分钟粒度还是小时粒度我日常用60分钟做功率预测才选5分钟。请求头需要带x-api-key字段不带的话会直接403。import os import requests API_KEY os.getenv(NSRDB_API_KEY) API_URL https://developer.nrel.gov/api/nsrdb/v2/solar/psm3-download.csv params { api_key: API_KEY, wkt: POINT(-122.2461 37.7509), # 注意坐标顺序经度在前纬度在后 names: 2022, leap_day: false, interval: 60, utc: true, email: your_emailexample.com, attributes: ghi,dhi,dni,wind_speed,air_temperature,solar_zenith_angle, } resp requests.get(API_URL, paramsparams, timeout60) resp.raise_for_status()注意观察字符串里的坐标顺序。NSRDB的接口定义是POINT(经度 纬度)跟常规的先纬度后经度习惯相反写反了请求不会报错但数据就指向地球另一面了。这个细节我在最开始调接口时反复出错趁早写进注释里。3.3 数据解析与清洗NSRDB返回的CSV文件细看会发现头部有一堆元信息行真正的列名在中间位置行数不固定。直接pd.read_csv(resp.text)会得到一堆垃圾列。我写了个小逻辑动态探测表头行位置import pandas as pd from io import StringIO csv_text resp.text lines csv_text.strip().split(\n) # 找到列名所在的行通常包含Year,Month,Day,Hour header_idx None for i, line in enumerate(lines): if line.startswith(Year,Month,Day): header_idx i break if header_idx is None: raise ValueError(CSV表头未找到请检查数据源返回格式) df pd.read_csv(StringIO(csv_text), skiprowsheader_idx) # 构造时间戳 df[timestamp] pd.to_datetime(df[[Year, Month, Day, Hour]]) df df.set_index(timestamp).sort_index()时间戳构造这里有个隐蔽点NSRDB里的小时含义是“该小时结束时刻”还是“开始时刻”不同数据集定义不同NSRDB官方文档写的是一天中的某个小时实测下来是从0点到23点的小时段我用Hour字段直接拼时间戳后减1小时校准。接下来做缺失值处理和单位归一化# NSRDB无效值统一映射为NaN df df.replace(-99999, pd.NA) # 只保留业务需要的核心字段 cols [ghi, dhi, dni, wind_speed, air_temperature, solar_zenith_angle] df df[cols].astype(float) # 转换单位W/m² → kWh/m²小时粒度可直接用数值/1000 df[ghi_kwh] df[ghi] / 1000.0这里稍微解释一下为什么小时粒度的W/m²除以1000就是kWh/m²W乘以小时数得到Wh1小时粒度下数值上等于Wh/m²再除以1000就是kWh/m²。日粒度数据不能这么简单除得先按天聚合再换算。3.4 可视化输出清洗完之后出图是最直观的校验方式。我用matplotlib画全年GHI逐时曲线再用plotly画一个可交互的散点图把太阳高度角作为颜色映射一眼就能看出数据有没有明显异常import matplotlib.pyplot as plt df.plot(yghi_kwh, figsize(14, 4), titleGHI - 2022 (kWh/m²)) plt.xlabel(Time) plt.ylabel(GHI (kWh/m²)) plt.tight_layout() plt.savefig(ghi_2022.png, dpi150)运行完如果看到的是平滑的年度正弦波形态说明数据质量大概率没问题如果出现大量毛刺或突变回头检查时区和缺失值处理逻辑别急着往下游算法里丢。4. 常见问题与排查技巧实录4.1 高频报错403、超时、空数据这块我直接整理成速查表都是几个数据源实测时踩过的坑现象可能原因解决方案请求返回403API Key没传或写错检查环境变量是否加载临时打印Key前几位确认请求超时目标区域历史数据量大加timeout参数按年份分多次请求返回CSV但没有数据行经纬度坐标写反检查POINT(经度 纬度)的顺序数据全是-99999海域或无人区、无卫星反演更换数据源或平移坐标到附近陆地时间戳跑到很晚或很早时区未对齐统一转UTC后再转本地时区4.2 实测心得三个容易让人放弃的坎第一个坎是元信息表头。NSRDB的CSV头部会有一段包含数据请求元信息的长文本直接给read_csv的话会变成一堆乱七八糟的列。解决办法就是我上面写的动态定位表头行别硬编码行号因为不同年份返回的头部信息可能有差异。第二个坎是数据源之间的粒度差异。NSRDB是5分钟或60分钟Open-Meteo是15分钟Solcast可以到5分钟。做多源对比时先重采样到同一个时间粒度再算误差不然RMSE的值会因为对齐方式不同而飘忽不定。我习惯统一到小时粒度对比误差分析前先看一眼对齐后的有效样本数。第三个坎是年度文件的体积。NSRDB一个点位的全年60分钟数据量不大但如果你跑的是5分钟粒度或者一次处理几百个点位pandas的read_csv内存会直接爆。这种情况我分步走先按年下载再按点位循环清洗聚合完毕后再拼接而不是一次性全读进来。4.3 多做一步数据签名与版本管理太阳能数据集是“源数据”基本不会被修改但下载脚本、清洗参数、单位换算规则可能一直在变。如果下游分析结果出了问题回溯时没有数据版本管理会非常痛苦。我给每次下载的数据生成一个哈希签名并存一份meta.json记录数据源、请求参数、处理脚本版本。这样任何一次分析都能准确溯源到那份特定的数据快照排查问题效率高很多。另外把清洗后的标准DataFrame存成Parquet格式而不是CSV读取速度快好几倍也能保留列的类型信息对后续批量建模友好很多。5. 这个项目后续还能怎么扩展SolarData目前只做了下载和基础清洗但太阳能数据项目的天花板远不止于此。我在实际使用中已经往这几个方向扩展一是接入阴影分析。从NSRDB拿到DNI和太阳高度角后结合光伏板朝向和倾角可以算出道道光损再用晴空辐射模型做理论发电量对比这套逻辑跑通了选址评估就多了一个量化的维度。二是做功率预测的数据管道。把SolarData下载的历史辐射、温度、风速数据接进LSTM或XGBoost模型预测未来24小时光伏输出。这个方向基础设施很重要数据管道稳定了模型迭代才谈得上。三是在污染比较重的场景中引入空气质量数据。气溶胶浓度会明显削弱DNI影响光伏电站的短期出力。这个属于“隐性因素”目前很多公开工具没有考虑做精细评估时可以当成亮点。回到开头说的那个朋友他后来用我这套流程把几个候选厂址的数据统一拉了下来对比了年总辐射量、温度导致的效率折减、冬季阴雨天占比两天时间就出初稿。拿到一手干净数据的过程本身就是项目里最容易被低估的价值环节。最后再分享一个细节处理任何太阳能数据集之前先画一张全年GHI曲线并人工看一眼。这一步能拦下八成以上的脏数据问题比写一百行校验代码都管用。本文还有配套的精品资源点击获取