- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我目前正在使用 GDAL 的 Python 绑定(bind)来处理相当大的栅格数据集(> 4 GB)。由于一次将它们加载到内存中对我来说不是可行的解决方案,所以我将它们读入较小的 block 并逐个进行计算。为避免对每个 block 读取进行新分配,我使用 buf_obj
参数 ( here ) 将值读入预分配的 NumPy 数组。有一次我必须计算整个栅格的均值和标准差。当然,我使用 np.std
进行计算。然而,通过分析我的程序的内存消耗,我意识到每次调用 np.std
都会额外分配和释放内存。
演示此行为的最小工作示例:
In [1] import numpy as np
In [2] a = np.random.rand(20e6) # Approx. 150 MiB of memory
In [3] %memit np.mean(a)
peak memory: 187.30 MiB, increment: 0.48 MiB
In [4] %memit np.std(a)
peak memory: 340.24 MiB, increment: 152.91 MiB
在 GitHub 上的 NumPy 源代码树中搜索显示,np.std
函数在内部调用 _methods.py
中的 _var
函数(here)。在某一时刻,_var
计算与平均值的偏差并将它们相加。因此创建了输入数组的临时副本。该函数基本上按如下方式计算标准偏差:
mu = sum(arr) / len(arr)
tmp = arr - mu
tmp = tmp * tmp
sd = np.sum(tmp) / len(arr)
虽然这种方法适用于较小的输入数组,但绝对不能用于较大的输入数组。由于我使用的是如前所述的较小内存块,因此从我程序的内存角度来看,这个额外的副本并不是一个破坏游戏的问题。然而,让我感到困扰的是,对于每个 block ,都会在读取下一个 block 之前进行并释放新的分配。
NumPy 或 SciPy 中是否有一些其他函数利用像 Welford 算法 (Wikipedia) 这样的内存消耗恒定的方法一次性计算均值和标准差?
另一种方法是使用预分配缓冲区(如 NumPy ufuncs)的可选 out
参数实现自定义版本的 _var
函数。使用这种方法,不会消除额外的副本,但至少内存消耗会保持不变,并且每个 block 中的分配的运行时间得以节省。
编辑:按照 kezzos 的建议测试了 Welford 算法的 Cython 实现。
Cython 实现(从 kezzos 修改而来):
cimport cython
cimport numpy as np
from libc.math cimport sqrt
@cython.boundscheck(False)
def iterative_approach(np.ndarray[np.float32_t, ndim=1] a):
cdef long n = 0
cdef float mean = 0
cdef float M2 = 0
cdef long i
cdef float delta
cdef float a_min = 10000000 # Must be set to Inf and -Inf for real cases
cdef float a_max = -10000000
for i in range(len(a)):
n += 1
delta = a[i] - mean
mean += delta / n
M2 += delta * (a[i] - mean)
if a[i] < a_min:
a_min = a[i]
if a[i] > a_max:
a_max = a[i]
return a_min, a_max, mean, sqrt(M2 / (n - 1))
NumPy 实现(均值和标准差可以在一个函数中计算):
def vector_approach(a):
return np.min(a), np.max(a), np.mean(a), np.std(a, ddof=1)
使用随机数据集的测试结果(时间以毫秒为单位,25 次中最好):
----------------------------------
| Size | Iterative | Vector |
----------------------------------
| 1e2 | 0.00529 | 0.17149 |
| 1e3 | 0.02027 | 0.16856 |
| 1e4 | 0.17850 | 0.23069 |
| 1e5 | 1.93980 | 0.77727 |
| 1e6 | 18.78207 | 8.83245 |
| 1e7 | 180.04069 | 101.14722 |
| 1e8 | 1789.60228 | 1086.66737 |
----------------------------------
似乎使用 Cython 的迭代方法对于较小的数据集更快,而 NumPy 向量(可能是 SIMD 加速)方法对于具有 10000 多个元素的较大数据集。所有测试均使用 Python 2.7.9 和 NumPy 1.9.2 版进行。
请注意,在实际情况下,上层函数将用于计算单个栅格 block 的统计数据。所有 block 的标准偏差和均值将与维基百科 (here) 中建议的方法相结合。它的优点是不需要对栅格的所有元素求和,从而避免了 float 溢出问题(至少在某种程度上)。
最佳答案
我怀疑您会在 numpy
中找到任何此类函数。 numpy
存在的理由是它利用了 vector processor。指令集——执行大量数据的相同指令。基本上 numpy
以内存效率换取速度效率。然而,由于 Python 的内存密集型特性,numpy
也能够通过将数据类型与整个数组相关联而不是每个单独的元素来实现一定的内存效率。
提高速度但仍然牺牲一些内存开销的一种方法是计算 block 中的标准偏差,例如。
import numpy as np
def std(arr, blocksize=1000000):
"""Written for py3, change range to xrange for py2.
This implementation requires the entire array in memory, but it shows how you can
calculate the standard deviation in a piecemeal way.
"""
num_blocks, remainder = divmod(len(arr), blocksize)
mean = arr.mean()
tmp = np.empty(blocksize, dtype=float)
total_squares = 0
for start in range(0, blocksize*num_blocks, blocksize):
# get a view of the data we want -- views do not "own" the data they point to
# -- they have minimal memory overhead
view = arr[start:start+blocksize]
# # inplace operations prevent a new array from being created
np.subtract(view, mean, out=tmp)
tmp *= tmp
total_squares += tmp.sum()
if remainder:
# len(arr) % blocksize != 0 and need process last part of array
# create copy of view, with the smallest amount of new memory allocation possible
# -- one more array *view*
view = arr[-remainder:]
tmp = tmp[-remainder:]
np.subtract(view, mean, out=tmp)
tmp *= tmp
total_squares += tmp.sum()
var = total_squares / len(arr)
sd = var ** 0.5
return sd
a = np.arange(20e6)
assert np.isclose(np.std(a), std(a))
显示加速 --- blocksize
越大,加速越大。并且显着降低内存开销。较低的内存开销并非 100% 准确。
In [70]: %timeit np.std(a)
10 loops, best of 3: 105 ms per loop
In [71]: %timeit std(a, blocksize=4096)
10 loops, best of 3: 160 ms per loop
In [72]: %timeit std(a, blocksize=1000000)
10 loops, best of 3: 105 ms per loop
In [75]: %memit np.std(a)
peak memory: 512.70 MiB, increment: 152.59 MiB
In [73]: %memit std(a, blocksize=4096)
peak memory: 360.11 MiB, increment: 0.00 MiB
In [74]: %memit std(a, blocksize=1000000)
peak memory: 360.11 MiB, increment: 0.00 MiB
关于python - NumPy 函数标准差的内存消耗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41501891/
作为脚本的输出,我有 numpy masked array和标准numpy array .如何在运行脚本时轻松检查数组是否为掩码(具有 data 、 mask 属性)? 最佳答案 您可以通过 isin
我的问题 假设我有 a = np.array([ np.array([1,2]), np.array([3,4]), np.array([5,6]), np.array([7,8]), np.arra
numpy 是否有用于矩阵模幂运算的内置实现? (正如 user2357112 所指出的,我实际上是在寻找元素明智的模块化减少) 对常规数字进行模幂运算的一种方法是使用平方求幂 (https://en
我已经在 Numpy 中实现了这个梯度下降: def gradientDescent(X, y, theta, alpha, iterations): m = len(y) for i
我有一个使用 Numpy 在 CentOS7 上运行的项目。 问题是安装此依赖项需要花费大量时间。 因此,我尝试 yum install pip install 之前的 numpy 库它。 所以我跑:
处理我想要旋转的数据。请注意,我仅限于 numpy,无法使用 pandas。原始数据如下所示: data = [ [ 1, a, [, ] ], [ 1, b, [, ] ], [ 2,
numpy.random.seed(7) 在不同的机器学习和数据分析教程中,我看到这个种子集有不同的数字。选择特定的种子编号真的有区别吗?或者任何数字都可以吗?选择种子数的目标是相同实验的可重复性。
我需要读取存储在内存映射文件中的巨大 numpy 数组的部分内容,处理数据并对数组的另一部分重复。整个 numpy 数组占用大约 50 GB,我的机器有 8 GB RAM。 我最初使用 numpy.m
处理我想要旋转的数据。请注意,我仅限于 numpy,无法使用 pandas。原始数据如下所示: data = [ [ 1, a, [, ] ], [ 1, b, [, ] ], [ 2,
似乎 numpy.empty() 可以做的任何事情都可以使用 numpy.ndarray() 轻松完成,例如: >>> np.empty(shape=(2, 2), dtype=np.dtype('d
我在大型 numpy 数组中有许多不同的形式,我想使用 numpy 和 scipy 计算它们之间的边到边欧氏距离。 注意:我进行了搜索,这与堆栈中之前的其他问题不同,因为我想获得数组中标记 block
我有一个大小为 (2x3) 的 numpy 对象数组。我们称之为M1。在M1中有6个numpy数组。M1 给定行中的数组形状相同,但与 M1 任何其他行中的数组形状不同。 也就是说, M1 = [ [
如何使用爱因斯坦表示法编写以下点积? import numpy as np LHS = np.ones((5,20,2)) RHS = np.ones((20,2)) np.sum([ np.
假设我有 np.array of a = [0, 1, 1, 0, 0, 1] 和 b = [1, 1, 0, 0, 0, 1] 我想要一个新矩阵 c 使得如果 a[i] = 0 和 b[i] = 0
我有一个形状为 (32,5) 的 numpy 数组 batch。批处理的每个元素都包含一个 numpy 数组 batch_elem = [s,_,_,_,_] 其中 s = [img,val1,val
尝试为基于文本的多标签分类问题训练单层神经网络。 model= Sequential() model.add(Dense(20, input_dim=400, kernel_initializer='
首先是一个简单的例子 import numpy as np a = np.ones((2,2)) b = 2*np.ones((2,2)) c = 3*np.ones((2,2)) d = 4*np.
我正在尝试平均二维 numpy 数组。所以,我使用了 numpy.mean 但结果是空数组。 import numpy as np ws1 = np.array(ws1) ws1_I8 = np.ar
import numpy as np x = np.array([[1,2 ,3], [9,8,7]]) y = np.array([[2,1 ,0], [1,0,2]]) x[y] 预期输出: ar
我有两个数组 A (4000,4000),其中只有对角线填充了数据,而 B (4000,5) 填充了数据。有没有比 numpy.dot(a,b) 函数更快的方法来乘(点)这些数组? 到目前为止,我发现
我是一名优秀的程序员,十分优秀!