计算多个大文件的百分位数而不将它们全部保存在内存中(Python)

问题描述 投票:0回答:1

我正在尝试计算气候再分析数据集 MERRA2 中某个值的第 99 个百分位数。 43 年来(1980-2022 年),我每小时都在 361 x 576 点的经纬度网格上进行观察。目前,我在年度 pickle (pkl) 文件中有我的计算值(来自 obs。)以便于访问 - 每个文件包含一个大小为 8760 x 361 x 576 的 np 数组。

有没有一种方法可以通过逐年加载并丢弃一些以前的数据来迭代计算第 99 个百分位数,以保持所需的内存有限?我已经阅读了一些算法,但还没有找到适合我需要的东西。

如果我遍历每个纬度/经度对,我可以通过读入每年的数据并将其附加到数组,然后使用 np.percentile 来计算每个点的整个时间序列的第 99 个百分位数。然而,每个点需要大约 5 分钟,而对于大约 200k 点,这将花费太长时间。我正在寻找更快/更高效的东西。即使是可靠的近似也可以。

提前致谢!

python numpy sorting bigdata percentile
1个回答
0
投票

根据 Stef 的观察,我们只需要跟踪前 1%,但我使用 NumPy 数组和分区来做到这一点:

import numpy as np

# Simulated files (3x5 grid instead of 361x576)
files = [
  np.random.random((8760, 3, 5))
  for _ in range(43)
]

# Compute expectation with np.percentile
whole = np.vstack(files)
expect = np.percentile(whole, 99, 0, method='closest_observation')
print('expect:')
print(expect)

# Preparation for getting top 1% = top k
k = round(43 * 8760 / 100 + 1)
def top_k(a):
    return np.partition(a, -k, 0)[-k:]

# Compute the result
result = top_k(files[0])
for other in files[1:]:
    other = top_k(other)
    both = np.vstack((result, other))
    result = top_k(both)
result = result[0]

# Show result and difference
print('\nresult:')
print(result)
print('\ndifference:')
print(result - expect)

输出(在线尝试!):

expect:
[[0.99005919 0.9899604  0.98997587 0.99005714 0.9898474 ]
 [0.98995784 0.98983902 0.99030891 0.99011658 0.99002087]
 [0.98974323 0.98984458 0.98986231 0.99006893 0.99034963]]

result:
[[0.99005919 0.9899604  0.98997587 0.99005714 0.9898474 ]
 [0.98995784 0.98983902 0.99030891 0.99011658 0.99002087]
 [0.98974323 0.98984458 0.98986231 0.99006893 0.99034963]]

difference:
[[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]

使用模拟的 36x58 网格,“计算结果”部分在 ATO 站点上花费了不到 30 秒。所以对于你自己电脑上的真实数据,应该不到一个小时。

© www.soinside.com 2019 - 2024. All rights reserved.