2015-04-16 6 views
5

La mia prima domanda qui su Stackoverflow ... spero che la mia domanda sia abbastanza specifica.Regressione lineare - Accelerare la struttura in Swift

Ho un array in Swift con misurazioni in determinate date. Come:

var myArray:[(day: Int, mW: Double)] = [] 
myArray.append(day:0, mW: 31.98) 
myArray.append(day:1, mW: 31.89) 
myArray.append(day:2, mW: 31.77) 
myArray.append(day:4, mW: 31.58) 
myArray.append(day:6, mW: 31.46) 

Alcuni giorni mancano, ho solo non ha preso una misura ... Tutte le misurazioni devono essere su una linea, più o meno. Quindi ho pensato alla regressione lineare. Ho trovato il framework Accelerate, ma manca la documentazione e non riesco a trovare esempi.

Per le misurazioni mancanti mi piacerebbe avere una funzione, con in input un giorno mancante e come risultato un'ipotesi migliore, basata sulle altre misurazioni.

func bG(day: Int) -> Double { 
    return // return best guess for measurement 
} 

Grazie per l'aiuto.

risposta

10

La mia risposta non parla in modo specifico di Accelerate Framework, tuttavia ho pensato che la domanda fosse interessante e ho pensato di dargli una pugnalata. Da quello che raccolgo, stai fondamentalmente cercando di creare una linea di best fit e interpolare o estrapolare più valori di mW da quello. Per fare questo ho usato il metodo dei minimi Piazza, dettagliato qui: http://hotmath.com/hotmath_help/topics/line-of-best-fit.html e implementato questo Parchi giochi utilizzando Swift:

// The typealias allows us to use '$X.day' and '$X.mW', 
// instead of '$X.0' and '$X.1' in the following closures. 
typealias PointTuple = (day: Double, mW: Double) 

// The days are the values on the x-axis. 
// mW is the value on the y-axis. 
let points: [PointTuple] = [(0.0, 31.98), 
          (1.0, 31.89), 
          (2.0, 31.77), 
          (4.0, 31.58), 
          (6.0, 31.46)] 

// When using reduce, $0 is the current total. 
let meanDays = points.reduce(0) { $0 + $1.day }/Double(points.count) 
let meanMW = points.reduce(0) { $0 + $1.mW }/Double(points.count) 

let a = points.reduce(0) { $0 + ($1.day - meanDays) * ($1.mW - meanMW) } 
let b = points.reduce(0) { $0 + pow($1.day - meanDays, 2) } 

// The equation of a straight line is: y = mx + c 
// Where m is the gradient and c is the y intercept. 
let m = a/b 
let c = meanMW - m * meanDays 

Nel codice precedente a e b fare riferimento alla seguente formula dal sito web:

a : enter image description here

b: enter image description here

Ora è possibile creare la funzione che utilizza la linea di best fit per interpolare/estrapolare mW:

func bG(day: Double) -> Double { 
    return m * day + c 
} 

e usarlo in questo modo:

bG(3) // 31.70 
bG(5) // 31.52 
bG(7) // 31.35 
+0

Grazie mille per il tuo codice (e le tue modifiche alla mia domanda), ABakerSmith! Sono molto contento ... Btw, come ho detto, sono nuovo di Stackoverflow ... dovrei votare un altro badge per te? Sarei felice di ... :-) – arakweker

+0

Fantastico, sono contento che sia stato d'aiuto! Se ritieni che una risposta risolva il tuo problema, puoi contrassegnarlo come corretto premendo il segno di spunta sulla sinistra. Puoi anche votare le risposte alle domande, ma credo che tu abbia bisogno di 15 punti per questo. – ABakerSmith

+0

Benvenuti nello Stack Overflow a proposito! – ABakerSmith

3

Se si vuole fare regressioni lineari veloci a Swift, Suggerisco di utilizzare il framework Upsurge. Fornisce una serie di semplici funzioni che racchiudono la libreria Accelerate e in questo modo ottieni i vantaggi di SIMD su iOS o OSX senza doversi preoccupare della complessità delle chiamate vDSP.

Per fare una regressione lineare con funzioni di base recrudescenza è semplicemente:

 
let meanx = mean(x) 
let meany = mean(y) 
let meanxy = mean(x * y) 
let meanx_sqr = measq(x) 

let slope = (meanx * meany - meanxy)/(meanx * meanx - meanx_sqr) 
let intercept = meany - slope * meanx 

Questo è essenzialmente ciò è implementato nella funzione linregress.

È possibile utilizzarlo con una matrice di [Double], altre classi come RealArray (fornito con Upsurge) o i propri oggetti se possono esporre memoria contigua.

Quindi, uno script per soddisfare le vostre esigenze sarà simile:

 
#!/usr/bin/env cato 

import Upsurge 

typealias PointTuple = (day: Double, mW:Double) 

var myArray:[PointTuple] = [] 

myArray.append((0, 31.98)) 
myArray.append((1, 31.89)) 
myArray.append((2, 31.77)) 
myArray.append((4, 31.58)) 
myArray.append((6, 31.46)) 

let x = myArray.map { $0.day } 
let y = myArray.map { $0.mW } 

let (slope, intercept) = Upsurge.linregress(x, y) 

func bG(day: Double) -> Double { 
    return slope * day + intercept 
} 

(ho lasciato in accodamento piuttosto che usare letterali, come è probabile che a livello di codice aggiunge al vostro array se è di notevole lunghezza)

e completa dichiarazione di non responsabilità: ho contribuito al codice di linea. Spero di aggiungere anche il co-efficiente della determinazione ad un certo punto in futuro.