跳转到主要内容

一个快速的,向量化Python版本的suncalc.js

项目描述

suncalc-py

Test Package version Downloads

一个快速的,向量化Python实现,用于计算给定位置和时间的太阳位置和阳光阶段(日出、日落、黄昏等时间)的suncalc.js

虽然存在其他类似的库,但我最初没有遇到任何满足我要求的库,即公开授权、向量化且易于使用 1

安装

pip install suncalc

使用

示例

suncalc旨在与单个值和值的数组一起使用。

首先,导入模块

from suncalc import get_position, get_times
from datetime import datetime

目前有两种方法:get_position,用于获取给定日期和位置的太阳方位角和高度,以及get_times,用于获取给定日期和位置的阳光阶段。

date = datetime.now()
lon = 20
lat = 45
get_position(date, lon, lat)
# {'azimuth': -0.8619668996997687, 'altitude': 0.5586446727994595}

get_times(date, lon, lat)
# {'solar_noon': Timestamp('2020-11-20 08:47:08.410863770'),
#  'nadir': Timestamp('2020-11-19 20:47:08.410863770'),
#  'sunrise': Timestamp('2020-11-20 03:13:22.645455322'),
#  'sunset': Timestamp('2020-11-20 14:20:54.176272461'),
#  'sunrise_end': Timestamp('2020-11-20 03:15:48.318936035'),
#  'sunset_start': Timestamp('2020-11-20 14:18:28.502791748'),
#  'dawn': Timestamp('2020-11-20 02:50:00.045539551'),
#  'dusk': Timestamp('2020-11-20 14:44:16.776188232'),
#  'nautical_dawn': Timestamp('2020-11-20 02:23:10.019832520'),
#  'nautical_dusk': Timestamp('2020-11-20 15:11:06.801895264'),
#  'night_end': Timestamp('2020-11-20 01:56:36.144269287'),
#  'night': Timestamp('2020-11-20 15:37:40.677458252'),
#  'golden_hour_end': Timestamp('2020-11-20 03:44:46.795967773'),
#  'golden_hour': Timestamp('2020-11-20 13:49:30.025760010')}

这些方法也适用于数组数据,并且由于实现是向量化,因此比Python中的for循环快得多。

import pandas as pd

df = pd.DataFrame({
    'date': [date] * 10,
    'lon': [lon] * 10,
    'lat': [lat] * 10
})
pd.DataFrame(get_position(df['date'], df['lon'], df['lat']))
# azimuth	altitude
# 0	-1.485509	-1.048223
# 1	-1.485509	-1.048223
# ...

pd.DataFrame(get_times(df['date'], df['lon'], df['lat']))['solar_noon']
# 0   2020-11-20 08:47:08.410863872+00:00
# 1   2020-11-20 08:47:08.410863872+00:00
# ...
# Name: solar_noon, dtype: datetime64[ns, UTC]

如果您想将这些数据合并回您的DataFrame,可以使用pd.concat

times = pd.DataFrame(get_times(df['date'], df['lon'], df['lat']))
pd.concat([df, times], axis=1)

API

get_position

计算给定日期和经纬度的太阳位置(方位角和高度)

  • date (datetime 或 pandas的datetime系列):查找太阳位置的日期和时间。日期时间必须为UTC
  • lng (floatfloat 的 numpy 数组):查找太阳位置的长经度
  • lat (floatfloat 的 numpy 数组):查找太阳位置的纬度

返回一个包含两个键的 dictazimuthaltitude。如果输入值是单个值,则 dict 的值将是浮点数。否则,它们将是浮点数的 numpy 数组。

get_times

  • date (datetime 或 pandas 日期时间的系列):查找阳光阶段的时间和日期。必须使用 UTC。

  • lng (floatfloat 的 numpy 数组):查找阳光阶段的经度

  • lat (floatfloat 的 numpy 数组):查找阳光阶段的纬度

  • height (floatfloat 的 numpy 数组,默认 0):观测者的高度(米)

  • times (Iterable[Tuple[float, str, str]]):一个可迭代的对象,定义了地平线以上的角度和自定义阳光阶段字符串。默认值是

    # (angle, morning name, evening name)
    DEFAULT_TIMES = [
        (-0.833, 'sunrise', 'sunset'),
        (-0.3, 'sunrise_end', 'sunset_start'),
        (-6, 'dawn', 'dusk'),
        (-12, 'nautical_dawn', 'nautical_dusk'),
        (-18, 'night_end', 'night'),
        (6, 'golden_hour_end', 'golden_hour')
    ]
    

返回一个 dict,其键为 solar_noonnadir 以及 times 参数中传递的任何键。如果输入值是单个值,则 dict 的值将是 datetime.datetime 类型(如果您已安装 pandas,则为 pd.Timestamp,它是 datetime.datetime 的子类,因此与 datetime.datetime 兼容)。否则,它们将是 pandas DateTime 系列。返回的时间将使用 UTC。

基准测试

此基准测试旨在证明向量化实现几乎比 Python 中的 for 循环快 100 倍。

首先设置一个包含随机数据的 DataFrame。这里我创建了 100,000 行。

from suncalc import get_position, get_times
import pandas as pd

def random_dates(start, end, n=10):
    """Create an array of random dates"""
    start_u = start.value//10**9
    end_u = end.value//10**9
    return pd.to_datetime(np.random.randint(start_u, end_u, n), unit='s')

start = pd.to_datetime('2015-01-01')
end = pd.to_datetime('2018-01-01')
dates = random_dates(start, end, n=100_000)

lons = np.random.uniform(low=-179, high=179, size=(100_000,))
lats = np.random.uniform(low=-89, high=89, size=(100_000,))

df = pd.DataFrame({'date': dates, 'lat': lats, 'lon': lons})

然后两种方式计算 SunCalc.get_position:第一种使用向量化实现,第二种使用 df.apply,这相当于 for 循环。第一种比第二种快超过 100倍

%timeit get_position(df['date'], df['lon'], df['lat'])
# 41.4 ms ± 437 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit df.apply(lambda row: get_position(row['date'], row['lon'], row['lat']), axis=1)
# 4.89 s ± 184 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

同样,两种方式计算 SunCalc.get_times:第一种使用向量化实现,第二种使用 df.apply。第一种比第二种快 2800倍!这里的一些差异在于,在底层,非向量化方法使用 pd.to_datetime,而向量化实现使用 np.astype('datetime64[ns, UTC]')pd.to_datetime 真的非常慢!!

%timeit get_times(df['date'], df['lon'], df['lat'])
# 55.3 ms ± 1.91 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%time df.apply(lambda row: get_times(row['date'], row['lon'], row['lat']), axis=1)
# CPU times: user 2min 33s, sys: 288 ms, total: 2min 34s
# Wall time: 2min 34s

1: pyorbital 看起来很棒,但许可证是 GPL3;pysolar 也是 GPL3 许可证;pyEphem 是 LGPL3 许可证。 suncalcPysuncalc.js 的另一个端口,许可证是 MIT,但未使用 Numpy,因此没有向量化。我最近发现了 sunpyastropy,两者都可能工作,但最初我没有看到它们,而且它们看起来对这个简单任务来说相当复杂...

变更日志

[0.1.3] - 2023-04-18

  • 确保 pandas 2.0 兼容性(修复日期时间的整型转换)

[0.1.2] - 2020-12-02

  • 在传递给 datetime.utcfromtimestamp 之前尝试捕获 NaN

[0.1.1] - 2020-11-20

  • 通过添加 MANIFEST.in 修复 PyPI 安装
  • 更新文档

[0.1.0] - 2020-11-19

  • 在 PyPI 上进行初始发布

项目详细信息


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于 安装软件包 的信息。

源代码发行版

suncalc-0.1.3.tar.gz (13.1 kB 查看散列)

上传于 源代码

支持