数値配列の平均と標準偏差を頻繁に計算する必要があります。そこで、機能するように見える数値型の小さなプロトコルと拡張機能を作成しました。これを行った方法に問題がある場合は、フィードバックをお願いします。具体的には、 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)))
}}
}