Pythonic способ вернуть массив правильного измерения - PullRequest
2 голосов
/ 06 января 2012

Я хотел бы создать функцию, которая возвращает пустой массив, если он указан, или многомерный массивный массив, если он указан.Например:

import numpy as np;
def running_average(data,windowSize):
    dShape = np.shape(data);
    if(len(dShape)==1):
        raOut = np.zeros(len(data));
        rSum = 0.0;
        for row,value in enumerate(data):
            if row<windowSize:
                rSum+=float(value);
            else:
                rSum=rSum-data[row-windowSize]+value;
            raOut[row]=rSum/windowSize;
    else:
        raOut = np.zeros(dShape);
        for col in xrange(dShape[1]):
            rSum=0.0;
            for row,value in enumerate(data[:,col]):
                if row<windowSize:
                    rSum+=float(value);
                else:
                    rSum=rSum-data[row-windowSize,col]+value;
                raOut[row,col]=rSum/windowSize;

    return raOut;

Но должен быть хороший тест, чтобы мне не пришлось по сути повторяться в выражениях if и else.

Я новичок в pythonчто такое преференциальный метод?

Ответы [ 3 ]

4 голосов
/ 06 января 2012

Как насчет чего-то вроде:

def running_avg(data, ws):
    tmp = np.cumsum(data, axis=-1, dtype='float')
    ra = (tmp[..., ws:] - tmp[..., :-ws]) / ws
    return ra

Это будет принимать среднее значение по последней оси, если вы хотите стать действительно умным, вы можете сделать так, чтобы функция принимала аргумент оси и принимала среднее значение по произвольномуaxis.

UPDATE

Я считаю, что эта версия соответствует приведенному выше коду.

def running_avg(data, ws):
    ra = np.cumsum(data, axis=-1, dtype='float') / ws
    ra[..., ws:] = ra[..., ws:] - ra[..., :-ws]
    return ra

Для более общего вопроса используйте встроенные функции numpys, такие как cumsum помогаетпотому что они уже это делают, но если вам нужно сделать цикл, вы можете использовать A = np.zeros (A.shape), чтобы получить массив той же формы, что и вход, а затем использовать A [..., i], чтобы всегда работатьв последнем измерении или A [..., i,:] всегда работать со второго по последнее измерение и так далее.Также иногда люди делают data = np.roll (data, axis), чтобы переместить ось в начало, а затем вы используете A [i] для работы с первым измерением и переместите ось назад, если вам нужно.

UPDATE2:

Я только что вспомнил, почему следующее очень плохая идея (по крайней мере, в этом случае):

ra[..., ws:] -= ra[..., :-ws]

Вы должны использовать это вместо:

ra[..., ws:] = ra[..., ws:] - ra[..., :-ws]
1 голос
/ 06 января 2012

Мне нравится ответ Питера, но есть альтернатива с меньшим количеством изменений в вашем коде.Просто проверьте количество столбцов - считайте «один», если у вас его нет.

import numpy as np
def running_average(data,windowSize):
    dShape = np.shape(data)

    try:
        dShape[1]
    except:
        data = [data]
        dShape = np.shape(data)

    raOut = np.zeros(dShape)
    for col in dShape[1]:
        rSum=0.0
        for row,value in enumerate(data[:][col]):
            if row<windowSize:
                rSum+=float(value)
            else:
                rSum=rSum-data[row-windowSize][col]+value
            raOut[row][col]=rSum/windowSize

    return np.squeeze(raOut)
1 голос
/ 06 января 2012

Прежде всего, вы переосмысливаете форму. np.zeros(dShape) будет делать то, что вы хотите, является ли data одномерным или двумерным массивом. (В случае одномерного массива dShape будет одноэлементным кортежем, и zeros знает, что с этим делать.)

Во-вторых, прекратите ставить точки с запятой в конце строк и скобок в своих операторах if. Это Python, они вам не нужны.

Что касается повторения кода, я бы взял все в цикле for row, value in ... и абстрагировал его в итератор.

Итак:

import numpy as np

def average_iterator(data, windowSize):
  rSum = 0.0
  for row, value in enumerate(data):
    if row < windowSize:
      rSum += float(value)
    else:
      rSum = rSum - data[row-windowSize] + value
    yield row, rSum / windowSize

def running_average(data, windowSize):
  dShape = np.shape(data)
  raOut = np.zeros(dShape)
  if len(dShape) == 1:
    for row, avg in average_iterator(data, windowSize):
      raOut[row] = avg
  else:
    for col in xrange(dShape[1]):
      for row, avg in average_iterator(data[:,col], windowSize):
        raOut[row, col] = avg
  return raOut

Вы также можете сделать average_iterator локальным определением внутри running_average, в этом случае вам не нужно будет передавать windowSize.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...