给出权重列表:
let weights = [0.1, 0.2, 0.4, 0.2, 0.1]
和一系列测量,我想实现加权平均值。
这就是我在Python中的表现:
y=[]
w = length(weights)
for n in range(w,len(x)-w):
y[n-w/2-1]=sum([a*b for a,b in zip(weights,x[n-w/2:n+w/2+1])])
#y[n-3]=W[1]*x[n-2]+W[2]*x[n-1]+W[3]*x[n]+W[4]*x[n+1]+W[5]*x[n+2]
我知道Haskell没有数组,我想要实现的是low-pass-filter,我可以在其中手动定义权重。
答案 0 :(得分:3)
可以使用mealy机器计算移动平均值,其中内部状态是先前的值。
我会在三个参数示例中显示移动平均线,您可以将自己弄到例如使它在大小上具有可辨识性。
Mealy机器本质上是一个初始状态," state + input"到"新州+输出"功能:
Mealy i o ~ (s, s -> i -> (o, s))
我们假设初始状态全为零,并为3以上的移动平均值编写函数。
type S = (Double, Double)
type I = Double
type O = Double
initialState :: S
initialState = (0, 0)
weight0, weight1, weight2 :: Double
weight0 = 0.25
weight1 = 0.5
weight2 = 0.25
ma :: S -> I -> (O, S)
ma (x0, x1) x2 = (o, s)
where
s = (x1, x2)
o = x0 * weight0 + x1 * weight1 + x2 * weight2
现在我们得到了所有的部分,让我们在输入上运行机器:
runMealy :: (S -> I -> (O, S)) -> S -> [I] -> [O]
runMealy _ _ [] = []
runMealy f s (x : xs) =
let (o, s') = f s x
in o : runMealy f s' xs
试一试:
λ *Main > runMealy ma initialState [1,2,3,4,5,6,7,8,9]
[0.25,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]
您可以删除第一个生成的值,因为机器内部状态为"预热"。
对于任意大小的移动平均机,你可以使用Data.Sequence
,因为当你推到一端时它会有更好的数据结构,而从另一端弹出,然后是单链表1} em>,[]
。
为什么我要谈论Mealy机器?因为在某些时候,您很可能遇到需要在Haskell中使用某些流式库的情况:pipes
,conduit
或machines
。那么Mealy机器方法将是唯一合理的解决方案。
你也可以制作自回归模型!
答案 1 :(得分:3)
压缩会自动处理对齐:
wma :: Num a => [a] -> [a] -> [a]
wma weights = map (sum . zipWith (*) weights ) -- weighted-moving-average
. foldr (zipWith (:)) (repeat [])
. take (length weights)
. tails
(see also)。
答案 2 :(得分:2)
tails
为您提供输入列表的尾部列表。所以tails [1,2,3] = [[1,2,3],[2,3],[3],[]]
。由于我们不需要最后一个空列表,因此我们使用(init.tails)
来获取尾部列表中除最后一个元素之外的所有内容。
import Data.List (tails)
averages :: Num a => [a] -> [a] -> [a]
averages weights xs = sum . zipWith (*) weights <$> (init.tails) xs
请注意,这很可能不会在列表的开头和结尾以您想要的方式运行。特别是因为它在开始时和结束时表现不同。第一个元素是第一个length weight
元素的平均值,但最后一个元素只是head weight * last xs
。
如果你想在开始时结束行为,你可以使用这样的东西:
import Data.List (tails)
averages :: Num a => [a] -> [a] -> [a]
averages weights xs = sum . zipWith (*) weights <$>
(init.tails) (replicate (length weights - 1) 0 ++ xs)
如果您想在开始时结束行为,可以使用:
import Data.List (tails)
averages :: Num a => [a] -> [a] -> [a]
averages weights xs = sum . zipWith (*) weights <$>
takeWhile (not . null . drop (l-1)) (tails xs)
where l = length weights
如果你想以第一个/最后一个元素与权重列表的中心元素相乘开始和结束,我们必须使用上述两个答案的组合:
import Data.List (tails)
averages :: Num a => [a] -> [a] -> [a]
averages weights xs = sum . zipWith (*) weights <$>
takeWhile (not . null . drop half) (replicate half 0 ++ xs)
where half = length weights `quot` 2