【问题标题】:Fast, elegant way to calculate empirical/sample covariogram计算经验/样本协方差图的快速、优雅的方法
【发布时间】:2014-05-29 21:28:03
【问题描述】:

如果可能的话,有没有人知道在 Python 中计算经验/样本协变函数的好方法?

这是book 的屏幕截图,其中包含协方差图的良好定义:

如果我理解正确,对于给定的滞后/宽度 h,我应该得到由 h(或小于 h)分隔的所有点对,乘以它的值,并且对于这些点中的每一个,计算其平均值,在这种情况下,定义为 m(x_i)。但是,根据 m(x_{i}) 的定义,如果我想计算 m(x1),我需要获得距离 x1 距离 h 内的值的平均值。这看起来像一个非常密集的计算。

首先,我理解正确吗?如果是这样,假设二维空间计算这个的好方法是什么?我尝试在 Python 中编写代码(使用 numpy 和 pandas),但这需要几秒钟,我什至不确定它是否正确,这就是为什么我不会在此处发布代码的原因。这是另一个非常天真的实现的尝试:

from scipy.spatial.distance import pdist, squareform
distances = squareform(pdist(np.array(coordinates))) # coordinates is a nx2 array
z = np.array(z) # z are the values
cutoff = np.max(distances)/3.0 # somewhat arbitrary cutoff
width = cutoff/15.0
widths = np.arange(0, cutoff + width, width)
Z = []
Cov = []

for w in np.arange(len(widths)-1): # for each width
    # for each pairwise distance
    for i in np.arange(distances.shape[0]): 
        for j in np.arange(distances.shape[1]): 
            if distances[i, j] <= widths[w+1] and distances[i, j] > widths[w]:
                m1 = []
                m2 = []
                # when a distance is within a given width, calculate the means of
                # the points involved
                for x in np.arange(distances.shape[1]):
                    if distances[i,x] <= widths[w+1] and distances[i, x] > widths[w]:
                        m1.append(z[x])

                for y in np.arange(distances.shape[1]):
                    if distances[j,y] <= widths[w+1] and distances[j, y] > widths[w]:
                        m2.append(z[y])

                mean_m1 = np.array(m1).mean() 
                mean_m2 = np.array(m2).mean()
                Z.append(z[i]*z[j] - mean_m1*mean_m2)
    Z_mean = np.array(Z).mean() # calculate covariogram for width w
    Cov.append(Z_mean) # collect covariances for all widths

但是,现在我已经确认我的代码中存在错误。我知道,因为我使用了变异函数来计算协变异函数(covariogram(h) = covariogram(0) - variogram(h)),我得到了一个不同的图:

它应该是这样的:

最后,如果您知道用于计算经验协变函数的 Python/R/MATLAB 库,请告诉我。至少,这样我可以验证我做了什么。

【问题讨论】:

  • 如所写,m 的等式没有意义。如果您对i 求和,那么在总和之外(即在m(x_i) 中)按i 进行索引并不意味着任何事情;也就是说,右侧没有i
  • 对。我也觉得这很混乱。如果您阅读了我最后添加的参考资料(这是books.google.com/… 的确切页面),那么总和似乎是位于距离 h 内的点上,而不是在同一个 i 上。也就是说,第一个等式中的 N(h) 与第二个等式中的 N(h) 不同。正如我所说,这本书的符号比维基百科更好。
  • 我认为这并不像您想象的那么难,但是如果没有正确的方程式,就很难知道。我也不完全想读一本书的章节来找出正确的方程式。我会等一下,但最终我会投票关闭,因为不清楚。不过,基本上,您只想对成对度量求和,这在 numpy.xml 中可能很容易做到。但首先你需要知道你需要做什么。
  • 好吧,我可以尝试改变方程式。顺便说一句,如果您单击我之前评论中的链接,它会导致等式。让我知道如何改进问题,而不是投票结束。
  • 另外,你有多少分?即,计算所有点间距离是否有意义?

标签: python numpy covariogram


【解决方案1】:

可以使用scipy.cov,但如果直接进行计算(这很容易),还有更多方法可以加快计算速度。

首先,制作一些具有一定空间相关性的假数据。我将首先进行空间相关性,然后使用由此生成的随机数据点,其中数据根据底层地图定位,并采用底层地图的值。

编辑 1:
我更改了数据点生成器,因此位置完全是随机的,但 z 值与空间图成正比。而且,我更改了地图,使左侧和右侧相对于彼此移动,从而在很大程度上产生负相关h

from numpy import *
import random
import matplotlib.pyplot as plt

S = 1000
N = 900
# first, make some fake data, with correlations on two spatial scales
#     density map
x = linspace(0, 2*pi, S)
sx = sin(3*x)*sin(10*x)
density = .8* abs(outer(sx, sx))
density[:,:S//2] += .2
#     make a point cloud motivated by this density
random.seed(10)  # so this can be repeated
points = []
while len(points)<N:
    v, ix, iy = random.random(), random.randint(0,S-1), random.randint(0,S-1)
    if True: #v<density[ix,iy]:
        points.append([ix, iy, density[ix,iy]])
locations = array(points).transpose()
print locations.shape
plt.imshow(density, alpha=.3, origin='lower')
plt.plot(locations[1,:], locations[0,:], '.k')
plt.xlim((0,S))
plt.ylim((0,S))
plt.show()
#     build these into the main data: all pairs into distances and z0 z1 values
L = locations
m = array([[math.sqrt((L[0,i]-L[0,j])**2+(L[1,i]-L[1,j])**2), L[2,i], L[2,j]] 
                         for i in range(N) for j in range(N) if i>j])

这给出了:

以上只是模拟数据,我没有尝试优化它的生产等。我假设这是 OP 开始的地方,下面的任务,因为数据已经存在于真实情况中。


现在计算“协变函数”(顺便说一句,这比生成假数据要容易得多)。这里的想法是按h 对所有对和相关值进行排序,然后使用ihvals 对它们进行索引。也就是说,索引ihval 的总和是等式中N(h) 的总和,因为这包括所有hs 低于所需值的对。

编辑 2:
正如下面的 cmets 所建议的,N(h) 现在只是 h-dhh 之间的对,而不是 0h 之间的所有对(其中 dhh 的间距-ihvals 中的值——即,下面使用了 S/1000。

# now do the real calculations for the covariogram
#    sort by h and give clear names
i = argsort(m[:,0])  # h sorting
h = m[i,0]
zh = m[i,1]
zsh = m[i,2]
zz = zh*zsh

hvals = linspace(0,S,1000)  # the values of h to use (S should be in the units of distance, here I just used ints)
ihvals = searchsorted(h, hvals)
result = []
for i, ihval in enumerate(ihvals[1:]):
    start, stop = ihvals[i-1], ihval
    N = stop-start
    if N>0:
        mnh = sum(zh[start:stop])/N
        mph = sum(zsh[start:stop])/N
        szz = sum(zz[start:stop])/N
        C = szz-mnh*mph
        result.append([h[ihval], C])
result = array(result)
plt.plot(result[:,0], result[:,1])
plt.grid()
plt.show()

这在我看来是合理的,因为在 h 值的预期值处可以看到颠簸或低谷,但我没有仔细检查。

scipy.cov 的主要加速是可以预先计算所有产品zz。否则,对于每个新的h,都会将zhzsh 输入cov,并且所有产品都将重新计算。这个计算可以通过部分求和来加快速度,即在每个时间步从ihvals[n-1]ihvals[n] n,但我怀疑这是必要的。

【讨论】:

  • 谢谢!我稍后会看看这个。
  • +1。谢谢您的回答。您似乎将 m_+h 和 m_-h 解释为距离 h 以下的平均值。也许你是对的,但我将其解释为距离 h 内的平均值,对于 Cov(h) 定义中的总和内的每个值。显然,我的解释需要更深入的计算。你知道一些可以证实你的解释的参考资料吗?
  • 另一个问题是 N(h) 的定义。我认为正确的定义是距离 h 内的一组对,但不包括以前的距离。否则,随着我们增加滞后,协变函数几乎总是为零,因为 N(h) 在该点几乎包含每一对点。此外,我见过的几个实现包括一个阈值,以便捕获 h-e 和 h+e 之间的点,其中 e 是一个容差值。
  • @Robert:我认为你对 N(h) 的看法是正确的,使用定义,它不是累积的,所以总和应该超过 zh[ihval-1:ihval],其中你的“公差值”是这个 h 的跨度。 (而且这个问题不是也回答了 m 和“密集计算”的差异,还是你认为有什么不同?)我会在有机会时尝试改变我的答案。
  • 当然,没问题。至于 m 的差异,我认为它仍然可以像您一样解释为由距离 h 分隔的一对值的平均值(给定公差值)或作为 Cov(h) 总和中考虑的每个值的平均值.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-14
  • 1970-01-01
相关资源
最近更新 更多