Wszystkie artykuły

KajoData / Tableau

MoM i YoY w Tableau: wzrost procentowy z poprawną bazą

Pokazuję formuły MoM i YoY, ale zaczynam od sprawdzenia, z czym porównujesz wynik. Wyjaśniam luki w datach, zerową bazę i filtry usuwające historię.

Kajo RudzińskiOpublikowano Aktualizacja 11 min czytania

Dwie osie czasu z mostami porównującymi sąsiednie i odległe okresy oraz jedną luką

Wzrost miesiąc do miesiąca wygląda jak prosty wzór. Odejmuję poprzednią wartość od obecnej i dzielę przez poprzednią. W Tableau najwięcej problemów sprawia jednak ustalenie, która wartość rzeczywiście jest poprzednia. Jedna luka w miesiącach albo filtr daty potrafią zmienić znaczenie wskaźnika bez żadnego błędu składni.

Ja zaczynam od tabeli kontrolnej. Chcę obok siebie zobaczyć miesiąc, bieżącą sprzedaż i bazę porównania. Dopiero kiedy te kolumny mają sens, zamieniam je na wykres. Zielona strzałka może chwilę poczekać. Szczególnie jeśli ma pokazywać wzrost względem zupełnie innego okresu, niż obiecuje tytuł.

Co oznaczają MoM i YoY

MoM, czyli month over month, porównuje miesiąc z poprzednim miesiącem. YoY, czyli year over year, w analizie miesięcznej zestawia go z tym samym miesiącem poprzedniego roku. Luty porównuję więc odpowiednio ze styczniem albo z lutym rok wcześniej.

Oba wskaźniki odpowiadają na inne pytania. MoM pomaga zobaczyć krótkoterminową zmianę, ale może mocno reagować na sezonowość. YoY utrzymuje nazwę miesiąca w porównaniu, jednak nadal może obejmować inne warunki: święta, zmianę oferty lub wyjątkowo słabą bazę. Sam procent nie wyjaśnia przyczyny.

Przy dodatniej bazie stosuję wzór: różnica między wartością obecną i bazową, podzielona przez wartość bazową. Przy zmianie ze 100 na 120 dostaję 20%. Przy powrocie ze 120 do 100 spadek wynosi około 16,7%, ponieważ mianownik jest inny. Więcej o samym rachunku przeczytasz w artykule o wzroście procentowym.

Przygotuj miesiąc, który zawiera także rok

W tym poradniku zakładam pole daty [Order Date] i liczbową miarę [Sales]. Nazwy możesz zmienić, ale muszą odpowiadać polom w Twoim źródle. Dane obejmują zamknięte miesiące i porównywalną definicję sprzedaży. Nie łączę tu walut, planu z wykonaniem ani wartości brutto z netto.

Tworzę pole [Month], które reprezentuje początek miesiąca:

DATETRUNC('month', [Order Date])

Funkcja obcina datę do wskazanej części, co opisuje dokumentacja dat Tableau. W widoku używam pełnej daty miesięcznej, z rokiem. Sam dyskretny numer miesiąca mógłby zebrać wszystkie stycznie z różnych lat do jednej grupy.

Układam miesiące chronologicznie. Na początek umieszczam [Month] w wierszach, a SUM([Sales]) w tekście. Każdy wiersz ma oznaczać jeden miesiąc analizowanej serii. Jeżeli dodaję region, muszę ustalić, czy liczę osobny wzrost dla każdego regionu. Tę decyzję podejmuję przed wyborem wykresu.

Sprawdzam również poziom źródła. Jedna pozycja zamówienia i miesięczna suma to różne obserwacje. Gdy obie trafią do tej samej miary, wskaźnik wzrostu może być policzony poprawnie z błędnych sum. Dlatego najpierw kontroluję zwykłą sprzedaż, a dopiero później tempo jej zmiany.

LOOKUP wskazuje pozycję w widoku

Tworzę pole [Previous month]:

LOOKUP(SUM([Sales]), -1)

LOOKUP pobiera wartość wyrażenia z pozycji przesuniętej względem bieżącej w obrębie partycji. Jeśli nie da się ustalić pozycji docelowej, zwraca NULL. Tak definiuje ją dokumentacja funkcji tabelarycznych.

Z tego wynika ważne ograniczenie: minus jeden oznacza poprzednią pozycję obliczenia. Przy pełnej miesięcznej osi będzie to poprzedni miesiąc. Jeśli pomiędzy styczniem i marcem nie ma lutego, poprzednią dostępną pozycją może być styczeń. Nazwanie wyniku MoM nie sprawi, że brakujący miesiąc się pojawi.

Dodaję to pole do tabeli obok sprzedaży. Dla pierwszego miesiąca oczekuję braku bazy, jeśli historia zaczyna się właśnie tam. Dla drugiego chcę zobaczyć sprzedaż z pierwszego. Ten prosty odczyt daje znacznie więcej niż sprawdzanie samego procentu, bo pokazuje, skąd formuła bierze mianownik.

Ustaw kierunek i partycje

Obliczenia tabelaryczne pracują na wartościach widoku. Wymiary dzielą je na partycje i określają kierunek przechodzenia między pozycjami. Te pojęcia opisuje instrukcja obliczeń tabelarycznych.

W prostej tabeli z miesiącami w wierszach ustawiam obliczanie po miesiącu, zgodnie z kolejnością rosnącą. Jeśli korzystam ze Specific Dimensions, zaznaczam pełne pole [Month] jako wymiar adresowania. Region, gdy ma wyznaczać osobną serię, pozostawiam jako partycję. Ustawienie musi odpowiadać rzeczywistemu układowi arkusza.

Nie podaję jednego uniwersalnego kliknięcia „Table Across”, ponieważ po przeniesieniu miesiąca z kolumn do wierszy taki skrót może przestać odpowiadać zamiarowi. Patrzę na dane, po których przechodzi obliczenie. Przy dwóch regionach pierwszy miesiąc drugiego regionu nie może korzystać z ostatniego miesiąca pierwszego.

Każde pole z własnym LOOKUP wymaga sprawdzenia konfiguracji w używanym widoku. Zmiana układu dashboardu sama w sobie nie musi zmieniać obliczenia, ale dodanie wymiaru do arkusza może już zmienić jego szczegółowość. Po takiej zmianie wracam do tabeli kontrolnej zamiast zakładać, że wcześniejszy wynik nadal ma tę samą interpretację.

Formuła MoM z jawną regułą dla bazy

W tym przykładzie pokazuję zmianę procentową tylko dla dodatniej bazy. Dla braku danych, zera lub wartości ujemnej zostawiam NULL. To przyjęta reguła raportowania, którą trzeba uzgodnić dla własnej miary. Nie twierdzę, że ujemnych wyników nigdy nie wolno porównywać; wymagają osobnej interpretacji.

Pole [MoM] ma postać:

IF ISNULL([Previous month]) OR [Previous month] <= 0 THEN
    NULL
ELSE
    (SUM([Sales]) - [Previous month]) / [Previous month]
END

Składnię IF i ISNULL potwierdza dokumentacja funkcji logicznych. Wynik formatuję jako procent. Nie mnożę go dodatkowo przez sto, ponieważ wartość 0,2 ma być pokazana jako 20%.

Dane poniżej są syntetyczne, a rachunek wynika bezpośrednio z podanych kwot:

Miesiąc Sales Baza MoM MoM
2026-01 100 brak brak
2026-02 120 100 20%
2026-03 90 120 -25%
2026-04 0 90 -100%
2026-05 40 0 brak

Maj nie dostaje umownego 100% wzrostu. Pokazuję kwotę 40 i informację, że baza wynosi zero. Kwiecień może natomiast mieć -100%, ponieważ jego baza jest dodatnia. Te dwa przypadki warto omówić z odbiorcą przed wdrożeniem raportu.

Porównanie dwóch stosów wartości i kontrola pustej bazy pod lupą

YoY wymaga kompletnej serii miesięcy

Pole [Previous year month] tworzę tak:

LOOKUP(SUM([Sales]), -12)

Następnie pole [YoY]:

IF ISNULL([Previous year month]) OR [Previous year month] <= 0 THEN
    NULL
ELSE
    (SUM([Sales]) - [Previous year month]) / [Previous year month]
END

Warunek jest identyczny jak przy MoM, zmienia się baza. Dla stycznia 2026 o sprzedaży 150 i stycznia 2025 o sprzedaży 100 otrzymuję 50%. Taki wynik zakłada, że w partycji istnieje pełna, właściwie uporządkowana sekwencja miesięcy pomiędzy tymi datami.

Cztery wiersze z dwoma styczniami i dwoma lutymi nie wystarczą do pokazania działania przesunięcia minus dwanaście. Aby prześledzić przykład w widoku, potrzebujesz wszystkich miesięcznych pozycji od stycznia 2025 do stycznia 2026. Wtedy pomiędzy styczniami jest dokładnie dwanaście kroków.

Jeżeli źródło ma nieregularne okresy, nie traktuję przesunięcia jako kalendarza. W takim projekcie wolę przygotować w modelu pełny zestaw miesięcy i jawne dopasowanie okresów. Przed wyborem rozwiązania trzeba też określić, czy brak oznacza brak sprzedaży, czy brak informacji. To dwie różne sytuacje biznesowe.

Brak miesiąca i brak wartości

Tableau pozwala pokazać brakujące wartości nagłówków dat, gdy potrafi ustalić ich dziedzinę. Opcja Show Missing Values pomaga zobaczyć lukę, ale sama nie rozstrzyga, jaka sprzedaż powinna się w niej znaleźć. Dokumentacja odróżnia też brak całego okresu od NULL w istniejącym wierszu: Show or Hide Missing Values.

W praktyce pytam właściciela źródła, co stało się w lutym. Czy kanał faktycznie nic nie sprzedał, czy nie przyszedł plik? Jeśli bez sprawdzenia wstawię zero, marzec może dostać brak procentu zamiast uczciwej informacji o niekompletnej historii. Jeśli pominę lukę, porównam marzec ze styczniem.

Na etapie odbioru sprawdzam konkretnie luty i dwa sąsiednie miesiące. Oglądam daty bazy, kwoty i dopiero na końcu procent. W większym raporcie dodaję opis kompletności wejścia. Jeden brakujący okres może wpływać zarówno na MoM, jak i na późniejsze YoY, więc problem nie kończy się na jednej pustej komórce.

Filtr może usunąć potrzebną historię

Zwykły filtr daty działa przed obliczeniami tabelarycznymi. Jeśli zostawię w danych widoku tylko 2026 rok, styczniowi zabraknie grudnia 2025 do MoM, a całemu rokowi zabraknie 2025 do YoY. Kolejność tych operacji opisuje Tableau Order of Operations.

Oddzielam więc zakres potrzebny do liczenia od zakresu pokazywanego odbiorcy. Najprostszy etap diagnostyczny to pozostawienie całej historii w tabeli. Do prezentacji można ukryć wcześniejsze nagłówki zamiast usuwać ich dane zwykłym filtrem. Tableau pokazuje ten przypadek w opisie typów obliczeń.

Przy bardziej rozbudowanym rozwiązaniu można użyć filtra opartego na obliczeniu tabelarycznym, ale trzeba osobno sprawdzić jego działanie. Nie zamieniam filtra na inny typ w ciemno. Zapisuję oczekiwany wynik dla stycznia, stosuję wybór zakresu i porównuję bazę. To samo robię po użyciu filtrów regionu i produktu.

Procent, kwota i niepełny miesiąc

W dymku pokazuję bieżącą sprzedaż, bazę i zmianę procentową. Dzięki temu odbiorca widzi, czy duży procent wynika z dużej różnicy kwot, czy z bardzo małego punktu startu. Wzrost z 1 do 2 to 100%, tak samo jak wzrost ze 100 do 200, choć skala jest inna.

Nie porównuję połowy października z całym wrześniem pod zwykłą etykietą MoM. Wybieram zamknięte miesiące albo osobno definiuję porównanie miesiąca w toku z porównywalnym zakresem. Liczba dni, terminy księgowania i granica pobrania danych powinny być widoczne w opisie.

Jeśli wskaźnik dotyczy udziału lub marży procentowej, rozróżniam zmianę względną od punktów procentowych. Przejście z 20% do 25% oznacza wzrost o 5 punktów procentowych albo względnie o 25%. Wybór nazwy wpływa na interpretację. Nie kopiuję formuły sprzedażowej do dowolnej miary tylko dlatego, że obie pokazują znak procenta.

Szybkie obliczenie i własna formuła

Do prostego sprawdzenia można skorzystać z typu Percent Difference From i porównania względem poprzedniej wartości. Tableau opisuje tę opcję w dokumentacji typów obliczeń wskazanej wyżej. Nadal trzeba ustawić kierunek, partycje i właściwe okresy. Skrót w menu nie usuwa żadnego z tych założeń.

Ja wybieram własne pola, gdy chcę pokazać odbiorcy osobno bazę i zastosować jawną regułę dla wartości niedodatnich. Łatwiej wtedy wyjaśnić, dlaczego wskaźnik jest pusty. Nie zakładam też, że wbudowane obliczenie i moja formuła mają identyczną konwencję dla ujemnej bazy. Tutaj świadomie wykluczyłem taki przypadek z raportowania procentu.

Przy przekazywaniu arkusza zapisuję, którą metodę wybrałem. Jeśli ktoś później zastąpi pole szybkim obliczeniem, powinien porównać zachowanie na tych samych małych danych. Szczególnie interesują mnie pierwszy miesiąc serii, luka, baza zerowa i ujemna. Zgodność jednego zwykłego wzrostu nie potwierdza zgodności wszystkich przypadków.

Wzrost całości i wzrost poszczególnych kanałów

Przyjmijmy drugi przykład syntetyczny. W styczniu sklep ma sprzedaż 100, a internet 10. W lutym sklep nadal ma 100, natomiast internet rośnie do 20. Dla sklepu wzrost wynosi 0%, dla internetu 100%. Cała firma przechodzi jednak ze 110 do 120, więc rośnie o około 9,1%.

Zwykła średnia dwóch procentów dałaby 50%. To nie odpowiada zmianie sumy sprzedaży firmy. Mały kanał i duży kanał dostałyby w takim rachunku tę samą wagę. Kiedy buduję wskaźnik łączny, zaczynam od sum bieżącej i bazowej dla całego właściwego zakresu, a potem wyliczam zmianę.

Ta różnica jest szczególnie ważna po dodaniu regionu, produktu lub kanału do widoku. Chcę wiedzieć, czy karta z wynikiem ma pokazywać wzrost firmy, czy przeciętny wzrost wybranych grup. Oba pytania mogą mieć sens, ale potrzebują innych nazw i definicji. Nie wyciągam średniej z gotowych procentów tylko dlatego, że łatwo zmieścić ją w osobnej karcie.

Na dashboardzie sprawdzam więc także zachowanie sumy po wybraniu kanału. Jeśli filtr obejmuje jeden wykres, a karta wzrostu pozostaje na całej firmie, musi to być jasno opisane. Inaczej odbiorca może uznać, że duża liczba odnosi się do aktualnego zaznaczenia. Taki błąd interpretacji powstaje nawet przy poprawnych formułach w obu arkuszach.

Co zapisuję przy przekazaniu raportu

Do wyniku dołączam krótką definicję porównania. Wskazuję miarę, poziom miesiąca, zakres historyczny i sposób postępowania z zerową bazą. Dodaję informację, czy bieżący miesiąc jest wyłączony, oraz gdzie sprawdzić kompletność źródła. Dzięki temu osoba utrzymująca raport ma punkt odniesienia przy kolejnym odświeżeniu.

Jeśli źródło zmieni sposób księgowania sprzedaży, sam poprawny LOOKUP nie zachowa porównywalności. Potrzebna jest decyzja, czy przeliczyć historię, oznaczyć zmianę definicji, czy czasowo wstrzymać procent. Zostawiam takie ograniczenie przy raporcie, zamiast liczyć na pamięć autora. Wskaźnik ma być czytelny również za kilka miesięcy, gdy nikt nie będzie już pamiętał dyskusji z pierwszego spotkania.

Jak sprawdzam gotowy widok

Zaczynam od jednego kanału i kilku miesięcy, których wartości potrafię wyjaśnić. Sprawdzam pierwszy okres, zwykły wzrost, spadek, zero bieżące i zero bazowe. Potem dodaję drugi kanał i upewniam się, że serie nie mieszają się na granicy partycji. Dopiero wtedy oglądam całość na osi czasu.

Sprawdzam także zachowanie po sortowaniu. Wzrost ma iść po chronologii, nawet jeśli ktoś chce zobaczyć ranking najlepszych miesięcy. Ranking można pokazać osobno; kolejność użyta do porównania okresów powinna zostać jawna i stabilna. W przeciwnym razie „poprzedni” zaczyna oznaczać sąsiada w rankingu.

Porównuję wartości przed i po zmianie filtra daty. Na końcu odczytuję tytuły, jednostki i opis braku wskaźnika. Puste pole musi być zrozumiałe jako brak sensownej bazy, a nie jako brak zmiany. O samym układaniu czytelnych widoków piszę we wprowadzeniu do Tableau.

Ćwiczenie i materiał wideo

Zacznij od pięciu syntetycznych miesięcy z tabeli. Zbuduj trzy kolumny: Sales, Previous month i MoM. Wyjaśnij różnicę między kwietniowym -100% a majowym brakiem wskaźnika. Następnie usuń luty i sprawdź, jak zmienia się znaczenie poprzedniej pozycji. Przywróć pełną oś, zanim wrócisz do nazwy MoM.

Dla YoY przygotuj trzynaście kolejnych miesięcy. Pierwszemu i ostatniemu przypisz odpowiednio 100 i 150, a pozostałym dowolne małe dodatnie kwoty. Styczeń drugiego roku powinien odwoływać się do stycznia pierwszego. Zobacz, co stanie się po odfiltrowaniu pierwszego roku, i zapisz powód różnicy.

Starszy materiał pokazuje ideę porównywania wartości przez LOOKUP. Warunki dotyczące kompletności miesięcy, kierunku i bazy stosuj tak, jak opisuję powyżej.

Najważniejsze w pigułce

Czy LOOKUP z przesunięciem -12 zawsze daje poprzedni rok?

Nie. Wskazuje wartość dwanaście pozycji wcześniej w partycji. Odpowiada temu samemu miesiącowi rok wcześniej dopiero przy kompletnej, chronologicznej serii miesięcznej i poprawnym kierunku obliczenia.

Dlaczego MoM znika po ustawieniu filtra daty?

Zwykły filtr daty może usunąć miesiąc potrzebny jako baza przed wykonaniem obliczenia tabelarycznego. Zachowaj potrzebną historię i oddziel zakres obliczenia od zakresu prezentacji.

Jaki wzrost pokazać, gdy poprzednia wartość wynosi zero?

Zwykły wzór zmiany procentowej nie ma wtedy określonego wyniku. W przykładzie zostawiam brak wskaźnika i pokazuję kwoty, zamiast zastępować go zerem lub umownym procentem.

Przy pracy nad artykułem użyto w zautomatyzowany sposób sztucznej inteligencji. Jeśli też chcesz tak umieć, sprawdź ten projekt.

Kajo Rudziński

Newsletter KajoData

Zostańmy w kontakcie.

Piszę o analizie danych, uczeniu się i zmianie pracy. Dzielę się tym, co pomaga mi ogarniać technologię i zawodowe decyzje. Jeśli lubisz ten sposób myślenia, zapraszam do mojego newslettera.