沿Numpy阵列轴的质心的标准偏差

时间:2016-07-24 20:09:56

标签: python python-2.7 numpy standard-deviation weighted-average

我试图找到一种表现良好的方法来计算沿着Numpy阵列轴的质心/重心的标准偏差。

在公式中,这是(抱歉错位):

我能想到的最好的是:

def weighted_com(A, axis, weights):
    average = np.average(A, axis=axis, weights=weights)
    return average * weights.sum() / A.sum(axis=axis).astype(float)

def weighted_std(A, axis):
    weights = np.arange(A.shape[axis])
    w1com2 = weighted_com(A, axis, weights)**2
    w2com1 = weighted_com(A, axis, weights**2)
    return np.sqrt(w2com1 - w1com2)

weighted_com中,我需要纠正从权重之和到值之和的规范化(我猜这是一个丑陋的解决方法)。 weighted_std可能没问题。

为了避免XY问题,我仍然会问我真正想要的是什么(更好weighted_std)而不是我weighted_com的更好版本。

.astype(float)是一种安全措施,因为我将此应用于包含整数的直方图,这会导致整数除法因不在Python 3或from __future__ import division未激活时导致的问题。< / p>

1 个答案:

答案 0 :(得分:1)

您想要获取向量[1, 2, 3, ..., n]的均值,方差和标准偏差 - 其中n是沿感兴趣的轴的输入矩阵A的维度 - ,带权重由矩阵A本身给出。

具体而言,假设你想沿垂直轴(axis=0)考虑这些质心统计数据 - 这与你所写的公式相对应。对于固定列j,您可以执行

n = A.shape[0]
r = np.arange(1, n+1)
mu = np.average(r, weights=A[:,j])
var = np.average(r**2, weights=A[:,j]) - mu**2
std = np.sqrt(var)

为了将不同列的所有计算放在一起,你必须将一堆r(每列一个)的副本堆叠在一起以形成一个矩阵(我称之为{{1}在下面的代码中)。通过一些小心,您可以使Raxis=0都能正常工作。

axis=1

例如,

import numpy as np

def com_stats(A, axis=0):
    A = A.astype(float)    # if you are worried about int vs. float
    n = A.shape[axis]
    m = A.shape[(axis-1)%2]
    r = np.arange(1, n+1)
    R = np.vstack([r] * m)
    if axis == 0:
        R = R.T

    mu = np.average(R, axis=axis, weights=A)
    var = np.average(R**2, axis=axis, weights=A) - mu**2
    std = np.sqrt(var)
    return mu, var, std

编辑:

可以通过使用A = np.array([[1, 1, 0], [1, 2, 1], [1, 1, 1]]) print(A) # [[1 1 0] # [1 2 1] # [1 1 1]] print(com_stats(A)) # (array([ 2. , 2. , 2.5]), # centre-of-mass mean by column # array([ 0.66666667, 0.5 , 0.25 ]), # centre-of-mass variance by column # array([ 0.81649658, 0.70710678, 0.5 ])) # centre-of-mass std by column 来避免创建r的内存副本以构建R:交换行

numpy.lib.stride_tricks

以上

R = np.vstack([r] * m)

结果from numpy.lib.stride_tricks import as_strided R = as_strided(r, strides=(0, r.itemsize), shape=(m, n)) 是(strided)R,其基础数组与ndarray相同 - 绝对不会复制任何值。

r

输出:

from numpy.lib.stride_tricks import as_strided

FMT = '''\
Shape: {}
Strides: {}
Position in memory: {}
Size in memory (bytes): {}
'''

def find_base_nbytes(obj):
    if obj.base is not None:
        return find_base_nbytes(obj.base)
    return obj.nbytes

def stats(obj):
    return FMT.format(obj.shape,
                      obj.strides,
                      obj.__array_interface__['data'][0],
                      find_base_nbytes(obj))

n=10
m=1000
r = np.arange(1, n+1)
R = np.vstack([r] * m)
S = as_strided(r, strides=(0, r.itemsize), shape=(m, n))

print(stats(r))
print(stats(R))
print(stats(S))

感谢this SO answerthis one有关如何获取跨越Shape: (10,) Strides: (8,) Position in memory: 4299744576 Size in memory (bytes): 80 Shape: (1000, 10) Strides: (80, 8) Position in memory: 4304464384 Size in memory (bytes): 80000 Shape: (1000, 10) Strides: (0, 8) Position in memory: 4299744576 Size in memory (bytes): 80 的基础数组的内存地址和大小的解释。