2015-04-16 9 views
5

Moje pierwsze pytanie tutaj w Stackoverflow ... mam nadzieję, że moje pytanie jest wystarczająco szczegółowe.Regresja liniowa - przyspieszenie ram w Swift

Mam tablicę w Swift z pomiarami w określonych datach. Jak:

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) 

Kilka dni brakuje, po prostu nie wziąć pomiar ... Wszystkie pomiary powinny być na linii, bardziej lub mniej. Więc pomyślałem o regresji liniowej. Znalazłem framework Accelerate, ale brakuje dokumentacji i nie mogę znaleźć przykładów.

Dla brakujących pomiarów chciałbym mieć funkcję, jako dane wejściowe, brakujący dzień, a jako wynik najlepiej zgadnąć, na podstawie innych pomiarów.

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

Dzięki za pomoc. Jan

Odpowiedz

10

Moja odpowiedź nie mówi konkretnie o Accelerate Framework, jednak myślałem, że pytanie było interesujące i pomyślałem, że zrobię to z ukłuciem. Z tego, co odkrywam, zasadniczo dążysz do stworzenia linii najlepszego dopasowania i interpolacji lub ekstrapolacji więcej wartości mW z tego. Aby to zrobić, że użyłem metody najmniejszych kwadratów, szczegółowo tutaj: http://hotmath.com/hotmath_help/topics/line-of-best-fit.html i realizowane to na placach zabaw przy użyciu 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 

W powyższym kodzie a i b zapoznać się z poniższym wzorem ze strony:

a : enter image description here

b: enter image description here

Teraz można utworzyć funkcję, która wykorzystuje linię najlepszego dopasowania do interpolacji/ekstrapolacji mW:

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

i używać go tak:

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

Wielkie dzięki za twój kod (i twoje zmiany na moje pytanie), ABakerSmith! Jestem z tego bardzo zadowolony ... Btw, jak powiedziałem, jestem nowy w Stackoverflow ... czy powinienem głosować na inną odznakę dla ciebie? Byłbym szczęśliwy ... :-) – arakweker

+0

Niesamowite, cieszę się, że pomogło! Jeśli uważasz, że odpowiedź rozwiązała Twój problem, możesz oznaczyć go jako poprawny, naciskając znacznik wyboru po lewej stronie. Możesz również uzyskać odpowiedzi na pytania głosowe, ale uważam, że potrzebujesz 15 punktów za to. – ABakerSmith

+0

Witamy w Stack Overflow przy okazji! – ABakerSmith

3

Jeśli chcesz zrobić szybko regresji liniowej w Swift, Sugeruję użycie frameworków Upsurge. Zapewnia szereg prostych funkcji, które otaczają bibliotekę Accelerate, dzięki czemu można czerpać korzyści z SIMD na systemach iOS lub OSX bez obawy o złożoność wywołań vDSP.

Aby zrobić regresji liniowej z funkcji baza przypływ jest prosta:

 
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 

Jest to w zasadzie to, co jest realizowane w linregress funkcji.

Możesz go używać z tablicą [Double], innych klas, takich jak RealArray (pochodzi z Upsurge) lub własnych obiektów, jeśli mogą odsłonić przylegającą pamięć.

Więc skrypt do swoich potrzeb będzie wyglądać następująco:

 
#!/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 
} 

(zostawiłem w Dołącza zamiast używać literały jak jesteś prawdopodobnie programowo dodając do swojej tablicy, jeśli ma znaczną długość)

i pełne oświadczenie: Wpisałem kod linregress. Mam nadzieję, że dodam także współczynnik determinacji w pewnym momencie w przyszłości.