作为更大函数的一部分,我正在编写一些代码来生成包含输入向量/矩阵“x”的每列的平均值的向量/矩阵(取决于输入)。这些值存储在与输入向量相同形状的向量/矩阵中。
我对它在1-D和矩阵阵列上工作的初步解决方案非常(!)凌乱:
# 'x' is of type array and can be a vector or matrix.
import scipy as sp
shp = sp.shape(x)
x_mean = sp.array(sp.zeros(sp.shape(x)))
try: # if input is a matrix
shp_range = range(shp[1])
for d in shp_range:
x_mean[:,d] = sp.mean(x[:,d])*sp.ones(sp.shape(z))
except IndexError: # error occurs if the input is a vector
z = sp.zeros((shp[0],))
x_mean = sp.mean(x)*sp.ones(sp.shape(z))
来自MATLAB背景,这就是它在MATLAB中的样子:
[R,C] = size(x);
for d = 1:C,
xmean(:,d) = zeros(R,1) + mean(x(:,d));
end
这适用于矢量和矩阵,没有错误。
我的问题是,如果没有(丑陋的)try / except块,如何使我的python代码能够处理vector和matrix格式的输入?
谢谢!
答案 0 :(得分:6)
平均计算本身不需要区分向量和矩阵 - 如果使用axis
参数,Numpy将沿向量(对于向量)或列(对于矩阵)执行计算。然后构造输出,你可以使用一个很好的老式列表理解,虽然对于巨大的矩阵可能有点慢:
import numpy as np
m = np.mean(x,axis=0) # For vector x, calculate the mean. For matrix x, calculate the means of the columns
x_mean = np.array([m for k in x]) # replace elements for vectors or rows for matrices
使用列表推导创建输出很慢,因为它必须分配两次内存 - 一次用于列表,一次用于数组。使用np.repeat
或np.tile
会更快,但对于矢量输入会很有趣 - 输出将是一个嵌套的矩阵,每行有一个长向量。如果速度比优雅更重要,你可以用以下代码替换最后一行:
if len(x.shape) == 1:
x_mean = m*np.ones(len(x))
else:
x_mean = np.tile(m, (x.shape[1],1))
顺便说一句,您的Matlab代码对行向量和列向量的行为有所不同(尝试使用x
和x'
运行它。)
答案 1 :(得分:3)
首先关于numpy广播的快速说明。当我从matlab切换到python时,广播对我来说有点混乱,但是一旦我花时间去理解它,我就意识到它有多么有用。要了解有关广播的更多信息,请查看http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html,
因为在numpy中广播一个(m,)数组(你所谓的向量)基本上等于(1,m)数组或(1,1,m)数组等等。看起来你想让(m,)数组表现得像(m,1)数组。我相信有时会发生这种情况,特别是在linalg模块中,但是如果你要这样做,你应该知道你正在打破这种笨拙的惯例。
有了这个警告,就有代码:
import scipy as sp
def my_mean(x):
if x.ndim == 1:
x = x[:, sp.newaxis]
m = sp.empty(x.shape)
m[:] = x.mean(0)
return sp.squeeze(m)
和一个例子:
In [6]: x = sp.arange(30).reshape(5,6)
In [7]: x
Out[7]:
array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29]])
In [8]: my_mean(x)
Out[8]:
array([[ 12., 13., 14., 15., 16., 17.],
[ 12., 13., 14., 15., 16., 17.],
[ 12., 13., 14., 15., 16., 17.],
[ 12., 13., 14., 15., 16., 17.],
[ 12., 13., 14., 15., 16., 17.]])
In [9]: my_mean(x[0])
Out[9]: array([ 2.5, 2.5, 2.5, 2.5, 2.5, 2.5])
这比使用tile
更快,时间如下:
In [1]: import scipy as sp
In [2]: x = sp.arange(30).reshape(5,6)
In [3]: m = x.mean(0)
In [5]: timeit m_2d = sp.empty(x.shape); m_2d[:] = m
100000 loops, best of 3: 2.58 us per loop
In [6]: timeit m_2d = sp.tile(m, (len(x), 1))
100000 loops, best of 3: 13.3 us per loop