Swift Array扩展用于标准偏差

twi*_*iz_ 8 arrays numeric mean deviation swift

我经常需要计算数值数组的均值和标准差.所以我为一些似乎有用的数字类型编写了一个小协议和扩展.如果我这样做有什么不妥,我只想反馈.具体来说,我想知道是否有更好的方法来检查类型是否可以转换为Double,以避免需要asDouble变量和init(_:Double)构造函数.

我知道允许算术的协议存在问题,但这似乎工作正常,使我无法将标准偏差函数放入需要它的类中.

protocol Numeric {
    var asDouble: Double { get }
    init(_: Double)
}

extension Int: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Float: Numeric {var asDouble: Double { get {return Double(self)}}}
extension Double: Numeric {var asDouble: Double { get {return Double(self)}}}
extension CGFloat: Numeric {var asDouble: Double { get {return Double(self)}}}

extension Array where Element: Numeric {

    var mean : Element { get { return Element(self.reduce(0, combine: {$0.asDouble + $1.asDouble}) / Double(self.count))}}

    var sd : Element { get {
        let mu = self.reduce(0, combine: {$0.asDouble + $1.asDouble}) / Double(self.count)
        let variances = self.map{pow(($0.asDouble - mu), 2)}
        return Element(sqrt(variances.mean))
    }}
}
Run Code Online (Sandbox Code Playgroud)

编辑:我知道这是一种毫无意义的获得[Int].meansd,但因此它的一致性我可能会使用数字别处..

编辑:正如@Severin Pappadeux指出的那样,方差可以用避免数组上的三次传递的方式表示 - 然后是map然后表示.这是最终的标准偏差扩展

extension Array where Element: Numeric {

    var sd : Element { get {
        let sss = self.reduce((0.0, 0.0)){ return ($0.0 + $1.asDouble, $0.1 + ($1.asDouble * $1.asDouble))}
        let n = Double(self.count)
        return Element(sqrt(sss.1/n - (sss.0/n * sss.0/n)))
    }}
}
Run Code Online (Sandbox Code Playgroud)

小智 14

带有 FloatingPoint 元素的 Swift 4 数组扩展:

extension Array where Element: FloatingPoint {

    func sum() -> Element {
        return self.reduce(0, +)
    }

    func avg() -> Element {
        return self.sum() / Element(self.count)
    }

    func std() -> Element {
        let mean = self.avg()
        let v = self.reduce(0, { $0 + ($1-mean)*($1-mean) })
        return sqrt(v / (Element(self.count) - 1))
    }

}
Run Code Online (Sandbox Code Playgroud)


Jor*_*ith 8

实际上已经有一个提供此功能的类 - 称为NSExpression. 您可以通过使用它来减少代码大小和复杂性。这个类有很多东西,但是你想要的一个简单的实现如下。

let expression = NSExpression(forFunction: "stddev:", arguments: [NSExpression(forConstantValue: [1,2,3,4,5])])
let standardDeviation = expression.expressionValueWithObject(nil, context: nil)
Run Code Online (Sandbox Code Playgroud)

您也可以计算均值,等等。信息在这里:http : //nshipster.com/nsexpression/

  • 如果您打算移植到 Linux,请小心 - NSExpression 并未在那里实现。 (2认同)

mat*_*att 5

在 Swift 3 中,您可能(或可能不能)能够使用浮点协议节省一些重复,但除此之外,您所做的事情是完全正确的。