Pythonic方式返回正确维度的数组

时间:2012-01-06 17:54:47

标签: python numpy

我想创建一个函数,如果给出一个numpy数组,则返回一个numpy数组,如果给出,则返回一个多维numpy数组。例如:

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的新手,什么是prefferred方法?

3 个答案:

答案 0 :(得分:4)

如下:

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

这将取最后一个轴上的平均值,如果你想变得非常聪明,你可以让函数取一个轴参数并取任意轴上的平均值。

更新

我相信这个版本与上面的代码一致。

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(数据,轴)移动到开头,然后使用A [i]在第一维上操作,并在需要时将轴移回。

更新2:

我只记得为什么以下是一个非常糟糕的主意(至少在这种情况下):

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

你应该改用:

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

答案 1 :(得分:1)

首先,你是在过度思考形状的东西。无论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

答案 2 :(得分:1)

我喜欢Peter的回答,但这里有一个替代方案,对代码的更改较少。只测试列数 - 如果你没有列,则认为它是'1'。

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)