Montag, 8. August 2011

Multiple Regression mit UTL_NLA

Heute geht's erneut um die multiple Regression, die in diesem Beispiel mithilfe von UTL_NLA durchgeführt wird. UTL_NLA stellt dazu BLAS (Basic Linear Algebra Subroutines) und LAPACK (Linear Algebra PACKage) bereit.

Wie im vorherigen Post zu diesem Thema, werden die folgenden Daten verwendet:

y = Nachgefragte Menge in 1000 Stück
x1 = Werbeausgaben in 100.000 Euro für Printmedien
x2 = Werbeausgaben in 100.000 Euro für Fernsehen
x3 = Preis pro Mengeneinheit in 100 Euro

yx1x2x3
500 1 1 20
800 3 1 20
1500 3 3 18
2500 6 4 15
3200 6 6 12

Man erhält die Koeffizienten der Regressionsfunktion in Form des Vektors b durch:


Die Matrix X im Beispiel:


Der Vektor y im Beispiel:


Die Berechnung des Vektors b umfasst also die Bestimmung der Inversen, die Multiplikation von Matrizen und die Multiplikation einer Matrix mit einem Vektor. All diese Operationen lassen sich mithilfe von UTL_NLA durchführen. Für die Multiplikation von Matrizen wird BLAS_GEMM verwendet, für die Multiplikation einer Matrix mit einem Vektor wird BLAS_GEMV verwendet und für die Lösung des Gleichungssystems kommt LAPACK_GESV zum Einsatz.

Die Werte für die Matrizen werden entweder Zeilen- oder Spaltenweise angeben, je nachdem für welches Argument man sich für den Parameter PACK entscheidet. Im folgenden Beispiel wurde als Argument für den Parameter PACK 'R' gewählt. Die Deklaration stellt sich dann wie folgt dar:
v_matrix_xt UTL_NLA_ARRAY_DBL := UTL_NLA_ARRAY_DBL(  1 , 1 , 1 , 1 , 1, 
                                                     1 , 3 , 3 , 6 , 6, 
                                                     1 , 1 , 3 , 4 , 6,
                                                     20, 20, 18, 15, 12 );
 
v_matrix_x UTL_NLA_ARRAY_DBL := UTL_NLA_ARRAY_DBL(   1 , 1 , 1 , 20,
                                                     1 , 3 , 1 , 20,
                                                     1 , 3 , 3 , 18,
                                                     1 , 6 , 4 , 15, 
                                                     1 , 6 , 6 , 12 ); 
Der Aufruf der Prozedur UTL_NLA.BLAS_GEMM ermittelt nun die Matrix XTX.
UTL_NLA.BLAS_GEMM(
   transa => 'N',
   transb => 'N',
   m      => 4,
   n      => 4,
   k      => 5,
   alpha  => 1,
   a      => v_matrix_xt,
   lda    => 5,
   b      => v_matrix_x,
   ldb    => 4,
   beta   => 0,
   c      => v_matrix_xtx,
   ldc    => 4,
   pack   => 'R');
Nun wird der Vektor XTy mithilfe von UTL_NLA.BLAS_GEMV bestimmt:
UTL_NLA.BLAS_GEMV(
   trans  => 'N',
   m      => 4,
   n      => 5,
   alpha  => 1,
   a      => v_matrix_xt,
   lda    => 5,
   x      => v_vector_y,
   incx   => 1,
   beta   => 0,
   y      => v_vector_xty,
   incy   => 1,
   pack   => 'R');
Im finalen Schritt, zur Bestimmung der Koeffizienten, ist das folgende Gleichungssystem zu lösen:

XTXb=XTy

Diese Aufgabe erledigt die Prozedur UTL_NLA.LAPACK_GESV, wobei sich das Ergebnis nach dem Aufruf in der Variablen befindet, die als Argument für den Parameter b übergeben wurde.
UTL_NLA.LAPACK_GESV(
   n      => 4,
   nrhs   => 1,
   a      => v_matrix_xtx,
   lda    => 4,
   ipiv   => v_matrix_p,
   b      => v_vector_xty,
   ldb    => 1,
   info   => v_result,
   pack   => 'R');
Die Ausgabe der Koeffizienten ergibt:
for i in 1..v_vector_xty.count loop
 dbms_output.put_line('b' || (i-1) || ' = ' || to_number(v_vector_xty(i)));
end loop;

b0 = 1440.8163265303169
b1 = 168.36734693877926
b2 = 266.32653061226313
b3 = -69.38775510202751
Die Regressionsfunktion ergibt sich somit zu:

y = 1440,8163 + 168,3673∙x1 + 266,3265∙x2 - 69,3878∙x3

Abschließend sei noch erwähnt, dass eine Matrix bzw. ein Vektor vom Typ UTL_NLA_ARRAY_DBL bzw. UTL_NLA_ARRAY_FLT maximal 1.000.000 Elemente enthalten kann.

Natürlich befinden sich die Daten meist in einer Tabelle und man will die Matrix nicht manuell angeben. Vielmehr möchte man die Elemente durch SQL und PL/SQL gewinnen und in einer Variablen vom entsprechenden Typ speichern.

Aber das ist was für einen anderen Post...

4 Kommentare:

  1. Hi, leider funktioniert deine Beispiel seit Version 10.2g so nicht mehr. Der erste Aufruf von BLAS_GEMM konnte ich zum Laufen bekommen mit dem Parametern transa->T und transb->T.
    Die Funktion BLAS_GEMV scheint überhaupt nicht mehr zu wollen, da kann man tun was man will, stützt immer ab.

    vielleicht hast du eine Idee wie man dein Beispiel wieder zum Laufen bekommt?

    Danke für deine Meinung / Hilfe und beste Grüsse

    AntwortenLöschen
  2. In der Funktion GEMV muss lda auf 4 statt 5 stehen?

    UTL_NLA.BLAS_GEMV(
    trans => 'N',
    m => 4,
    n => 5,
    alpha => 1,
    a => v_matrix_xt,
    lda => 5,
    x => v_vector_y,
    incx => 1,
    beta => 0,
    y => v_vector_xty,
    incy => 1,
    pack => 'R');

    AntwortenLöschen
  3. jetzt kämpfe ich noch mit GESV:
    UTL_NLA.LAPACK_GESV(n => 4,
    nrhs => 1,
    a => v_matrix_xtx,
    lda => 4,
    ipiv => v_matrix_p,
    b => v_vector_xty,
    ldb => 1,
    info => v_result,
    pack => 'R');

    das stürzt auch noch ab.
    Habe jetzt als Zwischenresultate folgende Matrix:

    Anzahl v_matrix_x: 20
    Anzahl v_matrix_xtx: 16
    Anzahl v_vector_xty: 4

    AntwortenLöschen
  4. Parameter ldb von UTL_NLA.LAPACK_GESV angepasst:
    --alt : ldb => 1,
    --neu : ldb => 4,
    Mit dem Resultat, dass das Skript mal läuft, allerdings kommen nun nicht die gleichen Koeffizienten raus, aber ich werde jetzt nachdem es läuft, mal meine Werte einsetzen und mit dem Excel vergleichen....

    Vielen Dank schon mal für den grunsätzlichen Lösungsweg

    AntwortenLöschen