R Dersleri - Ali Onur Gitmez

Ana Sayfa Ders 1 Ders 2 Ders 3 Ders 4 Ders 5 Ders 6 Ders 7 Ders 8 Ders 9 Ders 10 Ders 11 Ders 12 Ders 13 Ders 14 Ders 15

Importing Data

Su ana kadar gordugumuz ornekler hep kendi verimizi olustsurma ustune kuruluydu. Ancak bir calisma yaparken neredeyse her zaman disaridan bir veri seti kullanacagiz. Ondan dolayi bu veri setlerini R’a aktarmayi ve ustunde calismayi ogrenmemiz lazim. Veri setleri Rdata, STATA, SPSS, csv, xlsx gibi bircok farkli formatta bulunabilir. Bunlar farkli istatistik dilleri icin hazirlanmis veriler olmasina ragmen paketler yardimiyla R’da kullanabiliriz. Bunun icin one cikan bazi paketler var: foreign, tidyverse paketinin de parcasi olan haven, readxl ve butun bunlari icinde barindirabilen rio. Paketlerin hepsi guncel olmayacabilecegi, okuma formatlari farkedebilecegi icin deneyerek o formata ve versiyona en uygun veri hangisiyse onu kullanmak en dogrusu olacaktir.

Verileri okumak icin haven paketini kullanabiliriz.

library(haven)
library(tidyverse)
library(reshape2)
library(readxl)

SPSS verisi okuma. Bu kodu calistirmayin cunku bu dosya klasorde yok.

spss_ess <- read_spss("cses5.sav")

STATA verisi okuma. Bu kodu calistirabilirsiniz.

 stata_ess <- read_stata("cses5-4.dta")

CSV verisi okuma. Bu kodu calistirmayin cunku bu dosya klasorde yok.

csv_ess <- read.csv("cses5.csv")

Goruldugu gibi her veri tipini okumak icin ona ozgun bir kod kullandik ve veriyi ayni sekilde okudu.Ancak okunan verilerin elimize ayni sekilde gecip gecmemesi hem R hem de veri formatini kuran kisinin sorumlulugu. Genelde csv formati basitligi ve hizi icin tercih edilir ancak sosyal bilimlerde analiz yapacak birisi icin dta ve sav formatlari da gayet uygundur ve bazen daha avantajli bile olabilir. Mesela degisken labellarini, deger labellarini tutmak istiyorsak stata kullanmak iyi bir cozum olabilir.

Bir veriyi bu formatlarda yazmamiz yani kaydetmemiz de mumkun. Eger kendi verimizi olusturduysak veya bir veri ustunde manipulasyon ve temizlik yapip ileride kullanmak icin kaydetmek amacimiz varsa bunu yapabiliriz.

library(writexl)
ornek_df <- data.frame(
  isim = c("Ece", "Onur", "Zeynep"),
  yas = c(28, 29, 27),
  kadin = c(TRUE, FALSE, TRUE)
)
write_xlsx(ornek_df, "ornek_veri.xlsx")

Tidy Data

Tidy data veri oluştururken verimizin düzenli gözükmesi için gereken prensiplere verilen isimdir. Bu prensipler sayesinde oluşturduğumuz veri kullanıcılar için düzenli ve kolay okunabilir olur. Burada 3 temel kuraldan bahsedebiliriz.

  • Her degiskenin kendi sütunu olmalı
  • Her gözlemin kendi satırı olmalı
  • Her değerin kendi hücresi olmalı.

Bu koşulları karşıladığımız zaman verimize düzenli diyebiliriz. Bu analiz yaparken işimizi kolaylaşıracaktır.

DATA MANIPULASYONU

Bu derste istatistik ile beraber ogrenecegimiz en onemli iki konudan birisi de bu. R ile calistiginiz zaman analizin onemli bir kismi buna harcanacak. Bu islemleri yaparak veriyi calismaya uygun hale getirecegiz. Onumuzdeki hafta isleyecegimiz veri temizlemenin oncesi olarak veri ustunde hangi islemleri yapacagimizi gorecegiz.

  • Sutun secme
  • Satir secme
  • Filtreleme
  • Yeni degiskenler olusturma
  • Verileri donusturme

gibi konulari isleyecegiz. Bunu yaparken kisa olarak base R ile nasil yapilacagini gordukten sonra temel odak noktamiz herkesin kullandigi tidyverse olacak.

İlk olarak verisetini aldığımız zaman basit veri dönüşümleri yapmaya öğreneceğiz. Bunlar veriyi numeriğe dönüştürme, karaktere dönüştürme gibi işlemler olacak. Örnek bir veriseti oluşturup bu işlemler nasıl yapılır öğrenelim.

ornek_df2 <- data.frame(
  isim = c("Ece", "Onur", "Zeynep"),
  yas = c("28", "29", "27"),
  kadin = c(TRUE, FALSE, TRUE),
  mezuniyet_tarihi = c("11-01-2018", 
                       "16-06-2016", "15-06-2019"),
  bolum = c("IR", "POLS", "POLS")
)

Bu veri setinde farklı tiplerde 5 değişkenimiz var. Bunların tipini bu komutla görebiliriz. Burada gözümüze çarpan bir nokta var. Yaş, mezuniyet tarihi ve bölüm değişkenlerinin hepsi karakter olarak kaydedilmiş. Ancak ben bunları farklı veri tiplerinde kullanmak isteyebilirim. Bunun için o verinin olduğu sütunun tipini değiştirmem gerekecek. Bunun için farklı yöntemler kullanabiliriz.

str(ornek_df2)
## 'data.frame':    3 obs. of  5 variables:
##  $ isim            : chr  "Ece" "Onur" "Zeynep"
##  $ yas             : chr  "28" "29" "27"
##  $ kadin           : logi  TRUE FALSE TRUE
##  $ mezuniyet_tarihi: chr  "11-01-2018" "16-06-2016" "15-06-2019"
##  $ bolum           : chr  "IR" "POLS" "POLS"

Yaş değişkenini numerik yapmak için

ornek_df2$yas <- as.numeric(ornek_df2$yas)
str(ornek_df2)
## 'data.frame':    3 obs. of  5 variables:
##  $ isim            : chr  "Ece" "Onur" "Zeynep"
##  $ yas             : num  28 29 27
##  $ kadin           : logi  TRUE FALSE TRUE
##  $ mezuniyet_tarihi: chr  "11-01-2018" "16-06-2016" "15-06-2019"
##  $ bolum           : chr  "IR" "POLS" "POLS"

Tarih değişkenini tarih formatına dönüştürmek için bunu kullanırız. Sondaki format kısmını şimdilik umursamayalım çünkü onu önümüzdeki hafta öğreneceğiz.

ornek_df2$mezuniyet_tarihi <- 
  as.Date(ornek_df2$mezuniyet_tarihi, format = "%d-%m-%Y")
str(ornek_df2)
## 'data.frame':    3 obs. of  5 variables:
##  $ isim            : chr  "Ece" "Onur" "Zeynep"
##  $ yas             : num  28 29 27
##  $ kadin           : logi  TRUE FALSE TRUE
##  $ mezuniyet_tarihi: Date, format: "2018-01-11" "2016-06-16" ...
##  $ bolum           : chr  "IR" "POLS" "POLS"

Eger veriyi faktör olarak kullanmak istiyorsak:

ornek_df2$bolum <- as.factor(ornek_df2$bolum)

ve son olarak faktör olan değişkene string olarak davranmak istiyorsak

ornek_df2$bolum <- as.character(ornek_df2$bolum)

Bu en basit yapacağımız işlemlerden birisiydi. Bundan sonra hem base R hem de ve asıl olarak tidyverse paketi kullanarak gerekli işlemleri nasıl yapacağımızı öğreneceğiz. Bunlar bir veriseti ile çalışırken genellikle kullanacağımız komutlar olacak.

Filtreleme en cok kullanacagımız yöntemlerden birisi. Bunu, verinin belli şartları karşılayan grubunu almak için kullanabiliriz. Bunu base R ile 2 farklı şekilde yapabiliriz

stata_ess_france <- stata_ess[stata_ess$E1006_NAM 
                              == "France", ]
stata_ess_france2 <- subset(stata_ess, E1006_NAM 
                            == "France")

Bunu tidyverse komutları kullanarak yapmak içinse

stata_ess_france3 <- stata_ess %>% filter(E1006_NAM
                                          == "France")

Gördüğümüz üzere üçü de aynı sonucu verdi. Bunların hepsi bizi aynı sonuca çıkartan farklı yöntemler aslında. İlk yöntem en az tercih edilenlerden olsa bile subet ve filter komutları farklı kişilerce kullanılır. Burada tercih kişinin hangi sisteme bağlı olmak istediğine kalmış. Üçüncü komutta dikkat çeken bir %>% işareti var. Bu daha önce de bashettiğim R’da bolca kullanacağımız bir operator. En az <- kadar önemli olacak. Bunun adı piping operatoru. Bunu kullandığımız zaman sonrasında yazacağımız her işlem solunda bulunan değişkene ait oluyor. Mesela bu örnekte filter komutunun $ kullanmadan stata_ess objesine ait olduğunu söylemiş oluyoruz. Bu özellikle, birden çok işlem yapmamız gerektiği zaman işe yarıyor. Böylece aynı veri üstünde sıralı işlem yapmamız gerekiyorsa ortanca veriler oluşturmak yerine bunu kullanabiliyoruz. Bunun detaylı bir örneğini daha fazla konu gördükten sonra öğreneceğiz.

Rowları seçtiğimiz gibi columnları da seçmemiz mümkün. Mesela sadece belli değişkenlerle ilgileniyorsak diğer değişkenlerin verimizde bulunması hem veriyi görüntülemeyi zorlaştırır hem de daha çok yer kaplamasına neden olur. Bunu yine farklı yöntemlerle yapabiliriz.

stata_columns1 <- stata_ess_france[, c("E3005_1", 
                                       "E3005_2", 
                                       "E3005_3",
                                "E3005_4", 
                                "E3005_5")]
stata_columns2 <- data.frame(stata_ess_france$E3005_1, 
                             stata_ess_france$E3005_2,
                            stata_ess_france$E3005_3, 
                            stata_ess_france$E3005_4,
                            stata_ess_france$E3005_5)
stata_columns3 <- subset(stata_ess_france, 
                         select = c(E3005_1, E3005_2, 
                                    E3005_3,
                                    E3005_4, 
                                    E3005_5))
stata_columns4 <- select(stata_ess_france, E3005_1, 
                         E3005_2, E3005_3,E3005_4,
                        E3005_5 )

Görüldüğü üzere hepsi yine aynı işlevi yerine getirdi. Burada farkedebileceğimiz bi durum bütün değişken isimlerinin aynı sistemle başlaması ve sonunda _X ile ayrılmaları. Bu yöntem anket verilerinde sıkça kullanılır ve değişken gruplarını ayırmaya yarar. Bunun gibi durumlarda bütün değişken isimlerini teker teker yazmaya gerek olmadan ortak bir pattern bularak da işlem yapabiliriz.

stata_numara_column <- 
  stata_ess_france[, grep("^E3005_[0-5]$",
                          names(stata_ess_france),
                          value = TRUE)]
stata_numara_column2 <- 
  stata_ess_france[, paste0("E3005_", 1:5)]
stata_numara_column3 <- 
  subset(stata_ess_france, select = 
           grep("^E3005_[0-9]$", 
                names(stata_ess_france)))
stata_numara_column4 <- 
  stata_ess_france %>% select(starts_with("E3005_"))

Burada görebileceğimiz gibi en az kod bilgisi gerektiren, en basit yapıda olan ve ilk bakışta en rahatlıkla anlaşışabilir olan yöntem dplyr paketi ile kullandığımız select komutu. Bu kody paylaştığımız kişilerin de anlaması açısından daha önemli olabilir.

Burada gördüğümğz gibi E3005 veriye verilmiş bir kod ve ilk bakışta bizim için bir anlam ifade etmiyor. Ne olduğunu görmek için ya veri ile beraber indirdiğimiz codebook kullanacağız ya da veriyi açıp açıklamasına bakacağız. Bu her durum için geçerli olmasa bile column adını değiştirip, anlaşılır ve mantıklı bir formata oturtabiliriz. Bunun için:

stata_ess_france_age <-
  names(stata_ess_france)[names(stata_ess_france)
                          == "E2001_A"] <- "age"
stata_ess_france_age2 <- 
  stata_ess_france2 %>% rename(age = E2001_A)

dplyr ile çok daha basitçe column isimlerini değiştirebiliyoruz.

Veriyi sıralamak istediğimiz zaman yine base R ve dplyr olarak iki alternatif karşımıza çıkar. Mesela yaşa göre sıralayacaksak:

stata_ess_france_sort1 <- 
  stata_ess_france_age2[order
                        (stata_ess_france_age2$age), ]
stata_ess_france_sort2 <- 
  stata_ess_france_age2[order
                        (stata_ess_france_age2$age, 
                              decreasing = TRUE), ]
stata_ess_france_sort3 <- 
  stata_ess_france_age2 %>% arrange(age)
stata_ess_france_sort4 <- 
  stata_ess_france_age2 %>% arrange(desc(age))

Yine dplyr ile çok daha basit olduğunu görebiliyoruz.

Bazı durumlarda birden çok columna göre sıralama yapmak isteyebiliriz. Bunun için ise

stata_ess_france_sort5 <- 
  stata_ess_france_age2[order
                        (stata_ess_france_age2$age,
                          stata_ess_france_age2$
                            E2003), ]
stata_ess_france_sort56 <-
  stata_ess_france_age2 %>% arrange(age, E2003)

Mutate ise en çok kullanacağımız komutlardan birisi olacak. Mutate yeni column oluşturmak veya mevcut bir sütunu editlemek için kullanılır. Mesela elimizdeki 5 columın toplamını yeni bir değişkene atayacağımızı varsayalım. Bunu 2 farklı yolla yapabiliriz.

stata_ess_france3$elite <- 
  stata_ess_france3$E3005_1 + 
  stata_ess_france3$E3005_2 + 
  stata_ess_france3$E3005_3 + 
  stata_ess_france3$E3005_4 + 
  stata_ess_france3$E3005_5 
stata_ess_france3 <- 
  transform(stata_ess_france3,elite2 = E3005_1 
            + E3005_2 + E3005_3 + 
              E3005_4 + E3005_5)
stata_ess_france3 <- 
  stata_ess_france3 %>% 
  mutate(elite3 = E3005_1 + E3005_2 + 
           E3005_3 + E3005_4 + E3005_5)

Across komutu ile de bir işlemi bütün veriseti üstüne uygulayabiliriz.

across_ornek <-ornek_df2 %>% 
  mutate(across(where(is.numeric), ~ .x * 2))

Veri üstünde if-else mantığında tidyverse kullanarak da rahatça kondisyonlara bağlı olarak dönüşüm yapabiliriz.

notlar <- data.frame(ders_notu = c(66,73,81))
not_df <- cbind(ornek_df2, notlar)
not_df %>%
  mutate(ders_notu = case_when(
    ders_notu >= 90 ~ "A",
    ders_notu >= 80 ~ "B",
    ders_notu >= 70 ~ "C",
    ders_notu >= 60 ~ "D",
    TRUE ~ "F"
  ))
##     isim yas kadin mezuniyet_tarihi bolum ders_notu
## 1    Ece  28  TRUE       2018-01-11    IR         D
## 2   Onur  29 FALSE       2016-06-16  POLS         C
## 3 Zeynep  27  TRUE       2019-06-15  POLS         B

Farklı columnlarda olan verileri tek bir sütunde birleştirebilir veya aynı üründe olanları ayırabiliriz.

deneme_df <- data.frame(
  isim = c("Ece Ucar", "Onur Gitmez", "Zeynep Önal"),
  yas = c(28, 30, 27)
)

ayrı_df <- deneme_df %>%
  separate(isim, into = c("ad", "soyad"), sep = " ")

birlesik_df <- ayrı_df %>%
  unite(isim, ad, soyad, sep = " ")

Verilerin istatistik özetini de dplyr paketlerini kullanıp çıkartabiliriz.

stata_ess_france3 %>% 
  summarize(mean_age = mean(E2001_A), 
            median_age = median(E2001_A))
##   mean_age median_age
## 1 50.74153         52
aggregate(E2001_A ~ E2007, stata_ess_france3,
          FUN = function(x) c(mean = mean(x), 
                              median = median(x)))
##    E2007 E2001_A.mean E2001_A.median
## 1     11     73.00000       77.00000
## 2     12     64.66667       62.00000
## 3     13     65.42857       68.00000
## 4     14     56.75000       60.50000
## 5     21     57.00000       59.00000
## 6     22     57.86207       61.00000
## 7     23     56.27083       57.00000
## 8     24     56.49206       60.00000
## 9     25     51.66667       51.00000
## 10    26     57.08000       64.00000
## 11    31     60.03226       60.00000
## 12    32     45.29825       42.00000
## 13    33     54.51064       55.50000
## 14    34     49.63333       46.50000
## 15    35     45.12500       48.50000
## 16    41     59.43137       63.00000
## 17    42     40.10526       39.00000
## 18    43     56.61538       55.00000
## 19    44     52.60465       52.00000
## 20    51     45.24359       44.50000
## 21    52     46.91489       42.50000
## 22    53     50.27778       50.00000
## 23    54     48.20690       48.00000
## 24    61     56.57333       58.00000
## 25    71     51.13725       52.00000
## 26    72     54.93023       55.00000
## 27    73     40.44444       43.00000
## 28    74     62.28571       68.50000
## 29    75     52.02439       55.00000
## 30    81     52.94595       55.00000
## 31    82     49.50000       42.00000
## 32    83     55.40426       59.00000
## 33    91     57.32394       61.00000
## 34    92     44.50000       44.50000
## 35    93     38.00000       34.00000
## 36    94     49.00000       44.50000
## 37    96     48.72727       51.00000
## 38   999     39.14286       35.00000

Eğer verileri gruplayıp çıkarmak istiyorsak

stata_ess_france3 %>% 
  group_by(E2007) %>%
  summarize(mean_age = mean(E2001_A), 
            median_age = median(E2001_A))
## # A tibble: 38 × 3
##    E2007                                                     mean_age median_age
##    <dbl+lbl>                                                    <dbl>      <dbl>
##  1 11 [11. CHIEF EXECUTIVES, SENIOR OFFICIALS AND LEGISLATO…     73         77  
##  2 12 [12. ADMINISTRATIVE AND COMMERCIAL MANAGERS]               64.7       62  
##  3 13 [13. PRODUCTION AND SPECIALIZED SERVICES MANAGERS]         65.4       68  
##  4 14 [14. HOSPITALITY, RETAIL AND OTHER SERVICES MANAGERS]      56.8       60.5
##  5 21 [21. SCIENCE AND ENGINEERING PROFESSIONALS]                57         59  
##  6 22 [22. HEALTH PROFESSIONALS]                                 57.9       61  
##  7 23 [23. TEACHING PROFESSIONALS]                               56.3       57  
##  8 24 [24. BUSINESS AND ADMINISTRATION PROFESSIONALS]            56.5       60  
##  9 25 [25. INFORMATION AND COMMUNICATIONS TECHNOLOGY PROFES…     51.7       51  
## 10 26 [26. LEGAL, SOCIAL AND CULTURAL PROFESSIONALS]             57.1       64  
## # ℹ 28 more rows

Bu işlemler verilerin içindeki değerler üstünde çalışmamıza yarıyordu. Ancak bütün veriseti üstünde de genel işlemler yapabiliriz. Bunları yine tidyverse içinde bulunan dplyr ve tidyr ile yapacağız.

ornek_df3 <- data.frame(
  isim = c("Can", "Burak", "Ayça"),
  yas = c(31, 26, 29),
  kadin = c(FALSE, FALSE, TRUE),
  mezuniyet_tarihi = c("13-01-2020", 
                       "16-06-2016", 
                       "15-06-2019"),
  bolum = c("ECON", "PSY", "POLS")
)


cbind_df <- 
  data.frame(ogrenci_no = 
               c(153, 189, 563, 285, 634, 353))

Elimizde benzer yapıya sahip verisetleri olunca bunları birleştirebiliriz. Basit birleştirme komutlarını daha önce görmüştük. Hatırlayarak devam etmek gerekirse

birlesik <- rbind(ornek_df2, ornek_df3)
noeklenmis <- cbind(birlesik, cbind_df)
birlesik2 <- bind_rows(ornek_df2, ornek_df3)
noeklenmis2 <- cbind(birlesik2, cbind_df)

Bu orneklerde verileri doğrudan birleştirmiştik ve R otomatik olarak değişkenleri eşleştirip yapmıştı. Bunu da endekslere göre yapmıştı. Ancak her zaman endeks sırasına göre veriye sahip olmayız. Bu gibi durumlarda ise bir key belirleyip ona göre atama yapabiliriz. Bunları farklı şekillerde yapmamız mümkün.

bolumler <- data.frame(bolum = c("IR", "POLS"),
                       fakulte = c("IIBF", "IIBF"))

inner_join her iki verisetinde de karşılığı olan rowları tutarken olmayanları birleşen verisetine eklemez.

join_df1 <- inner_join(ornek_df2, 
                       bolumler, by = "bolum")

left_join ve right_join ise soldaki veya sağdaki verisetindeki bütün değerleri tutarken diğer verisetinden sadece eşleşen değerleri alır.

join_df2 <- left_join(ornek_df3, 
                      bolumler, by = "bolum")
join_df3 <- right_join(ornek_df3, 
                       bolumler, by = "bolum")

full_join ise iki verisetindeki datayı da koruyarak birleştirmeye yarar

join_df4 <- full_join(ornek_df3, 
                      bolumler, by = "bolum")

semi_join iki versetinde de ortak olarak gözüken değerleri öğrenmemize yarar.

pols403 <- data.frame(isim = c("Ece Ucar", 
                               "Onur Gitmez", 
                               "Canberk Aydın"),
                      harf_notu = c(65,63,54))
join_df5 <- semi_join(birlesik_df, 
                      pols403, by = "isim")

anti_join ise iki verisetinde ortak olmayan değerleri alır. Bunu semi_joinin tersi olarak düşünebiliriz.

join_df6 <- anti_join(birlesik_df, 
                      pols403, by = "isim")

Zaten semi_join ve anti_join verilerini birleştirirsek orijinal verimizi yeniden oluştururuz.

Verisetleri long veya wide formatlarda olabilir. Wide format en alışkın olduğumuz formattır. Bu formatta her satır farklı bir kişi veya objedir ve bunun aldığı farklı değerler sütunlara dağılmıştır. Long format ise her satır ayrı bir gözlemdir. O kişinin veya objenin farklı sütunlarda aldığı değerleri bu sefer teker teker farklı satırlara gireriz. Örnek ile bakarsak daha açıklayıcı olur. Bu örnekte illere göre seçim sonuçlarını farklı yıllarda nasıl olduğunu görebiliyoruz.

wide_data <- data.frame(
  region = c("Ankara", "İstanbul", 
             "İzmir", "Adana", "Bursa"),
  AKP_2015 = c(45, 30, 40, 35, 38),
  CHP_2015 = c(40, 55, 42, 48, 45),
  MHP_2015 = c(15, 15, 18, 17, 17),
  AKP_2018 = c(47, 32, 41, 37, 40),
  CHP_2018 = c(38, 53, 40, 46, 43),
  MHP_2018 = c(15, 15, 19, 17, 17),
  AKP_2023 = c(46, 33, 42, 38, 41),
  CHP_2023 = c(39, 52, 39, 45, 42),
  MHP_2023 = c(15, 15, 19, 17, 17)
)
long_data <- data.frame(
  region = rep(c("Ankara", "İstanbul", 
                 "İzmir", "Adana", "Bursa"), 
               each = 9),
  party = rep(rep(c("AKP", "CHP", "MHP"),
                  each = 3), 5),
  year = rep(c(2015, 2018, 2023), 15),
  vote_percentage = c(
    45, 47, 46, 40, 38, 39, 15, 15, 15,
    30, 32, 33, 55, 53, 52, 15, 15, 15,
    40, 41, 42, 42, 40, 39, 18, 19, 19,
    35, 37, 38, 48, 46, 45, 17, 17, 17,
    38, 40, 41, 45, 43, 42, 17, 17, 17
  )
)

Bu iki veri formatını görmüş olduk. İkisinin de belli avantajı ve dezavantajı var elbet.

Wide: - Wide data en çok kullandığımız tip olduğu için gözümüze daha yakın gelebilir. - Anket verilerini genelde bu formatta kullanırız - Her kişinin değerleri tek satırda olduğu için takip etmesi kolaydır. - Ek olarak değişkenlerin summary statisticlerini çıkarmamız mümkün olacak. - Repeated measure analiz yapıyorsak, mesela bir sınıfın X hocasından ders almadan önce ve sonra ders notlarına bakmak gibi, uygun bir format olmayabilir. - Yeni verileri eklemek zor olabilir.

Long: - Genelde subject id’si, değişken adı ve değişken değeri olarak veriyi gireriz. Elbette buna ek başka girişler de olabilir ancak en temel şekilde veri formatı budur. - Aynı kişi birden çok rowda değer alabilir. - Bu çok değişken varsa ve yeni değişken eklememiz gerekiyorsa daha iyi bir formattır. - Bazı istatistiksel yöntemler için daha uygundur. Mesela time series - Anlaması daha zor olabilir - Missing dataların anlaşılması daha kolaydır

Verileri bu 2 formatta buluruz ancak her zaman geldiği formatta kullanmak zorunda değiliz. Bu gibi durumlarda daha önceden öğrendiğimiz transpose komutuna benzer komutlar kullanarak verimizi wide veya long format arasında dönüştürebiliriz. Bunun için farklı komutlar kullanıyoruz.

long_data_new <- wide_data %>%
  pivot_longer(
    cols = -region,
    names_to = c("party", "year"),
    names_sep = "_",
    values_to = "vote_percentage"
  )
wide_data_new <- long_data %>%
  pivot_wider(
    names_from = c(party, year),
    values_from = vote_percentage,
    names_sep = "_"
  )

Base R ile yapmak için reshape kullanbiliriz ancak bu veriyi dönüştürürken ek adımlar gerektirebileceği için tercih edilmez. Bunlara ek olarak reshape 2 paketini kullanabiliriz.

library(reshape2)
long_data_melt <- melt(wide_data, 
                       id.vars = "region",
                       variable.name = "party_year",
                       value.name = "vote_percentage")
wide_data_dcast <- dcast(long_data, 
                         region ~ party + year, 
                         value.var = "vote_percentage")

VERI TEMIZLIGI VE EKSIK VERI

Bütün veri setleri kendi oluşturduğumuz gibi eksiksiz veya sorunsuz olmayacak. Bazen veriler eksik olacak, bazen giriliş düzeni consistent olmayacak, bazen verilerde sonucu etkileyen outlier dediğimiz uç değerler olacak ve bazen de aynı değerler birden çok girilmiş olacak. Bu durumlar analiz sonuçlarımızı önemli derecede etkileyebilir.

Bu gibi durumlarda eksik verileri nasıl handle edebileceğimizi öğrenmemiz gerekir. Bu örnek veri ülkelerin GDP verisini yıllara göre tutuyor ancak bazı ülkeler zamanında varolmadığı veya düzgün veri sağlamadıkları için veri kısmı boş kalabiliyor.

worldbankgdpdata <- read_xls("worldbankdgpdata.xls")

Burada ortalamasına bakmak istedik ancak verimizde NA değerler olduğu için ortalamayı alamadık ve NA sonucunu bize verdi.

mean(worldbankgdpdata$`1960`)
## [1] NA

Analiz yaparken bu gibi durumların önüne geçmemiz gerekir. Yoksa bir sonuç elde etmemiz mümkün değil.

Bu durumlarda veri içinde NA değer var mı yok mu varsa da hangileri diye bakabiliriz. Bunun için:

is.na(worldbankgdpdata$`1960`)
##   [1]  TRUE FALSE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
##  [13]  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE
##  [25]  TRUE  TRUE FALSE FALSE FALSE  TRUE FALSE  TRUE  TRUE FALSE FALSE FALSE
##  [37]  TRUE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE  TRUE
##  [49] FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE FALSE FALSE
##  [61] FALSE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE  TRUE FALSE  TRUE
##  [73] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE  TRUE FALSE
##  [85]  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE FALSE  TRUE FALSE FALSE
##  [97] FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE
## [109]  TRUE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE
## [121]  TRUE FALSE  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE
## [133] FALSE  TRUE  TRUE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE  TRUE
## [145] FALSE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE FALSE  TRUE  TRUE FALSE  TRUE
## [157] FALSE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
## [169]  TRUE FALSE FALSE  TRUE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE
## [181] FALSE FALSE  TRUE  TRUE FALSE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE
## [193] FALSE  TRUE FALSE FALSE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE FALSE
## [205] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE  TRUE  TRUE FALSE  TRUE FALSE
## [217]  TRUE FALSE  TRUE  TRUE FALSE  TRUE  TRUE FALSE FALSE  TRUE FALSE FALSE
## [229]  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## [241] FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE
## [253]  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE FALSE
## [265] FALSE FALSE
anyNA(worldbankgdpdata$`1960`)
## [1] TRUE

İlk örnek bize NA değerlerin yerini de gösterirken, ikinci kod sadece TRUE ve FALSE olarak sonucu verdi.

Bu sorunu çözmenin belli yolları var. Mesela sadece bütün verinin tam olduğu durumu almak istiyorsak:

worldbankgdpdata_tam <- 
  worldbankgdpdata[complete.cases(worldbankgdpdata), ]

Ancak bu normalde işimize yarayacak önemli sayıda veriyi kaybetmemize sebep olacaktır. Bu durumun önüne geçmek için analizimize göre na değerleri ignore etmek veya onları imputation yöntemiyle doldurmak olabilir. Hepsini çıkarmamız da analizmizin sonuçlarını biased yapabilir.

Tek bir değişkenden NA değerleri şu şekilde çıkarabiliriz.

worldbankgdpdata_yeni <- 
  worldbankgdpdata[!is.na(worldbankgdpdata$`1960`), ]
worldbankgdpdata_yeni2 <- 
  worldbankgdpdata %>% drop_na(`1960`)

Bu çıkartma yöntemleri veriyi bozabildiği ve küçülttüğü için çok iyi olmayabilir. Ondan dolayı bunları analize katmama veya replace etme yöntemlerini tercih edebiliriz. Eğer NA değerleri hesaba katmak istemiyorsak:

mean(worldbankgdpdata$`1960`, na.rm = TRUE)
## [1] 72030050011

NA verilerle uğraşmanın başka bir yolu da onları mean veya median gibi yöntemlerle doldurmaktır. Bu örnekte çok mantıklı bir doldurma yöntemi olmasa

worldbankgdpdata$
  `1960`[is.na(worldbankgdpdata$`1960`)] <- 
  mean(worldbankgdpdata$`1960`, na.rm = TRUE)

Son olaraksa bazen NA değerlerin yerine başka bir değer atamak isteyebiliriz. Bunu R’da klasik NA değerin yerine x koy diyerek yapabileceğimiz gibi dplyr komutu ile de yapabiliriz.

worldbankgdpdata$`1960` <- 
  replace_na(worldbankgdpdata$`1960`, 0)

Bazı verilerde ise aynı veri birden fazla girilmiş olabilir. Bu analizimizi hatalı bir noktaya çekebilir.

pols403_duplicate <- data.frame(isim 
                                = c("Ece Ucar", 
                                    "Onur Gitmez", 
                                         "Canberk Aydın", 
                                    "Onur Gitmez"),
                      harf_notu = c(65,63,54, 63))

Bu veri basit olduğu için çift değeri hemen gördük ancak büyük verilerde bu kadar basit olmayacaktır. Bu gibi durumlarda komutlar kullanarak yapabiliriz.

Bir değer duplicate mu görmek için bu komutu kullanabiliriz. Ancak bu bize sadece ilkinden sonra duplicate olan değerleri verecektir.

duplicated(pols403_duplicate)
## [1] FALSE FALSE FALSE  TRUE

Bu komut ise veri içinde her bir unique değeri alacak. Yani duplicate değer varsa onun sadece 1 tanesini alır ve kalanları dışarı atar.

unique(pols403_duplicate)
##            isim harf_notu
## 1      Ece Ucar        65
## 2   Onur Gitmez        63
## 3 Canberk Aydın        54

Bu çift değerlerden kurtulmak için:

pols403_unique <- 
  pols403_duplicate%>% distinct()

Istersek tek bir columndaki çift değerlerden de kurtulabiliriz.

pols403_unique_isim <- pols403_duplicate %>% 
  distinct(isim, .keep_all = TRUE)

Outlier değerler analizimizi bozabilir. Çok yüksek veya çok düşüş değerler analiz sonucunu etkileyecek kadar ortalamadan uzaktaysa buna dikkat etmemiz gerekir.

mal_varlıkları <- data.frame(isim = 
                               c("Ece Ucar", 
                                 "Onur Gitmez", 
                                         "Zeynep Önal", 
                                 "Ali Koç"),
                      para = c(600000,700000,800000, 
                               1000000000))
mean(mal_varlıkları$para)
## [1] 250525000

Burada ortalama mal varlığına baktığımız zaman çok yüksek bir sayı görüyoruz ancak bunun temel sebebi 1 observationın aşırı yüksek bir değere sahip olması. Eğer bu olmasaydı daha düzgün bir değer görecektik.

Bu duruma önlem olarak farklı yöntemler deneyebiliriz.Outlier değerleri belirlemek için interquantiale range olarak tanımladığımız kısmın 1.5 katı üstü ve altını alırız. IQR konusuna ileride daha detaylı değineceğim ancak temel olarak verinin %25.ci kısmi ile %75.ci kısmı arasında kalan yer. Buradaki sayıyı alıp 1.5 ile çarptığımız zaman, bunu en tepeye eklediğimiz ve en tabandan çıkardığımız zaman kalan değerler outlier değerler olur.

ilk100sayı <- c(1:100)
summary(ilk100sayı)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1.00   25.75   50.50   50.50   75.25  100.00
Q1 <- quantile(mal_varlıkları$para, 0.25)
Q3 <- quantile(mal_varlıkları$para, 0.75)
IQR <- Q3 - Q1

lower_bound <- Q1 - 1.5 * IQR
upper_bound <- Q3 + 1.5 * IQR

outliers <- 
  mal_varlıkları$para < 
  lower_bound | mal_varlıkları$para > 
  upper_bound
outliers
## [1] FALSE FALSE FALSE  TRUE

Burada gördüğümüz üzere Ali Koç outlier değer olarak gözümüze çarpıyor. Bunları veri görselleştirme ile de görebiliriz ancak onu veri görselleştirme öğrendikten sonra göreceğiz. Şimdilik bu bizim için yeterli.

Outlier değerler için 2 farklı yöntem izleyebiliriz. Biri bu değerleri veriden atmak diğeri ise o değerlerin logunu alıp dönüşütürmek. Log konusuna daha sonra değineceğim.

Eğer veriden atmak istiyorsak:

mal_varlıkları_outliersız <- 
  mal_varlıkları[!outliers, ]

Eğer log dönüşümü yapmak istiyorsak:

# Log transformation
mal_varlıkları$para2 <- log(mal_varlıkları$para)

Log ettiğimiz zaman verilerin artık daha yakın olduğunu ve devasa farkların gözükmediğini gördük. Ancak aradaki ilişki hala aynı düzeyde kalıyor.

Outlier değerler üstünden bir analiz yapacaksak bazı durumlarda bunu mean gibi ortalamayı çok etkileyecek bir işlem üstünden değil median kullanarak yapabiliriz.

median(mal_varlıkları$para)
## [1] 750000

SON