14

数値配列の平均と標準偏差を頻繁に計算する必要があります。そこで、機能するように見える数値型の小さなプロトコルと拡張機能を作成しました。これを行った方法に問題がある場合は、フィードバックをお願いします。具体的には、 asDouble 変数とコンストラクターの必要性を回避するために、型を Double としてキャストできるかどうかを確認するより良い方法があるかどうか疑問に思っています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))
    }}
}

[Int].mean編集:とを取得するのは無意味であることはわかっていsdますが、他の場所で数値を使用する可能性があるため、一貫性のために..

編集:@Severin Pappadeuxが指摘したように、分散は、配列のトリプルパスを回避する方法で表現できます-平均してからマップしてから平均します。これが最終的な標準偏差拡張です

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)))
    }}
}
4

6 に答える 6

4

Swift 3 では、FloatingPoint プロトコルとの重複を避けることができるかもしれません (またはできないかもしれません)。

于 2016-07-17T14:28:43.357 に答える
2

Swiftを知っているわけではありませんが、数値のPOVからすると、少し効率が悪いです

基本的に、配列に対して 2 つのパス (実際には 3 つ) を実行して 2 つの値を計算しますが、1 つのパスで十分なはずです。Vairance は E(X 2 ) - E(X) 2として表現される場合があるため、擬似コードでは次のようになります。

tuple<float,float> get_mean_sd(data) {
    float s  = 0.0f;
    float s2 = 0.0f;
    for(float v: data) {
        s  += v;
        s2 += v*v;
    }
    s  /= count;
    s2 /= count;

    s2 -= s*s;
    return tuple(s, sqrt(s2 > 0.0 ? s2 : 0.0));
}
于 2016-07-21T00:38:00.797 に答える