7  Veri içe aktarma

7.1 Giriş

R paketlerinin sağladığı verilerle çalışmak, veri bilimi araçlarını öğrenmenin harika bir yoludur; ancak bir noktada öğrendiklerinizi kendi verilerinize uygulamak istersiniz. Bu bölümde veri dosyalarını R’a içe aktarmanın temellerini öğreneceksiniz.

Bu bölüm özellikle tablo biçimindeki düz metin dosyalarını okumaya odaklanır. Sütun adları, sütun türleri ve eksik veriler gibi özellikleri ele almaya yönelik pratik önerilerle başlayacağız. Ardından, birden fazla dosyadan aynı anda veri okumayı ve R’dan bir dosyaya veri yazmayı öğreneceksiniz. Son olarak, R’da veri çerçevelerini elle nasıl oluşturacağınızı öğreneceksiniz.

7.1.1 Ön koşullar

Bu bölümde çekirdek tidyverse’in bir parçası olan readr paketiyle düz metin dosyalarını R’a içe aktarmayı öğreneceksiniz.

7.2 Bir dosyadan veri okuma

Başlangıçta en yaygın tablo biçimli veri dosyası türüne odaklanacağız: virgülle ayrılmış değerler (comma-separated values) anlamına gelen CSV. Basit bir CSV dosyası şuna benzer. Genellikle başlık satırı (header row) olarak adlandırılan ilk satır sütun adlarını verir ve ardından gelen altı satır veriyi sağlar. Sütunlar virgülle ayrılır; başka bir deyişle virgül burada ayraç (delimiter) görevi görür.

Student ID,Full Name,favourite.food,mealPlan,AGE
1,Sunil Huffmann,Strawberry yoghurt,Lunch only,4
2,Barclay Lynn,French fries,Lunch only,5
3,Jayendra Lyne,N/A,Breakfast and lunch,7
4,Leon Rossini,Anchovies,Lunch only,
5,Chidiegwu Dunkel,Pizza,Breakfast and lunch,five
6,Güvenç Attila,Ice cream,Lunch only,6

Tablo 7.1 aynı verinin bir tablo olarak temsilini gösterir.

Tablo 7.1: students.csv dosyasındaki veri, bir tablo olarak.
Student ID Full Name favourite.food mealPlan AGE
1 Sunil Huffmann Strawberry yoghurt Lunch only 4
2 Barclay Lynn French fries Lunch only 5
3 Jayendra Lyne N/A Breakfast and lunch 7
4 Leon Rossini Anchovies Lunch only NA
5 Chidiegwu Dunkel Pizza Breakfast and lunch five
6 Güvenç Attila Ice cream Lunch only 6

Bu dosyayı read_csv()’i kullanarak R’a okuyabiliriz. İlk argüman en önemlisidir: dosyanın yolu. Yolu dosyanın adresi olarak düşünebilirsiniz: Dosyanın adı students.csv’dir ve dosya data klasöründe bulunur.

students <- read_csv("data/students.csv")
#> Rows: 6 Columns: 5
#> ── Column specification ─────────────────────────────────────────────────────
#> Delimiter: ","
#> chr (4): Full Name, favourite.food, mealPlan, AGE
#> dbl (1): Student ID
#> 
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Yukarıdaki kod, projenizde bir data klasöründe students.csv dosyasına sahipseniz çalışacaktır. students.csv dosyasını https://pos.it/r4ds-students-csv adresinden indirebilir veya onu doğrudan o URL’den şu şekilde okuyabilirsiniz:

students <- read_csv("https://pos.it/r4ds-students-csv")

read_csv() çalıştırıldığında verilerin satır ve sütun sayısını, kullanılan ayracı ve sütun belirtimini (içerdikleri veri türüne göre gruplanmış sütun adlarını) açıklayan bir mesaj görüntüler. Ayrıca tam sütun belirtimini nasıl görebileceğinizi ve bu mesajı nasıl gizleyebileceğinizi de açıklar. Bu mesaj readr’ın ayrılmaz bir parçasıdır ve Bölüm 7.3 bölümünde ona geri döneceğiz.

7.2.1 Pratik öneriler

Verileri okuduktan sonraki ilk adım, analizinizin geri kalanında çalışmayı kolaylaştıracak bir dönüşüm yapmak olur. Bunu aklımızda tutarak students verisine tekrar bir bakalım.

students
#> # A tibble: 6 × 5
#>   `Student ID` `Full Name`      favourite.food     mealPlan            AGE  
#>          <dbl> <chr>            <chr>              <chr>               <chr>
#> 1            1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2            2 Barclay Lynn     French fries       Lunch only          5    
#> 3            3 Jayendra Lyne    N/A                Breakfast and lunch 7    
#> 4            4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5            5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6            6 Güvenç Attila    Ice cream          Lunch only          6

favourite.food sütununda çeşitli yiyecek adlarının yanı sıra, aslında R’ın “mevcut değil” (not available) olarak tanıyacağı gerçek bir NA olması gereken N/A karakter dizisi bulunur. Bu, na argümanını kullanarak ele alabileceğimiz bir şeydir. Varsayılan olarak, read_csv() bu veri kümesinde yalnızca boş karakter dizilerini ("") NA olarak tanır ve "N/A" karakter dizisini de tanımasını istiyoruz.

students <- read_csv("data/students.csv", na = c("N/A", ""))

students
#> # A tibble: 6 × 5
#>   `Student ID` `Full Name`      favourite.food     mealPlan            AGE  
#>          <dbl> <chr>            <chr>              <chr>               <chr>
#> 1            1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2            2 Barclay Lynn     French fries       Lunch only          5    
#> 3            3 Jayendra Lyne    <NA>               Breakfast and lunch 7    
#> 4            4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5            5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6            6 Güvenç Attila    Ice cream          Lunch only          6

Student ID ve Full Name sütunlarının ters tırnak (backtick) içine alındığını da fark etmiş olabilirsiniz. Bunun nedeni boşluk içermeleri ve R’ın değişken adlarına ilişkin olağan kurallarına uymamalarıdır; bunlar söz dizimsel olmayan (non-syntactic) adlardır. Bu değişkenlere atıfta bulunmak için, onları ters tırnaklarla, `, çevrelemeniz gerekir:

students |> 
  rename(
    student_id = `Student ID`,
    full_name = `Full Name`
  )
#> # A tibble: 6 × 5
#>   student_id full_name        favourite.food     mealPlan            AGE  
#>        <dbl> <chr>            <chr>              <chr>               <chr>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2          2 Barclay Lynn     French fries       Lunch only          5    
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch 7    
#> 4          4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6          6 Güvenç Attila    Ice cream          Lunch only          6

Alternatif bir yaklaşım, hepsini bir kerede snake case’e dönüştürmek için bazı sezgisel yöntemler kullanan janitor::clean_names()’i kullanmaktır1.

students |> janitor::clean_names()
#> # A tibble: 6 × 5
#>   student_id full_name        favourite_food     meal_plan           age  
#>        <dbl> <chr>            <chr>              <chr>               <chr>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2          2 Barclay Lynn     French fries       Lunch only          5    
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch 7    
#> 4          4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6          6 Güvenç Attila    Ice cream          Lunch only          6

Veriyi okuduktan sonraki bir başka yaygın görev, değişken türlerini göz önünde bulundurmaktır. Örneğin, meal_plan, bilinen bir olası değerler kümesine sahip kategorik bir değişkendir ve R’da bir faktör olarak temsil edilmelidir:

students |>
  janitor::clean_names() |>
  mutate(meal_plan = factor(meal_plan))
#> # A tibble: 6 × 5
#>   student_id full_name        favourite_food     meal_plan           age  
#>        <dbl> <chr>            <chr>              <fct>               <chr>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only          4    
#> 2          2 Barclay Lynn     French fries       Lunch only          5    
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch 7    
#> 4          4 Leon Rossini     Anchovies          Lunch only          <NA> 
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch five 
#> 6          6 Güvenç Attila    Ice cream          Lunch only          6

meal_plan değişkenindeki değerlerin aynı kaldığına, ama değişken adının altında belirtilen değişken türünün karakterden (<chr>) faktöre (<fct>) değiştiğine dikkat edin. Faktörler hakkında Bölüm 16 bölümünde daha fazla bilgi edineceksiniz.

Bu veriyi analiz etmeden önce, muhtemelen age sütununu düzeltmek isteyeceksiniz. Şu anda age, gözlemlerden biri sayısal 5 yerine five olarak yazıldığından, bir karakter değişkenidir. Bu sorunu düzeltmenin ayrıntılarını Bölüm 20 bölümünde tartışıyoruz.

students <- students |>
  janitor::clean_names() |>
  mutate(
    meal_plan = factor(meal_plan),
    age = parse_number(if_else(age == "five", "5", age))
  )

students
#> # A tibble: 6 × 5
#>   student_id full_name        favourite_food     meal_plan             age
#>        <dbl> <chr>            <chr>              <fct>               <dbl>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
#> 2          2 Barclay Lynn     French fries       Lunch only              5
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch     7
#> 4          4 Leon Rossini     Anchovies          Lunch only             NA
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch     5
#> 6          6 Güvenç Attila    Ice cream          Lunch only              6

Buradaki yeni fonksiyon, üç argüman alan if_else() fonksiyonudur. İlk argüman olan test, mantıksal bir vektör olmalıdır. Sonuçta test değeri TRUE olduğunda ikinci argümanın (yes), FALSE olduğunda ise üçüncü argümanın (no) değeri kullanılır. Burada, age "five" karakter dizisiyse onu "5" yap, değilse age olarak bırak diyoruz. if_else() ve mantıksal vektörler hakkında Bölüm 12 bölümünde daha fazla bilgi edineceksiniz.

7.2.2 Diğer argümanlar

Bahsetmemiz gereken birkaç önemli argüman daha var ve önce size kullanışlı bir numara gösterirsek bunları göstermek daha kolay olacak: read_csv(), oluşturup bir CSV dosyası gibi biçimlendirdiğiniz metin karakter dizilerini okuyabilir:

read_csv(
  "a,b,c
  1,2,3
  4,5,6"
)
#> Warning: The `file` argument of `read_csv()` should use `I()` for literal data as of
#> readr 2.2.0.
#>   
#>   # Bad (for example):
#>   read_csv("x,y\n1,2")
#>   
#>   # Good:
#>   read_csv(I("x,y\n1,2"))
#> # A tibble: 2 × 3
#>       a     b     c
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3
#> 2     4     5     6

read_csv() genellikle verilerin ilk satırını sütun adları olarak kullanır; bu çok yaygın bir kuraldır. Ancak dosyanın başında birkaç satır üst veri bulunması da olağandır. İlk n satırı atlamak için skip = n kullanabilir veya (örneğin) # ile başlayan tüm satırları düşürmek için comment = "#" kullanabilirsiniz:

read_csv(
  "The first line of metadata
  The second line of metadata
  x,y,z
  1,2,3",
  skip = 2
)
#> # A tibble: 1 × 3
#>       x     y     z
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3

read_csv(
  "# A comment I want to skip
  x,y,z
  1,2,3",
  comment = "#"
)
#> # A tibble: 1 × 3
#>       x     y     z
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3

Diğer durumlarda, verinin sütun adları olmayabilir. read_csv()’e ilk satırı başlık olarak ele almamasını ve bunun yerine X1’den Xn’e kadar sırayla etiketlemesini söylemek için col_names = FALSE kullanabilirsiniz:

read_csv(
  "1,2,3
  4,5,6",
  col_names = FALSE
)
#> # A tibble: 2 × 3
#>      X1    X2    X3
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3
#> 2     4     5     6

Alternatif olarak, col_names’e sütun adları olarak kullanılacak bir karakter vektörü de geçebilirsiniz:

read_csv(
  "1,2,3
  4,5,6",
  col_names = c("x", "y", "z")
)
#> # A tibble: 2 × 3
#>       x     y     z
#>   <dbl> <dbl> <dbl>
#> 1     1     2     3
#> 2     4     5     6

Bu argümanlar, pratikte karşılaşacağınız CSV dosyalarının çoğunu okumak için bilmeniz gereken her şeydir. (Geri kalanı için, .csv dosyanızı dikkatlice incelemeniz ve read_csv()’in diğer pek çok argümanının dokümantasyonunu okumanız gerekecek.)

7.2.3 Diğer dosya türleri

read_csv() fonksiyonunda ustalaştıktan sonra readr’ın diğer fonksiyonlarını kullanmak kolaydır; yalnızca hangi fonksiyonu çağıracağınızı bilmeniz gerekir:

  • read_csv2() noktalı virgülle ayrılmış dosyaları okur. Bunlar, alanları ayırmak için , yerine ; kullanır ve ondalık işareti olarak , kullanan ülkelerde yaygındır.

  • read_tsv() sekmeyle ayrılmış dosyaları okur.

  • read_delim(), herhangi bir ayraç kullanan dosyaları okur; ayracı belirtmezseniz otomatik olarak tahmin etmeye çalışır.

  • read_fwf() sabit genişlikli dosyaları okur. Alanları fwf_widths() ile genişliklerine göre veya fwf_positions() ile konumlarına göre belirtebilirsiniz.

  • read_table(), sütunların boşlukla ayrıldığı sabit genişlikli dosyaların yaygın bir varyasyonunu okur.

  • read_log() Apache tarzı günlük (log) dosyalarını okur.

7.2.4 Alıştırmalar

  1. Alanların “|” ile ayrıldığı bir dosyayı okumak için hangi fonksiyonu kullanırdınız?

  2. file, skip ve comment dışında, read_csv() ve read_tsv()’nin ortak olarak başka hangi argümanları var?

  3. read_fwf()’in en önemli argümanları nelerdir?

  4. Bazen bir CSV dosyasındaki karakter dizileri virgül içerir. Sorun yaratmalarını önlemek için, " veya ' gibi bir tırnak karakteriyle çevrelenmeleri gerekir. Varsayılan olarak, read_csv() tırnak karakterinin " olacağını varsayar. Aşağıdaki metni bir veri çerçevesine okumak için, read_csv()’e hangi argümanı belirtmeniz gerekir?

    "x,y\n1,'a,b'"
  5. Aşağıdaki satır içi CSV dosyalarının her birinde neyin yanlış olduğunu belirleyin. Kodu çalıştırdığınızda ne olur?

    read_csv("a,b\n1,2,3\n4,5,6")
    read_csv("a,b,c\n1,2\n1,2,3,4")
    read_csv("a,b\n\"1")
    read_csv("a,b\n1,2\na,b")
    read_csv("a;b\n1;3")
  6. Aşağıdaki veri çerçevesinde sözdizimsel olmayan isimlere atıfta bulunmayı şu şekilde pratik edin:

    1. 1 adlı değişkeni çıkarın.
    2. 1’e karşı 2’nin bir saçılım grafiğini çizin.
    3. 2’nin 1’e bölünmesiyle elde edilen 3 adlı yeni bir sütun oluşturun.
    4. Sütunları one, two ve three olarak yeniden adlandırın.
    annoying <- tibble(
      `1` = 1:10,
      `2` = `1` * 2 + rnorm(length(`1`))
    )

7.3 Sütun türlerini denetleme

Bir CSV dosyası, her değişkenin türü hakkında herhangi bir bilgi içermez (yani mantıksal mı, sayı mı, karakter dizisi mi vb.), bu yüzden readr türü tahmin etmeye çalışır. Bu bölüm, tahmin sürecinin nasıl çalıştığını, başarısız olmasına neden olan bazı yaygın sorunların nasıl çözüleceğini ve gerekirse sütun türlerini kendinizin nasıl sağlayacağını açıklar. Son olarak readr dosyayı doğru biçimde ayrıştıramıyorsa ve dosya yapısı hakkında daha fazla bilgi edinmeniz gerekiyorsa yararlanabileceğiniz birkaç genel stratejiden söz edeceğiz.

7.3.1 Türleri tahmin etme

readr, sütun türlerini bulmak için sezgisel bir yöntem kullanır. Her sütun için, eksik değerleri göz ardı ederek, ilk satırdan sona kadar eşit aralıklarla dağılmış 1.000 satırın2 değerlerini çeker. Ardından şu soruları sırayla ele alır:

  • Yalnızca F, T, FALSE veya TRUE mü içeriyor (büyük/küçük harf gözetmeksizin)? Öyleyse, bir mantıksaldır.
  • Yalnızca sayılar mı içeriyor (örneğin, 1, -4.5, 5e6, Inf)? Öyleyse, bir sayıdır.
  • ISO8601 standardıyla eşleşiyor mu? Öyleyse, bir tarih veya tarih-saattir. (Tarih-saatlere Bölüm 17.2 bölümünde daha ayrıntılı geri döneceğiz.)
  • Aksi takdirde, bir karakter dizisi olmalıdır.

Bu davranışı bu basit örnekte eylem halinde görebilirsiniz:

read_csv("
  logical,numeric,date,string
  TRUE,1,2021-01-15,abc
  false,4.5,2021-02-15,def
  T,Inf,2021-02-16,ghi
")
#> # A tibble: 3 × 4
#>   logical numeric date       string
#>   <lgl>     <dbl> <date>     <chr> 
#> 1 TRUE        1   2021-01-15 abc   
#> 2 FALSE       4.5 2021-02-15 def   
#> 3 TRUE      Inf   2021-02-16 ghi

Bu sezgisel yöntem temiz veri kümelerinde iyi çalışır; ancak gerçek yaşamda çeşit çeşit tuhaf ayrıştırma hatasıyla karşılaşırsınız.

7.3.2 Eksik değerler, sütun türleri ve sorunlar

Sütun türü tespitinin en yaygın başarısızlık biçimi, sütunun beklenmedik değerler içermesi ve daha özel bir tür yerine karakter sütunu olarak okunmasıdır. Bunun en yaygın nedenlerinden biri, readr’ın beklediği NA dışında bir şey kullanılarak kaydedilmiş bir eksik değerdir.

Bu basit, tek sütunlu CSV dosyasını örnek olarak ele alalım:

simple_csv <- "
  x
  10
  .
  20
  30"

Onu herhangi bir ek argüman olmadan okursak, x bir karakter sütunu haline gelir:

read_csv(simple_csv)
#> # A tibble: 4 × 1
#>   x    
#>   <chr>
#> 1 10   
#> 2 .    
#> 3 20   
#> 4 30

Bu çok küçük durumda, eksik değeri, .’yi, kolayca görebilirsiniz. Ama aralarına serpiştirilmiş .’lerle temsil edilen yalnızca birkaç eksik değere sahip binlerce satırınız olsaydı ne olurdu? Bir yaklaşım, readr’a x’in sayısal bir sütun olduğunu söylemek ve ardından nerede başarısız olduğunu görmektir. Bunu, adları CSV dosyasındaki sütun adlarıyla eşleşen, adlandırılmış bir liste alan col_types argümanıyla yapabilirsiniz:

df <- read_csv(
  simple_csv, 
  col_types = list(x = col_double())
)
#> Warning: One or more parsing issues, call `problems()` on your data frame for
#> details, e.g.:
#>   dat <- vroom(...)
#>   problems(dat)

Şimdi read_csv(), bir sorun olduğunu bildiriyor ve problems() ile daha fazlasını öğrenebileceğimizi söylüyor:

problems(df)
#> # A tibble: 1 × 5
#>     row   col expected actual file                                          
#>   <int> <int> <chr>    <chr>  <chr>                                         
#> 1     3     1 a double .      /tmp/RtmpblFazD/vroom-chr-to-file-1fc325b1ab44

Bu bize, readr’ın bir double beklediği ama bir . aldığı satır 3, sütun 1’de bir sorun olduğunu söylüyor. Bu, bu veri kümesinin eksik değerler için . kullandığını düşündürüyor. Bu yüzden na = "." ayarladığımızda, otomatik tahmin başarılı olur ve bize istediğimiz sayısal sütunu verir:

read_csv(simple_csv, na = ".")
#> # A tibble: 4 × 1
#>       x
#>   <dbl>
#> 1    10
#> 2    NA
#> 3    20
#> 4    30

7.3.3 Sütun türleri

readr, kullanmanız için toplam dokuz sütun türü sağlar:

  • col_logical() ve col_double(), mantıksal değerleri ve gerçek sayıları okur. Görece nadiren ihtiyaç duyulurlar (yukarıdaki durum hariç), çünkü readr genellikle bunları sizin için tahmin edecektir.
  • col_integer() tam sayıları okur. Bu kitapta tam sayıları ve double’ları nadiren ayırt ediyoruz, çünkü işlevsel olarak eşdeğerler; ama tam sayıları açıkça okumak bazen yararlı olabilir, çünkü double’ların yarısı kadar bellek kaplarlar.
  • col_character() karakter dizilerini okur. Bir nesneyi tanımlayan ama üzerinde matematiksel işlemler uygulamak mantıklı olmayan uzun rakam dizileri olan, yani sayısal bir tanımlayıcı olan bir sütununuz olduğunda bunu açıkça belirtmek yararlı olabilir. Örnekler arasında telefon numaraları, sosyal güvenlik numaraları, kredi kartı numaraları vb. bulunur.
  • col_factor(), col_date() ve col_datetime(), sırasıyla faktörler, tarihler ve tarih-saatler oluşturur; bu veri türlerine Bölüm 16 ve Bölüm 17 bölümlerinde geldiğimizde bunlar hakkında daha fazla bilgi edineceksiniz.
  • col_number(), sayısal olmayan bileşenleri yok sayan hoşgörülü bir sayısal ayrıştırıcıdır ve özellikle para birimleri için yararlıdır. Bu konuda Bölüm 13 bölümünde daha fazla bilgi edineceksiniz.
  • col_skip(), bir sütunu atlayarak sonuca dahil edilmemesini sağlar; bu, büyük bir CSV dosyanız varsa ve yalnızca bazı sütunları kullanmak istiyorsanız veriyi okumayı hızlandırmak için yararlı olabilir.

list() yerine cols() kullanıp .default değerini belirterek tür tahmini yapan varsayılan sezgisel yöntemi geçersiz kılabilirsiniz:

another_csv <- "
x,y,z
1,2,3"

read_csv(
  another_csv, 
  col_types = cols(.default = col_character())
)
#> # A tibble: 1 × 3
#>   x     y     z    
#>   <chr> <chr> <chr>
#> 1 1     2     3

Bir başka yararlı yardımcı, yalnızca belirttiğiniz sütunları okuyacak olan cols_only()’dur:

read_csv(
  another_csv,
  col_types = cols_only(x = col_character())
)
#> # A tibble: 1 × 1
#>   x    
#>   <chr>
#> 1 1

7.4 Birden fazla dosyadan veri okuma

Bazen veriniz tek bir dosyada bulunmak yerine birden fazla dosyaya bölünmüştür. Örneğin, birden fazla aya ait satış verileriniz olabilir; her ayın verisi ayrı bir dosyada: Ocak için 01-sales.csv, Şubat için 02-sales.csv ve Mart için 03-sales.csv. read_csv() ile bu verileri bir kerede okuyabilir ve tek bir veri çerçevesinde üst üste yığabilirsiniz.

sales_files <- c("data/01-sales.csv", "data/02-sales.csv", "data/03-sales.csv")
read_csv(sales_files, id = "file")
#> # A tibble: 19 × 6
#>   file              month    year brand  item     n
#>   <chr>             <chr>   <dbl> <dbl> <dbl> <dbl>
#> 1 data/01-sales.csv January  2019     1  1234     3
#> 2 data/01-sales.csv January  2019     1  8721     9
#> 3 data/01-sales.csv January  2019     1  1822     2
#> 4 data/01-sales.csv January  2019     2  3333     1
#> 5 data/01-sales.csv January  2019     2  2156     9
#> 6 data/01-sales.csv January  2019     2  3987     6
#> # ℹ 13 more rows

Yine, yukarıdaki kod, projenizde bir data klasöründe CSV dosyalarına sahipseniz çalışacaktır. Bu dosyaları https://pos.it/r4ds-01-sales, https://pos.it/r4ds-02-sales ve https://pos.it/r4ds-03-sales adreslerinden indirebilir veya onları doğrudan şu şekilde okuyabilirsiniz:

sales_files <- c(
  "https://pos.it/r4ds-01-sales",
  "https://pos.it/r4ds-02-sales",
  "https://pos.it/r4ds-03-sales"
)
read_csv(sales_files, id = "file")

id argümanı, ortaya çıkan veri çerçevesine file adlı yeni bir sütun ekler; bu sütun verilerin hangi dosyadan geldiğini belirtir. Bu, okuduğunuz dosyaların, gözlemleri orijinal kaynaklarına geri izlemenize yardımcı olacak bir tanımlayıcı sütuna sahip olmadığı durumlarda özellikle yararlıdır.

Okumak istediğiniz çok sayıda dosyanız varsa, adlarını bir liste olarak yazmak külfetli hale gelebilir. Bunun yerine, dosya adlarında bir kalıp eşleştirerek dosyaları sizin için bulmak üzere temel list.files() fonksiyonunu kullanabilirsiniz. Bu kalıplar hakkında Bölüm 15 bölümünde daha fazla bilgi edineceksiniz.

sales_files <- list.files("data", pattern = "sales\\.csv$", full.names = TRUE)
sales_files
#> [1] "data/01-sales.csv" "data/02-sales.csv" "data/03-sales.csv"

7.5 Bir dosyaya yazma

readr ayrıca veriyi diske geri yazmak için iki yararlı fonksiyonla birlikte gelir: write_csv() ve write_tsv(). Bu fonksiyonların en önemli argümanları x (kaydedilecek veri çerçevesi) ve file’dır (kaydedileceği konum). Ayrıca eksik değerlerin na ile nasıl yazılacağını ve verileri mevcut bir dosyanın sonuna eklemek isteyip istemediğinizi de belirtebilirsiniz.

write_csv(students, "students.csv")

Şimdi o csv dosyasını tekrar okuyalım. Az önce kurduğunuz değişken türü bilgisinin, CSV’ye kaydettiğinizde kaybolduğuna dikkat edin; çünkü düz metin dosyasından okuyarak tekrar baştan başlıyorsunuz:

students
#> # A tibble: 6 × 5
#>   student_id full_name        favourite_food     meal_plan             age
#>        <dbl> <chr>            <chr>              <fct>               <dbl>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
#> 2          2 Barclay Lynn     French fries       Lunch only              5
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch     7
#> 4          4 Leon Rossini     Anchovies          Lunch only             NA
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch     5
#> 6          6 Güvenç Attila    Ice cream          Lunch only              6
write_csv(students, "students-2.csv")
read_csv("students-2.csv")
#> # A tibble: 6 × 5
#>   student_id full_name        favourite_food     meal_plan             age
#>        <dbl> <chr>            <chr>              <chr>               <dbl>
#> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
#> 2          2 Barclay Lynn     French fries       Lunch only              5
#> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch     7
#> 4          4 Leon Rossini     Anchovies          Lunch only             NA
#> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch     5
#> 6          6 Güvenç Attila    Ice cream          Lunch only              6

Bu durum CSV dosyalarını ara sonuçları önbelleğe almak için biraz güvenilmez kılar: Dosyayı her yüklediğinizde sütun belirtimini yeniden oluşturmanız gerekir. İki temel alternatif vardır:

  1. write_rds() ve read_rds(), temel readRDS() ve saveRDS() fonksiyonları için tutarlı bir arayüz sunan sarmalayıcılardır. Verileri RDS adı verilen, R’a özgü ikili dosya biçiminde saklarlar. Bu, nesneyi yeniden yüklediğinizde, sakladığınız tamamen aynı R nesnesini yüklediğiniz anlamına gelir.

    write_rds(students, "students.rds")
    read_rds("students.rds")
    #> # A tibble: 6 × 5
    #>   student_id full_name        favourite_food     meal_plan             age
    #>        <dbl> <chr>            <chr>              <fct>               <dbl>
    #> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
    #> 2          2 Barclay Lynn     French fries       Lunch only              5
    #> 3          3 Jayendra Lyne    <NA>               Breakfast and lunch     7
    #> 4          4 Leon Rossini     Anchovies          Lunch only             NA
    #> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch     5
    #> 6          6 Güvenç Attila    Ice cream          Lunch only              6
  2. arrow paketi, programlama dilleri arasında paylaşılabilen hızlı bir ikili dosya biçimi olan Parquet dosyalarını okuyup yazmanızı sağlar. arrow’a Bölüm 22 bölümünde daha derinlemesine geri döneceğiz.

    library(arrow)
    write_parquet(students, "students.parquet")
    read_parquet("students.parquet")
    #> # A tibble: 6 × 5
    #>   student_id full_name        favourite_food     meal_plan             age
    #>        <dbl> <chr>            <chr>              <fct>               <dbl>
    #> 1          1 Sunil Huffmann   Strawberry yoghurt Lunch only              4
    #> 2          2 Barclay Lynn     French fries       Lunch only              5
    #> 3          3 Jayendra Lyne    NA                 Breakfast and lunch     7
    #> 4          4 Leon Rossini     Anchovies          Lunch only             NA
    #> 5          5 Chidiegwu Dunkel Pizza              Breakfast and lunch     5
    #> 6          6 Güvenç Attila    Ice cream          Lunch only              6

Parquet genellikle RDS’den çok daha hızlıdır ve R dışında da kullanılabilir; ancak arrow paketini gerektirir.

7.6 Elle veri girişi

Bazen R scriptinizin içinde veri girerek bir tibble’ı “elle” oluşturmanız gerekir. Bunu yapmanıza yardımcı olacak, tibble’ı sütunlara göre mi yoksa satırlara göre mi düzenlediğinize göre farklılık gösteren iki yararlı fonksiyon vardır. tibble() sütun bazında çalışır:

tibble(
  x = c(1, 2, 5), 
  y = c("h", "m", "g"),
  z = c(0.08, 0.83, 0.60)
)
#> # A tibble: 3 × 3
#>       x y         z
#>   <dbl> <chr> <dbl>
#> 1     1 h      0.08
#> 2     2 m      0.83
#> 3     5 g      0.6

Verileri sütunlara göre düzenlemek satırlar arasındaki ilişkileri görmeyi zorlaştırabilir. Bir alternatif, verileri satır satır düzenlemenizi sağlayan ve transposed tibble (devrik tibble) ifadesinin kısaltması olan tribble() fonksiyonudur. tribble(), kodda veri girişi için özelleştirilmiştir: sütun başlıkları ~ ile başlar ve girdiler virgüllerle ayrılır. Bu, az miktarda veriyi okunması kolay bir formda düzenlemeyi mümkün kılar:

tribble(
  ~x, ~y, ~z,
  1, "h", 0.08,
  2, "m", 0.83,
  5, "g", 0.60
)
#> # A tibble: 3 × 3
#>       x y         z
#>   <dbl> <chr> <dbl>
#> 1     1 h      0.08
#> 2     2 m      0.83
#> 3     5 g      0.6

7.7 Özet

Bu bölümde, read_csv() ile CSV dosyalarını nasıl yükleyeceğinizi ve tibble() ile tribble() ile kendi veri girişinizi nasıl yapacağınızı öğrendiniz. CSV dosyalarının nasıl çalıştığını, karşılaşabileceğiniz bazı sorunları ve bunların nasıl aşılacağını öğrendiniz. Bu kitapta veri içe aktarmaya birkaç kez daha döneceğiz: Excel ve Google E-Tablolar’dan Bölüm 20, veritabanlarından veri yüklemeyi göstereceğimiz Bölüm 21, Parquet dosyalarından Bölüm 22, JSON’dan Bölüm 23 ve web sitelerinden Bölüm 24.

Kitabın bu bölümünün neredeyse sonuna geldik; ama ele almamız gereken önemli bir son konu daha var: nasıl yardım alınır. Bu yüzden bir sonraki bölümde yardım arayabileceğiniz iyi kaynakları, yararlı yanıt alma olasılığınızı artıracak yeniden üretilebilir bir örneği (reprex) nasıl oluşturacağınızı ve R dünyasını takip etmeye yönelik bazı genel önerileri öğreneceksiniz.


  1. janitor paketi tidyverse’in bir parçası değildir; ancak veri temizlemeye yönelik yararlı fonksiyonlar sunar ve |> kullanan veri işlem hatlarında iyi çalışır.↩︎

  2. 1000 varsayılanını guess_max argümanıyla geçersiz kılabilirsiniz.↩︎