Projekt - Analiza Danych - grupa 3

1. Informacje wstępne.

    Zbiór danych poddany analizie dotyczy historycznych sprzedaży supermarketów Biedronka, które zostały
zarejestrowane w trzech różnych oddziałach przez trzy pierwsze miesiące 2019 roku (1.01.2019 - 30.03.2019). 
Zmienne uwzglednione w zbiorze to: 
  - 'Invoice.ID': Numer identyfikacyjny faktury sprzedaży wygenerowany komputerowo; 
  - 'Branch': Oddział supercentrum A, B i C; 
  - 'City': Lokalizacja supercentrów w miastach Naypyitaw, Yangon i Mandalay;
  - 'Customer.type': Typ klientów, zarejestrowanych jako "członek" ("Member") dla klientów korzystających 
     z karty członkowskiej i "normalny" ("Normal") dla klientów nie posiadających karty członkowskiej; 
  - 'Gender': Płeć klienta - kobieta ("Female") i mężczyzna ("Male"); 
  - 'Product.line': Ogólne grupy kategoryzacji przedmiotów - Akcesoria elektroniczne ("Electronic 
     accessories"), Akcesoria modowe ("Fashion accessories"), Żywność i napoje ("Food and beverages"), 
     Zdrowie i uroda ("Health and beauty"), Dom i styl życia ("Home and lifestyle"), Sport i podróże 
     ("Sports and travel"); 
  - 'Unit.price': Cena każdego produktu w $; 
  - 'Quantity': Liczba produktów zakupionych przez klienta; 
  - 'Tax.5.': Opłata podatkowa w wysokości 5% dla klienta dokonującego zakupu;
  - 'Total': Całkowita cena z 5% podatkiem;
  - 'Date': Data zakupu (rekord dostępny od stycznia 2019 r. do marca 2019 r.); 
  - 'Time': Czas zakupu (od 10:00 do 21:00); 
  - 'Payment': Forma płatności wykorzystana przez klienta do zakupu (dostępne są 3 metody - gotówka 
     ("Cash"), karta kredytowa ("Credit card") i portfel elektroniczny ("Ewallet"); 
  - 'cogs': Koszt sprzedanych towarów; 
  - 'gross.margin.percentage': Procentowa marża brutto; 
  - 'gross.income': Dochód brutto; 
  - 'Rating': Ocena stratyfikacji klientów dotycząca ich ogólnego doświadczenia zakupowego 
     (w skali od 1 do 10).

2. Analiza brakujacych obserwacji.

Ze wstępnej analizy wynika, że zbiór danych zawiera 400 brakujących wartości.

Tabela podsumowująca braki

    Powyższa tabela wskazuje rozłożenie brakujących wartości w zbiorze. Największa liczba braków dotyczy kolumn
'gross.income' oraz 'Rating', w których znajdowało się po 150 liczb NA. W kolumnie 'City' natomiast, braki stanowiły 
10% wszystkich obserwacji dla tej zmiennej.

Wizualizacja lokalizacji braków

    Wizualizacja prezentująca lokalizację braków w zbiorze skłania ku stwierdzeniu, że pojawiające się wartości NA
są rozmieszczone w sposób losowy, bez wyraźnych wzorców grupowania się w określonych obszarach zbioru.
    Ponadto braki te stanowią 2,9% wszystkich obserwacji, co wskazuje na ich stosunkowo niewielką liczbę.

Współwystępowanie braków

    W celu dokładniejszej analizy stworzono wykres UpSet, który prezentuje współwystępowanie braków między
zmiennymi. Wynika z niego, że:
  - dla zmiennej 'gross.income' 116 braków (ok. 77.33%) występuje niezależnie od innych zmiennych z brakującymi 
    wartościami. Ponadto 20 braków współwystępuje ze zmienną 'Rating', 13 ze zmienną 'City', a 1 przypadek 
    braku dotyczy wszystkich trzech zmiennych jednocześnie;
  - zmienna 'Rating' posiada 113 braków (ok. 75.33%) niezależnych oraz 16 przypadków współwystępujących 
    ze zmienną 'City';
  - zmienna 'City', poza wskazanymi zależnościami, posiada 70 braków (70%), które nie występują równocześnie 
    w innych rekordach.
    Podsumowując, w analizowanym zbiorze braki najczęściej występują osobno w poszczególnych kolumnach
(299 przypadków NA), ale istnieje określona liczba przypadków, w których braki te współwystępują w dwóch 
(49 przypadków NA) lub trzech kolumnach (1 przypadek NA). Sugerować to może, że istnieje pewna zależność 
między brakami w analizowanych zmiennych, jednak przez wzgląd na ich niewielką liczbę w stosunku do całkowitej
liczby braków (12.5%) – za ich występowanie może odpowiadać przypadek.

    W celu zweryfikowania tej hipotezy, przeprowadza się dalszą analizę brakujących obserwacji. 

    Mapa występowania braków odzwierciedla wskazane przez wykres UpSet zależności. Dodatkowo odczytać z niej 
można, że w 651 wierszach w zbiorze nie występują żadne braki. W pozostałych 349 rekordach pojawiają się 
pojedyncze, podwójne oraz potrójne wartości NA, co zostało wykazane powyżej.

Macierz korelacji braków

    Aby sprawdzić zależności pomiędzy brakującymi obserwacjami a wartościami pozostałych zmiennych, sporządza
się macierz korelacji braków. 
    
    W macierzy korelacji braków kolumny i wiersze reprezentują zmienne ze zbioru, a wartości w macierzy
odpowiadają współczynnikom korelacji między wskaźnikami braków (zmiennymi binarnymi oznaczającymi
obecność braków) lub między wskaźnikami braków a wartościami innych zmiennych. Na jej podstawie można
określić, czy wartości brakujące pojawiają się losowo (MCAR, Missing Completely at Random), 
czy w przypadku silnych korelacji ich występowanie zależy od innych zmiennych (MAR, Missing at Random). 

W celu jej utworzenia, wyróżnia się następujące etapy:
  I. Sprawdzenie struktury danych w zbiorze.
  II. Przekodwoanie wskazanych zmiennych jakościowych na ilościowe.
  III. Obliczenie korelacji między brakami a zmiennymi ze zbioru.
  IV. Wygenerowanie macierzy korelacji braków.

Etap I. Sprawdzenie struktury danych w zbiorze.

    Tabela prezentuje strukturę zmiennych w zbiorze. Ich analiza jest konieczna, aby móc dokonać przekształceń 
zmiennych jakościowych (character) na zmienne ilościowe (numeric, integer) i przejść do etapu obliczania korelacji 
między brakami a zmiennymi. Wybrane zmienne do przekodowania to:
  - 'Ivioice.ID'
  - 'Branch'
  - 'City'
  - 'Customer.type'
  - 'Gender'
  - 'Product.line'
  - 'Date'
  - 'Time'
  - 'Payment'.

Etap II. Przekodwoanie wskazanych zmiennych jakościowych na ilościowe.

data2 <- data.frame(data, row.names = TRUE)

data2$Branch <- ifelse((data2$Branch) == "A", 1, 
                       ifelse(data2$Branch == "B", 2, 0))

data2$City <- ifelse(is.na(data2$City), NA, ifelse(data2$City == "Naypyitaw", 1,
                                                   ifelse(data2$City == "Mandalay", 2, 0)))

data2$Customer.type <- ifelse((data2$Customer.type) == "Member", 1, 0)

data2$Gender <- ifelse((data2$Gender) == "Male", 1, 0)

data2$Product.line <- ifelse(data2$Product.line == "Electronic accessories", 1,
                             ifelse(data2$Product.line == "Fashion accessories", 2,
                                    ifelse(data2$Product.line == "Food and beverage", 3,
                                           ifelse(data2$Product.line == "Health and beauty", 4,
                                                  ifelse(data2$Product.line == "Sports and travel", 5, 0)))))

data2$Payment <- ifelse(data2$Payment == "Cash", 1, 
                        ifelse(data2$Payment == "Credit card", 2, 0))

data2$Date <- as.Date(data2$Date, format = "%m/%d/%Y")
data2 <- data2 %>%
  mutate(Date = month(Date))

data2$Time <- as.numeric(sub(":(\\d{2}):.*", ".\\1", data2$Time))
Na etapie przekodowania zmiennych, dokonano przekształcenia:
  - na zmienne binarne (0,1): 'Customer.type' oraz 'Gender';
  - na zmienne wielokategorialne (w zakresie 0-5): 'Branch' (0,1,2), 'City' (0,1,2), 'Product.line' (0,1,2,3,4,5)
    i 'Payment' (0,1,2).
      
    Ponadto przypisano zmiennej określającej datę zakupu towaru ('Date') odpowiadające jej numery miesiąca (1,2,3),
w celu wydobycia z niej możliwie istotnych informacji (np. konkretny wzorzec występowania braków) oraz przypisano 
zmienną 'Invoice.ID' do nazw wierszy, przez wzgląd na jej niewielką wartość informacyjną.

Etap III. Obliczenie korelacji między brakami a zmiennymi ze zbioru.

    Po utowrzeniu zmiennej binarnej (0,1) reprezentującej wskaźnik braków, gdzie 1 oznacza brak wartości, 
a 0 - jej obecność, obliczono wartość korelacji między danymi wskaźnikami oraz wskaźnikami i wartościami
innych zmiennych.
data_cor <- data2 %>% mutate(gross.margin.percentage = NULL)

NA_cor2 <- cor_mat(data_cor)
    Dla 'gross.margin.percentage' korelacja nie mogła zostać policzona, ze względu na powtarzające sie wartości tej 
zmiennej w każdym kolejnym wierszu, wynikiem czego korelacja skutkowała nieprawidłową wartością NA. Z tego
względu zmienna ta została wykluczona z analizy korelacji, w celach dalszej wizualizacji korelacji braków.

Etap IV. Wygenerowanie macierzy korelacji braków.

    Macierz korelacji braków przedstawiona na wizualizacji wskazuje na istnienie bardzo silnej, dodatniej korelacji między
wartościami brakującymi a wartościami zmiennych: 'Total', 'Tax.5.', 'cogs' oraz 'gross.income' i silnej, dodatniej korelacji
wartości zmiennych: 'cogs', 'Unit.price', 'Quantity' i 'gross.income'. Ponadto zaobserwowano istotną korelację
dodatnią dla zmiennych 'Branch' i 'City'.
    Wyniki te oznaczają, że jeśli jedna ze wskazanych zmiennych posiada brakującą wartość, istnieje duże
prawdopodobieństwo, że pozostałe zmienne również będą zawierać brakujące obserwacje.
    To z kolei sugeruje, że w przypadku zmiennych o charakterze finansowym, takie braki mogą być losowe (MAR),
zależne od innych wartości, lub jeśli wartości były celowo pomijane - nielosowe (NMAR), niezależne od pozostałych
zmiennych. 
    Natomiast w przypadku zmiennych dotyczących lokalizacji sklepów, bardziej prawdopodobne jest, że braki
w zmiennej 'City' mają charakter losowy (MAR). Wynika to z faktu, że konkretna lokalizacja jest powiązana
z danym oddziałem sklepu ('Branch'), więc brak informacji o mieście wynikać może z wcześniej podanej informacji
o oddziale.
    Dodatkowo, braki w zmiennej 'Rating' nie wykazują żadnych zależności z innymi wartościami zmiennych. Na tej
podstawie można przypuszczać, że są to braki typu MCAR i zasadnym jest zastosowanie prostej imputacji danych.

Sprawdzenie zależności występowania braków w zmiennej ‘gross.income’

    W celu sprawdzenia mechanizmu występowania wartości brakujących w zmiennej 'gross.income' oraz dobrania 
do niej odpowiedniej formy imputacji, należy dokonać analizy wykazanych zależności z wartościami zmiennych 
'Total', 'Tax.5.', 'cogs' oraz 'Quantity' i 'Unit.price'.

    Występowanie korelacji pomiędzy wymienionymi zmiennymi można wyjaśnić w prosty sposób, biorąc pod uwagę
definicję wskazanych zmiennych i ich odzwiercielenie faktycznych wartości finansowych. 
Analiza wartości tych zmiennych wykazuje, że:
  - zmienna 'cogs' mówiąca o koszcie wytworzenia sprzedanych towarów jest równa przychodowi ze sprzedaży, a co 
    za tym idzie - iloczynowi ilości sprzedanych produktów ('Quantity') i kosztowi jednostkowemu produktu ('Unit.price'):
    'cogs' = 'Quantity' * 'Unit.price';
  - zmienna 'Tax.5.' mówiąca o opłacie podatkowej od sprzedaży w wysokości 5% jest równa iloczynowi kosztu
    sprzedanych towarów ('cogs') i 5% podatku:
    'Tax.5. = 'cogs' * 5%;
  - zmienna 'Total' mówiąca o całkowitej kwocie do zapłaty przez klienta za pojedynczą fakturę, z uwzglenieniem
    podatku jest równa sumie kosztów sprzedanych towarów ('cogs') i opłacie podatkowej w wysokości 5% ('Tax.5.'):
    'Total' = 'cogs' + 'Tax.5.';
  - zmienna 'gross.income' mówiąca o dochodzie brutto (zysku) za sprzedane towary, która w rzeczywistości
    odzwierciedla różnicę przychodów ze sprzedaży i kosztu sprzedanych produktów, w zbiorze danych jest
    równowartością różnicy całkowitej kwoty do zapłaty z podatkiem ('Total') i kosztów wytworzenia sprzedanych
    produktów ('cogs'):
    'gross.income' = 'Total' - 'cogs'
Jeśli zatem 'Total' = 'cogs' + 'Tax.5.', to 'gross.income' = ('cogs' + 'Tax.5.') - 'cogs' = 'Tax.5.'.

    Tę zależność potwierdza poniższa wizualziacja.

    Histogram przedstawia porównanie rozkładów zmiennych 'gross.income' oraz 'Tax.5.'. Obie zmienne są nałożone
na siebie, w celu umożliwienia bezpośredniego porównania ich kształtu i rozkładu. Ze zbioru obserwacji zmiennej
'gross.income' wykluczono 150 obserwacji brakujących, co nieznacznie zaniża jej rozkład. Zauważyć jednak można,
że dla obu zmiennych, wartości obserwacji skupiają sie w zakresie 0-25, czyniąc je prawostronnie skośnymi. 
Ponadto obserwowalna jest zależność, w której częstość występowania danych wartości dla obu zmiennych 
odzwierciedla niemalże identyczny kształt rozkładu, z wysokimi i niskimi częstościami w tych samych przedziałach.

    W związku z powyższą analizą dotyczącą zależności między brakami zmiennej 'gross.inocme' a zmiennymi 'Total', 
'Tax.5.' oraz 'cogs' można wyciągnąć wniosek, że związek wartości 'gross.income' z wartościami pozostałych
zmiennych wynika z finansowych powiązań między nimi. Dodatkowo, można przyjąć, że wartości zmiennej 
'gross.income' odpowiadają wartościom zmiennej 'Tax.5.' i zasadnym jest zastosowanie imputacji poprzez 
zastąpienie wartości brakujących obserwacjami pełnowartościowej zmiennej.

Sprawdzenie zależności występowania braków w ‘City’ od zmiennej ‘Branch’

    Aby lepiej zrozumieć zależność między wartościami brakujacymi w zmiennej 'City' a wartościami zmiennej 'Branch'
sporządzono powyższy wykres słupkowy. Wskazuje on, że braki w każdym z oddziałów ('Branch') są rozłożone
równomiernie (wynoszą ok. 3.5%), z niewielkimi odchyleniami (ok. 0.47 p. %). Może to świadczyć o tym, że braki 
te nie są zależne od konkretnych oddziałów.
Wynik testu chi-kwadrat
Statistic p_value df
X-squared 1.54 0.46 2
    W ramach sprawdzenia zależności braków zmiennej 'City' od zmiennej 'Branch' wykonano nieparametryczny test 
zależności chi2. Hipotezy dla tesu brzmią następująco:

    H0: Braki w zmiennej 'City' są niezależne od zmiennej 'Branch'.
    HA: Braki w zmiennej 'City' są zależne od zmiennej 'Branch'.
    
    Statystyka chi2 równa 1,54 przy wartości p-value (0,46) większej od przyjętego poziomu istotności (0,05) wykazała, 
że nie ma podstaw do odrzucenia H0 mówiącego o niezależności braków obserwacji zmiennej 'City' od wartości 
zmiennej 'Branch'. 
    Wobec tego, można wskazać, że braki występujące w zmiennej 'City' nie mają statystycznie istotnej zależności 
i można zastosować dla nich prostą imputację danych.

PODSUMOWANIE ANALIZY BRAKUJĄCYCH OBSERWACJI

    Z powyższej analizy dotyczącej obserwacji brakujących w zbiorze danych dotyczącym sprzedaży w trzech sklepach
Biedronka wynika, że wartości NA występują w trzech zmiennych: 'gross.income' (150 przypadków braków), 'Rating'
(150 przypadków braków) oraz 'City' (100 przypadków braków).

    Przedstawione wizualizacje oraz testy wykazały, że braki te najprawdopodobniej są losowe (MAR) lub kompletnie
losowe (MCAR) w przypadku zmiennej finansowej 'gross.income' oraz zmiennej dotyczącej lokalzacji 'City', i kompletnie
losowe (MCAR) w przypadku zmiennej 'Rating'. 
    W zwiazku z tym, zaleca się stosowanie prostej imputacji danych polegającej na uzupełnieniu brakujących wartości 
w zmiennej 'gross.income' wartościami ze zmiennej 'Tax.5.', przypisaniu brakującym wartościom zmiennej 'City'
odpowieniej nazwy miasta w oparciu o oddział 'Branch', jaki jest mu przypisany oraz zastosowaniu np. średniej
lub mediany w uzupełnieniu zmiennej 'Rating', bądź uzupełnianiu jej poprzez wielokrotną imputację, przy pomocy
pakietu "mice" (Multiple Imputation by Chained Equations).

3. Walidacja danych.

    W celu sprawdzenia, czy wartości w zbiorze danych spełniają określone krytera dla zmiennych, których poprawne
zachowanie jest niezbędne do dalszej analizy obejmującej m.in. imputację, wizualizację, wnioskowanie statatystyczne
i testowanie, stosuje się walidację danych. 
    Proces ten polega na definiowaniu reguł, jakie muszą spełnić zmienne w zbiorze, a następnie sprawdzenie, czy
występują w nim jakiekolwiek nieprawidłowości w postaci "brudnych" danych. Jeżeli analiza wykaże obecność takich
wartości, kolejnym etapem jest "czyszczenie" zbioru. Może to obejmować poprawę danych (np. dopasowanie
do prawidłowego formatu) lub usunięcie informacji, które są nieistotne dla badania, a mogą zakłócać działanie
programu i proces dalszej analizy. 

Sprawdzanie poprawności danych zależnych

    Dla analizowanego zbioru danych zdefiniowano reguły walidacyjne, dla wybranych zmiennych zależnych
jakościowych i ilościowych, których nieprawidłowości mogłyby mieć istotny wpływ na dalszą analizę.

Określone reguły przedstawia się następująco:

    Powyższa wizualizacja wskazuje, że w analizowanym zbiorze danych nie występują nieprawidłowości w postaci 
"brudnych" wartości w zmiennych zależnych o określonych regułach.

Sprawdzenie poprawności zmiennych kategorycznych

    Ponadto można stweirdzić, że zbiór ten nie posiada również nieprawidłowości w postaci m.in. literówek 
w wartościach zmiennych kategorycznych.

Sprawdzenie występowania duplikatów rekordów

W zbiorze tym nie występują również duplikaty wierszów. 

PODSUMOWANIE WALIDACJI DANYCH

    Z powyższej analizy dotyczącej identyfikacji nieprawidłowości w zbiorze danych dotyczącym sprzedaży w trzech 
sklepach Biedronka wynika, że wartości zmiennych są poprawne i nie wymagają poddania procesowi czyszczenia
danych (Data Cleansing).

4. Czyszczenie danych z brakujacych obserwacji.

    Poniższy kod uzupełnia brakujące wartości w kolumnach, wykorzystując zależności między zmiennymi i proces 
imputacji. 

Wobec tego:
  - kolumna 'City' została uzupełniona na podstawie jednoznacznej relacji z kolumną 'Branch';
  - braki w kolumnie 'gross.income' zastąpiono wartościami z kolumny 'Tax.5.', ponieważ dane te były tożsame; 
  - braki w kolumnie 'Rating' uzupełniono za pomocą imputacji z pakietu "mice", wykorzystując metodę dopasowania 
    predyktywnego ("pmm").
# Mapowanie relacji między 'Branch' a 'City'
branch_to_city <- data %>%
  filter(!is.na(City)) %>%
  distinct(Branch, City) %>%
  group_by(Branch) %>%
  summarize(City = first(City))

# Łączenie danych, aby wypełnić brakujące wartości w kolumnie 'City'
data <- data %>%
  left_join(branch_to_city, by = "Branch", suffix = c("", ".y")) %>%
  mutate(City = ifelse(is.na(City), City.y, City)) %>%
  select(-City.y)

# Sprawdzanie liczby brakujących wartości w kolumnie 'City'
sum(is.na(data$City))
## [1] 0
# Sprawdzanie dostępnych kolumn
colnames(data)
##  [1] "Invoice.ID"              "Branch"                 
##  [3] "City"                    "Customer.type"          
##  [5] "Gender"                  "Product.line"           
##  [7] "Unit.price"              "Quantity"               
##  [9] "Tax.5."                  "Total"                  
## [11] "Date"                    "Time"                   
## [13] "Payment"                 "cogs"                   
## [15] "gross.margin.percentage" "gross.income"           
## [17] "Rating"
# Zastępowanie brakujących wartości w kolumnie 'gross.income' wartością z kolumny 9
data <- data %>%
  mutate(`gross.income` = ifelse(is.na(`gross.income`), data[[9]], `gross.income`))

# Sprawdzanie liczby brakujących wartości w kolumnie 'gross income'
sum(is.na(data$`gross.income`))
## [1] 0
# Imputacja brakujących wartości w zmiennej 'Rating' za pomocą pakietu 'mice'
imputed_data <- mice(data, m = 1, method = "pmm", maxit = 50, seed = 123)
## 
##  iter imp variable
##   1   1  Rating
##   2   1  Rating
##   3   1  Rating
##   4   1  Rating
##   5   1  Rating
##   6   1  Rating
##   7   1  Rating
##   8   1  Rating
##   9   1  Rating
##   10   1  Rating
##   11   1  Rating
##   12   1  Rating
##   13   1  Rating
##   14   1  Rating
##   15   1  Rating
##   16   1  Rating
##   17   1  Rating
##   18   1  Rating
##   19   1  Rating
##   20   1  Rating
##   21   1  Rating
##   22   1  Rating
##   23   1  Rating
##   24   1  Rating
##   25   1  Rating
##   26   1  Rating
##   27   1  Rating
##   28   1  Rating
##   29   1  Rating
##   30   1  Rating
##   31   1  Rating
##   32   1  Rating
##   33   1  Rating
##   34   1  Rating
##   35   1  Rating
##   36   1  Rating
##   37   1  Rating
##   38   1  Rating
##   39   1  Rating
##   40   1  Rating
##   41   1  Rating
##   42   1  Rating
##   43   1  Rating
##   44   1  Rating
##   45   1  Rating
##   46   1  Rating
##   47   1  Rating
##   48   1  Rating
##   49   1  Rating
##   50   1  Rating
# Wybór ukończonego zestawu danych
data <- complete(imputed_data, 1)

# Sprawdzanie liczby brakujących wartości w całym zbiorze danych po imputacji
sum(is.na(data))
## [1] 0

5. Wartości Odstające.

    Wartości odstające to obserwacje znacząco odbiegające od reszty danych, które mogą zniekształcać wyniki
analiz statystycznych. Aby zminimalizować ich wpływ, przeprowadzono analizę zmiennych 'Unit.price', 'Total',
'Quantity' i 'Rating'.
# Rysowanie boxplotów dla wybranych zmiennych
b1 <- ggplot(data, aes(y = Unit.price)) +
  geom_boxplot() +
  labs(title = "Boxplot: Unit Price") +
  theme_minimal()

b2 <- ggplot(data, aes(y = Total)) +
  geom_boxplot() +
  labs(title = "Boxplot: Total") +
  theme_minimal()

# Rysowanie histogramów dla wybranych zmiennych
h1 <- ggplot(data, aes(x = Unit.price)) +
  geom_histogram(bins = 30, fill = "#0c4c8a") +
  labs(title = "Histogram: Unit Price", x = "Unit Price", y = "Frequency") +
  theme_minimal()

h2 <- ggplot(data, aes(x = Total)) +
  geom_histogram(bins = 30, fill = "#0c4c8a") +
  labs(title = "Histogram: Total", x = "Total", y = "Frequency") +
  theme_minimal()

# Wyświetlenie wykresów w siatce 2x2
grid.arrange(b1, b2, h1, h2, nrow = 2)

replace_outliers_with_median <- function(column) {
  Q1 <- quantile(column, 0.25, na.rm = TRUE)
  Q3 <- quantile(column, 0.75, na.rm = TRUE)
  IQR <- Q3 - Q1
  lower_bound <- Q1 - 1.5 * IQR
  upper_bound <- Q3 + 1.5 * IQR
  column[column < lower_bound | column > upper_bound] <- median(column, na.rm = TRUE)
  return(column)
}
    W przypadku analizowanych zmiennych 'Unit.price' i 'Total' zaobserwowano obecność wartości odstających.

    Dla zmiennej 'Unit.price' mediana wynosi około 55 dolarów, natomiast wartości maksymalne przekraczają 100 
dolarów, co wskazuje na obecność wyjątkowo wysokich wartości, które znacznie przewyższają typowy zakres cen 
jednostkowych produktów.

    Dla zmiennej 'Total' mediana oscyluje w granicach 250 dolarów, podczas gdy wartość maksymalna wynosi ponad 
1000 dolarów. Tak duże różnice sugerują, że pewne transakcje znacząco odbiegają od typowego poziomu całkowitych 
kwot zakupów.

    Obecność takich wartości odstających może mieć istotny wpływ na wyniki analiz statystycznych, szczególnie 
w przypadku miar wrażliwych na ekstremalne wartości, takich jak średnia arytmetyczna. Aby zminimalizować ich 
wpływ i poprawić jakość dalszej analizy danych, wartości odstające zostały zastąpione medianą zmiennych.

    Działanie to pozwala na bardziej reprezentatywną ocenę danych, co może mieć kluczowe znaczenie w kontekście 
analizy zachowań klientów, segmentacji rynku lub przewidywania przyszłych trendów sprzedażowych.

Wyświetlanie wartości odstających dla zmiennej ‘Total’

## [1] 167 168 351 358 423 558 700 793 997
Wartości odstające zostały zastąpione poprzez medianę wartości zmiennej.

PODSUMOWANIE ANALIZY WARTOŚCI ODSTAJĄCYCH

    Zastąpienie wartości odstających w danych pozwala na uzyskanie bardziej reprezentatywnych wyników, eliminując 
wpływ skrajnych wartości, które mogą zniekształcać analizy. Dzięki temu modelowanie i wnioskowanie staje się 
bardziej precyzyjne, a interpretacja danych jest łatwiejsza i bardziej wiarygodna. Takie podejście pomaga lepiej 
uchwycić rzeczywiste zależności w analizowanej próbie.

6. Statystyki opisowe.

statystyki <- function(x) {
  data.frame(
    "Min" = min(x, na.rm = TRUE),
    "Max" = max(x, na.rm = TRUE),
    "Kwartyl dolny" = quantile(x, 0.25, na.rm = TRUE),
    "Mediana" = round(median(x, na.rm = TRUE), 2),
    "Kwartyl górny" = quantile(x, 0.75, na.rm = TRUE),
    "Średnia" = round(mean(x, na.rm = TRUE), 2),
    "Odch. std." = round(sd(x, na.rm = TRUE), 2),
    "IQR" = round(IQR(x, na.rm = TRUE), 2),
    "Odchylenie ćwiartkowe" = round(IQR(x, na.rm = TRUE) / 2, 2),
    "Odch. std. w %" = round((sd(x, na.rm = TRUE) / mean(x, na.rm = TRUE)) * 100, 2),
    "Odch. ćwiartkowe w %" = round((IQR(x, na.rm = TRUE) / median(x, na.rm = TRUE)) * 100, 2),
    "Skośność" = round(skewness(x, na.rm = TRUE), 2),
    "Kurtoza" = round(kurtosis(x, na.rm = TRUE), 2)
  )
}

Statystyki dla zmiennej ‘Total’ według płci (‘Gender’)

# Obliczenie statystyk
statystyki_total <- data %>%
  group_by(Gender) %>%
  summarise(across(Total, statystyki)) %>%
  unnest(cols = c(Total))

# Przekształcenie danych na format długi
tabela_total <- statystyki_total %>%
  pivot_longer(cols = -Gender, names_to = "Statystyka", values_to = "Wartość") %>%
  pivot_wider(names_from = Gender, values_from = Wartość)

# Wyświetlenie tabel
knitr::kable(tabela_total,
             digits = 2,
             align = "lcc",
             caption = "Tabela 1. Statystyki dla 'Total' wg płci.",
             col.names = c("Statystyka", "Kobiety", "Mężczyźni"))
Tabela 1. Statystyki dla ‘Total’ wg płci.
Statystyka Kobiety Mężczyźni
Min 12.69 10.68
Max 951.82 950.25
Kwartyl.dolny 132.76 117.95
Mediana 264.76 244.23
Kwartyl.górny 478.23 453.18
Średnia 325.87 306.17
Odch..std. 237.61 235.63
IQR 345.47 335.23
Odchylenie.ćwiartkowe 172.74 167.62
Odch..std..w.. 72.91 76.96
Odch..ćwiartkowe.w.. 130.49 137.26
Skośność 0.78 0.93
Kurtoza 2.66 2.95
Tabela przedstawia statystyki zmiennej 'Total' dla kobiet i mężczyzn. 

Na jej podstawie stwierdzić można, że:
  - Wartości minimalne i maksymalne są podobne w obu grupach, co sugeruje zbliżony zakres danych.
  - Mediana i kwartyle pokazują, że kobiety osiągają nieco wyższe wartości 'Total' niż mężczyźni 
    (mediana: 272,58 vs. 244,23). Podobny trend widać w średniej, co oznacza, że ogólnie wartości
    zmiennej 'Total' są wyższe dla kobiet.
  - Zmienność wyników w obu grupach jest porównywalna – wskazują na to zbliżone wartości odchylenia 
    standardowego i rozstępu międzykwartylowego (IQR). 
  - Skośność dodatnia (0,83 dla kobiet, 0,96 dla mężczyzn) oznacza, że rozkłady są asymetryczne 
    w prawo – większość wartości jest niższa, ale pojawiają się pojedyncze wysokie obserwacje.
  - Kurtoza (2,81 dla kobiet, 3,04 dla mężczyzn) sugeruje, że rozkłady mają umiarkowanie grubsze 
    ogony niż rozkład normalny.

Statystyki dla ‘gross.income’ według płci (‘Gender’)

# Obliczenie statystyk
statystyki_income <- data %>%
  group_by(Gender) %>%
  summarise(across(gross.income, statystyki)) %>%
  unnest(cols = c(gross.income))

# Przekształcenie danych na format długi
tabela_income <- statystyki_income %>%
  pivot_longer(cols = -Gender, names_to = "Statystyka", values_to = "Wartość") %>%
  pivot_wider(names_from = Gender, values_from = Wartość)

# Wyświetlenie tabel
knitr::kable(tabela_income,
             digits = 2,
             align = "lcc",
             caption = "Tabela 2. Statystyki dla 'gross.income' wg płci.",
             col.names = c("Statystyka", "Kobiety", "Mężczyźni"))
Tabela 2. Statystyki dla ‘gross.income’ wg płci.
Statystyka Kobiety Mężczyźni
Min 0.60 0.51
Max 49.65 49.49
Kwartyl.dolny 6.32 5.62
Mediana 12.98 11.63
Kwartyl.górny 23.16 21.75
Średnia 15.96 14.80
Odch..std. 11.87 11.52
IQR 16.84 16.14
Odchylenie.ćwiartkowe 8.42 8.07
Odch..std..w.. 74.40 77.87
Odch..ćwiartkowe.w.. 129.75 138.76
Skośność 0.83 0.96
Kurtoza 2.81 3.04
Tabela przedstawia statystyki dotyczące gross.income w podziale na płeć.

Na jej podstawie stwierdzić można, że:
  - Mediana oraz kwartyle pokazują, że kobiety osiągają nieco wyższe wartości Gross Income niż
    mężczyźni (mediana: 13,57 vs. 11,22), co znajduje odzwierciedlenie również w średniej (16,03
    vs. 14,83).
  - Zmienność w obu grupach jest porównywalna – świadczą o tym podobne wartości odchylenia
    standardowego oraz rozstępu międzykwartylowego (IQR). 
  - Dodatnia skośność (0,83 dla kobiet, 0,96 dla mężczyzn) sugeruje, że w obu przypadkach rozkład
    jest asymetryczny w prawo, czyli większość wartości jest stosunkowo niska, ale pojawiają się
    pojedyncze wysokie obserwacje. 
  - Kurtoza (2,90 dla kobiet, 3,03 dla mężczyzn) wskazuje, że rozkład ma nieco grubsze ogony niż
    rozkład normalny, co oznacza większą liczbę wartości skrajnych.

Statystyki dla ‘Rating’ według typu klienta (‘Customer.type’)

# Obliczenie statystyk
statystyki_rating <- data %>%
  group_by(Customer.type) %>%
  summarise(across(Rating, statystyki)) %>%
  unnest(cols = c(Rating))

# Przekształcenie danych na format długi
tabela_rating <- statystyki_rating %>%
  pivot_longer(cols = -Customer.type, names_to = "Statystyka", values_to = "Wartość") %>%
  pivot_wider(names_from = Customer.type, values_from = Wartość)

# Wyświetlenie tabel
knitr::kable(tabela_rating,
             digits = 2,
             align = "lcc",
             caption = "Tabela 3. Statystyki dla 'Rating' wg typu klienta.",
             col.names = c("Statystyka", "Normal", "Member"))
Tabela 3. Statystyki dla ‘Rating’ wg typu klienta.
Statystyka Normal Member
Min 4.00 4.00
Max 10.00 10.00
Kwartyl.dolny 5.40 5.60
Mediana 6.90 7.00
Kwartyl.górny 8.40 8.40
Średnia 6.90 6.99
Odch..std. 1.73 1.69
IQR 3.00 2.80
Odchylenie.ćwiartkowe 1.50 1.40
Odch..std..w.. 25.01 24.12
Odch..ćwiartkowe.w.. 43.48 40.00
Skośność 0.03 0.00
Kurtoza 1.85 1.88
    Tabela przedstawia statystyki dotyczące ocen ('Rating') wystawianych przez klientów w podziale
na typ (Normal i Member). 

Na jej podstawie stwierdzić można, że:
  - Zakres ocen w obu grupach jest identyczny (od 4,00 do 10,00). Mediana i kwartyle wskazują, że
    członkowie programu lojalnościowego (Member) wystawiają nieco wyższe oceny niż klienci zwykli
    (Normal), choć różnice są niewielkie (mediana: 7,10 vs. 7,00). Średnia również jest
    minimalnie wyższa dla członków (7,05 vs. 6,97).
  - Rozkłady ocen w obu grupach są bardzo podobne – zarówno odchylenie standardowe, jak i rozstęp
    międzykwartylowy (IQR) mają zbliżone wartości. Skośność bliska zeru (-0,01 dla Normal, -0,02
    dla Member) oznacza, że rozkłady są niemal symetryczne. 
  - Kurtoza (1,84 dla Normal, 1,83 dla Member) wskazuje na spłaszczony kształt rozkładu w
    porównaniu do rozkładu normalnego, co oznacza mniejszą liczbę skrajnych ocen.

Statystyk dla ‘Unit.price’ według kategorii produktów (‘Product.line’)

# Obliczenie statystyk
statystyki_unit_price <- data %>%
  group_by(Product.line) %>%
  summarise(across(Unit.price, statystyki)) %>%
  unnest(cols = c(Unit.price))

# Przekształcenie danych na format długi
tabela_unit_price <- statystyki_unit_price %>%
  pivot_longer(cols = -Product.line, names_to = "Statystyka", values_to = "Wartość") %>%
  pivot_wider(names_from = Product.line, values_from = Wartość)

# Wyświetlenie tabel
knitr::kable(tabela_unit_price,
             digits = 2,
             align = "lcc",
             caption = "Tabela 4. Statystyki dla 'Unit Price' wg kategorii produktów.",
             col.names = c("Statystyka", unique(data$Product.line)))
Tabela 4. Statystyki dla ‘Unit Price’ wg kategorii produktów.
Statystyka Health and beauty Electronic accessories Home and lifestyle Sports and travel Food and beverages Fashion accessories
Min 10.56 10.18 10.13 10.08 10.53 10.17
Max 99.73 99.89 99.79 99.96 99.92 99.96
Kwartyl.dolny 27.98 35.52 33.47 32.42 34.31 34.42
Mediana 51.50 55.09 54.00 57.41 55.59 58.65
Kwartyl.górny 75.90 81.10 78.74 76.13 77.52 80.68
Średnia 53.55 57.15 56.01 54.85 55.32 56.99
Odch..std. 26.75 26.67 26.27 26.35 26.21 26.91
IQR 47.92 45.58 45.27 43.71 43.21 46.26
Odchylenie.ćwiartkowe 23.96 22.79 22.63 21.85 21.61 23.13
Odch..std..w.. 49.95 46.66 46.90 48.04 47.38 47.21
Odch..ćwiartkowe.w.. 93.04 82.74 83.84 76.14 77.73 78.88
Skośność 0.10 0.01 0.06 -0.07 -0.01 -0.06
Kurtoza 1.70 1.81 1.81 1.85 1.80 1.72
    Tabela przedstawia statystyki dotyczące Unit Price (ceny jednostkowej) w podziale na
kategorie produktów. 

Na jej podstawie stwierdzić można, że:
  - Wszystkie kategorie mają podobny zakres cen – wartości minimalne wahają
    się od 10,08 (Sports and travel) do 10,56 (Health and beauty), natomiast maksymalne ceny są
    bardzo zbliżone i mieszczą się w przedziale 99,73–99,96.
  - Mediana ceny jednostkowej jest najwyższa dla Fashion accessories (58,65) oraz Sports and
    travel (57,41), a najniższa dla Home and lifestyle (54,00). Średnie wartości są również do
    siebie zbliżone, ale najwyższą średnią cenę mają Electronic accessories (57,15), a najniższą
    Sports and travel (54,85) oraz Food and beverages (55,32).
  - Odchylenie standardowe we wszystkich grupach jest bardzo podobne – waha się od 26,21 (Food
    and beverages) do 26,91 (Fashion accessories), co wskazuje na zbliżoną zmienność cen w każdej
    kategorii. Rozstęp międzykwartylowy (IQR) również pokazuje, że ceny w poszczególnych
    kategoriach nie różnią się znacznie pod względem rozproszenia – najwyższy IQR ma Health and
    beauty (47,92), a najniższy Food and beverages (43,21).
  - Skośność we wszystkich przypadkach jest bliska zeru, co oznacza, że rozkłady cen są
    symetryczne – nie występuje wyraźne przesunięcie w stronę niższych lub wyższych wartości.
  - Kurtoza we wszystkich kategoriach mieści się w przedziale 1,70–1,85, co oznacza, że rozkłady
    cen są lekko spłaszczone w porównaniu do rozkładu normalnego. Wskazuje to na mniejszą liczbę
    wartości skrajnych, czyli rzadziej występujące wyjątkowo niskie lub wysokie ceny.

7. Wykresy.

Wykres kołowy

    Wykres kołowy prezentuje preferencje metody płatności wezględu na płeć. Wynika z niego, że mężczyźni wolą 
płacić karta debetową, kobiety natomiast preferują płatności gotówką.

Histogram i wykres pudełkowy

    Histogram przedstawia rozkład ocen w poszczególnych miastach, pokazując, jak często występują określone 
wartości ocen. Dzięki niemu możemy łatwo zauważyć ogólny kształt rozkładu, jego skośność oraz ewentualne 
wartości odstające.
    
    Z kolei wykres pudełkowy (boxplot) pozwala lepiej zobaczyć rozkład danych pod kątem ich mediany, kwartylów 
oraz wartości odstających. Środkowa linia w pudełku reprezentuje medianę ocen, a granice pudełka pokazują
zakres między pierwszym a trzecim kwartylem. Wąsy wskazują wartości minimalne i maksymalne, pomijając
odstające obserwacje, które są zaznaczone jako osobne punkty. Wykres pudełkowy ułatwia szybkie porównanie 
mediany ocen między różnymi miastami oraz identyfikację ewentualnych różnic w rozproszeniu danych.
# Tworzenie histogramu
# Wyświetlenie wykresów obok siebie
grid.arrange(plot_female, plot_male, ncol = 2)

# Oddzielne histogramy dla każdego miasta
ggplot(data, aes(x = Rating)) +
  geom_histogram(bins = 30, fill = "#69b3a2", color = "black", alpha = 0.8) +
  facet_wrap(~ City, scales = "free_y") +  # Oddzielne panele dla każdego miasta
  labs(
    title = "Rozkład ocen (Rating) w zależności od miasta",
    x = "Ocena (Rating)",
    y = "Liczba obserwacji"
  ) +
  theme_minimal() +
  theme(
    strip.text = element_text(size = 12, face = "bold"),  # Wyraźne etykiety miast
    axis.text = element_text(size = 10),
    axis.title = element_text(size = 12)
  )

# Rozkład dla oceny 
ggplot(data, aes(x = City, y = Rating, fill = City)) +
  geom_boxplot(alpha = 0.8) +
  labs(
    title = "Porównanie ocen (Rating) w zależności od miasta",
    x = "Miasto",
    y = "Ocena (Rating)",
    fill = "Miasto"
  ) +
  theme_minimal() +
  scale_fill_brewer(palette = "Pastel1")

Wykres słupkowy

    Wykres słupkowy przedstawia średnią sprzedaż dla każdej linii produktów, co pozwala na szybkie porównanie
wyników poszczególnych kategorii. Słupki mają kolor niebieski, a ich wysokość odpowiada wartości średniej 
sprzedaży w danej linii produktów.
# Tworzenie wykresu słupkowego 
# Obliczanie średniej sprzedaży dla każdej linii produktów
average_sales <- aggregate(Total ~ Product.line, data = data, mean)

# Zwiększenie marginesów dla większej przestrzeni na etykiety
par(mar = c(8, 4, 4, 2) + 0.1)

# Tworzenie wykresu słupkowego z bardziej czytelnymi etykietami
barplot(
  average_sales$Total, 
  names.arg = average_sales$Product.line, 
  col = "lightblue",  # Kolor słupków
  main = "Średnia sprzedaż według linii produktów", 
  xlab = "",          # Usuń opis osi X, aby nie dublować etykiet
  ylab = "Średnia sprzedaż",
  las = 2,            # Pionowe etykiety osi X
  cex.names = 0.6     # Zmniejszenie rozmiaru tekstu etykiet
)

# Dodanie opisu osi X poniżej wykresu
mtext("Linia produktów", side = 1, line = 7, cex = 1.2)

Wykres typu “heatmapa”

    Wykres typu heatmapa przedstawia średnie oceny (Rating) w zależności od miasta i płci. Kolor kafelków
odzwierciedla wartość średniej oceny – jaśniejsze odcienie oznaczają niższe wartości, a ciemniejsze wyższe.
# Tworzenie wykresu typu "heatmapa"
# Agregowanie danych
heatmap_data <- data %>%
  group_by(City, Gender) %>%
  summarise(Average_Rating = mean(Rating, na.rm = TRUE)) %>%
  ungroup()
## `summarise()` has grouped output by 'City'. You can override using the
## `.groups` argument.
# Tworzenie wykresu
ggplot(heatmap_data, aes(x = Gender, y = City, fill = Average_Rating)) +
  geom_tile(color = "white") +
  labs(
    title = "Średnie oceny (Rating) w zależności od miasta i płci",
    x = "Płeć",
    y = "Miasto",
    fill = "Średnia ocena"
  ) +
  theme_minimal() +
  scale_fill_gradient(low = "lightblue", high = "darkblue")

Wykres linowy

    Wykres liniowy przedstawia trend sprzedaży w czasie, umożliwiając obserwację zmian w całkowitej sprzedaży 
na przestrzeni dni. Linia łączy punkty reprezentujące dzienne sumy sprzedaży, co pozwala na łatwe dostrzeżenie 
wzorców, takich jak okresowe wzrosty i spadki.
# Tworzenie wykresu trendów 
# Konwersja kolumny 'Date' na format daty
data$Date <- as.Date(data$Date, format = "%m/%d/%Y")

# Grupowanie danych według daty i obliczanie całkowitej sprzedaży
daily_sales <- aggregate(Total ~ Date, data = data, sum)

# Tworzenie wykresu liniowego
plot(
  daily_sales$Date, 
  daily_sales$Total, 
  type = "l",             # Typ wykresu: linia
  col = "blue",           # Kolor linii
  lwd = 2,                # Grubość linii
  main = "Sprzedaż w czasie", 
  xlab = "Data", 
  ylab = "Całkowita sprzedaż"
)

# Dodanie punktów na wykresie dla lepszej widoczności
points(
  daily_sales$Date, 
  daily_sales$Total, 
  col = "black",            # Kolor punktów
  pch = 16                # Typ punktów: kropki
)

Porównanie ‘Total’ i ‘Branch’

Wykres pudełkowy przedstawia porównanie wartości 'Total' dla trzech gałęzi (A, B, C).
  
Każda gałąź ma podobnyrozkład wartości, z medianą na zbliżonym poziomie. 
Występują wartości odstające (outliers) powyżej 1000. 
Rozstęp międzykwartylowy (IQR) jest podobny dla wszystkich gałęzi, co sugeruje względnie równomierne
rozproszenie danych.
# Porównanie Total wg gałęzi
ggplot(data, aes(x = Branch, y = Total, fill = Branch)) +
  geom_boxplot() +
  labs(title = "Porównanie 'Total' wg gałęzi", x = "Gałęzie", y = "Total")

Rozkład ‘gross income’ i ‘customer type’

Większość transakcji generuje niskie wartości 'gross.income' (głównie poniżej 10), co widać po wysokich
słupkach na początku osi X. 
Rozkład jest prawostronnie skośny – im wyższy Gross Income, tym rzadsze transakcje. 
Klienci Normal (turkusowy kolor) mają więcej transakcji o niższych wartościach Gross Income, ale ich
rozkład jest zbliżony do członków Member (czerwony kolor).
ggplot(data, aes(x = gross.income, fill = Customer.type)) +
  geom_histogram(bins = 20, alpha = 0.7, position = "identity") +
  labs(title = "Rozkład 'Gross Income' wg typu klienta", x = "Gross Income", y = "Liczba transakcji")

Rozkład ‘Rating’ według płci (‘Gender’)

Wykres przedstawia rozkład ocen w zależności od płci (Female – czerwony, Male – turkusowy).
  
Ogólny rozkład ocen dla obu płci jest podobny, ale są pewne różnice w gęstości.
Mężczyźni (turkusowy) mają większą koncentrację ocen wokół 6-7, co oznacza, że częściej wystawiają oceny 
w tym zakresie.
Kobiety (czerwony) mają więcej ocen w skrajnych wartościach – widoczny jest nieco większy udział ocen 
w okolicach 4-5 oraz 9-10.

Ogólnie, różnice nie są duże, ale kobiety częściej wystawiają zarówno bardzo niskie, jak i bardzo wysokie oceny,
a mężczyźni częściej oceniają w średnim zakresie.
ggplot(data, aes(x = Rating, fill = Gender)) +
  geom_density(alpha = 0.5) +
  labs(title = "Rozkład ocen wg płci", x = "Ocena", y = "Gęstość")

Porównanie ‘gross.income’ i płci (‘Gender’)

Wykres przedstawia porównanie dochodów brutto ze względu na płeć. 
    
Mediana dochodów kobiet i mężczyzn jest na zbliżonym poziomie, co sugeruje brak istotnych różnic 
w przeciętnych zarobkach między grupami. 
Rozkład dochodów w obu przypadkach jest podobny, choć widać kilka wartości odstających, wskazujących 
na jednostki z wyraźnie wyższymi zarobkami. 

Ogólnie dochody obu płci mają porównywalną strukturę.
ggplot(data, aes(x = Gender, y = gross.income, fill = Gender)) +
  geom_boxplot() +
  labs(title = "Gross Income wg płci", x = "Płeć", y = "Gross Income")

Porównanie ‘Customer.type’ i ‘Total’

Wykres przedstawia porównanie całkowitej wartości zakupów w zależności od typu klienta.
    
Mediana wydatków dla członków programu lojalnościowego (Member) i klientów standardowych (Normal) jest 
na podobnym poziomie, co sugeruje brak istotnych różnic w przeciętnych wartościach zakupów. 
Rozkład wydatków jest zbliżony dla obu grup, choć występują pojedyncze wartości odstające wskazujące na
wyjątkowo wysokie zakupy.

Ogólnie rzecz biorąc, typ klienta nie wydaje się mieć dużego wpływu na poziom wydatków.
ggplot(data, aes(x = Customer.type, y = Total, fill = Customer.type)) +
  geom_boxplot() +
  labs(title = "Total wg typu klienta", x = "Typ klienta", y = "Total")

Porównanie ‘Rating’ i ‘Branch’

Wykres przedstawia porównanie ocen (Rating) dla trzech różnych gałęzi (A, B, C). 
    
Mediany ocen we wszystkich gałęziach są zbliżone, co sugeruje, że poziom ocen klientów jest podobny
niezależnie od oddziału. Rozkład ocen jest szeroki, co oznacza, że w każdej gałęzi występują zarówno niskie,
jak i wysokie oceny. 

Ogólnie rzecz biorąc, nie widać znaczących różnic w ocenach między oddziałami.
ggplot(data, aes(x = Branch, y = Rating, fill = Branch)) +
  geom_boxplot() +
  labs(title = "Porównanie 'Rating' wg gałęzi", x = "Gałęzie", y = "Rating")

Porównanie ‘gross.income’ i ‘Product.line’

Wykres przedstawia porównanie dochodu brutto ("Gross Income") w różnych kategoriach produktów.
    
Większość kategorii produktów ma podobną medianę wartości dochodu brutto, co sugeruje, że przeciętny dochód 
dla różnych typów produktów jest zbliżony. 
Szerokość pudełek jest podobna w większości kategorii, co oznacza porównywalną zmienność danych. 
W każdej kategorii występują wartości odstające, co sugeruje, że w niektórych przypadkach dochód brutto był 
wyjątkowo wysoki.

Ogólnie rzecz biorąc, różnice między kategoriami produktów nie są znaczące, co sugeruje, że żadna z nich nie 
wyróżnia się wyraźnie pod względem dochodu brutto.
ggplot(data, aes(x = Product.line, y = gross.income, fill = Product.line)) +
  geom_boxplot() +
  labs(title = "Porównanie 'Gross Income' wg kategorii produktów", x = "Kategoria produktu", y = "Gross Income") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

8. Wnioskowanie statystyczne.

    Końcowa analiza zbioru danych dotyczącego sprzedaży w trzech sklepach Biedronka polega na przeprowadzeniu
testów parametrycznych i nieparametrycznych w celu zrozumienia określonych wartości zmiennych.

    Zmienne ilościowe brane pod uwagę przy testowaniu to: 'Rating', Unit.price', 'Quantity' i 'Total', natomiast 
zmienne kategoryczne to: 'City', 'Customer.type' i 'Payment'.

Testowanie normalności rozkładów

    Testowanie normalności rozkładów zmiennych opiera się na statystyce Shapiro-Wilka oraz wykresie Q-Q 
(Quantile-Quantile), porównującym rozkład empiryczny danej zmiennej z rozkładem normalnym.

    Hipotezy dla testu Shapiro-Wilka brzmią następująco:
    
    H0: Badana zmienna posiada rozkład normalny wartości.
    HA: Badana zmienna nie posiada rozkładu normalnego wartości.

> Zmienna ‘Rating’

Test Shapiro-Wilka
Statystyka p_value
W 0.96 0

> Zmienna ‘Unit.price’

Test Shapiro-Wilka
Statystyka p_value
W 0.95 0

> Zmienna ‘Quantity’

Test Shapiro-Wilka
Statystyka p_value
W 0.93 0

> Zmienna ‘Total’

Test Shapiro-Wilka
Statystyka p_value
W 0.91 0

    Testy normalności rozkładów zmiennych: 'Rating', 'Unit.price', 'Quantity' oraz 'Total' wykazały, że są to zmienne
nie posiadające rozkładów normalnych swoich wartości. 
    Wniosek ten uzasadnia statystyka Shapiro-Wilka, która w przypadku każdej zmiennej wyniosła ok. 0.96,
a odpowiadająca jej wartość p-value przyjęła wartość niższą od przyjętego poziomu istotności (0 < 0,05), czym 
wykazała, że istnieją przesłanki, aby odrzucić H0 mówiącą o normalności rozkładu wartości badanych zmiennych.
    Ponadto wykresy Q-Q dla wymienionych zmiennych nie przyjęły postaci linii prostej, znacznie odchylając się od 
rozkładu normalnego, czym również przyczyniły się do wsparcia hipotezy o braku rozkładu normalnego zmiennych 
'Rating', 'Unit.price', 'Quantity' oraz 'Total'.

    Wobec powyższego przyjmuje się, że dalsze analizowanie zmiennych opierać się będzie o testy nieparametryczne.

Testy nieparametryczne dla wybranych zmiennych ilościowych i kategorycznych

Histogramy i test Wilcoxona

Przedstatwione wyżej histogramy dla wybranych zmiennych ilościowych wykazały, że:
  - rozkład wartości dla zmiennej 'Rating' jest lewostronnie skośny, gdyż większość wartości skupia się po prawej
    stronie od mediany równej 5.5. Ponadto najczęściej przyznawaną oceną dla sklepu było 6 (17,5%
    klientów), a najrzadsze oceny miały zakres 1-3,9 (0% klientów).
  - rozkład wartości dla zmiennej 'Unit.price' nie wykazuje obserwowalnego skupienia po którejś ze stron mediany
    równej 55,23. Oznacza to, że ceny produktów były mniej więcej podobne, istnieją jednak pojedyncze odstępstwa
    od tych wartości;
  - rozkład wartości dla zmiennej 'Quantity' jest nieznacznie prawostronnie skośny od mediany równej 5, co świadczyć
    może, że zwyczajowa liczba produktów kupowana przez badanych klientów była większa niż 5. Ponadto największa
    liczba klientów (ok. 11,5%) kupowała 10 sztuk towaru w danej lokalizacji i czasie;
  - rozkład wartości dla zmiennej 'Total' jest prawostronnie skośny, o czym świadczy fakt, że wartości rozciągają się
    po prawej stronie od mediany równej 253,85, a większość wartości koncentruje się po jej lewej stornie. Stwierdzić
    zatem można, że największa liczba transakcji opiewała na kwoty z przedziału ok. 0-250 dolarów, gdyż wartości
    w przedziale 0-250 dolarów dominują, ale pojawiają się również wartości dochodzące do 1050 dolarów, co ma
    wpływ na końcową skośność. 
    
    Ponadto statystyka Wilcoxona, dla której testowane są hipotezy:
    
    H0: Rozkład wartości zmiennej nie różni się od mediany jej wartości,
    HA: Rozkład wartości zmiennej różni się od mediany jej wartości,
    
    wykazała, że na podstawie wartości p-value, która jest bliska 0 dla wszystkich zmiennych (p-value < 0,05) można
odrzucić H0 mówiące o braku różnic między wartościami zmiennych, a ich medianą.

Testy zależności

Testy zależności dla zmiennej ‘Rating’

Dla nieparametrycznego testu Kruskala-Wallisa zależności bada się następujące hipotezy:

    H0: Rozkład wartości zmiennej ocen ('Rating') w każdym mieście ('City') jest taki sam.
    HA: Rozkład wartości zmiennej ocen ('Rating') w każdym mieście ('City') nie jest taki sam.
    
    Statystyka testu wyniosła 1,86 przy wartości p-value większej od przyjętego poziomu istotności alfa (0,39 > 0,05), 
co wskazuje, że nie ma istotnych przesłanek do odrzucenia H0, twierdzącego, że rozkłady wartości ocen we wszystkich 
trzech miastach, gdzie znajdują się sklepy są sobie równe.

Dla nieparametrycznego testu zależności Manna-Whitneya między zmienną 'Rating' a 'Customer.type' bada się hipotezy:

    H0: Mediany ocen ('Rating') nadawanych przez oba typy klientów ('Customer.type') są sobie równe, a rozkłady 
           dla klienta "Member" i "Normal" są identyczne.
    HA: Mediany ocen ('Rating') nadawanych przez oba typy klientów ('Customer.type') nie są sobie równe, 
            a rozkłady dla klienta "Member" i "Normal" są nie identyczne.
        HA1: Mediana ocen ('Rating') nadawanych przez posiadaczy karty członkowskiej jest większa od mediany ocen
                 osób nieposiadających karty.
        HA2: Mediana ocen ('Rating') nadawanych przez posiadaczy karty członkowskiej jest mniejsza od mediany 
                 ocen osób nieposiadających karty.
    
    Statystyka testu wyniosła ok. 119 000 przy wartości p-value większej od przyjętego poziomu istotności alfa
(0,2 > 0,05), co wskazuje, że nie ma istotnych przesłanek do odrzucenia H0 twierdzącego, że mediany wartości ocen 
nadawanych przez osobę posiadającą kartę członkowską nie różnią się znacząco od mediany ocen przyznawanych 
przez klientów nie będących w jej posiadaniu. Ponadto test wykazał, że rozkłady dla obu typów klientów są z dużym 
prawdopodobieństwem identyczne.

Testy zależności zmiennej ‘Quantity’ oraz ‘Gender’

Dla nieparametrycznego testu zależności Manna-Whitneya zmiennej 'Gender' i 'Quantity' bada się hipotezy:

    H0: Mediany ilości zakupionych produktów ('Quantity') przez klientów obu płci ('Customer.type') są sobie
            równe i rozkłady dla "Female" i "Male" są identyczne.
    HA: Mediany ilości zakupionych produktów ('Quantity') przez klientów obu płci ('Customer.type') nie są sobie 
            równe i rozkłady dla "Female" i "Male" nie są identyczne.
        HA1: Mediana ilości zakupionych produktów ('Quantity') przez kobiety ("Female") jest większa od
                 mediany ilości towarów dla mężczyzn ("Male").
        HA2: Mediana ilości zakupionych produktów ('Quantity') przez kobiety ("Female") jest mniejsza od
                 mediany ilości towarów dla mężczyzn ("Male").
Statystyka testu wyniosła ok. 136 000 przy wartości p-value mniejszej od przyjętego poziomu istotności alfa 
(0,2 < 0,05), co wskazuje, że istnieją istotne przesłanki, aby odrzucić H0 twierdzącą, że mediany ilości produktów 
zakupionych przez klientów obu płci są sobie równe, a rozkład wartości ilości zakupionych produktów dla kobiet 
i mężczyzn są identyczne. Ponadto stwierdzić można, że mediana ilości zakupionych towarów kobiet jest większa 
od mediany dla mężczyzn.

Test korelacji między zmiennymi ‘Customer.type’ i ‘Payment’

    Dla nieparametrycznego testu Pearsona (p) badającego korelację między zmiennymi 'Customer.type' i 'Payment'
bada się następujące hipotezy:

    H0: Nie istnieje korelacja między osobami posiadającymi i nieposiadającymi kartę członkowską sklepu a formą 
           płatności za zakupy (p = 0).
    HA: Istnieje korelacja między osobami posiadającymi i nieposiadającymi kartę członkowską sklepu a formą 
           płatności za zakupy (p =/= 0).
    
    Statystyka testu Pearsona (p) wyniosła 5,22 przy wartości p-value mniejszej od przyjętego poziomu istotności alfa
(0,03 < 0,05) dla osoby nie będącej posiadaczem karty lojalnosciowej sklepu i większej dla osoby, która tę kartę ma
(0,83 > 0,05). W związku z tym dla osoby nie posiadającej karty, istnieją istotne przesłanki, aby odrzucić H0, a co 
za tym idzie - jej korelacja z formą płatności istnieje i jest dodatnia (p > 0), natomiast dla osoby posiadającej taką
kartę nie ma podstaw do odrzucenia H0, zatem jej korelacja z formą płatności nie występuje.

PODSUMOWANIE CZĘŚCI TESTOWEJ

Przeprowadzone testy wykazały następujące zależności:
  - Ocena klientów ('Rating') nigdy nie była niższa od oceny 4, natomiast najczęściej przyznawana ocena przez
    klientów to 6. Ponadto prawdopodobnym jest, że przyznawane oceny nie są zależne ani od miasta, w jakim się
    znajduje dany sklep Biedronka, ani od faktu, czy klient posiada kartę lojalnościową czy też nie.
  - Ilość zakupionych produktów 'Quantity' przez przeciętnego, badanego klienta w trzech pierwszych miesiącach 2019
    wynosiła więcej niż 5. Ponadto środkowa liczba oznaczająca ilość zakupionych produktów przez kobiety była w tym
    okresie wyższa od mediany zakupionych produktów przez mężczyzn.
  - Istnieje pewna zależność pomiędzy osobami nieposiadającymi kartę członkowską sklepu a formą, jaką wybierają
    przy płatności za zakupy. Można się spodziewać, że takie osoby częściej wybiorą płatność poprzez portfel
    elektroniczny niż kartą kredytową czy gotówką. Dodatkowo płatność kartą kredytową wybiorą najmniej chętnie.
    Nie istnieją jednak przesłanki, aby móc zakładać, że osoby posiadające kartę członkowską preferują daną formę
    płatności za zakupy.