Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 碾压混凝土的有效方法_Python_Numpy - Fatal编程技术网

Python 碾压混凝土的有效方法

Python 碾压混凝土的有效方法,python,numpy,Python,Numpy,我有一个1-D NumPy数组,我在其中创建一个滚动窗口,然后计算np.nanstd: import numpy as np def rolling_window(a, window): a = np.asarray(a) shape = a.shape[:-1] + (a.shape[-1] - window + 1, window) strides = a.strides + (a.strides[-1],) return np.lib.stride_tr

我有一个1-D NumPy数组,我在其中创建一个滚动窗口,然后计算
np.nanstd

import numpy as np

def rolling_window(a, window):
    a = np.asarray(a)
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)

    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

if __name__ == "__main__":
    n = 100_000_000
    nan_indices = np.random.choice(np.arange(n), size=1000, replace=False)
    T = np.random.rand(n)
    T[nan_indices] = np.nan
    m = 50
    np.nanstd(rolling_window(T, m), axis=T.ndim)
然而,我注意到这不仅非常耗时,而且占用了大量内存。有没有办法同时提高内存和速度性能(Numba是一个选项)?

NumPy矢量化 经过艰苦的数学计算后,以下是我最终得到的一些
np.convolve
和一些掩蔽,以得到一个矢量化的NumPy解-

def nanstd(a, W):
    k = np.ones(W, dtype=int)
    m = ~np.isnan(a)
    a0 = np.where(m, a,0)
    
    n = np.convolve(m,k,'valid')
    c1 = np.convolve(a0, k,'valid')
    f2 = c1**2
    p2 = f2/n**2
    f1 = np.convolve((a0**2)*m,k,'valid')+n*p2
    out = np.sqrt((f1 - (2/n)*f2)/n)
    return out
  • 完整的解释在这篇文章的末尾
熊猫当量 这是相当于熊猫的版本,性能还不错-

import pandas as pd

def pdroll(T,m):
    return pd.Series(T).rolling(m).std(ddof=0).values[m-1:]
标杆管理 使用包(打包在一起的一些基准测试工具;免责声明:我是它的作者)对建议的解决方案进行基准测试

def setup(n):
    nan_indices = np.random.choice(np.arange(n), size=10, replace=False)
    T = np.random.rand(n)
    T[nan_indices] = np.nan
    return T

import benchit
f = {'rolling': lambda T,m: np.nanstd(rolling_window(T, m), axis=T.ndim),
     'pdroll': pdroll, 'conv':nanstd}
in_={(n,w):(setup(n),w) for n in 10**np.arange(2,6) for w in [5,10,20,50,80,100]}
t = benchit.timings(f, in_, multivar=True)
t.plot(logx=True, sp_ncols=2, save='timings.png', dpi=200)

NumPy one适合较小的窗户尺寸,而熊猫则适合较大的窗户尺寸


NumPy矢量化:关于NumPy版本的说明
nanstd

基本上,
np.nanstd
正在计算
std
忽略
NaNs
。现在,
std
可以基于
mean
计算

因此,对于没有NAN的数组
a
,它将是:

np.sqrt(np.mean((a-np.mean(a))**2))   # (1)
In [48]: np.nanstd(a)
Out[48]: 1.5811388300841898
In [89]: np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - (2/n)*np.sum(a0*np.sum(a0))
Out[89]: 10.0

In [90]: c2 + n_comp*(c1/n_comp)**2 - (2/n_comp)*c1**2
Out[90]: array([10.        ,  4.66666667,  4.66666667, 10.        ,  8.75      ])
让我们证明一下:

In [43]: a = np.arange(1,6).astype(float)

In [44]: np.nanstd(a)
Out[44]: 1.4142135623730951

In [45]: np.sqrt(np.mean((a-np.mean(a))**2))
Out[45]: 1.4142135623730951
现在,假设我们有一个
NaN

In [46]: a[2] = np.nan

In [47]: a
Out[47]: array([ 1.,  2., nan,  4.,  5.])
带有
nanstd
std
将是:

np.sqrt(np.mean((a-np.mean(a))**2))   # (1)
In [48]: np.nanstd(a)
Out[48]: 1.5811388300841898
In [89]: np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - (2/n)*np.sum(a0*np.sum(a0))
Out[89]: 10.0

In [90]: c2 + n_comp*(c1/n_comp)**2 - (2/n_comp)*c1**2
Out[90]: array([10.        ,  4.66666667,  4.66666667, 10.        ,  8.75      ])
让我们根据
(1)
计算出等效值

让我们从
(a-np.mean(a))**2开始

这个:

In [72]: (a-np.mean(a))**2
Out[72]: array([nan, nan, nan, nan, nan])
In [73]: (a0 - np.sum(a0)/n)**2
Out[73]: array([4., 1., 9., 1., 4.])
In [75]: m*((a0 - np.sum(a0)/n)**2)
Out[75]: array([4., 1., 0., 1., 4.])

这个:

In [72]: (a-np.mean(a))**2
Out[72]: array([nan, nan, nan, nan, nan])
In [73]: (a0 - np.sum(a0)/n)**2
Out[73]: array([4., 1., 9., 1., 4.])
In [75]: m*((a0 - np.sum(a0)/n)**2)
Out[75]: array([4., 1., 0., 1., 4.])
不!因为
a
是:

In [76]: a
Out[76]: array([ 1.,  2., nan,  4.,  5.])
In [79]: (2/n)*np.sum(a0*np.sum(a0))
Out[79]: 72.0
我们需要使
NaN
位置一
0

这个:

In [72]: (a-np.mean(a))**2
Out[72]: array([nan, nan, nan, nan, nan])
In [73]: (a0 - np.sum(a0)/n)**2
Out[73]: array([4., 1., 9., 1., 4.])
In [75]: m*((a0 - np.sum(a0)/n)**2)
Out[75]: array([4., 1., 0., 1., 4.])
对!

那么,什么是
np.意思((a-np.意思(a))**2)
?它将是,
[75]
中的总和除以
n

In [77]: np.sum(m*((a0-np.sum(a0)/n)**2))/n
Out[77]: 2.5
因此,最终标准值:

In [78]: np.sqrt(np.sum(m*((a0-np.sum(a0)/n)**2))/n)
Out[78]: 1.5811388300841898
总结:

In [55]: m = ~np.isnan(a)       # (2)
    ...: a0 = np.where(m, a,0)
    ...: n = m.sum()
    ...: out0 = np.sqrt(np.sum(m*((a0-np.sum(a0)/n)**2))/n)

In [56]: out0
Out[56]: 1.5811388300841898
下一部分是结合滑动性质。因此,我们需要以滑动的方式执行
(2)
。因此,前两个步骤仍然存在

因此,它从以下内容开始:

m = ~np.isnan(a)
a0 = np.where(m, a,0)
但最后两个会改变,让我们看看如何

让我们关注计算
out0
的最后一步。我们有:

m*((a0-np.sum(a0)/n)**2)
然后,我们计算总和:

np.sum(m*((a0-np.sum(a0)/n)**2))
我们有:
(a-b)**2=a**2+b**2-2*a*b
。所以,前面的步骤变得更加简单

np.sum(m*(a0**2 + (np.sum(a0)/n)**2 - 2*a0*np.sum(a0)/n))
进一步重新安排导致:

np.sum(m*(a0**2 + (np.sum(a0)/n)**2) - np.sum(2*a0*np.sum(a0)/n))

np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - np.sum(2*a0*np.sum(a0)/n)

np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - 2*np.sum(a0*np.sum(a0))/n

np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - (2/n)*np.sum(a0*np.sum(a0)) # (3)
让我们集中在总结的前两部分

也让我们拿一个样本来让事情具体化。我们将设置两个数据集-一个用于完整阵列设置,另一个用于完整阵列的窗口版本

设置:

#=========================== 1. Complete setup
a = np.arange(1,10).astype(float)
a[[2,5]] = np.nan

W = 5
k = np.ones(W, dtype=int)
m_comp = ~np.isnan(a)
a0_comp = np.where(m_comp, a,0)

n_comp = np.convolve(m_comp,k,'valid')
c1 = np.convolve(a0_comp, k,'valid')
c2 = np.convolve((a0_comp**2)*m_comp,k,'valid')

#=========================== 2. Windowed setup
a1 = np.arange(1,6).astype(float)
a1[2] = np.nan
m = ~np.isnan(a1)
a0 = np.where(m, a1,0)
n = m.sum()
out0 = np.sqrt(np.sum(m*((a0-np.sum(a0)/n)**2))/n)
通过窗口设置,我们有:

In [51]: np.sum(m*(a0**2 + (np.sum(a0)/n)**2))
Out[51]: 82.0

In [52]: np.sum(m*(a0**2) + m*((np.sum(a0)/n)**2))
Out[52]: 82.0

In [53]: np.sum(m*(a0**2)) + np.sum(m*((np.sum(a0)/n)**2))
Out[53]: 82.0
第一个总结部分:

In [86]: np.sum(m*(a0**2))
Out[86]: 46.0

# complete setup version :
In [87]: c2
Out[87]: array([ 46.,  45.,  90., 154., 219.])
In [54]: np.sum(m*((np.sum(a0)/n)**2))
Out[54]: 36.0

# complete setup version :
In [55]: n_comp*(c1/n_comp)**2
Out[55]: 
array([ 36.        ,  40.33333333,  85.33333333, 144.        ,
       210.25      ])
第二部分总结:

In [86]: np.sum(m*(a0**2))
Out[86]: 46.0

# complete setup version :
In [87]: c2
Out[87]: array([ 46.,  45.,  90., 154., 219.])
In [54]: np.sum(m*((np.sum(a0)/n)**2))
Out[54]: 36.0

# complete setup version :
In [55]: n_comp*(c1/n_comp)**2
Out[55]: 
array([ 36.        ,  40.33333333,  85.33333333, 144.        ,
       210.25      ])
n
(3)
中剩下的一块拼图是:

In [76]: a
Out[76]: array([ 1.,  2., nan,  4.,  5.])
In [79]: (2/n)*np.sum(a0*np.sum(a0))
Out[79]: 72.0
让我们把重点放在它的实质上:

In [80]: np.sum(a0*np.sum(a0))
Out[80]: 144.0
在完整设置中,它将对应于:

In [81]: c1**2
Out[81]: array([144., 121., 256., 576., 841.])
因此,对于整个剩余部分:

In [82]: (2/n)*np.sum(a0*np.sum(a0))
Out[82]: 72.0

# complete setup version :
In [83]: (2/n_comp)*c1**2
Out[83]: 
array([ 72.        ,  80.66666667, 170.66666667, 288.        ,
       420.5       ])
因此,
(3)
及其完整版本对应物应为:

np.sqrt(np.mean((a-np.mean(a))**2))   # (1)
In [48]: np.nanstd(a)
Out[48]: 1.5811388300841898
In [89]: np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - (2/n)*np.sum(a0*np.sum(a0))
Out[89]: 10.0

In [90]: c2 + n_comp*(c1/n_comp)**2 - (2/n_comp)*c1**2
Out[90]: array([10.        ,  4.66666667,  4.66666667, 10.        ,  8.75      ])
要获得最终的std值,我们需要除以每个窗口的有效值计数,然后应用
sqrt

In [99]: np.sqrt((c2 + n_comp*(c1/n_comp)**2 - (2/n_comp)*c1**2)/n_comp)
Out[99]: array([1.58113883, 1.24721913, 1.24721913, 1.58113883, 1.47901995])
因此,通过一些清理,我们最终得到了最终的
nanstd
版本。

NumPy矢量化 经过艰苦的数学计算后,以下是我最终得到的一些
np.convolve
和一些掩蔽,以得到一个矢量化的NumPy解-

def nanstd(a, W):
    k = np.ones(W, dtype=int)
    m = ~np.isnan(a)
    a0 = np.where(m, a,0)
    
    n = np.convolve(m,k,'valid')
    c1 = np.convolve(a0, k,'valid')
    f2 = c1**2
    p2 = f2/n**2
    f1 = np.convolve((a0**2)*m,k,'valid')+n*p2
    out = np.sqrt((f1 - (2/n)*f2)/n)
    return out
  • 完整的解释在这篇文章的末尾
熊猫当量 这是相当于熊猫的版本,性能还不错-

import pandas as pd

def pdroll(T,m):
    return pd.Series(T).rolling(m).std(ddof=0).values[m-1:]
标杆管理 使用包(打包在一起的一些基准测试工具;免责声明:我是它的作者)对建议的解决方案进行基准测试

def setup(n):
    nan_indices = np.random.choice(np.arange(n), size=10, replace=False)
    T = np.random.rand(n)
    T[nan_indices] = np.nan
    return T

import benchit
f = {'rolling': lambda T,m: np.nanstd(rolling_window(T, m), axis=T.ndim),
     'pdroll': pdroll, 'conv':nanstd}
in_={(n,w):(setup(n),w) for n in 10**np.arange(2,6) for w in [5,10,20,50,80,100]}
t = benchit.timings(f, in_, multivar=True)
t.plot(logx=True, sp_ncols=2, save='timings.png', dpi=200)

NumPy one适合较小的窗户尺寸,而熊猫则适合较大的窗户尺寸


NumPy矢量化:关于NumPy版本的说明
nanstd

基本上,
np.nanstd
正在计算
std
忽略
NaNs
。现在,
std
可以基于
mean
计算

因此,对于没有NAN的数组
a
,它将是:

np.sqrt(np.mean((a-np.mean(a))**2))   # (1)
In [48]: np.nanstd(a)
Out[48]: 1.5811388300841898
In [89]: np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - (2/n)*np.sum(a0*np.sum(a0))
Out[89]: 10.0

In [90]: c2 + n_comp*(c1/n_comp)**2 - (2/n_comp)*c1**2
Out[90]: array([10.        ,  4.66666667,  4.66666667, 10.        ,  8.75      ])
让我们证明一下:

In [43]: a = np.arange(1,6).astype(float)

In [44]: np.nanstd(a)
Out[44]: 1.4142135623730951

In [45]: np.sqrt(np.mean((a-np.mean(a))**2))
Out[45]: 1.4142135623730951
现在,假设我们有一个
NaN

In [46]: a[2] = np.nan

In [47]: a
Out[47]: array([ 1.,  2., nan,  4.,  5.])
带有
nanstd
std
将是:

np.sqrt(np.mean((a-np.mean(a))**2))   # (1)
In [48]: np.nanstd(a)
Out[48]: 1.5811388300841898
In [89]: np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - (2/n)*np.sum(a0*np.sum(a0))
Out[89]: 10.0

In [90]: c2 + n_comp*(c1/n_comp)**2 - (2/n_comp)*c1**2
Out[90]: array([10.        ,  4.66666667,  4.66666667, 10.        ,  8.75      ])
让我们根据
(1)
计算出等效值

让我们从
(a-np.mean(a))**2开始

这个:

In [72]: (a-np.mean(a))**2
Out[72]: array([nan, nan, nan, nan, nan])
In [73]: (a0 - np.sum(a0)/n)**2
Out[73]: array([4., 1., 9., 1., 4.])
In [75]: m*((a0 - np.sum(a0)/n)**2)
Out[75]: array([4., 1., 0., 1., 4.])

这个:

In [72]: (a-np.mean(a))**2
Out[72]: array([nan, nan, nan, nan, nan])
In [73]: (a0 - np.sum(a0)/n)**2
Out[73]: array([4., 1., 9., 1., 4.])
In [75]: m*((a0 - np.sum(a0)/n)**2)
Out[75]: array([4., 1., 0., 1., 4.])
不!因为
a
是:

In [76]: a
Out[76]: array([ 1.,  2., nan,  4.,  5.])
In [79]: (2/n)*np.sum(a0*np.sum(a0))
Out[79]: 72.0
我们需要使
NaN
位置一
0

这个:

In [72]: (a-np.mean(a))**2
Out[72]: array([nan, nan, nan, nan, nan])
In [73]: (a0 - np.sum(a0)/n)**2
Out[73]: array([4., 1., 9., 1., 4.])
In [75]: m*((a0 - np.sum(a0)/n)**2)
Out[75]: array([4., 1., 0., 1., 4.])
对!

那么,什么是
np.意思((a-np.意思(a))**2)
?它将是,
[75]
中的总和除以
n

In [77]: np.sum(m*((a0-np.sum(a0)/n)**2))/n
Out[77]: 2.5
因此,最终标准值:

In [78]: np.sqrt(np.sum(m*((a0-np.sum(a0)/n)**2))/n)
Out[78]: 1.5811388300841898
总结:

In [55]: m = ~np.isnan(a)       # (2)
    ...: a0 = np.where(m, a,0)
    ...: n = m.sum()
    ...: out0 = np.sqrt(np.sum(m*((a0-np.sum(a0)/n)**2))/n)

In [56]: out0
Out[56]: 1.5811388300841898
下一部分是结合滑动性质。因此,我们需要以滑动的方式执行
(2)
。因此,前两个步骤仍然存在

因此,它从以下内容开始:

m = ~np.isnan(a)
a0 = np.where(m, a,0)
但最后两个会改变,让我们看看如何

让我们关注计算
out0
的最后一步。我们有:

m*((a0-np.sum(a0)/n)**2)
然后,我们计算总和:

np.sum(m*((a0-np.sum(a0)/n)**2))
我们有:
(a-b)**2=a**2+b**2-2*a*b
。所以,前面的步骤变得更加简单

np.sum(m*(a0**2 + (np.sum(a0)/n)**2 - 2*a0*np.sum(a0)/n))
进一步重新安排导致:

np.sum(m*(a0**2 + (np.sum(a0)/n)**2) - np.sum(2*a0*np.sum(a0)/n))

np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - np.sum(2*a0*np.sum(a0)/n)

np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - 2*np.sum(a0*np.sum(a0))/n

np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - (2/n)*np.sum(a0*np.sum(a0)) # (3)
让我们集中在总结的前两部分

也让我们拿一个样本来让事情具体化。我们将设置两个数据集-一个用于完整阵列设置,另一个用于完整阵列的窗口版本

设置:

#=========================== 1. Complete setup
a = np.arange(1,10).astype(float)
a[[2,5]] = np.nan

W = 5
k = np.ones(W, dtype=int)
m_comp = ~np.isnan(a)
a0_comp = np.where(m_comp, a,0)

n_comp = np.convolve(m_comp,k,'valid')
c1 = np.convolve(a0_comp, k,'valid')
c2 = np.convolve((a0_comp**2)*m_comp,k,'valid')

#=========================== 2. Windowed setup
a1 = np.arange(1,6).astype(float)
a1[2] = np.nan
m = ~np.isnan(a1)
a0 = np.where(m, a1,0)
n = m.sum()
out0 = np.sqrt(np.sum(m*((a0-np.sum(a0)/n)**2))/n)
通过窗口设置,我们有:

In [51]: np.sum(m*(a0**2 + (np.sum(a0)/n)**2))
Out[51]: 82.0

In [52]: np.sum(m*(a0**2) + m*((np.sum(a0)/n)**2))
Out[52]: 82.0

In [53]: np.sum(m*(a0**2)) + np.sum(m*((np.sum(a0)/n)**2))
Out[53]: 82.0
第一个总结部分:

In [86]: np.sum(m*(a0**2))
Out[86]: 46.0

# complete setup version :
In [87]: c2
Out[87]: array([ 46.,  45.,  90., 154., 219.])
In [54]: np.sum(m*((np.sum(a0)/n)**2))
Out[54]: 36.0

# complete setup version :
In [55]: n_comp*(c1/n_comp)**2
Out[55]: 
array([ 36.        ,  40.33333333,  85.33333333, 144.        ,
       210.25      ])
第二部分总结:

In [86]: np.sum(m*(a0**2))
Out[86]: 46.0

# complete setup version :
In [87]: c2
Out[87]: array([ 46.,  45.,  90., 154., 219.])
In [54]: np.sum(m*((np.sum(a0)/n)**2))
Out[54]: 36.0

# complete setup version :
In [55]: n_comp*(c1/n_comp)**2
Out[55]: 
array([ 36.        ,  40.33333333,  85.33333333, 144.        ,
       210.25      ])
n
(3)
中剩下的一块拼图是:

In [76]: a
Out[76]: array([ 1.,  2., nan,  4.,  5.])
In [79]: (2/n)*np.sum(a0*np.sum(a0))
Out[79]: 72.0
让我们把重点放在它的实质上:

In [80]: np.sum(a0*np.sum(a0))
Out[80]: 144.0
在完整设置中,它将对应于:

In [81]: c1**2
Out[81]: array([144., 121., 256., 576., 841.])
因此,对于整个剩余部分:

In [82]: (2/n)*np.sum(a0*np.sum(a0))
Out[82]: 72.0

# complete setup version :
In [83]: (2/n_comp)*c1**2
Out[83]: 
array([ 72.        ,  80.66666667, 170.66666667, 288.        ,
       420.5       ])
因此,
(3)
及其完整版本对应物应为:

np.sqrt(np.mean((a-np.mean(a))**2))   # (1)
In [48]: np.nanstd(a)
Out[48]: 1.5811388300841898
In [89]: np.sum(m*(a0**2 + (np.sum(a0)/n)**2)) - (2/n)*np.sum(a0*np.sum(a0))
Out[89]: 10.0

In [90]: c2 + n_comp*(c1/n_comp)**2 - (2/n_comp)*c1**2
Out[90]: array([10.        ,  4.66666667,  4.66666667, 10.        ,  8.75      ])
为了得到最终的std值,我们需要除以有效的std值的计数