This is an old revision of the document!


Laboratorium 4: Cechy wielomianowe

Będziemy przetwarzali następujące pliki:

  • xy-002 $f_{true}=-1.5x^2+3x+4$
  • xy-003 $f_{true}=-1.5x^2+3x+4$
  • xy-004 $f_{true}=-10x^2+500x-25$
  • xy-005 $f_{true}=(x+4)(x+1)(x-3)$

Wykorzystamy kod z poprzedniego laboratorium (Regresja Liniowa)

1. Cechy wielomianowe 2 stopnia

Umieść kod w klasie LinearRegressionPolynomialFeaturesOrderTwo

1. Dodaj do zbioru danych kolumnę X2 zawierającą po prostu wynik wyrażenia “X*X”

Czyli, np. dla xy-002.csv po załadowaniu i przetworzeniu danych wynikiem będzie:

+--------+----------+------------------+
|       X|         Y|                X2|
+--------+----------+------------------+
|0.411194|-59.938274|    0.169080505636|
|0.549662|-72.006761|    0.302128314244|
|0.860093|-68.979336|    0.739759968649|
| 1.27504|  32.07157|1.6257270015999998|
|2.202931|-91.531894|    4.852904990761|
+--------+----------+------------------+
only showing top 5 rows

root
 |-- X: double (nullable = true)
 |-- Y: double (nullable = true)
 |-- X2: double (nullable = true)

2. Zmień konfigurację VectorAssembler tak, aby budował wektory na podstawie kolumn [“X”, “X2”]

3. Zbuduj model regresji

4. Wyświetl wyniki. Przy wyświetlaniu aproksymowanej funkcji wywoływana jest funkcja lrModel.predict(). Jako argument musisz dostarczyć wektor zawierający zarówno wartość wejściową, jak i jej kwadrat. Możesz to zrealizować dodają parametr order do funkcji plot (przyda się przy regresji 3-stopnia) lub po prostu dodając element.

5. Przetwórz wszystkie pliki i wyświetl ich wykresy.

Niewątpliwie ciekawym wykresem jest dopasowanie wielomianu 2-stopnia do danych wygenerowanych z wielomianu 3 stopnia

ale bardziej zastanawiający jest przypadek xy-004.csv

6. Popraw dopasowanie (jest to możliwe)

Przeanalizuj parametry algorytmu. Na przykład:

        LinearRegression lr = new LinearRegression()
                .setMaxIter(10)
                .setRegParam(0.3)
                .setElasticNetParam(0.8)
                .setFeaturesCol("features")
                .setLabelCol("Y");

Które z nich można zmienić? Sprawdź, co się stanie, gdy

  • usuniemy regularyzację
  • zwiększymy liczbę iteracji
  • Porównaj metryki, zamieśc wykresy

Uwagi:

  • usuwanie regularyzacji na ogół (dla niesyntetycznych zbiorów danych) psuje zdolność generalizacji
  • zwiększenie liczby iteracji dla dużych zbiorów danych proporcjonalnie zwiększa czas uczenia

2. Cechy wielomianowe 3 stopnia

Umieść kod w klasie LinearRegressionPolynomialFeaturesOrderThree

1. Podobnie, jak w poprzednim przypadku dodaj kolumnę X3 z wartościami kolumny X podniesionymi do 3 potęgi

2. Zmodyfikuj odpowiednio VectorAssembler

3. Przeprowadź regresję (dla wszystkich zbiorów danych)

4. Zamieść wykres xy-005.csv

5. Porównaj w tabelce wartości miary r2 i MSE dla regresji 2 i 3 stopnia (dla wszystkich zbiorów danych)

  • Sprawdź, czy w przypadku regresji 3-stopnia dla danych wygenerowanych z funkcji kwadratowej współczynniki przy $x^3$ były zerowe?
  • Z reguły niewielkie zwiększenie współczynnika regularyzacji i liczby iteracji poprawia dopasowanie dla krzywych 2 stopnia

3.Pipeline

Kod umieść w klasie LinearRegressionPolynomialFeaturesPipeline

Ponieważ przetwarzane są kolejne zbiory, najlepiej umieść kod w funkcji postci static void processDataset(SparkSession spark,String filename,int degree,Function<Double,Double> f_true) Dodawanie manualne cech jako kolumn zbioru danych jest zbyt żmudne - zachodzi konieczność nazywania tych kolumn, później modyfikacji kodu w kilku miejscach. Raczej buduje się ciąg przetwarzania: Pipeline, którego elementami są wstępne przetwarzanie danych i budowa modelu estymatora. Rozszerzenie cech o cechy wielomianowe jest dokonywane za pomocą odpowiedniej funkcji transformującej dane tablicowe : PolynomialExpansion. ==== Budowa ciągu przetwarzania ==== Kolejne etapy przetwarzania to: * zastosowanie VectorAssembler * PolynomialExpansion * LinearRegression Zamiast wykonywać je natychmiast utwórz i skonfiguruj odpowiednie obiekty <code java> VectorAssembler vectorAssembler=new VectorAssembler() .setInputCols(new String[]{“X”}) .setOutputCol(“features”); Dataset<Row> df_trans = vectorAssembler.transform(df); PolynomialExpansion polyExpansion = new PolynomialExpansion() .setInputCol(“features”) .setOutputCol(“polyFeatures”) .setDegree(degree); df_trans = polyExpansion.transform(df_trans); LinearRegression lr = new LinearRegression() … </code> a następnie zdefinuj ciąg przetwarzania Pipeline i wywołaj jego metodę fit() <code java> Pipeline pipeline = new Pipeline() .setStages(new PipelineStage[] {vectorAssembler, polyExpansion, lr}); PipelineModel model = pipeline.fit(df); </code> Aby uzyskać dostęp do konkretnego elementu ciagu - nalezy po prostu zrzutować wybrany element <code java> LinearRegressionModel lrModel = (LinearRegressionModel)model.stages()[2]; </code> ==== Funkcja do rysowania wykresów ==== Zmodyfikujemy sygnaturę funkcji. <code java> * * @param x - współrzedne x danych * @param y - współrzedne y danych * @param pipelineModel - model pipeline * @param spark - sesja Spark * @param title - tytuł do wyswietlenia (może być null) * @param f_true - funkcja f_true (może być null) */ static void plot(List<Double>x, List<Double> y, PipelineModel pipelineModel, SparkSession spark, String title, Function<Double,Double> f_true) </code> W odróżnieniu od funkcji używanej dotychczas - przekazujemy do niej pipelineModel. Wykorzystamy go, aby wyświetlić przebieg funkcji wyznaczonej w wyniku regresji. 1. Załóżmy, że mamy punkty, dla których mamy wyznaczyć wartości funkcji zgromadzone na liście fx <code java> var xdelta = 0.05*(xmax-xmin); var fx = NumpyUtils.linspace(xmin-xdelta,xmax+xdelta,100); </code> Aby przetworzyć je za pomocą pipeline musimy zamienić je na Dataset<Row> zawierający kolumnę o nazwie X z odpowiednimi wartościami. 2. Zamiana wartości double na Row Przeiteruj przez elementy fx i dla każdego z nich utwórz obiekt Row, np. wołając Row r = RowFactory.create(d); lub odpowiednią funkcje strumienia. Zbierz wynik w List<Row> rows 3. Zdefiniuj schemat i utwórz zbiór danych: <code java> StructType schema = new StructType().add(“X”, “double”); Dataset<Row> df_test = spark.createDataFrame(rows,schema); df_test.show(5); df_test.printSchema(); </code> Wynik: <code> +——————–+ | X| +——————–+ | -2.0917333| | -1.5355272333333332| | -0.9793211666666666| |-0.42311509999999974| | 0.13309096666666687| +——————–+ only showing top 5 rows </code> 3. Wywołaj funkcję transform() obiektu pipeline <code java> Dataset<Row> df_pred = pipelineModel.transform(df_test); df_pred.show(5); df_pred.printSchema(); </code> W wyniku jej wykonania do zbioru zostaną dodane kolejno kolumny features, polyfeatures i prediction zgodnie z kolejnymi etapami przetwarzania <code> +——————–+——————–+——————–+——————-+ | X| features| polyFeatures| prediction| +——————–+——————–+——————–+——————-+ | -2.0917333| [-2.0917333]|[-2.0917333,4.375…| -33.40167605867543| | -1.5355272333333332|[-1.5355272333333…|[-1.5355272333333…|-29.392038747489657| | -0.9793211666666666|[-0.9793211666666…|[-0.9793211666666…| -26.24979833578732| |-0.42311509999999974|[-0.4231150999999…|[-0.4231150999999…|-23.976336940609087| | 0.13309096666666687|[0.13309096666666…|[0.13309096666666…| -22.57303667899562| +——————–+——————–+——————–+——————-+ only showing top 5 rows root |– X: double (nullable = true) |– features: vector (nullable = true) |– polyFeatures: vector (nullable = true) |– prediction: double (nullable = false) </code> 4. Należy oczywiście wyświetlić zawartość kolumny prediction ===== 4. Podział na zbiór uczący i testowy ===== Podziały przetestujemy na pliku xy-003.csv dla cech wielomianowych 3 stopnia. ==== Rozwiązanie 1 ==== 1. Po załadowaniu zbioru do podziel go korzystając z funkcji limit i offset: <code java> long rowsCount = df.count(); int trainCount = (int)(rowsCount*.7); var df_train = df.select(“*”).limit(trainCount); var df_test = df.select(“*”).offset(trainCount); System.out.println(df_train.count()); System.out.println(df_test.count()); </code> 2. Zamień wywołania w kodzie tak, aby przetwarzany i wyświetlany był zbiór df_train 3. Dodaj wyświeltanie df_test: <code java> x = df_test.select(“X”).as(Encoders.DOUBLE()).collectAsList(); y = df_test.select(“Y”).as(Encoders.DOUBLE()).collectAsList(); plot(x,y,model,spark,String.format(“Linear regression: %s (test data)”,filename),f_true); </code> 4. Dodaj kod odpowiedzialny za obliczanie metryk na zbiorze testowym * wpierw przetrannsformuj go * następnie oblicz metryki korzystając z kolumn Y i prediction <code java> var df_test_prediction = model.transform(df_test); RegressionEvaluator evaluator = new RegressionEvaluator() .setLabelCol(“Y”) .setPredictionCol(“prediction”) .setMetricName(“rmse”); or any other evaluation metric double rmse = evaluator.evaluate(df_test_prediction); evaluator.setMetricName(“r2”); double r2 = evaluator.evaluate(df_test_prediction); </code> 5. Wydrukuj wartości metryk i obejrzyj wykresy <code> Scores on training set: r2=0.63 RMSE=317.19 Scores on test set: r2=-1.02 RMSE=647.06 </code>

ed/lab_04.1710093177.txt.gz · Last modified: 2024/03/10 18:52 by pszwed
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0