4  Duomenų importavimas ir eksportavimas

Įprastai didesnės apimties duomenys laikomi įvairaus formatų failuose, kaip pvz. .txt, .csv, .dat, .xlsx, .JSON ir taip toliau. Bendrai tariant, failų formatus galima klasifikuoti į tekstinius ir binarinius. Šios kategorijos turi skirtingas duomenų saugojimo įpatybes, todėl reikalingi skirtingi būdai kaip tokius failus nuskaityti ar išsaugoti tokiu formatu.

Pagrindinis skirtumas tarp tekstinių ir binarinių failų yra tas, kad binariniai failai neturi jokių vidinių apribojimų (gali būti bet kokia baitų seka) ir jie turi būti atidaromi atitinkama programa, žinančia failo formatą (pvz. „Adobe Photoshop“, „SumatraPDF“ ir kt.). Pagal susitarimą kiekvieno tekstinio failo turinys atitinka tam tikras taisykles ir gali būti redaguojamas bet kuria teksto redagavimo programa.

Norint tinkamai dirbti su duomenimis reikia mokėti apdoroti skirtingų formatų failus, todėl šis skyrius yra išskaidytas į tekstinių ir binarinių failų nuskaitymą ir įrašymą.

4.1 Darbinio katalogo nustatymas

Prieš pradedant darbą su R, pravartu nustatyti, iš kokio aplanko bus nuskaitomi ir įrašomi failai. Įsijungus naują R sesiją, pagal nutylėjimą darbinis katalogas yra vartotojo namų aplankas. Norint patikrinti, kuri kompiuterio direktorija yra darbinė, naudojama funkcija getwd()

Kodas
#> [1] "C:/Users/DonatasSl/Desktop"

Jei norite, kad R failų ieškotų kitame aplanke – naudojama funkcija setwd(), kurios vienintelis argumentas yra absoliutus arba santykinis kelias:

Kodas
setwd(dir = "C:/Users/DonatasSl/Desktop/R konspektas")

Svarbu žinoti, jog įprastai kelias iki aplanko ar failo nurodomas su atgaliniu pasviruoju brūkšniu \, tačiau R kalboje tai yra specialus simbolis (escape character), kūrį reikia ištraukti naudojant tokį patį simbolį. Tokiu atveju, nurodomas kelias atrodytų taip:

Kodas
setwd(dir = "C:\\Users\\DonatasSl\\Desktop\\R konspektas")

Yra ir kitas galimas simbolis nurodant kelią - priekinis pasvirasis brūkšnys /. Tokiu atveju, nurodomas kelias atrodytų taip:

Kodas
setwd(dir = "C:/Users/DonatasSl/Desktop/R konspektas")

Žinoma, norint nustatyti tam tikrą katalogą, pirma jis turi būti sukurtas.

4.2 Duomenų nuskaitymas

4.2.1 Tekstiniai failai

Tekstinių failų nuskaitymui R turi keletą procedūrų. Aptarsime skirtingus nuskaitomų duomenų atvejus.

Vektoriaus nuskaitymas

Vieno vektoriaus elementų nuskaitymui naudojama funkcija scan(). Ši funkcija vektoriaus elementus nuskaito eilutėmis.

Argumentas Reikšmė
file failo vardas arba kelias iki failo, nurodytas kabutėse
what vektoriaus tipas: numeric(), character() ir t.t
sep vektoriaus elementus skiriantis simbolis, pagal nutylėjimą tarpas
dec dešimtainio kablelio simbolis, pagal nutylėjimą - taškas
skip pirmųjų nenuskaitomų failo eilučių skaičius
nlines nuskaitomų failo eilučių skaičius
n maksimalus vektoriaus elementų skaičius

Jei argumento file reikšmė nenurodoma, tai vektoriaus reikšmės bus įvedamos iš klaviatūros.

Atidarysime testinį failą test_numeric.dat, kuris sudarytas iš skaitinių reikšmių.

Kodas
x <- scan(file = "data/test_numeric.dat")
x
#> [1] 3.141593 3.141600 3.140000 2.718282 2.718300 2.720000

Šiuo atveju nereikėjo nurodyti, kokio tipo reikšmės bus nuskaitomos, nes pagal nutylėjimą duomenys nuskaitomi kaip double() tipo. Tačiau jeigu vektoriaus elementai yra simboliai, reikia nurodyti argumentą what = character(). Pavyzdžiui, nuskaitomas tekstinių duomenų failas test_character.dat.

Kodas
x <- scan(file = "data/test_character.dat", what = character())
x
#> [1] "Lorem" "ipsum" "dolor" "sit"   "amet"

Ši funkcija naudinga tuo, kad ji leidžia nuskaityti duomenų failus tiesiai iš interneto. Tokiu atveju funkcijos parametrui file reikia nurodyti pilną failo adresą.

Kodas
adresas <- "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
x <- scan(file = adresas, what = character(), sep = ",")
x[1:5]
#> [1] "5.1"         "3.5"         "1.4"         "0.2"         "Iris-setosa"

Visai teksto eilutei nuskaityti kaip vieną elementą naudojama specialiai tam skirta funkcija readLines(). Argumentas n nurodo nuskaitomų eilučių skaičių.

Kodas
adresas <- "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
x <- readLines(adresas, n = 4)
x
#> [1] "5.1,3.5,1.4,0.2,Iris-setosa" "4.9,3.0,1.4,0.2,Iris-setosa"
#> [3] "4.7,3.2,1.3,0.2,Iris-setosa" "4.6,3.1,1.5,0.2,Iris-setosa"

Duomenų lentelės nuskaitymas

Duomenų lentelės iš failo nuskaitymui naudojama funkcija read.table().

Argumentas Reikšmė
file failo vardas arba kelias iki failo, nurodytas kabutėse
header TRUE nurodo, kad pirmoje eilutėje surašyti kintamųjų pavadinimai
sep stulpelius skiriantis simbolis, pagal nutylėjimą tarpas
dec dešimtainio kablelio simbolis, pagal nutylėjimą - taškas
skip pirmųjų nenuskaitomų failo eilučių skaičius
nrows nuskaitomų failo eilučių skaičius
row.names eilučių vardų vektorius, jų stulpelio numeris arba pavadinimas
col.names stulpelių pavadinimų vektorius
na.strings praleistos reikšmės simbolis, pagal nutylėjimą NA
as.is jei TRUE, kategoriniai kintamieji nuskaitomi kaip faktoriai

Pavyzdžiui, nuskaitomas tas pats simbolių vektorius, kurio reikšmės duomenų faile yra surašytos stulpeliu.

Kodas
df <- read.table(file = "data/test_character.dat")
df
#>      V1
#> 1 Lorem
#> 2 ipsum
#> 3 dolor
#> 4   sit
#> 5  amet

Nenurodžius stulpelio pavadinimo, jis sudaromas automatiškai.

Kaip ir funkcijai scan(), čia galima nurodyti, kad duomenų failas yra internete.

Kodas
df <- read.table(file = adresas, 
                 sep = ",", 
                 nrows = 4, 
                 col.names = c("Sepal.Length","Sepal.Width","Petal.Length","Petal.Width","Species")
                 )
df
#>   Sepal.Length Sepal.Width Petal.Length Petal.Width     Species
#> 1          5.1         3.5          1.4         0.2 Iris-setosa
#> 2          4.9         3.0          1.4         0.2 Iris-setosa
#> 3          4.7         3.2          1.3         0.2 Iris-setosa
#> 4          4.6         3.1          1.5         0.2 Iris-setosa

Kad duomenis būtų galima nesunkiai perkelti iš vienos programos į kitą, jie į failus rašomi tam tikru standartiniu formatu, kurį daugelis programų žino kaip nuskaityti. Vienas iš populiariausių tekstinio duomenų failo formatas yra taip vadinamas comma separated values arba sutrumpintai .csv. Jis skirtas lentelės pavidalo duomenims užrašyti, kur stulpeliuose yra kintamieji, o eilutėse yra stebiniai.

Funkcija read.csv() naudojama nuskaityti failams, kuriuose stulpeliai vienas nuo kito atskirti kableliu, o trupmeninė skaičiaus dalis skiriama tašku. Nuskaitysime, duomenų rinkinų adult.csv.

Kodas
df <- read.csv(file = "data/adult.csv", nrows = 5)
df
#>   age workclass fnlwgt    education education.num marital.status
#> 1  90         ?  77053      HS-grad             9        Widowed
#> 2  82   Private 132870      HS-grad             9        Widowed
#> 3  66         ? 186061 Some-college            10        Widowed
#> 4  54   Private 140359      7th-8th             4       Divorced
#> 5  41   Private 264663 Some-college            10      Separated
#>          occupation  relationship  race    sex capital.gain capital.loss
#> 1                 ? Not-in-family White Female            0         4356
#> 2   Exec-managerial Not-in-family White Female            0         4356
#> 3                 ?     Unmarried Black Female            0         4356
#> 4 Machine-op-inspct     Unmarried White Female            0         3900
#> 5    Prof-specialty     Own-child White Female            0         3900
#>   hours.per.week native.country income
#> 1             40  United-States  <=50K
#> 2             18  United-States  <=50K
#> 3             40  United-States  <=50K
#> 4             40  United-States  <=50K
#> 5             40  United-States  <=50K

Jei stulpeliai vienas nuo kito atskiriami kabliataškiu, tai trupmeninė skaičiaus dalis skiriama mums įprastu kableliu. Tokio formatuo duomenų failui nuskaityti naudojama funkcija read.csv2().

Aišku, .csv formato failą galima nuskaityti ir naudojant funkciją read.table(), tačiau šiuo atveju nuskaitymo komanda yra paprastesnė. Jei stulpeliai faile atskiriami tabuliacijos ženklu „, tada tokiems duomenims nuskaityti gali būti taikoma funkcija read.delim() arba read.delim2().

Iš tikro visos šios išvardytos funkcijos viduje naudoją vieną ir ta pačią funkciją read.table(), tik su iš anksto nustatytais šios funkcijos argumentais.

4.2.2 Binariniai failai

Jei duomenys sudėtingos struktūros, kaip pavyzdžiui sąrašai, sudėtinga duomenų lentelė su atributais, R statistinių procedūrų rezultatai, saugoti juos tekstinio failo formatu yra nepatogu. Dingtų atributai, faktorių lygiai ar net tikslumas. Tokiems atvejams R turi binarinį saugojimo formatą su išplėtimu .Rdata.

Tokio formato failai importuojami naudojant funkciją load(). Nuskaitysime duomenų rinkinį woman.Rdata. Nuskaitymo rezultato nereikia priskirti jokiam objektui - importuotas duomenų rinkinys po nuskaitymo iškart matomas prie R sesijos objektų sąrašo.

Kodas
load(file = "data/woman.Rdata")

Kadangi binariai failai neturi vienos bendros struktūros, skirtingo formatų failams reikalingos specifinės funkcijos. Pavyzdžiui, tam pačiam .xlsx formato duomenims nuskaityti, reikalingos funkcijos iš kitų R paketų.

Šio formato failams skaityti yra sukurtas ne vienas paketas. Kuo jie visi skiriasi? Vieni naudojami tik failų nuskaitymui, kiti - ir nuskaitymui, ir įrašymui. Keletas iš jų reikalauja įdiegtos Java JDK, kiti turi mažiau priklausomybių nuo išorinių programų.

Paketas Kada verta rinktis?
readxl kasdieninėje veikloje tik greitam failų nuskaitymui
openxlsx2 didelės apimties failams nuskaityti ir įrašyti (> 100 tūkst. eilučių)
xlsx galima nuskaityti ir įrašyti failus, reikalinga Java JDK ir rJava
tidyxl neįprastai suformatuotiems duomenims nuskaityti
XLConnect niekada nenaudoti

Jeigu dirbant su duomenimis reikalingas .xlsx formato duomenų nuskaitymas, 99% atvejų tinka readxl paketo funkcijos. Jeigu reikia duomenų lenteles saugoti šiuo formatu - naudoti openxlsx2 paketą.

Pavyzdžiui, nuskaitysime duomenų rinkinį Titanic.xlsx naudojant funkciją read_xlsx() iš paketo readxl.

Kodas
# instaliuojamas paketas
install.packages("readxl")
Kodas
# įsikeliamas paketas
library(readxl)

df <- read_xlsx(path = "data/Titanic.xlsx", n_max = 5)
df
#> # A tibble: 5 × 12
#>   PassengerId Survived Pclass Name    Sex     Age SibSp Parch Ticket  Fare Cabin
#>         <dbl>    <dbl>  <dbl> <chr>   <chr> <dbl> <dbl> <dbl> <chr>  <dbl> <chr>
#> 1           1        0      3 Braund… male     22     1     0 A/5 2…  7.25 <NA> 
#> 2           2        1      1 Cuming… fema…    38     1     0 PC 17… 71.3  C85  
#> 3           3        1      3 Heikki… fema…    26     0     0 STON/…  7.92 <NA> 
#> 4           4        1      1 Futrel… fema…    35     1     0 113803 53.1  C123 
#> 5           5        0      3 Allen,… male     35     0     0 373450  8.05 <NA> 
#> # ℹ 1 more variable: Embarked <chr>

Svarbu paminėti, jog readxl paketas nuskaito duomenis į R sesiją ne kaip data.frame klasės objektą, o kaip tibble lentelę. Tai alternatyvi klasė duomenų lentelėms. Šiame skyriuje daugiau apie tai nebus aptarta.

Nuskaitymo funkcijų palyginimas

Skirtingų paketų nuskaitymo greitį galima palyginti tarpusavyje. Šiame pavyzdyje nuskaitysime didelės apimties .xlsx formato failą 5 kartus.

Kodas
failas <- "data/100mb.xlsx"

library(microbenchmark)   # palyginimui naudojamas paketas
library(xlsx)             
library(readxl)           
library(openxlsx2)        
library(tidyxl)        

read_xlsx_java   <- function() { xlsx::read.xlsx(failas, sheetIndex = 1) }
read_xlsx_readxl <- function() { readxl::read_xlsx(failas, sheet = 1) }
read_xlsx_ox2    <- function() { openxlsx2::read_xlsx(failas, sheet = 1) }
read_xlsx_tidyxl <- function() { tidyxl::xlsx_cells(failas, sheets = 1) }

set.seed(20250529)
rezultatas <- microbenchmark(
  # xlsx      = read_xlsx_java(),
  readxl    = read_xlsx_readxl(),
  openxlsx2 = read_xlsx_ox2(),
  tidyxl    = read_xlsx_tidyxl(),
  times = 5
)

print(rezultatas, signif = 3)

Išvada: readxl paketo funkcija nuskaitymui veikia greičiausiai iš šių trijų variantų. Šiame eksperimente readxl paketo funkcija veikė greičiau už openxlsx2 du kartus, o už tidyxl - beveik net 3 kartus.

4.3 Duomenų eksportavimas

4.3.1 Tekstiniai failai

Vektoriaus įrašymas

Vektoriaus ar matricos reikšmės į tekstinį failą įrašomos naudojant funkciją write(). Duomenys į failą įrašomi pagal eilutes.

Argumentas Reikšmė
x R objektas: vektorius arba matrica
file kuriamo duomenų failo vardas arba kelias iki failo
sep simbolis, kuriuo faile atskiriamos vektoriaus reikšmės
ncolumns vektoriaus elementų skaičius vienoje failo eilutėje
append loginis kintamasis; jeigu TRUE - reikšmės įrašomos į jau esantį failą

Kintamojo reikšmės surašomos į tekstinį failą, bet failo išplėtimas nebūtinai turi būti .txt. Pagal nutylėjimą, skaitinio vektoriaus reikšmės faile surašomos po 5 reikšmes į eilutę, o simbolinio - po vieną elementą į eilutę.

Pavyzdžiui, įrašysime skaitinį vektorių į tekstinį failą.

Kodas
v <- exp(1:5)

write(x = v, file = "data_exp/numeric.vec")
Klausimas

Kaip žinoti, kokiame kataloge išsaugotas failas numeric.vec?

Tą patį vektorių išsaugome į failą, atskiriant reikšmes po vieną per eilutę.

Kodas
write(x = v, file = "data_exp/numeric.vec", sep = "\n")
# arba
write(x = v, file = "data_exp/numeric.vec", ncolumns = 1)

Matricas taip pat galima įrašyti į failą, nes jos suprantamos kaip vektoriaus elementai išdėstyti stulpeliais arba eilutėmis. Kadangi matricos elementai nuskaitomi pagal stulpelius, o į failą įrašomi eilutėmis, tam, kad faile matrica turėtų tokius pat išmatavimus ir tinkamai būtų atvaizduota, ją reikia transponuoti.

Kodas
mat <- matrix(1:10, ncol = 2)

write(x = t(mat), file = "data_exp/numeric.matrix", ncolumns = 2)
Patarimas

Funkcijai write() nenurodžius failo vardo ar kelio iki jo, pagal nutylėjimą darbiniame kataloge automatiškai sukuriamas tekstinis failas data be jokio išplėtimo.

Jei parametras file="", tai vektorius išvedamas į konsolę.

Kodas
write(x = t(mat), file = "")
Užduotis
  1. Naudodami funkciją write(), užrašykite komandą, kuri matricos mat elementus į failą surašytų viename stulpelyje.

  2. Naudodami funkciją write(), užrašykite komandą, kuri tekstinio vektoriaus c("Pirmas sakinys.", "Antras sakinys.", "Trečias sakinys.", "Jau pabaiga.") elementus į konsolę užrašytų dviem stulpeliais.

  3. Papildykite antros užduoties rezultatą taip, kad elementai būtų išrašomi be tarpų.

Kodas
# 1. 
write(mat, file = "data_exp/ex_1", ncolumns = 1)

# 2. 
text_vec <- c("Pirmas sakinys.", "Antras sakinys.", "Trečias sakinys.", "Jau pabaiga.")
write(text_vec, file = "", ncolumns = 2)

# 3. 
write(text_vec, file = "", ncolumns = 2, sep = "")

Duomenų lentelės įrašymas

Duomenų lentelės į tekstinį failą rašomos naudojant funkciją write.table().

Argumentas Reikšmė
x duomenų lentelė
file kuriamo duomenų failo vardas arba kelias iki failo
sep simbolis, kuriuo faile atskiriamos vektoriaus reikšmės
dec dešimtainis kablelio simbolis, pagal nutylėjimą - taškas
row.names jei TRUE, tai lentelė įrašoma su eilučių pavadinimais
col.names jei TRUE, tai lentelė įrašoma su stulpelių pavadinimais
append jei TRUE, vektoriaus reikšmės įrašomos į jau egzistuojantį failą
quote jei TRUE, tekstiniai kintamieji ir faktoriai rašomi kabutėse

Vietoje loginių reikšmių, parametrams row.names ir col.names galima priskirti vardų vektorių.

Sudarysime duomenų lentelę df, kurios stulpeliuose yra trys skirtingo tipo vektoriai. Ją išsaugosime į failą duomenys.dat.

Kodas
x <- c(22.1, 37.5, 68.3, 15)
y <- c(FALSE, TRUE, TRUE, FALSE)
z <- c("sutinku", "nesutinku",  "visiškai sutinku",  "nesutinku")

df <- data.frame(x, y, z)

write.table(df, file = "data_exp/duomenys.dat")

Kategorinė reikšmė gali būti keli žodžiai, pvz. „Jonas Petraitis“. Jei stulpelius failuose skiriame tarpu, toks įrašas išsiskaidytų vieną reikšmę į kelis pavienius stulpelius, todėl R visus kelių žodžių tekstus automatiškai įrašo kabutėse. Naudodami kitą skirtuką (tabuliatorių „, kabliataškį ir pan.) kabučių nebereikia, t.y. quote = FALSE.

Atskiras stulpelius sukuriamas eilučių pavadinimams įrašant į failą. Tais atvejais, eilučių pavadinimai sutampa su numeriais, į failą jų galima ir nerašyti.

Kodas
write.table(df, file = "data_exp/duomenys.dat", row.names = FALSE)

Analogiškai nuskaitymui, funkcijos write.csv() ir write.csv2() skirtos duomenų lentelių įrašymui .csv formatu. Šios funkcijos remiasi write.table() funkcija su iš anksto nustatytais sep ir dec parametrais.

Naudojame write.csv(), kai stulpeliai atskiriami vienas nuo kito kableliu, o su write.csv2() stulpeliai atskiriami kabliataškiu, tai kableliu atskiriama trupmeninė skaičiaus dalis.

Kodas
write.csv(x = df, file = "data_exp/csv_duomenys.csv")
write.csv2(x = df, file = "data_exp/csv2_duomenys.csv")
Užduotis
  1. Duomenų lentelėje iris yra duomenys apie kelių rūšių augalų žiedų matavimus. Naudodami funkciją write.table(), įrašykite šiuos matavimus į tekstinį failą: stulpeliai faile atskiriame tabuliacijos ženklu, kategoriniai kintamieji rašomi be kabučių, eilučių numerių nėra.

  2. Naudodami funkciją write.table(), duomenų lentelę cars įrašykite į tekstinį failą su lietuviškais stulpelių pavadinimais.

  3. .csv formatu įrašykite duomenų lentelę iris. Trupmeninė skaičiaus dalis turi būti skiriama kableliu.

Kodas
# 1. 
write.table(x = iris, file = "data_exp/irisas.txt", sep = "\t", quote = F, row.names = F)

# 2. 
write.table(cars, "data_exp/masinos.txt", col.names = c("greitis", "atstumas"))

# 3. 
write.csv2(iris, "data_exp/irisas.csv")

4.3.2 Binariniai failai

Binariniu formatu patogu saugoti objektus sukurtus R aplinkoje. R duomenų failai turi .RData išplėtimą. Duomenis binariniu formatu įrašome su funkcija save().

Pavyzdžiui, išsaugosime duomenų lentelę.

Kodas
save(df, file = "data_exp/duomenys.RData")

Į vieną binarinį failą galima išsaugoti keletą R objektų, funkcijoje atskiriant juos kableliu.

Kodas
save(x, text_vec, mat, file = "data_exp/daug_duomenu.RData")

Jei išsaugomų kintamųjų yra daug, jų R aplinkos vardus galima surašyti į character tipo vektorių ir nurodyti vektorių parametrui list.

Kodas
save(list = c("x", "v", "adresas", "text_vec", "mat"), file = "data_exp/dar_duomenu.RData")

Kitų formatų binariams failams įrašyti naudojamos specialios funkcijos iš tam tikrų paketų. Čia paminėsime tik dažnai pasitaikančią situaciją - .xlsx formato failų įrašymą.

Jau minėti paketai kaip openxlsx2 ir xlsx turi funkcijas skirtas .xlsx failų įrašymui. Dar vienas paketas, writexl, taip pat turi tokios paskirties funkciją.

Pavyzdžiui, įrašysime df duomenis į failą pvz.xlsx su skirtingų paketų funkcijomis. Jeigu paketai yra įdiegti, bet nenorime jų iškviesti, galima juose esančias funkcijas pasiekti tiesiogiai, naudojant paketas::f() tipo komandą.

Kodas
openxlsx2::write_xlsx(x = df, file = "data_exp/pvz.xlsx")
xlsx::write.xlsx(x = df, file = "data_exp/pvz.xlsx")
writexl::write_xlsx(x = df, path = "data_exp/pvz.xlsx")
Užduotis
  1. Vektorių v ir matricą m įrašykite į vieną binarinį failą vecmat.RData. Užrašykite ir komandos variantą, kuriame naudojamas parametras list.

  2. Iš duomenų rinkinio trees išrinkite pirmus pusę stebinių, parinktine kintamuosiuos Girth ir Volume. Gautą duomenų rinkinį įrašykite į failą puse_medziu.xlsxnaudodami funkciją write_xlsx()writexl paketo.

Kodas
# 1. 
save(v, mat, file = "data_exp/vecmat.Rdata")
save(list = c("v", "mat"), file = "data_exp/vecmat.Rdata")

# 2. 
medziai <- trees[1:(nrow(trees)/2), c("Girth", "Volume")]
writexl::write_xlsx(x = medziai, path = "data_exp/puse_medziu.xlsx")