作为一项帮助我学习Haskell的练习,我决定写一个小的“程序”来找出两个数字列表的Pearson相关系数。我对结果很不满意,因为我觉得打字很乱,而且很难读懂。
我希望有经验的人能帮助我改进我的代码,并告诉我他们会如何解决这个问题。
import Data.List
summation :: (Integral a, Fractional b) => a -> a -> (a -> b) -> b
summation i n e = if (i < n)
then (e i + summation (i+1) n e)
else (e i)
mean :: (Real a, Fractional b) => [a] -> b
mean x = (1 / (genericLength x)) *
(summation 1 (length x) (\i -> realToFrac (x !! (i-1))))
covariance :: (Real a, Fractional b) => [a] -> [a] -> b
covariance x y = (1 / (genericLength x)) *
(summation 1 (length x) (\i -> ((realToFrac (x !! (i-1)) - mean x) * (realToFrac (y !! (i-1)) - mean x))))
stddev :: (Real a, Floating b) => [a] -> b
stddev x = ((1 / (genericLength x)) *
(summation 1 (length x) (\i -> (realToFrac (x !! (i-1)) - mean x) ** 2))) ** (1/2)
pearson :: (Real a, Floating b) => [a] -> [a] -> b
pearson x y = covariance x y / (stddev x * stddev y)
发布于 2017-02-18 04:50:30
import Data.List
mean :: (Floating a) => [a] -> a
mean x = sum / genericLength x
where sum = foldl (+) 0 x
covariance :: (Floating a) => [a] -> [a] -> a
covariance x y = (mean xy) - (mean x) * (mean y)
where xy = zipWith (*) x y
pearson :: (Floating a) => [a] -> [a] -> a
pearson x y = (covariance x y) / (stddev x * stddev y)
where stddev z = (covariance z z)**0.5
它们是函数式编程的关键概念。
列表x
上的和可以写为foldl (+) 0 x
,产品将是foldl (*) 1 x
。这不仅限于基本的数学运算和数字。您可以为任何类型的元素提供任何函数。
以类似的方式,zipWith (*) x y
将两个列表连接到产品列表中。
您的函数mean
、covariance
和stddev
共享大量代码。永远不要复制粘贴代码。创建适当的模块化并重用它。在这里,可以将covariance
重新定义为只使用对mean
的调用,而stddev
只是自协方差(和平方根)。
https://codereview.stackexchange.com/questions/155662
复制相似问题