2012-01-18 16 views
6

że potrzebują pomocy w następujący: Mam plik danych (kolumny oddzielone przez „\ t” tabelarycznej), tak jak to data.datEkstrapolacja - awk podstawie

# y1 y2  y3  y4 
    17.1685 21.6875 20.2393 26.3158 

Są x wartości z 4 punktów na liniowych dopasowanie. Cztery wartości y są stałe: 0, 200, 400, 600.

Mogę utworzyć dopasowanie liniowe par punktów (x,y): (x1,y1)=(17.1685,0), (x2,y2)=(21.6875,200), (x3,y3)=(20.2393,400), (x4,y4)=(26.3158,600).

Teraz chciałbym zrobić liniowy pasowanie na trzy z tych punktów Paryża (x1,y1), (x2,y2), (x3,y3) and (x2,y2), (x3,y3), (x4,y4) and (x1,y1), (x3,y3), (x4,y4) and (x1,y1), (x2,y2), (x4,y4).

Jeśli mam te trzy punkty z liniowego dopasowania Chciałbym poznać wartość wartości X ekstrapolować punkt znajdujący się poza tymi trzema dopasowanymi punktami.

mam tak daleko ten kod awk:

#!/usr/bin/awk -f 

BEGIN{ 
    z[1] = 0; 
    z[2] = 200; 
    z[3] = 400; 
    z[4] = 600; 
} 

{ 
    split($0,str,"\t"); 
    n = 0.0; 

    for(i=1; i<=NF; i++) 
    { 
    centr[i] = str[i]; 
    n += 1.0; 
    # printf("%d\t%f\t%.1f\t",i,centr[i],z[i]); 
    } 
    # print ""; 

    if (n > 2) 
    { 
    lsq(n,z,centr); 
    } 
} 

function lsq(n,x,y) 
{ 
    sx = 0.0 
    sy = 0.0 
    sxx = 0.0 
    syy = 0.0 
    sxy = 0.0 
    eps = 0.0 

    for (i=1;i<=n;i++) 
    { 
    sx += x[i] 
    sy += y[i] 
    sxx += x[i]*x[i] 
    sxy += x[i]*y[i] 
    syy += y[i]*y[i] 
    } 

    if ((n==0) || ((n*sxx-sx*sx)==0)) 
    { 
    next; 
    } 
# print "number of data points = " n; 
    a = (sxx*sy-sxy*sx)/(n*sxx-sx*sx) 
    b = (n*sxy-sx*sy)/(n*sxx-sx*sx) 

    for(i=1;i<=n;i++) 
    { 
    ycalc[i] = a+b*x[i] 
    dy[i] = y[i]-ycalc[i] 
    eps  += dy[i]*dy[i] 
    } 

    print "# Intercept =\t"a" 
    print "# Slope  =\t"b" 

    for (i=1;i<=n;i++) 
    { 
    printf("%8g %8g %8g \n",x[i],y[i],ycalc[i]) 
    } 

} # function lsq() 

Więc

If we extrapolate to the place of 4th 
    0 17.1685 <--(x1,y1) 
    200 21.6875 <--(x2,y2) 
    400 20.2393 <--(x3,y3) 
    600 22.7692 <<< (x4 = 600,y1 = 22.7692) 

    If we extrapolate to the place of 3th 
    0 17.1685 <--(x1,y1) 
    200 21.6875 <--(x2,y2) 
    400 23.6867 <<< (x3 = 400,y3 = 23.6867) 
    600 26.3158 <--(x4,y4) 

    0 17.1685 
    200 19.35266 <<< 
    400 20.2393 
    600 26.3158 

    0 18.1192 <<< 
    200 21.6875 
    400 20.2393 
    600 26.3158 

Moja prąd wyjściowy jest następujący:

$> ./prog.awk data.dat 
# Intercept = 17.4537 
# Slope  = 0.0129968 
     0 17.1685 17.4537 
    200 21.6875 20.0531 
    400 20.2393 22.6525 
    600 26.3158 25.2518 
+2

Czy wartości stałej "y" nie były stałe? Jak się zamienili? –

Odpowiedz

4

Zakładając obliczenia podstawowego w funkcji lsq jest OK (wygląda na prawidłowy, ale go nie analizowałem), to daje ci nachylenie i ntercept dla najmniej sumy linii kwadratów najlepszego dopasowania dla zestawu danych wejściowych (parametry x, y, n). Nie jestem pewien, czy rozumiem końcowy koniec funkcji.

Aby "wziąć trzy punkty i obliczyć czwarty" problem, najprostszym sposobem jest wygenerowanie 4 podzbiorów (logicznie, poprzez usunięcie jednego punktu ze zbioru czterech na każdym z czterech wywołań) i ponowienie obliczeń.

Musisz wywołać inną funkcję, która pobiera dane linii (nachylenie, przecięcie) z lsq i interpoluje (ekstrapoluje) wartość przy innej wartości y. To prosta kalkulacja (x = m * y + c), ale trzeba określić, które y wartość brakuje zestaw 3 Ci przepustkę.

Mogłeś „Optymalizacja” (czyli „skomplikować”) Program ten przez upuszczenie jedną wartość w czasie od wartości "sum kwadratów" i "sum" i "sum produktów", przeliczając nachylenie, przechwycić, a następnie ponownie obliczając brakujący punkt.

(Będę również obserwował, że normalnie będą to współrzędne x o ustalonych wartościach 0, 200, 400, 600 i współrzędnymi y będą wartościami odczytanymi, ale to tylko kwestia orientacji, więc nie jest to istotne.)


Oto co najmniej wiarygodny działający kod. Ponieważ awk automatycznie dzieli się na białej przestrzeni, nie ma potrzeby dzielenia się na kartach; pętla do odczytu bierze to pod uwagę.

Kod wymaga poważnego refaktoryzacji; jest w nim mnóstwo powtórzeń - jednak mam też pracę, którą powinienem wykonać.

#!/usr/bin/awk -f 
BEGIN{ 
    z[1] = 0; 
    z[2] = 200; 
    z[3] = 400; 
    z[4] = 600; 
} 

{ 
    for (i = 1; i <= NF; i++) 
    { 
    centr[i] = $i 
    } 

    if (NF > 2) 
    { 
    lsq(NF, z, centr); 
    } 
} 

function lsq(n, x, y) 
{ 
    if (n == 0) return 

    sx = 0.0 
    sy = 0.0 
    sxx = 0.0 
    syy = 0.0 
    sxy = 0.0 

    for (i = 1; i <= n; i++) 
    { 
    print "x[" i "] = " x[i] ", y[" i "] = " y[i] 
    sx += x[i] 
    sy += y[i] 
    sxx += x[i]*x[i] 
    sxy += x[i]*y[i] 
    syy += y[i]*y[i] 
    } 

    if ((n*sxx - sx*sx) == 0) return 

# print "number of data points = " n; 
    a = (sxx*sy-sxy*sx)/(n*sxx-sx*sx) 
    b = (n*sxy-sx*sy)/(n*sxx-sx*sx) 

    for (i = 1; i <= n; i++) 
    { 
    ycalc[i] = a+b*x[i] 
    } 

    print "# Intercept = " a 
    print "# Slope  = " b 
    print "Line: x = " a " + " b " * y" 

    for (i = 1; i <= n; i++) 
    { 
    printf("x = %8g, yo = %8g, yc = %8g\n", x[i], y[i], ycalc[i]) 
    } 

    print "" 
    print "Different subsets\n" 

    for (drop = 1; drop <= n; drop++) 
    { 
    print "Subset " drop 
    sx = sy = sxx = sxy = syy = 0 
    j = 1 
    for (i = 1; i <= n; i++) 
    { 
     if (i == drop) continue 
     print "x[" j "] = " x[i] ", y[" j "] = " y[i] 
     sx += x[i] 
     sy += y[i] 
     sxx += x[i]*x[i] 
     sxy += x[i]*y[i] 
     syy += y[i]*y[i] 
     j++ 
    } 
    if (((n-1)*sxx - sx*sx) == 0) continue 
    a = (sxx*sy-sxy*sx)/((n-1)*sxx-sx*sx) 
    b = ((n-1)*sxy-sx*sy)/((n-1)*sxx-sx*sx) 
    print "Line: x = " a " + " b " * y" 

    xt = x[drop] 
    yt = a + b * xt; 
    print "Interpolate: x = " xt ", y = " yt 
    } 
} 

Od awk nie zapewniają łatwy sposób przejść z powrotem wiele wartości z funkcji, ani nie zapewniają inne niż konstrukcje tablic asocjacyjnych (czasami), to nie jest chyba najlepszym językiem do tego zadania. Z drugiej strony można go wykonać. Możesz być w stanie połączyć obliczenia najmniejszych kwadratów w funkcji, która zwraca tablicę zawierającą nachylenie i przechwycenie, a następnie użyj tego. Twoja kolej na zbadanie opcji.

Biorąc skrypt lsq.awk i plik wejściowy lsq.data pokazano, mam wyjście pokazany:

$ cat lsq.data 
17.1685 21.6875 20.2393 26.3158 
$ awk -f lsq.awk lsq.data 
x[1] = 0, y[1] = 17.1685 
x[2] = 200, y[2] = 21.6875 
x[3] = 400, y[3] = 20.2393 
x[4] = 600, y[4] = 26.3158 
# Intercept = 17.4537 
# Slope  = 0.0129968 
Line: x = 17.4537 + 0.0129968 * y 
x =  0, yo = 17.1685, yc = 17.4537 
x =  200, yo = 21.6875, yc = 20.0531 
x =  400, yo = 20.2393, yc = 22.6525 
x =  600, yo = 26.3158, yc = 25.2518 

Different subsets 

Subset 1 
x[1] = 200, y[1] = 21.6875 
x[2] = 400, y[2] = 20.2393 
x[3] = 600, y[3] = 26.3158 
Line: x = 18.1192 + 0.0115708 * y 
Interpolate: x = 0, y = 18.1192 
Subset 2 
x[1] = 0, y[1] = 17.1685 
x[2] = 400, y[2] = 20.2393 
x[3] = 600, y[3] = 26.3158 
Line: x = 16.5198 + 0.0141643 * y 
Interpolate: x = 200, y = 19.3526 
Subset 3 
x[1] = 0, y[1] = 17.1685 
x[2] = 200, y[2] = 21.6875 
x[3] = 600, y[3] = 26.3158 
Line: x = 17.7985 + 0.0147205 * y 
Interpolate: x = 400, y = 23.6867 
Subset 4 
x[1] = 0, y[1] = 17.1685 
x[2] = 200, y[2] = 21.6875 
x[3] = 400, y[3] = 20.2393 
Line: x = 18.163 + 0.007677 * y 
Interpolate: x = 600, y = 22.7692 
$ 

Edycja: W poprzedniej wersji odpowiedzi, podzbiory zostały pomnożenie przez n zamiast (n-1). Wartości w zrewidowanym produkcie wydają się zgodne z oczekiwaniami. Pozostałe kwestie są prezentacyjne, a nie obliczeniowe.

+0

Tak, to wydaje się jasne. Ale nie mogłem go wdrożyć do tej pory. Czy możesz mi pomóc pokazać, jakie funkcje i kody myślisz? Którą część należy edytować i jak? – user1116360

+0

Cześć, coś jest nie tak z przedstawionym kodem ... W pierwszych kilku wierszach wyjścia, na przykład Linia: x = 5.43577 + 0.0387496 * y nie jest poprawne ..., powinno być x = 18.1192 + 0,0115708 * y, czyż nie? – user1116360

+0

Zmodyfikowałem post z prawidłowym wymaganym wyjściem – user1116360