ANALIZA DANYCH-PROJEKT

Maciej Fleks, Małgorzata Dudanowicz, Krzysztof Kowalski

2024-01-24

#Na poczatku wczytujemy zbior danych
rowery<-read_excel("sklep_rowerowy.xlsx")
rowery 
## # A tibble: 1,000 × 13
##       ID `Marital Status` Gender Income Children Education           Occupation 
##    <dbl> <chr>            <chr>   <dbl>    <dbl> <chr>               <chr>      
##  1 12496 Married          Female  40000        1 Bachelors           Skilled Ma…
##  2 24107 Married          Male    30000        3 Partial College     Clerical   
##  3 14177 Married          Male    80000        5 Partial College     Profession…
##  4 24381 Single           <NA>    70000        0 Bachelors           Profession…
##  5 25597 Single           Male    30000        0 Bachelors           Clerical   
##  6 13507 Married          Female  10000        2 Partial College     Manual     
##  7 27974 Single           Male   160000        2 High School         Management 
##  8 19364 Married          Male    40000        1 Bachelors           Skilled Ma…
##  9 22155 <NA>             Male    20000        2 Partial High School Clerical   
## 10 19280 Married          Male       NA        2 Partial College     Manual     
## # ℹ 990 more rows
## # ℹ 6 more variables: `Home Owner` <chr>, Cars <dbl>, `Commute Distance` <chr>,
## #   Region <chr>, Age <dbl>, `Purchased Bike` <chr>

SKLEP ROWEROWY

Analizowany zbiór danych zawiera informacje na temat klientów sklepu rowerowego. Z jego pomocą możemy uzyskać informacje na temat wieku, dochodu, płci, liczby posiadanych dzieci czy regionu pochodzenia klientów sklepu. Celem projektu jest przeprowadzenie kompleksowej analizy danych, która obejmować będzie kilka kluczowych etapów, a mianowicie: czyszczenie danych, wizualizację, analizę opisową i wnioskowanie statystyczne.

I ETAP - CZYSZCZENIE DANYCH

1. Przegląd danych

Obserwujemy m.in. spacje w nazwach kolumn naszych zmiennych. Aby się ich pozbyć korzystamy z funkcji clean_names z pakietu ‘janitor’, która służy do przekształcania nazw kolumn w ramce danych w formę bardziej czytelną i zgodą z konwencją.

head(rowery) 
## # A tibble: 6 × 13
##      ID `Marital Status` Gender Income Children Education       Occupation    
##   <dbl> <chr>            <chr>   <dbl>    <dbl> <chr>           <chr>         
## 1 12496 Married          Female  40000        1 Bachelors       Skilled Manual
## 2 24107 Married          Male    30000        3 Partial College Clerical      
## 3 14177 Married          Male    80000        5 Partial College Professional  
## 4 24381 Single           <NA>    70000        0 Bachelors       Professional  
## 5 25597 Single           Male    30000        0 Bachelors       Clerical      
## 6 13507 Married          Female  10000        2 Partial College Manual        
## # ℹ 6 more variables: `Home Owner` <chr>, Cars <dbl>, `Commute Distance` <chr>,
## #   Region <chr>, Age <dbl>, `Purchased Bike` <chr>
rowery <- clean_names(rowery) 

1. Sprawdzenie występowania brakujących obserwacji NA

Poniżej przeprowadzona została analiza wartości brakujących NA dla poszczególnych zmiennych. Wskazano zarówno liczbę wierszy, w których występują braki, jak i konkretne ich numery. W ten sposób dowiadujemy się przykładowo, że zmienna “home_owner” ma 4 braki i występują one w wierszach: 7, 366, 647 i 944. Przedstawiono również wizualizację wartości brakujących.

sum(complete.cases(rowery)) 
## [1] 952

Zauważono 952 pełnych wierszy, czyli mamy 48 wierszy, w ktorych sa braki.

manyNAs(rowery) 
## [1] 689

689 wiersz zawiera najwiecej brakow.

sum(is.na(rowery)) 
## [1] 53

W sumie wystepuja 53 braki.

miss_var_summary(rowery) 
## # A tibble: 13 × 3
##    variable         n_miss pct_miss
##    <chr>             <int>    <dbl>
##  1 gender               11      1.1
##  2 cars                  9      0.9
##  3 children              8      0.8
##  4 age                   8      0.8
##  5 marital_status        7      0.7
##  6 income                6      0.6
##  7 home_owner            4      0.4
##  8 id                    0      0  
##  9 education             0      0  
## 10 occupation            0      0  
## 11 commute_distance      0      0  
## 12 region                0      0  
## 13 purchased_bike        0      0

Widzimy, że braki wystepuja jedynie dla zmiennych gender (11), cars(9),children (8), age(8), marital_status(7), income(6) i home_owner(4). Pozostale zmienne nie posiadaja zadnych wartosci brakujacych.

rowery %>% 
  miss_case_table()
## # A tibble: 4 × 3
##   n_miss_in_case n_cases pct_cases
##            <int>   <int>     <dbl>
## 1              0     952      95.2
## 2              1      44       4.4
## 3              2       3       0.3
## 4              3       1       0.1

Mamy 44 wiersze, w ktorych brak jest jednej wartosci, 3 wiersze z 2 brakami i jeden wiersz z 3 wartosciami NA

md.pattern(rowery) 

##     id education occupation commute_distance region purchased_bike home_owner
## 952  1         1          1                1      1              1          1
## 10   1         1          1                1      1              1          1
## 9    1         1          1                1      1              1          1
## 5    1         1          1                1      1              1          1
## 7    1         1          1                1      1              1          1
## 1    1         1          1                1      1              1          1
## 5    1         1          1                1      1              1          1
## 1    1         1          1                1      1              1          1
## 4    1         1          1                1      1              1          1
## 1    1         1          1                1      1              1          1
## 1    1         1          1                1      1              1          1
## 4    1         1          1                1      1              1          0
##      0         0          0                0      0              0          4
##     income marital_status children age cars gender   
## 952      1              1        1   1    1      1  0
## 10       1              1        1   1    1      0  1
## 9        1              1        1   1    0      1  1
## 5        1              1        1   0    1      1  1
## 7        1              1        0   1    1      1  1
## 1        1              1        0   0    1      0  3
## 5        1              0        1   1    1      1  1
## 1        1              0        1   0    1      1  2
## 4        0              1        1   1    1      1  1
## 1        0              1        1   0    1      1  2
## 1        0              0        1   1    1      1  2
## 4        1              1        1   1    1      1  1
##          6              7        8   8    9     11 53

Wykres do zilustrowania brakow kazdej zmiennej

which(is.na(rowery$gender))
##  [1]   4 155 336 602 689 696 868 909 952 974 998

4, 155, 336, 602, 689, 696, 868, 909, 952, 974, 998- numery wierszy, w ktorych sa braki dla zmiennej gender

which(is.na(rowery$cars)) 
## [1]  13 197 203 352 449 512 562 616 934

13, 197, 203, 352, 449, 512, 562, 616, 934- numery wierszy, w ktorych sa braki dla zmiennej cars

which(is.na(rowery$children))
## [1] 118 218 387 550 639 689 806 961

118, 218, 387, 550, 639, 689, 806, 961- numery wierszy, w ktorych sa braki dla zmiennej children

which(is.na(rowery$age)) 
## [1]  10  99 226 372 555 689 771 987

10, 99, 226, 372, 555, 689, 771, 987- numery wierszy, w ktorych sa braki dla zmiennej age

which(is.na(rowery$marital_status)) 
## [1]   9  28  50  99 151 235 302

9, 28, 50, 99, 151, 235, 302- numery wierszy, w ktorych sa braki dla zmiennej marital_status

which(is.na(rowery$income)) 
## [1]  10 111 192 302 442 510

10, 111, 192, 302, 442, 510-numery wierszy, w ktorych sa braki dla zmiennej income

which(is.na(rowery$home_owner)) 
## [1]   7 366 647 944

7, 366, 647, 944-numery wierszy, w ktorych sa braki dla zmiennej home_owner

2. Sprawdzenie typów danych w każdej kolumnie

Sprawdzanie typów danych w każdej kolumnie jest kluczowe dla zachowania poprawności, efektywności oraz precyzji analizy danych.

data_class <- data.frame(class = sapply(rowery, class))
data_class
##                      class
## id                 numeric
## marital_status   character
## gender           character
## income             numeric
## children           numeric
## education        character
## occupation       character
## home_owner       character
## cars               numeric
## commute_distance character
## region           character
## age                numeric
## purchased_bike   character

3. Sprawdzenie wiarygodności danych

Poprzez wywołanie podstawowych statystyk możemy sprawdzić, czy nasze dane wydają się być wiarygodne, tzn. czy średnia ilość posiadanych dzieci, czy samochodów wydaje się być prawdopodobna. Ponadto użycie ‘view(dfSummary(dane))’ dostarcza nam wielu cennych informacji m.in.:

  • widzimy, że każdy klient posiada unikalne id,
  • otrzymujemy podsumowanie braków obserwacji dla każdej zmiennej,
  • dla zmiennych jakościowych widzimy możliwe kategorie wyboru wraz z informacją o częstości jej wystąpienia.
summary(rowery)
##        id        marital_status        gender              income      
##  Min.   :11000   Length:1000        Length:1000        Min.   : 10000  
##  1st Qu.:15291   Class :character   Class :character   1st Qu.: 30000  
##  Median :19744   Mode  :character   Mode  :character   Median : 60000  
##  Mean   :19966                                         Mean   : 56268  
##  3rd Qu.:24471                                         3rd Qu.: 70000  
##  Max.   :29447                                         Max.   :170000  
##                                                        NA's   :6       
##     children     education          occupation         home_owner       
##  Min.   :0.00   Length:1000        Length:1000        Length:1000       
##  1st Qu.:0.00   Class :character   Class :character   Class :character  
##  Median :2.00   Mode  :character   Mode  :character   Mode  :character  
##  Mean   :1.91                                                           
##  3rd Qu.:3.00                                                           
##  Max.   :5.00                                                           
##  NA's   :8                                                              
##       cars       commute_distance      region               age       
##  Min.   :0.000   Length:1000        Length:1000        Min.   :25.00  
##  1st Qu.:1.000   Class :character   Class :character   1st Qu.:35.00  
##  Median :1.000   Mode  :character   Mode  :character   Median :43.00  
##  Mean   :1.455                                         Mean   :44.18  
##  3rd Qu.:2.000                                         3rd Qu.:52.00  
##  Max.   :4.000                                         Max.   :89.00  
##  NA's   :9                                             NA's   :8      
##  purchased_bike    
##  Length:1000       
##  Class :character  
##  Mode  :character  
##                    
##                    
##                    
## 
view(dfSummary(rowery))
## Switching method to 'browser'
## Output file written: C:\Users\macie\AppData\Local\Temp\RtmpaU9INy\file33f842ea14d8.html
descr(rowery)
## Non-numerical variable(s) ignored: marital_status, gender, education, occupation, home_owner, commute_distance, region, purchased_bike
## Descriptive Statistics  
## rowery  
## N: 1000  
## 
##                        age     cars   children         id      income
## ----------------- -------- -------- ---------- ---------- -----------
##              Mean    44.18     1.46       1.91   19965.99    56267.61
##           Std.Dev    11.36     1.12       1.63    5347.33    31067.82
##               Min    25.00     0.00       0.00   11000.00    10000.00
##                Q1    35.00     1.00       0.00   15289.50    30000.00
##            Median    43.00     1.00       2.00   19744.00    60000.00
##                Q3    52.00     2.00       3.00   24475.50    70000.00
##               Max    89.00     4.00       5.00   29447.00   170000.00
##               MAD    11.86     1.48       1.48    6848.13    29652.00
##               IQR    17.00     1.00       3.00    9180.00    40000.00
##                CV     0.26     0.77       0.85       0.27        0.55
##          Skewness     0.52     0.42       0.39       0.05        0.75
##       SE.Skewness     0.08     0.08       0.08       0.08        0.08
##          Kurtosis    -0.27    -0.41      -1.02      -1.19        0.50
##           N.Valid   992.00   991.00     992.00    1000.00      994.00
##         Pct.Valid    99.20    99.10      99.20     100.00       99.40

4. Sprawdzanie spełnienia pewnych reguł dla zbioru danych

Posiadając już podstawową wiedzę na temat naszych danych, chcemy sprawdzić kilka podstawowych reguł: czy zmienna wiek na pewno wszędzie przyjmuje wartości dodatnie, czy liczba posidanych dzieci nie jest nigdzie ujemna, czy liczba posiadanych samochodów nie jest ujemna, czy płeć przyjmuje jedną z dwóch kategorii ‘kobieta’ i ‘mężczyna’.

rules <- validator(age > 0, gender %in% c('Female','Male')
                  , income >= 0, children >= 0, cars >= 0)
cf <- confront(rowery, rules, key="id")
summary(cf)
##   name items passes fails nNA error warning                       expression
## 1   V1  1000    992     0   8 FALSE   FALSE                          age > 0
## 2   V2  1000    989     0  11 FALSE   FALSE gender %vin% c("Female", "Male")
## 3   V3  1000    994     0   6 FALSE   FALSE             income - 0 >= -1e-08
## 4   V4  1000    992     0   8 FALSE   FALSE           children - 0 >= -1e-08
## 5   V5  1000    991     0   9 FALSE   FALSE               cars - 0 >= -1e-08
barplot(cf, main="rowery") 
## Warning: The 'barplot' method for confrontation objects is deprecated. Use
## 'plot' instead

Wizualizacja spełnienia reguły as.data.frame(cf) %>% head()

Inny sposób:

RULE <- editset(c("age > 0","gender %in% c('Female','Male')"
                  , "income >= 0", "children >= 0", "cars >= 0"))
RULE
## 
## Data model:
## dat1 : gender %in% c('Female', 'Male') 
## 
## Edit set:
## num1 : 0 < age
## num2 : 0 <= income
## num3 : 0 <= children
## num4 : 0 <= cars
summary(violatedEdits(RULE, rowery))
## Edit violations, 1000 observations, 0 completely missing (0%):
## 
##  editname freq  rel
##      dat1   11 1.1%
## 
## Edit violations per record:
## 
##  errors freq   rel
##       0  961 96.1%
##       1   37  3.7%
##       2    1  0.1%
##       3    1  0.1%
#rowery[localizeErrors(RULE, rowery)$adapt] <- NA -> w razie niespelnienia ktores z regul wartosci zmieniamy na NA

Okazuje się, że wszystkie reguły w naszym zbiorze danych są spełnione.

2. Imputacja danych

Z analiz przeprowadzonych powyżej wynika, że w naszym zbiorze danych zlokalizowano 53 braki danych. Podjęto decyzję o nieusuwaniu żadnego z wierszy i uzupełnieniu wartości NA za pomocą różnych metod.

1. Imputacja-zmienne ilościowe

Braki w zmiennych dotyczących dochodu, wieku, liczby posidanych dzieci i samochodów wypełnione zostaną za pomocą średniej. Ze względu na specyfikę danych age, children i cars, wartości te nie powinny mieć żadnych miejsc po przecinku, gdyż nie możemy posiadać np. 1.5 dziecka.

rowery %>% filter(is.na(income)) %>% head
## # A tibble: 6 × 13
##      id marital_status gender income children education    occupation home_owner
##   <dbl> <chr>          <chr>   <dbl>    <dbl> <chr>        <chr>      <chr>     
## 1 19280 Married        Male       NA        2 Partial Col… Manual     Yes       
## 2 21006 Single         Female     NA        1 Partial Col… Manual     No        
## 3 26944 Single         Male       NA        2 High School  Manual     Yes       
## 4 17926 <NA>           Female     NA        0 Bachelors    Clerical   No        
## 5 11061 Married        Male       NA        2 Partial Col… Skilled M… Yes       
## 6 24357 Married        Male       NA        3 Bachelors    Professio… Yes       
## # ℹ 5 more variables: cars <dbl>, commute_distance <chr>, region <chr>,
## #   age <dbl>, purchased_bike <chr>
rowery[is.na(rowery$income), "income"] <- mean(rowery$income, na.rm = T)

# Inny sposob
#dochod<-imputate_na(rowery, income, method = "mean")
#summary(dochod)
#plot(dochod)

rowery %>% filter(is.na(age)) %>% head
## # A tibble: 6 × 13
##      id marital_status gender income children education    occupation home_owner
##   <dbl> <chr>          <chr>   <dbl>    <dbl> <chr>        <chr>      <chr>     
## 1 19280 Married        Male   56268.        2 Partial Col… Manual     Yes       
## 2 19441 <NA>           Male   40000         0 Graduate De… Clerical   Yes       
## 3 14135 Married        Male   20000         1 Partial Col… Manual     Yes       
## 4 22918 Single         Male   80000         5 Graduate De… Management Yes       
## 5 18580 Married        Female 60000         2 Graduate De… Professio… Yes       
## 6 11699 Single         <NA>   60000        NA Bachelors    Skilled M… No        
## # ℹ 5 more variables: cars <dbl>, commute_distance <chr>, region <chr>,
## #   age <dbl>, purchased_bike <chr>
rowery[is.na(rowery$age), "age"] <- round(mean(rowery$age, na.rm = T), digits=0)

rowery %>% filter(is.na(cars)) %>% head
## # A tibble: 6 × 13
##      id marital_status gender income children education    occupation home_owner
##   <dbl> <chr>          <chr>   <dbl>    <dbl> <chr>        <chr>      <chr>     
## 1 11434 Married        Male   170000        5 Partial Col… Professio… Yes       
## 2 16209 Single         Female  50000        0 Graduate De… Skilled M… Yes       
## 3 18626 Single         Male    40000        2 Partial Col… Clerical   Yes       
## 4 13572 Single         Male    10000        3 High School  Manual     Yes       
## 5 11383 Married        Female  30000        3 Graduate De… Clerical   Yes       
## 6 12207 Single         Male    80000        4 Bachelors    Management Yes       
## # ℹ 5 more variables: cars <dbl>, commute_distance <chr>, region <chr>,
## #   age <dbl>, purchased_bike <chr>
rowery[is.na(rowery$cars), "cars"] <- round(mean(rowery$cars, na.rm = T), digits=0)

rowery %>% filter(is.na(children)) %>% head
## # A tibble: 6 × 13
##      id marital_status gender income children education    occupation home_owner
##   <dbl> <chr>          <chr>   <dbl>    <dbl> <chr>        <chr>      <chr>     
## 1 24065 Single         Female  20000       NA High School  Manual     Yes       
## 2 13673 Single         Female  20000       NA Partial Hig… Manual     No        
## 3 28957 Single         Female 120000       NA Partial Hig… Professio… Yes       
## 4 13453 Married        Female 130000       NA Bachelors    Management Yes       
## 5 18949 Single         Male    70000       NA Graduate De… Management Yes       
## 6 11699 Single         <NA>    60000       NA Bachelors    Skilled M… No        
## # ℹ 5 more variables: cars <dbl>, commute_distance <chr>, region <chr>,
## #   age <dbl>, purchased_bike <chr>
rowery[is.na(rowery$children), "children"] <- round(mean(rowery$children, na.rm = T), digits=0)

2. Imputacja-zmienne jakościowe

Po uzupełnieniu braków w zmiennych ilościowych, przystępujemy teraz do korekty brakujących danych w przypadku zmiennych jakościowych. Ponieważ nasze zmienne jakościowe zawierają jedynie dwie kategorie, planujemy zidentyfikować, która z tych kategorii jest dominująca. Następnie, braki danych w tych zmiennych zostaną wypełnione wartościami dominującymi, aby zachować spójność i ułatwić analizę danych.

#uzupelnianie danych dominanta
rowery[is.na(rowery$home_owner), "home_owner"] <- "Yes" #68,5% klientow posiada dom, jest to wiekszosc, wiec braki w danych uzupelniamy wartosci 'Yes'
rowery[is.na(rowery$marital_status), "marital_status"] <- "Married" #53,9% klientow posiada meza/zone, wiec braki w danych uzupelniamy wartoscia 'Married'
rowery[is.na(rowery$gender), "gender"] <- "Male" #50,6% klientow to mezczyzni, wiec braki w danych uzupelniamy wartoscia 'Male'

view(dfSummary(rowery)) #Wywolujemy tabelke podsumowujaca nasze dane. Widzimy, ze wszystkie dane zostaly uzupelnione.
## Switching method to 'browser'
## Output file written: C:\Users\macie\AppData\Local\Temp\RtmpaU9INy\file33f8684933e7.html
unique(rowery$home_owner)
## [1] "Yes" "No"

Dwie kategorie dla zmiennej home_owner- tak i nie

unique(rowery$marital_status)
## [1] "Married" "Single"

Dwie kategorie dla zmiennej marital_status- zamężny i singiel

unique(rowery$gender) 
## [1] "Female" "Male"

Dwie kategorie dla zmiennej gender- kobieta i mężczyzna

mice_plot <-aggr(rowery, col=c('navyblue', 'yellow'),numbers=TRUE, sortVars=TRUE, labels=names(rowery), cex.axis=7, ylab=c("Histogram of missing data","Pattern"))

## 
##  Variables sorted by number of missings: 
##          Variable Count
##                id     0
##    marital_status     0
##            gender     0
##            income     0
##          children     0
##         education     0
##        occupation     0
##        home_owner     0
##              cars     0
##  commute_distance     0
##            region     0
##               age     0
##    purchased_bike     0

Wykres obrazujacy braki danych ### 3. Obserwacje odstające

Sprawdzanie zbioru danych pod kątem wartości odstających jest kluczowe dla utrzymania jakości analizy danych i poprawnego zrozumienia badanego zjawiska. W przypadku identyfikacji wartości odstających, istnieją różne metody ich obsługi, takie jak usuwanie, transformacja, czy stosowanie bardziej zaawansowanych technik modelowania. Przechodzimy więc do sprawdzenia naszego zbioru danych pod względem występowania wartości odstających.

1. Zlokalizowanie wartości odstających

Możemy przykładowo stworzyć funkcję, która będzie wykrywać obserwacje odstające.

find_outliers <- function(rowery, k = 1.5) {
quantiles <- quantile(rowery, c(0.25, 0.5, 0.75))
diff <- k * (quantiles[3] - quantiles[1])
lb <- quantiles[1] - diff 
ub <- quantiles[3] + diff
  
is_outlier <- function(el) {
    el < lb || ub < el  
  }}

Z pomocą funkcji ‘boxplot.stats’ możemy wyświetlić, które wartości są odstające. Widzimy, że mamy aż 10 wartości odstających dla zmiennej ‘income’.

out <-boxplot.stats(rowery$income)$out 
out
##  [1] 160000 170000 170000 150000 160000 150000 160000 150000 170000 150000

Możemy również skorzystać z testów statystycznych.

test <- grubbs.test(rowery$income)
test 
## 
##  Grubbs test for one outlier
## 
## data:  rowery$income
## G = 3.67182, U = 0.98649, p-value = 0.1151
## alternative hypothesis: highest value 170000 is an outlier

Test Grubba’a potwierdza, że najwyższa wartośc 170 000 jest odstająca.

test1 <- grubbs.test(rowery$income, opposite = TRUE)
test1 
## 
##  Grubbs test for one outlier
## 
## data:  rowery$income
## G = 1.49374, U = 0.99776, p-value = 1
## alternative hypothesis: lowest value 10000 is an outlier

Najmniejsza wartość nie jest odstająca.

Zwizualizujmy teraz wartości odstające na wykresie wraz z opisem, które z nich są odstające.

boxplot(rowery$income, col = "blue",
  ylab = "income",
  main = "Boxplot of income")
mtext(paste("Outliers: ", paste(out, collapse = ", ")))

Sprawdźmy jeszcze występowanie wartości odstających dla zmiennej ‘age’.

boxplot.stats(rowery$age)$out
## [1] 78 89 80 78

Mamy 4 wartosci odstające dla age.

test <- grubbs.test(rowery$age)
test
## 
##  Grubbs test for one outlier
## 
## data:  rowery$age
## G = 3.96061, U = 0.98428, p-value = 0.03514
## alternative hypothesis: highest value 89 is an outlier

Test potwierdza, że najwyższa wartość 89 jest odstająca.

2. Przekształcenie wartości odstających

Zdecydowano się przekształcić wartości odstające dla zmiennych “age” i “income” za pomocą metody capping. Metoda capping polega na ustaleniu górnej (max) i dolnej (min) granicy wartości dla danej zmiennej, a następnie przypisanie wszystkim wartościom przekraczającym te granice wartości skrajnych.

qnt <- quantile(rowery$income, probs=c(.25, .75), na.rm = T)
caps <- quantile(rowery$income, probs=c(.05, .95), na.rm = T)
H <- 1.5 * IQR(rowery$income, na.rm = T)
rowery$income[rowery$income < (qnt[1] - H)] <- caps[1]
rowery$income[rowery$income > (qnt[2] + H)] <- caps[2]
boxplot.stats(rowery$income)$out
## numeric(0)

Brak wartości odstających dla income.

qnt <- quantile(rowery$age, probs=c(.25, .75), na.rm = T)
caps <- quantile(rowery$age, probs=c(.05, .95), na.rm = T)
H <- 1.5 * IQR(rowery$age, na.rm = T)
rowery$age[rowery$age < (qnt[1] - H)] <- caps[1]
rowery$age[rowery$age > (qnt[2] + H)] <- caps[2]
boxplot.stats(rowery$age)$out
## numeric(0)

Brak wartości odstających dla age.

Dzięki procesowi czyszczenia danych osiągnięto spójność w zbiorze danych. Brakujące wartości zostały uzupełnione, a błędy zostały skorygowane, co pozwali teraz na bardziej precyzyjną analizę.

II ETAP-WIZUALIZACJE

Wizualizacje stanowią potężne narzędzie w każdym projekcie, wspomagają efektywną komunikację, lepsze zrozumienie danych oraz sprzyjają szybszemu i bardziej kreatywnemu podejmowaniu decyzji.Poniżej przedstawiono kilka ciekawych wizualizacji dla analizowanego zbioru danych.

1.Średni dochód w zależności od wieku i płci

Prezentowany wykres składa się z dwóch paneli, z których lewy reprezentuje dane dotyczące kobiet, natomiast prawy mężczyzn. Na obu panelach zaznaczone są czerwone punkty, odzwierciedlające empiryczne dane dotyczące średnich dochodów w poszczególnych grupach wiekowych. Linie trendu w kolorze niebieskim zostały dopasowane do punktów, ukazując ogólny trend wzrostu średnich dochodów w miarę postępującego wieku. Warto zauważyć, że panel mężczyzn charakteryzuje się większym zróżnicowaniem (różnicą) średnich dochodów, jednocześnie prezentując wyższą średnią wartość dochodu. Dodatkowo, dla mężczyzn zauważalny jest silniejszy trend wzrostu średniego dochodu wraz z wiekiem. To sugeruje, że w miarę upływu lat różnice w dochodach między różnymi grupami wiekowymi mężczyzn mogą się nasilać, tworząc bardziej zauważalne tendencje wzrostowe.

dw1<-rowery%>%
  group_by(age, gender)%>%
  summarize(meaninc=mean(income))
## `summarise()` has grouped output by 'age'. You can override using the `.groups`
## argument.
ggplot(dw1, aes(age, meaninc))+
  geom_line()+
  geom_point(colour="red")+
  facet_wrap(~gender)+
  labs(x="Wiek", y="Średnie dochody")

ggplot(dw1, aes(age, meaninc))+
  geom_line()+
  geom_point(colour="red")+
  facet_wrap(~gender)+labs(x="Wiek", y="Średnie dochody")+geom_smooth(method="lm")+ggtitle("Średni dochód w zależności od wieku oraz płci")
## `geom_smooth()` using formula = 'y ~ x'

2. Występowanie obserwacji o określonym wieku i dochodzie

Na ponizszym wykresie przedstawiony został wykres punktowy. Każdy punkt na wykresie reprezentuje jeden przypadek. Wielkość punktu z kolei odpowiada częstości występowania obserwacji o określonym wieku i poziomie dochodów.Analizując wykres można stwierdzić, że większość obserwacji skupia się w przedziale wiekowym 30-60 lat i niższym przedziale dochodowym.

ggplot(rowery, aes(age, income))+
  stat_sum(alpha=0.4)+
  scale_size(range=c(1,5))+
  ggtitle("Występowanie obserwacji o określonym wieku oraz poziomie dochodów")+labs(x="Wiek", y="Dochód", size="Występowanie")

3. Ilość posidanych samochodów w zależności od regionu

Na poniższym wykresie pokazany jest stosunek liczby posiadanych samochodów w gospodarstwie domowym ze względu na region z którego pochodzą klienci sklepu rowerowego. Rzuca sie w oczy fakt, że w Ameryce Północnej zdecydowanie najwięcej osób posiada 2 samochody.Region ten posiada również największy odsetek gospodarstw domowych z jednym samochodem. Najwięcej klientów nieposiadających samochodu zamieszkuje Europę- około 120.Jeśli chodzi o Pacyfik to jest tam najmniejszy odsetek gospodarstw bez samochodu, ponieważ tylko około 20. Ten region charakteryzyje się też najmniejszą dysproporcją jeżeli chodzi o liczbę samochodów.

ggplot(rowery, aes(x=cars, fill=region))+
  geom_bar(position="dodge")+
  labs(x="Ilość posiadanych samochodów", y="Występowanie", fill="Region")

4.Zagęszczenie obserwacji o określonym wieku w zależności od regionu

Poniższy wykres przedstawia rozkład wieku dla trzech różnych regionów: Europy, Ameryki Półnicnej i Pacyfiku. Oś pozioma (x) reprezentuje wiek, a oś pionowa (y) reprezentuje zagęszczenie, czyli estymowaną gęstość prawdopodobieństwa obserwacji w każdym punkcie osi wieku. W Europie największe zagęszczenie obserwacji występuje wśród osób w średnim wieku, z szczytem około 40 lat. Dla Ameryki Północnej rozkład wieku jest szerszy, z szczytem około 50 lat. Region Pacyfiku wydaje się mieć najszerszy rozkład wieku z największym zagęszczeniem wśród osób w wieku około 30 lat i stopniowym spadkiem w kierunku wyższych grup wiekowych. Rozkład wieku w Europie jest bardziej szpiczasty i mniej rozproszony niż w Ameryce Północnej, co może sugerować mniejszą różnorodność wieku w tym regionie. Linie obrysujące każdą z krzywych gęstości dają wyobrażenie o kształcie rozkładu dla każdego regionu, pozwalając dostrzec, gdzie znajdują się największe skupiska obserwacji.

ggplot(rowery, aes(age, fill=region))+
  geom_density(alpha=0.25)+
  labs(x="Wiek",y="Zagęszczenie", fill="Region")+
  ggtitle("Zagęszczenie obserwacji o określonym poziomie wieku w zależności od regionu")

5. Obserwacje o określonym poziomie dochodów w zależności od rodzaju zawodu

Na przedstawionym wykresie można zauważyć, że dochody poszczególnych grup zawodowych są znacznie zróżnicowane. Pracownicy fizyczni najczęściej osiągają najniższe wynagrodzenia, podczas gdy pracownicy biurowi zarabiają nieco więcej. Wykwalifikowani pracownicy fizyczni cieszą się średnimi dochodami, a pracownicy profesjonalni oraz ci na stanowiskach kierowniczych osiągają najwyższe wynagrodzenia.

ggplot(rowery, aes(income, fill=occupation))+
  geom_histogram(bins=20, color='black')+
  facet_wrap(~occupation, nrow=5)+
  labs(x="Dochód", y="Występowanie", fill="Praca")+
  theme(legend.position = 'none')+
  ggtitle("Wystepowanie obserwacji o określonym poziomie dochodów w zależności od rodzaju zawodu")

6. Wizualizacja poziomu dochodu w zależności od płci

Wykres poniżej pokazuje medianę dochodu, a także jego maksymalny, minimalny i średni poziom w zależności od płci.Mediana i średnie dochody są przedstawione na podobnym poziomie dla obu płci, z lekkim przesunięciem w kierunku wyższych wartości dla mężczyzn. Rozstęp dochodów, czyli różnica między kwartylem górnym a dolnym, również wydaje się być podobny dla obu grup.

ggplot(rowery, aes(income, fill=occupation))+
  geom_histogram(bins=20)+
  facet_wrap(~occupation, nrow=5)+
  labs(x="Dochód", y="Występowanie", fill="Praca")+
  theme(legend.position = 'none')

ggplot(rowery, aes(gender, income))+
  geom_boxplot(aes(fill=gender))+
  stat_boxplot(geom="errorbar",position="dodge")+
  stat_summary(aes(ymin=after_stat(y),ymax=after_stat(y)),fun=mean)+ggtitle("Mediana dochodów, maksymalny, minimalny oraz średni dochód w zależności od płci")+theme(legend.position='none')

7. Ilość posiadanych samochodów w zależności od posiadania roweru

Wykres poniżej może sugerować, że osoby posidające rower mają tendencję do posiadania mniej samochodów niż osoby, które roweru nie posiadają.

ggplot(rowery, aes(occupation, fill=occupation))+geom_bar()+facet_wrap(~education, nrow=5)+labs(x="Zatrudnienie", y="Występowanie")+theme(legend.position= 'none')

ggplot(rowery, aes(cars, fill=purchased_bike))+geom_histogram(bins=5, position="dodge", color='black')+facet_wrap(~purchased_bike)+theme(legend.position='none')+labs(x="Ilość posiadanych samochodów", y="Występowanie")+ggtitle("Ilość posiadanych samochodów w zależności od posiadania roweru")

8. Występowanie obserwacji o poszczególnym rodzaju wykonywanej pracy według wykształcenia

Poniższy rysunek przedstawia występowanie obserwacji o poszczególnym rodzaju wykonywanej pracy według wykształcenia. Najwięcej osób z wykształceniem licencjackim pracuje na stanowisku kierownicznym albo jako profesjonalista. Natomiast najmniej na stanowisku urzędniczym.Jeśli chodzi o osoby z wykształceniem wyższym to także najwięcej osób pracuje na stanowisku kierowniczym (ok. 60 obserwacji). Najmniej osób pracuje na stanowisku pracy fizycznej (ok. 10 obserwacji). Spoglądając na osoby z wykształceniem licealnym to największa ich liczba jest zatrudniona na stanowisku fachowego pracownika fizycznego, jako profesjonalista i pracownik fizyczny (odpowiednio ok. 60, 50 i 40 obserwacji). Natomiast najmniej osób z tym wykształceniem jest zatrudnionych jako menedżer lub pracownik biurowy (ok. 10 i 5 obserwacji). Analizując rodzaj wykonywanej pracy przez osoby z nieskończonymi studiami wyższymi to można zauważyć, iż największy udział pracujących to profesjonaliści (ok. 60 obserwacji), a najmniejszy dotyczy menedżerów (ok. 5 obserwacji). Analizując ostatnią kategorię wykształcenia, zaobserwowano tutaj najmniejszą liczbę obserwacji. Najwięcej osób z wykształceniem niepełnym licealnym jest zatrudnionych jako pracownik manualny (ok. 30 obsrwacji), a najmniej ponieważ 0 na stanowisku menedżera.

ggplot(rowery, aes(marital_status, age))+
  geom_boxplot(aes(fill=marital_status))+
  stat_boxplot(geom="errorbar", position="dodge")+
  stat_summary(aes(ymin=..y..,ymax=..y..), fun=mean)

ggplot(rowery, aes(occupation, fill=occupation))+
  geom_bar(color='black')+
  facet_wrap(~education, nrow=5)+
  labs(x="Zatrudnienie", y="Występowanie")+
  theme(legend.position= 'none')+
  ggtitle("Występowanie obserwacji o poszczególnym rodzaju wykonywanej pracy według wykształcenia")

9. Średni dochód według wykształcenia oraz rodzaju pracy

Mapa cieplna jest pomocna w szybkim zrozumieniu, jak różne kombinacje wykształcenia i zawodu wpływają na dochód, gdzie ciemniejsze kolory wskazją na wyższe dochody, a jaśniejsze na niższe. Kategoria ‘Management’ wydaje się oferować najwyższe dochody niezależnie od poziomu wykształcenia. Z kolei prace biurowe i prace fizyczne mają tendencję do przynoszenia niższych dochodów.

ggplot(rowery, aes(occupation, education, fill=income))+
  geom_tile(color='black')+
  scale_fill_gradient2(low="white", mid="yellow", high="red")+
  ggtitle("Średni dochód według wykształcenia oraz rodzaju pracy")+labs(x="Zawód", y="Wykształcenie", fill="Dochód")

10. Analiza wieku według stanu cywilnego

Z wykresu można zauważyć, że mediany wieku dla obu grup są różne-dla osób zamężnych/żonatych jest wyższa niż dla osób stanu wolnego. Średni wiek w obu grupach wydaje się zbliżony do mediany, ale nieznacznie wyższy u mężczyzn.

ggplot(rowery, aes(gender, income)) +
  geom_boxplot(aes(fill=gender))+
  stat_boxplot(geom="errorbar", position="dodge")+stat_summary(aes(ymin=..y..,ymax=..y..),fun=mean)

ggplot(rowery, aes(marital_status, age))+
  geom_boxplot(aes(fill=marital_status))+
  stat_boxplot(geom="errorbar", position="dodge")+
  stat_summary(aes(ymin=..y..,ymax=..y..), fun=mean)+
  labs(x="Stan cywilny", y="Wiek")+
  theme(legend.position='none')+
  ggtitle("Mediana, maksimum, minimum oraz średnia wieku według stanu cywilnego")

###11. Stan cywilny oraz region

Zdecydowanie najwięcej osób zamężnych wśród klientów sklepu rowerowego występowało w Ameryce Północnej. W Europie oraz Pacyfiku występuje niemal identyczna ilość zarówno singli jak i osób po ślubie.

ggplot(rowery, aes(marital_status, fill=marital_status))+
  geom_bar(position="dodge")+
  facet_wrap(~region)+
  theme(legend.position='none')+
  labs(x="Stan cywilny", y="Ilość")+
  ggtitle("Ilość osób o poszczególnym stanie cywilnym w zależności od regionu")

III ETAP-ANALIZA OPISOWA

Analiza opisowa jest nieodzownym elementem każdego projektu. Dostarcza podstawowych informacji, które stanowią punkt wyjścia do bardziej zaawansowanych analiz statystycznych i pomagają zrozumieć istotę danych.

1. Tabele liczebności

W pierwszym etapie naszej analizy pogrupujemy nasze dane w postaci prostej tabeli częstości.Napotykamy tutaj jednak pewne problemy. Przykładowo zmienna ‘income’ jest zmienną ciągłą. Dokonamy więc diskretyzacji danych-przekształcimy zmienną ciągłą na zmienną dyskretną poprzez podział zakresu wartości na przedziały.

1.Zmienna ciągła ‘income’

etykiety1<-c("0-25 000", "25 000-50 000", "50 000-75 000", "75 000-100 000", "100 000-125 000", "125 000-150 000")
limits1<-cut(rowery$income,seq(0,150000,by=25000),labels=etykiety1)
tabela2<-freq(limits1,type="html")
tabela2
## Frequencies  
## limits1  
## Type: Factor  
## 
##                         Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## --------------------- ------ --------- -------------- --------- --------------
##              0-25 000    147     14.70          14.70     14.70          14.70
##         25 000-50 000    327     32.70          47.40     32.70          47.40
##         50 000-75 000    294     29.40          76.80     29.40          76.80
##        75 000-100 000    157     15.70          92.50     15.70          92.50
##       100 000-125 000     43      4.30          96.80      4.30          96.80
##       125 000-150 000     32      3.20         100.00      3.20         100.00
##                  <NA>      0                               0.00         100.00
##                 Total   1000    100.00         100.00    100.00         100.00
tab1<-classIntervals(rowery$income,n=6,style="fixed",fixedBreaks=seq(0,150000,by=25000))
tab1
## style: fixed
##   one of 1,287 possible partitions of this variable into 6 classes
##       [0,25000)   [25000,50000)   [50000,75000)   [75000,1e+05)  [1e+05,125000) 
##             147             287             334             128              72 
## [125000,150000] 
##              32
jenks.tests(tab1)
##        # classes  Goodness of fit Tabular accuracy 
##        6.0000000        0.9624556        0.7887639

Wizualizacja:

hist(rowery$income, breaks="FD", col="green", probability = TRUE,
     main="INCOME")

Wskaźnik TAI jest dosyć wysoki, wiec możemy zaakceptować konstrukcję tabeli częstości.

2. Zmienna dyskretna ‘age’

etykiety<-c("20-30 lat","30-40 lat","40-50 lat","50-60 lat","60-70 lat","70-80 lat")
limits<-cut(rowery$age,seq(20,80,by=10),labels=etykiety)
tabela1<-freq(limits,type="html")
tabela1
## Frequencies  
## limits  
## Type: Factor  
## 
##                   Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
## --------------- ------ --------- -------------- --------- --------------
##       20-30 lat    108     10.80          10.80     10.80          10.80
##       30-40 lat    313     31.30          42.10     31.30          42.10
##       40-50 lat    305     30.50          72.60     30.50          72.60
##       50-60 lat    174     17.40          90.00     17.40          90.00
##       60-70 lat     93      9.30          99.30      9.30          99.30
##       70-80 lat      7      0.70         100.00      0.70         100.00
##            <NA>      0                               0.00         100.00
##           Total   1000    100.00         100.00    100.00         100.00
tab2<-classIntervals(rowery$age,n=6,style="fixed",fixedBreaks=seq(20,80,by=10))
tab2
## style: fixed
##   one of 2,118,760 possible partitions of this variable into 6 classes
## [20,30) [30,40) [40,50) [50,60) [60,70) [70,80] 
##      82     299     322     183     103      11
jenks.tests(tab2)
##        # classes  Goodness of fit Tabular accuracy 
##        6.0000000        0.9412382        0.7494848

Wizualizacja:

ggplot(rowery, aes(x = age)) +
  geom_histogram(binwidth = 2, fill = "blue", color = "red", alpha = 0.8) +
  labs(title = "Age Distribution", x = "Age", y = "Frequency")

Wskaźnik TAI jest dosyć wysoki, więc możemy zaakceptować konstrukcję tabeli częstości.

3. Pozostałe tabele liczebności

Education:

ggplot(rowery, aes(x = factor(education), fill = factor(education))) +
  geom_bar() +
  labs(title = "Education Distribution", x = "Education Level", y = "Count") +
  theme_minimal()

Region:

ggplot(rowery, aes(x = factor(region), fill = factor(region))) +
  geom_bar() +
  labs(title = "Region Distribution", x = "Region", y = "Count") +
  theme_minimal()

Liczebność pozostałych zmiennych: (zarówno liczbową, jak i procentową możemy odczytać z tabelki)

dfSummary(rowery)
## Data Frame Summary  
## rowery  
## Dimensions: 1000 x 13  
## Duplicates: 0  
## 
## -------------------------------------------------------------------------------------------------------------------------
## No   Variable           Stats / Values                  Freqs (% of Valid)     Graph                 Valid      Missing  
## ---- ------------------ ------------------------------- ---------------------- --------------------- ---------- ---------
## 1    id                 Mean (sd) : 19966 (5347.3)      1000 distinct values   : .     . .           1000       0        
##      [numeric]          min < med < max:                                       : : : : : : : : : :   (100.0%)   (0.0%)   
##                         11000 < 19744 < 29447                                  : : : : : : : : : :                       
##                         IQR (CV) : 9180 (0.3)                                  : : : : : : : : : :                       
##                                                                                : : : : : : : : : :                       
## 
## 2    marital_status     1. Married                      542 (54.2%)            IIIIIIIIII            1000       0        
##      [character]        2. Single                       458 (45.8%)            IIIIIIIII             (100.0%)   (0.0%)   
## 
## 3    gender             1. Female                       489 (48.9%)            IIIIIIIII             1000       0        
##      [character]        2. Male                         511 (51.1%)            IIIIIIIIII            (100.0%)   (0.0%)   
## 
## 4    income             Mean (sd) : 55877.6 (29892.9)   14 distinct values             :             1000       0        
##      [numeric]          min < med < max:                                               :             (100.0%)   (0.0%)   
##                         10000 < 60000 < 130000                                 . . .   :                                 
##                         IQR (CV) : 40000 (0.5)                                 : : :   : .                               
##                                                                                : : : : : : . . . :                       
## 
## 5    children           Mean (sd) : 1.9 (1.6)           0 : 274 (27.4%)        IIIII                 1000       0        
##      [numeric]          min < med < max:                1 : 169 (16.9%)        III                   (100.0%)   (0.0%)   
##                         0 < 2 < 5                       2 : 217 (21.7%)        IIII                                      
##                         IQR (CV) : 3 (0.8)              3 : 133 (13.3%)        II                                        
##                                                         4 : 126 (12.6%)        II                                        
##                                                         5 :  81 ( 8.1%)        I                                         
## 
## 6    education          1. Bachelors                    306 (30.6%)            IIIIII                1000       0        
##      [character]        2. Graduate Degree              174 (17.4%)            III                   (100.0%)   (0.0%)   
##                         3. High School                  179 (17.9%)            III                                       
##                         4. Partial College              265 (26.5%)            IIIII                                     
##                         5. Partial High School           76 ( 7.6%)            I                                         
## 
## 7    occupation         1. Clerical                     177 (17.7%)            III                   1000       0        
##      [character]        2. Management                   173 (17.3%)            III                   (100.0%)   (0.0%)   
##                         3. Manual                       119 (11.9%)            II                                        
##                         4. Professional                 276 (27.6%)            IIIII                                     
##                         5. Skilled Manual               255 (25.5%)            IIIII                                     
## 
## 8    home_owner         1. No                           314 (31.4%)            IIIIII                1000       0        
##      [character]        2. Yes                          686 (68.6%)            IIIIIIIIIIIII         (100.0%)   (0.0%)   
## 
## 9    cars               Mean (sd) : 1.5 (1.1)           0 : 238 (23.8%)        IIII                  1000       0        
##      [numeric]          min < med < max:                1 : 276 (27.6%)        IIIII                 (100.0%)   (0.0%)   
##                         0 < 1 < 4                       2 : 342 (34.2%)        IIIIII                                    
##                         IQR (CV) : 1 (0.8)              3 :  85 ( 8.5%)        I                                         
##                                                         4 :  59 ( 5.9%)        I                                         
## 
## 10   commute_distance   1. 0-1 Miles                    366 (36.6%)            IIIIIII               1000       0        
##      [character]        2. 1-2 Miles                    169 (16.9%)            III                   (100.0%)   (0.0%)   
##                         3. 10+ Miles                    111 (11.1%)            II                                        
##                         4. 2-5 Miles                    162 (16.2%)            III                                       
##                         5. 5-10 Miles                   192 (19.2%)            III                                       
## 
## 11   region             1. Europe                       300 (30.0%)            IIIIII                1000       0        
##      [character]        2. North America                508 (50.8%)            IIIIIIIIII            (100.0%)   (0.0%)   
##                         3. Pacific                      192 (19.2%)            III                                       
## 
## 12   age                Mean (sd) : 44.1 (11.1)         51 distinct values         . : .             1000       0        
##      [numeric]          min < med < max:                                         : : : :             (100.0%)   (0.0%)   
##                         25 < 43 < 74                                           . : : : : :                               
##                         IQR (CV) : 17 (0.3)                                    : : : : : : : . .                         
##                                                                                : : : : : : : : : .                       
## 
## 13   purchased_bike     1. No                           519 (51.9%)            IIIIIIIIII            1000       0        
##      [character]        2. Yes                          481 (48.1%)            IIIIIIIII             (100.0%)   (0.0%)   
## -------------------------------------------------------------------------------------------------------------------------

2. Podstawowe statystyki opisowe

Kolejnym etapem będzie przedstawienie podstawowych statystyk opisowych dla zmiennych ilościowych za pomocą zbiorczej tabelki.

descr(rowery)
## Non-numerical variable(s) ignored: marital_status, gender, education, occupation, home_owner, commute_distance, region, purchased_bike
## Descriptive Statistics  
## rowery  
## N: 1000  
## 
##                         age      cars   children         id      income
## ----------------- --------- --------- ---------- ---------- -----------
##              Mean     44.12      1.45       1.91   19965.99    55877.61
##           Std.Dev     11.15      1.12       1.62    5347.33    29892.86
##               Min     25.00      0.00       0.00   11000.00    10000.00
##                Q1     35.00      1.00       0.00   15289.50    30000.00
##            Median     43.00      1.00       2.00   19744.00    60000.00
##                Q3     52.00      2.00       3.00   24475.50    70000.00
##               Max     74.00      4.00       5.00   29447.00   130000.00
##               MAD     11.86      1.48       1.48    6848.13    29652.00
##               IQR     17.00      1.00       3.00    9180.00    40000.00
##                CV      0.25      0.77       0.85       0.27        0.53
##          Skewness      0.44      0.43       0.39       0.05        0.56
##       SE.Skewness      0.08      0.08       0.08       0.08        0.08
##          Kurtosis     -0.55     -0.39      -1.01      -1.19       -0.15
##           N.Valid   1000.00   1000.00    1000.00    1000.00     1000.00
##         Pct.Valid    100.00    100.00     100.00     100.00      100.00

3. Korelacja

Poniżej przedstawiona została korelacja pomiędzy zmiennymi ilościowymi.

cor((rowery[,c(4,5,9,12)]), method="pearson")
##             income  children      cars       age
## income   1.0000000 0.2647358 0.4313941 0.1747145
## children 0.2647358 1.0000000 0.2753641 0.5328957
## cars     0.4313941 0.2753641 1.0000000 0.1895145
## age      0.1747145 0.5328957 0.1895145 1.0000000
corrplot(cor(rowery[,c(4,5,9,12)]), method = "number", type = "upper", diag =FALSE)

corr_matrix<-cor(rowery[,c(4,5,9,12)])
corrplot(corr_matrix, method="color")

IV ETAP- WNIOSKOWANIE STATYSTYCZNE

Testowanie hipotez opiera się na założeniu pewnych warunków w populacji, a następnie analizie próby w celu zweryfikowania, czy dane założenie jest prawdziwe. Statystyki testowe i wartości p-value dostarczają nam narzędzi do dokładnego zrozumienia, czy obserwowane różnice między grupami czy parametrami są statystycznie istotne. Jako poziom istotności przyjęto wartość 0.05.

1. Pytania badawcze

  • Czy wartość dochodu jest zależna od regionu?
  • Czy poziom wykształcenia na wpływ na poziom dochodu?
  • Czy w małżeństwach rodzi się wiecej dzieci?
  • Czy mężczyźni więcej zarabiają?
  • Czy osoby, które nie posiadają samochodu częściej kupują rowery?
  • Czy osoby, które posiadają domy częściej kupują rowery?

1. pytanie badawcze

Dla zmiennych ,region’ i ‘income’ zastosowano polecenie ggbetweenstats, adekwatne dla porównywania zmiennej jakościowej z ilościową. Na podstawie wartości p-value można stwierdzić, źe dochód istotnie różni się w zależności od regionu.

ggbetweenstats(rowery, region, income)+ggtitle("Średni dochód w zależności od regionu")+labs(x="Region", y="Dochód")

2. pytanie badawcze

Dla zmiennych ‘home_owner’ i ‘occupation’ zastosowano funkcję ggbarstats, odpowiednią w przypadku porównywania ze sobą dwóch zmiennych jakościowych. Na podstawie wartości p-value można stwierdzić, że odsetek populacji posiadającej własny dom bądź mieszkanie istotnie różni się w zależności od rodzaju wykonywanej pracy.

ggbarstats(rowery, home_owner, occupation)+ggtitle("Posiadanie domu w zależności od rodzaju wykonywanej pracy")+labs(x="Zawód", y="Odsetek", fill="Posiadanie domu")

3. pytanie badawcze

Na podstawie wartości p-value można stwierdzić, że średnia liczba posiadanych samochodów jest istotnie niższa wśród osób posiadających rower.

ggbetweenstats(rowery, purchased_bike, cars)+ggtitle("Ilość posiadanych samochodów w zależności od posiadania roweru")+labs(x="Posiadanie roweru", y="Ilość posiadanych samochodów")

4. pytanie badawcze

Na podstawie otrzymanych wartości p-value można przyjąć, że średnie dochody istotnie różnią się w zależności od poziomu wykształcenia.

ggbetweenstats(rowery, education, income)+ggtitle("Średnie dochody w zależności od poziomu wykształcenia")+labs(x="Wykształcenie", y="Dochody")

5. pytanie badawcze

Na podstawie wartości p-value dotyczącej całości obserwacji można przyjąć, że liczba posiadanych dzieci istotnie różni się w zależności od stanu cywilnego ankietowanej jednostki. Jednak przy analizie obserwacji dotyczącej wyłącznie osób posiadających dwójkę bądź trójkę dzieci, relacji pomiędzy liczbą dzieci, a stanem cywilnym nie można uznać za istotną z uwagi na wartość p-value przekraczającą przyjęty poziom istotności wynoszący 0.05.

ggpiestats(rowery, marital_status, children)+ggtitle("Ilość posiadanych dzieci w zależności od stanu cywilnego")

2. Model logitowy

Dla zmiennej ‘purchased_bike’ postanowiono stworzyć model logitowy, który ma za zadanie sprawdzić, jaki wpływ mają poszczególne zmienne na fakt, że klient zdecydował się na kupno roweru. Zmienna ‘purchased_bike’ jest jakościowa i przyjmuje dwie kategorie ‘Yes’ oraz ‘No’. Za pomocą model.matrix zmienna ta została przekodowana tak, aby miała postać binarną, czyli przyjmowała tylko dwie wartości 0 dla ‘No’ i 1 dla ‘Yes’. Zmienne o największej wartości p-value były stopniowo usuwane z początkowego modelu zgodnie z metodą a posteriori, tak, aby otrzymać ostateczny model końcowy- model7.

encoded_data <- model.matrix(~purchased_bike - 1, data = rowery)

model= glm(encoded_data ~ gender + marital_status + region + cars + income + age + occupation + education + home_owner + commute_distance, family = binomial, data=rowery)
summary(model)
## 
## Call:
## glm(formula = encoded_data ~ gender + marital_status + region + 
##     cars + income + age + occupation + education + home_owner + 
##     commute_distance, family = binomial, data = rowery)
## 
## Coefficients:
##                                Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                   4.703e-02  4.452e-01   0.106 0.915874    
## genderMale                   -1.226e-02  1.374e-01  -0.089 0.928917    
## marital_statusSingle         -6.247e-01  1.531e-01  -4.080 4.50e-05 ***
## regionNorth America           1.529e-01  2.136e-01   0.716 0.474025    
## regionPacific                -8.040e-01  2.412e-01  -3.333 0.000860 ***
## cars                          4.778e-01  8.914e-02   5.360 8.31e-08 ***
## income                       -1.360e-05  4.189e-06  -3.246 0.001170 ** 
## age                           5.482e-03  7.140e-03   0.768 0.442646    
## occupationManagement          2.600e-01  4.152e-01   0.626 0.531141    
## occupationManual              5.634e-02  2.850e-01   0.198 0.843298    
## occupationProfessional       -2.836e-01  3.296e-01  -0.861 0.389481    
## occupationSkilled Manual      1.409e-01  2.668e-01   0.528 0.597499    
## educationGraduate Degree      3.562e-01  2.198e-01   1.620 0.105157    
## educationHigh School         -1.371e-01  2.468e-01  -0.556 0.578415    
## educationPartial College      2.646e-01  2.133e-01   1.241 0.214739    
## educationPartial High School  5.272e-01  3.584e-01   1.471 0.141218    
## home_ownerYes                -2.592e-01  1.644e-01  -1.577 0.114883    
## commute_distance1-2 Miles     1.307e-01  2.107e-01   0.620 0.535288    
## commute_distance10+ Miles     1.059e+00  2.909e-01   3.641 0.000272 ***
## commute_distance2-5 Miles    -1.406e-02  2.145e-01  -0.066 0.947737    
## commute_distance5-10 Miles    6.088e-01  2.399e-01   2.538 0.011150 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1384.9  on 999  degrees of freedom
## Residual deviance: 1246.9  on 979  degrees of freedom
## AIC: 1288.9
## 
## Number of Fisher Scoring iterations: 4

Kolejno zgodnie z metoda a posteriori usuniete zostaly zmienne: commute_distance, gender, occupation, education, home_owner.

Ostateczna postać modelu:

model7= glm(encoded_data ~ marital_status  + cars + income + age, family = binomial, data=rowery)
summary(model7)
## 
## Call:
## glm(formula = encoded_data ~ marital_status + cars + income + 
##     age, family = binomial, data = rowery)
## 
## Coefficients:
##                        Estimate Std. Error z value Pr(>|z|)    
## (Intercept)          -2.274e-01  3.033e-01  -0.750 0.453550    
## marital_statusSingle -4.999e-01  1.367e-01  -3.657 0.000255 ***
## cars                  5.112e-01  6.888e-02   7.422 1.16e-13 ***
## income               -1.300e-05  2.547e-06  -5.107 3.28e-07 ***
## age                   1.182e-02  6.205e-03   1.906 0.056694 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1384.9  on 999  degrees of freedom
## Residual deviance: 1302.4  on 995  degrees of freedom
## AIC: 1312.4
## 
## Number of Fisher Scoring iterations: 4

Liczymy iloraz szans, aby otrzymać wartości do interpretacji

OR=exp(model7$coefficients)
OR
##          (Intercept) marital_statusSingle                 cars 
##            0.7966333            0.6065888            1.6673378 
##               income                  age 
##            0.9999870            1.0118945

INTERPRETACJE: Jeżeli klient sklepu rowerowego jest singlem, to szanse na to, że kupi on rower maleją o około 40%. Jeżeli klient posiada samochód, to szanse na to, że kupi rower wzrastają o około 67%. Wraz ze wzrostem wieku o 1 rok, szanse na to, że klient kupi rower wzrastają o około 1,19%.

3. ANOVA ??