我想创建一个函数,如果给出一个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方法?
答案 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)