Написание функций для работы с векторами и матрицами - PullRequest
3 голосов
/ 17 декабря 2011

Как часть большой функции, я пишу некоторый код для генерации вектора / матрицы (в зависимости от входных данных), содержащих среднее значение каждого столбца входного вектора / матрицы 'x'.Эти значения хранятся в векторе / матрице той же формы, что и входной вектор.

Мое предварительное решение для работы с одномерными и матричными массивами очень (!) Грязное:

# '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

Это работает как на векторах, так и на матрицах без ошибок.

MyВопрос в том, как заставить мой код Python работать при вводе как векторного, так и матричного формата без (уродливого) блока try / Кроме?

Спасибо!

Ответы [ 2 ]

6 голосов
/ 17 декабря 2011

Вам не нужно различать векторы и матрицы для самого вычисления среднего - если вы используете параметр 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 было бы быстрее, но это забавно для векторных входных данных - на выходе будет вложенная матрица с вектором длиной 1 в каждой строке. Если скорость важнее элегантности, вы можете заменить последнюю строку следующим образом:

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').

3 голосов
/ 17 декабря 2011

Первый Небольшая заметка о вещании в NumPy.Когда я переключился с matlab на python, вещание меня немного смутило, но как только я нашел время, чтобы понять это, я понял, насколько это полезно.Чтобы узнать больше о вещании, взгляните на http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html,

Поскольку вещание массива (m,) в numpy (то, что вы называете вектором) по существу эквивалентно массиву (1, m) или(1, 1, м) массив и так далее.Кажется, вы хотите, чтобы массив (m,) вел себя как массив (m, 1).Я полагаю, что это иногда случается, особенно в модуле linalg, но если вы собираетесь это сделать, вы должны знать, что вы нарушаете соглашение о numpy.

С этим предупреждением есть код:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...