Matlab Tutorial #6

Choć MATLAB może być traktowany jako język programowania, na pewno może zaskoczyć nietypowymi, dla "rasowego" programisty rozwiązaniami. Idea jest w zasadzie taka, by użytkownik środowiska MATLAB analizując dane nie musiał uciekać się na każdym kroku do tworzenia funkcji pomocniczych i wykorzystywania konstrukcji programistycznych takich jak pętle i instrukcje warunkowe. One w MATLABie oczywiście istnieją  i są w wielu sytuacjach niezbędne, jednak wiele można zrobić bez nich.

Poszukiwanie maksimum

W poprzedniej części samouczka udało Ci się zidentyfikować lipiec 2003 roku jako nietypowy, pod względem liczby oddanych do użytku w Polsce mieszkań, miesiąc. Problem polega na tym, że w celu identyfikacji tego określonego w czasie punktu trzeba było dokładnie przeanalizować wykres. Oczywiście, analiza wykresów to w zasadzie podstawa pracy z każdymi danymi, jednak optymalnie byłoby po zerknięciu na wykres wydobyć informacje o interesujących nas punktach w sposób przynajmniej częściowo zautomatyzowany. Zacznijmy jednak (prawie) od początku.

  • Wczytaj dane zebrane w pliku bud.mat,
  • Z macierzy BMdaneM wybierz dane dotyczące miesięcznej łącznej liczby oddanych do użytku mieszkań (ogółem) i zapisz je jako wektor w zmiennej ogolemV
  • Wygeneruj wektor czasu odpowiadający długością wektorowi ogolemV
  • Umieść dane na wykresie.

 

load bud
ogolemM = BMdaneM(2:6:end,:)'; % wybranie danych i transpozycja (operator - apostrof)
ogolemV = reshape(ogolemM, [], 1);
ogolemV = ogolemM(:); % alternatywna metoda
t1 = datetime(1991,1,31)
dt = calendarDuration(0,1,0)
N = length(ogolemV); % zapisanie informacji o długości wektora
t = t1:dt:t1+(N-1)*dt;
plot(t, ogolemV);

mieszkania ogółem 1991-2015

W kodzie przedstawionym powyżej zaszło kilka zmian względem tego, co można znaleźć w Matlab Tutorial #5. Przestawiam zatem kilka wyjaśnień.

ogolemV = ogolemM(:); % alternatywna metoda

Zgodnie z tekstem dodanym jako komentarz po znaku '%', jest to alternatywny sposób przekształcenia macierzy ogolemM w wektor.  W przypadku funkcji reshape użytkownik może określić, jakie maja być wymiary macierzy wynikowej, w przypadku wykorzystania operatora (:) wynikiem zawsze jest wektor o rozmiarach Nx1. Inaczej rzecz ujmując, cała zawartość macierzy trafia do jednej kolumny.

N = length(ogolemV); 
t = t1:dt:t1+(N-1)*dt;

Dzięki zastosowaniu funkcji length w zmiennej N została zapisana długość wektora ogolemV. Pisząc ten poradnik opieram się na danych z końca roku 2015, zawartych w pliku mieszkania_91_15.xls Prawdopodobnie w kolejnych latach pliki umieszczane na stronach Głównego Urzędu Statystycznego będą uzupełnianie o nowe dane i wielkości macierzy BMdaneM tworzonej na podstawie wskazówek umieszczonych w Matlab Tutorial #3 może wzrosnąć. Wprowadzenie do procesu przetwarzania zmiennej N ma na celu uniezależnienie tworzonego kodu od wielkości macierzy. Dzięki temu, jeśli zaczniesz przerabiać ten turorial na początku roku 2017, a GUS udostępni w międzyczasie dodatkowe dane, również one mogą być uwzględnione w analizie. Wektor t nie jest tworzony na sztywno. Ostatnia data, jak się w nim znajdzie, jest wyliczana na podstawie ilości elementów wektora ogolemV.

Odszukanie wartości maksymalnej to oczywiście żaden problem, wystarczy wykorzystać przedstawioną już wcześniej funkcję max.

m = max(ogolemV);

To niestety jednak tylko część sukcesu. Wiemy już jaka była maksymalna wartość, ale nie wiemy ciekawszej rzeczy, kiedy ta wartość została osiągnięta.

Wielokrotne argumenty wyjściowe funkcji

Okazuje się, że w MATLABie funkcja max może zwrócić nam dwie informacje.

  1. Jaka jest wartość maksymalna.
  2. Gdzie ta wartość maksymalna się znajduje (w którym miejscu macierzy).

I właśnie to jest nam potrzebne. Jeśli funkcja ma zwrócić więcej niż jeden argument wyjściowy, wszystkie nazwy zmiennych, które mają służyć do przechowywania wyniku, należy umieścić w nawiasach kwadratowych po lewej stronie znaku równości.

  • zastosuj funkcję max na wektorze ogolemV zapisując wynik do dwóch argumentów wyjściowych
  • wykorzystaj drugi argument wyjściowy do wyznaczenia daty ("zaindeksowania" wektora t)
[m, idx] = max(ogolemV);
x = t(idx)


x =

31-Jul-2003

Dobrze zapamiętać, że w MATLABie pojedyncza funkcja może bardzo często zostać wykorzystana na wiele różnych sposobów. Należy tylko odpowiednio operować argumentami wejściowymi i wyjściowymi.

Poza olbrzymim pikiem z lipca 2003 na wykresie widać jeszcze kilka ciekawych punktów, których wartość przekracza 20000. Jak je poprawnie zidentyfikować? W MATLABie jest to niezwykle łatwe dzięki technice indeksowania logicznego. Zanim do tego przejdziemy, należy jednak powiedzieć (w moim przypadku raczej napisać) parę słów o operacjach logicznych.

Operacje logiczne

Poza tym, że liczby w MATLABie możemy dodawać, dzielić, pierwiastkować itp. możemy je również porównywać. Przykładowo, może zainteresować nas, czy liczba liczba  \pi jest większa od 3.

pi > 3


ans =

1

W wyniku pojawiła się jedynka, co oznacza prawdę. Konkretnie, nasze zdanie pi > 3 jest prawdziwe. Nic nie stoi na przeszkodzie, by wynik operacji logicznej zapisać do zmiennej.

x = pi <= 3

Po wykonaniu powyższego kodu do zmiennej x zostanie zapisane 0, co oznacza fałsz. Dzięki temu wiemy, że pi nie jest mniejsze lub równe 3. To ile może wynosić liczba pi?

x = pi == 3.14

Powyższy kod umożliwia sprawdzenie, czy liczba pi wynosi 3.14 (operator przyrównania to == ). Odpowiedzią jest fałsz, gdyż MATLAB przechowuje wartość liczby pi z nieco większą dokładnością. Bez jakiejś zbędnej przesady, ta dokładność to 15 miejsc po przecinku.
Możliwe jest tworzenie całych macierzy logicznych zer i jedynek. Można to robić "ręcznie":

x = [true false true]

Zazwyczaj jednak takie macierze powstają jako wynik operacji logicznych przeprowadzanych na macierzach liczbowych.

  • Przy pomocy funkcji rand wygeneruj macierz losową r o rozmiarach 3 x 3
  • Sprawdź, które elementy macierzyr mają wartość większą od 0.5
r = rand(3)
x = r > 0.5


r =

0.8147 0.9134 0.2785

0.9058 0.6324 0.5469

0.1270 0.0975 0.9575


x =

1 1 0

1 1 1

0 0 1

Indeksowanie logiczne

W tym momencie dochodzimy do najciekawszej części. Macierze i wektory logiczne w MATLABie mogą posłużyć do indeksowania innych macierzy. Warunek jest taki, że rozmiar macierzy indeksującej i indeksowanej musi być taki sam. Jak to wykorzystać w praktyce? Dla przykładu, możemy teraz "wyzerować" wszystkie elementy macierzy r, które spełniają warunek >0.5. To częsty scenariusz w przypadku pracy z algorytmami, które wykorzystują progowanie.

r(x) = 0


r =

0      0      0.2785

0      0      0

0.1270 0.0975 0

 Wpisując powyższy kod wydajemy polecenie: W macierzy r wstaw 0 na wszystkich pozycjach, na których w macierzy x znajduje się 1.

Wróćmy do naszych danych związanych z budownictwem mieszkaniowym. Jeśli wstępny przykład nie jest do końca czytelny, to teraz wszystko powinno się rozjaśnić. Przypominam jakie stoi przed nami zadanie, chcemy zidentyfikować wszystkie miesiące, w których liczba oddanych do użytku mieszkań przekraczała 20000.  Pomińmy od razu lipiec 2003 roku, ten punkt mamy już przeanalizowany.

  • Utwórz wektor logiczny idx, w którym jedynki wskażą miesiące dla których liczba oddanych do użytku mieszkań przekroczyła 20000 i jedocześnie jest mniejsza od 43492 (wartość maksymalna z lipca 2003 wyznaczona już dzięki funkcji max)
  • Sprawdź, ile jest takich miesięcy.
idx = (ogolemV > 20000) & (ogolemV < 43492); % & - iloczyn logiczny
sum(idx)


ans =

5

Operator & odpowiada za przeprowadzenie operacji iloczynu logicznego (Suma logiczna jest realizowana dzięki operatorowi | ). Teraz kluczowy moment, chcemy dowiedzieć się w jakich miesiącach spełniony został postawiony przez nas warunek oraz ile dokładnie mieszkań zostało wtedy oddanych do użytku. Do realizacji naszego celu możemy wykorzystać wektor logiczny idx.

t_powyzej20000 = t(idx)
oddanych_powyzej2000 = ogolemV(idx)' %transpozycja kosmetyczna


t_powyzej20000 =

31-Dec-1991 31-Mar-1992 31-Dec-1992 31-Dec-2008 31-Jan-2009


oddanych_powyzej2000 =

30960 28833 23395 29877 22096

Indeksowanie logiczne to naprawdę niezwykle skuteczna i zarazem prosta technika wydobywania potrzebnych informacji z zestawu danych. Powyżej zrealizowaliśmy jeden ze standardowych scenariuszy; wyławiamy interesujące nas zdarzenie i identyfikujemy, kiedy miało ono miejsce. Możemy równie dobrze zadziałać w drugą stronę. Przypuśćmy, że z naszego wektora ogolemV potrzebne są nam informacje dotyczące wyłącznie trzech miesięcy: kwietnia, maja i czerwca. Można by było w tym momencie sięgnąć po macierz BMdaneM ale załóżmy, że do dyspozycji mamy jedynie wektory ogolemV i t i tylko na nich możemy operować.
Zanim przejdziemy do operacji logicznych, wymagane będzie drobne przekształcenie wektora t.

kwartal = quarter(t)

Dzięki metodzie quarter z wektora t wyciągnęliśmy tylko to, co nas interesuje, czyli numer kwartału (dostępne są również metody month, year i day). Teraz można przeprowadzić operację logiczną - szukamy wyłącznie kwartału oznaczonego liczbą 2.

idx = (kwartal == 2);

Ostatni krok to wykorzystanie wektora idx do zaindeksowania wektora ogolemV:

ogolem_q2= ogolemV(idx);
histogram(ogolem_q2);

(Visited 1 440 times, 1 visits today)

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *