R are cinci tipuri de date principale (atomi), după cum urmează:
character: "a", "swc"
numeric: 2, 15.5
integer: 2L (sufix-ul L îi spune R-ului să stocheze numărul ca pe un întreg)
logical: TRUE, FALSE
complex: 1+4i (numere complexe)
R pune la dispoziție mai multe funcții cu ajutorul cărora se pot examina trăsăturile vectorilor sau a altor obiecte, cum ar fi de exemplu
class() - ce tip de obiect este
typeof() - care este tipul de date al obiectului (similar cu mode())
length() - care este lungimea obiectului
attributes() - care sunt atributele obiectului (metadata)
# Exemplux <-"curs de statistica"typeof(x)
[1] "character"
attributes(x)
NULL
y <-1:10y
[1] 1 2 3 4 5 6 7 8 9 10
typeof(y)
[1] "integer"
length(y)
[1] 10
z <-as.numeric(y)z
[1] 1 2 3 4 5 6 7 8 9 10
typeof(z)
[1] "double"
În plus, putem să testăm dacă un obiect x aparține unui anumit tip de date prin apelarea funcțiilor de forma is.xxx unde xxx este tipul de date (character, numeric, integer, logical și complex):
x <-"statistica"is.numeric(x)
[1] FALSE
is.character(x)
[1] TRUE
Mai mult, R permite conversia între diferite tipuri de date prin folosirea funcțiilor de forma as.xxx unde xxx este tipul de date:
as.numeric("1234")
[1] 1234
as.complex("2")
[1] 2+0i
as.logical("TRUE")
[1] TRUE
as.character(3.0e10)
[1] "3e+10"
as.logical(5)
[1] TRUE
as.logical(0)
[1] FALSE
as.logical(-1)
[1] TRUE
Tabelul 1 de mai jos sumarizează tipurile de conversie:
Tabelul 1: Exemple de conversie a tipurilor de date.
De la tipul
La tipul
Funcția
Conversie
logical
numeric
as.numeric
FALSE \(\to\) 0
TRUE \(\to\) 1
logical
character
as.character
FALSE \(\to\) “FALSE”
TRUE \(\to\) “TRUE”
character
numeric
as.numeric
“123” \(\to\) 123
“stat” \(\to\) NA
character
logical
as.logical
“FALSE” \(\to\) FALSE
“TRUE” \(\to\) TRUE
“alte caractere” \(\to\) NA
numeric
logical
as.logical
0 \(\to\) FALSE
alte numere \(\to\) TRUE
numeric
character
as.character
123 \(\to\) “123”
În limbajul R regăsim mai multe structuri de date. Printre acestea enumerăm
vectori (structuri atomice)
matrice și array
liste
data frame-uri
factori
În cele ce urmează vom prezenta fiecare structură de date în parte precizând moduri de construcție, operații și metode de indexare.
Scalari și vectori
Cel mai de bază tip de obiect în R este vectorul. Una dintre regulile principale ale vectorilor este că aceștia pot conține numai obiecte de același tip, cu alte cuvinte putem avea doar vectori de tip caracter, numeric, logic, etc.. În cazul în care încercăm să combinăm diferite tipuri de date, acestea vor fi forțate la tipul cel mai flexibil (a se vedea Tabelul 1). Tipurile de la cel mai puțin la cele mai flexibile sunt: logice, întregi, numerice și caractere.
Metode de construcție a vectorilor
Putem crea vectori fără elemente (empty) cu ajutorul funcției vector(), modul default este logical dar acesta se poate schimba în funcție de necesitate.
vector() # vector logic gol
logical(0)
vector("character", length =5) # vector de caractere cu 5 elemente
[1] "" "" "" "" ""
character(5) # acelasi lucru dar in mod direct
[1] "" "" "" "" ""
numeric(5) # vector numeric cu 5 elemente
[1] 0 0 0 0 0
logical(5) # vector logic cu 5 elemente
[1] FALSE FALSE FALSE FALSE FALSE
Putem crea vectori specificând în mod direct conținutul acestora. Pentru aceasta folosim funcția c() de concatenare:
Funcția poate fi folosită de asemenea și pentru (combinarea) adăugarea de elemente la un vector
z <-c("Sandra", "Traian", "Ionel")z <-c(z, "Ana")z
[1] "Sandra" "Traian" "Ionel" "Ana"
z <-c("George", z)z
[1] "George" "Sandra" "Traian" "Ionel" "Ana"
O altă funcție des folosită în crearea vectorilor, în special a celor care au repetiții, este funcția rep(). Pentru a vedea documentația acestei funcții apelați help(rep). De exemplu, pentru a crea un vector de lungime 5 cu elemente de 0 este suficient să scriem
rep(0, 5)
[1] 0 0 0 0 0
Dacă în plus vrem să creăm vectorul 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3 sau 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3 atunci putem scrie
rep(c(1,2,3), 5)
[1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
rep(c(1,2,3), each =5)
[1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
Ce se întâmplă dacă apelăm rep(c(1,2,3), 1:3) ? Vom obține vectorul 1, 2, 2, 3, 3, 3 unde primul element din vectorul c(1,2,3) a fost repetat o dată, al doilea de două ori și al treilea de trei ori
rep(c(1,2,3), 1:3)
[1] 1 2 2 3 3 3
În cazul în care vrem să creăm un vector care are elementele egal depărtate între ele, de exemplu 1.3, 2.3, 3.3, 4.3, 5.3, atunci putem folosi funcția seq():
Tabelul 2 sumarizează funcțiile de creare a vectorilor:
Tabelul 2: Funcții utile pentru crearea unui vector.
Funcție
Exemplu
Rezultat
c(a, b, ...)
c(1, 5, 9)
1, 5, 9
a:b
1:5
1, 2, 3, 4, 5
seq(from, to, by, length.out)
seq(from = 0, to = 6, by = 2)
0, 2, 4, 6
rep(x, times, each, length.out)
rep(c(7, 8), times = 2, each = 2)
7, 7, 8, 8, 7, 7, 8, 8
Operații cu vectori
Operațiile elementare (binare) pe care le puteam face cu scalari (adunarea +, scăderea -, înmulțirea *, împărțirea /, ridicarea la putere ^, etc.) putem să le facem și cu vectori (între vectori sau între vectori și scalari):
Observăm că atunci când facem o operație între un scalar și un vector, se aplică scalarul la fiecare element al vectorului. În cazul în care aplicăm o operație la doi vectori de aceeași lungime, elementele vectorului rezultat se obțin prin aplicarea operației între elementele de pe pozițiile corespunzătoare ale celor doi vectori:
# vectori de aceeasi lungimea <-1:5b <-c(2, 2, 1, 3, 4)a + b
[1] 3 4 4 7 9
a - b
[1] -1 0 2 1 1
a * b
[1] 2 4 3 12 20
a / b
[1] 0.500000 1.000000 3.000000 1.333333 1.250000
a ^ b
[1] 1 4 3 64 625
a %/% b
[1] 0 1 3 1 1
a %% b
[1] 1 0 0 1 1
Dacă efectuăm o operație binară între doi vectori de lungimi diferite, R va recicla (completa prin repetiție) în mod automat vectorul de lungime mai mică până când se obține un vector de aceeași lungime cu cel mai mare după care se va efectua operația.
# vectori cu lungimi diferitea <-1:6b <-c(2, 2, 1)a + b
[1] 3 4 4 6 7 7
a +c(2, 2, 1, 2, 2, 1)
[1] 3 4 4 6 7 7
a <-1:5b <-c(2, 2, 1)a + b
Warning in a + b: longer object length is not a multiple of shorter object
length
[1] 3 4 4 6 7
a +c(2, 2, 1, 2, 2)
[1] 3 4 4 6 7
Funcțiile elementare, exp(), log(), sin(), cos(), tan(), asin(), acos(), atan(), etc. sunt funcții vectoriale în R, prin urmare pot fi aplicate unor vectori.
Alte funcții utile des întâlnite în manipularea vectorilor numerici sunt: min(), max(), sum(), prod(), mean(), sd(), length(), round(), ceiling(), floor(), %% (operația modulo), %/% (div), table(), unique(). Pentru mai multe informații privind modul lor de întrebuințare apelați help(nume_functie) sau ?nume_functie.
y =c("M", "M", "F", "F", "F", "M", "F", "M", "F")unique(y)
[1] "M" "F"
table(y)
y
F M
5 4
O altă operație importantă care apare des în practică este operația de sortare. Funcția sort() permite sortarea vectorilor în ordine crescătoare sau descrescătoare:
Adițional, funcția rev() rearanjează elementele unui vector în sens invers:
rev(x)
[1] 2 1 8 10 4 6 5 9 7 3
Trebuie menționat de asemenea că limbajul R suportă și o serie de operații cu mulțimi pe vectori. Cele mai des întâlnite astfel de operații sunt sumarizate în Tabelul 3 de mai jos:
Tabelul 3: Funcții utile operații cu mulțimi pe vectori.
Funcție
Scurtă descriere
union(A, B)
Reuniunea mulțimilor (elementelor vectorilor) \(A\) și \(B\): \(A\cup B\)
intersect(A, B)
Intersecția mulțimilor (elementelor vectorilor) \(A\) și \(B\): \(A\cap B\)
setdiff(A, B)
Diferența mulțimilor (elementelor vectorilor) \(A\) și \(B\): \(A\setminus B\)
setequal(A, B)
Test pentru egalitatea mulțimilor
A %in% B
Testarea apartenenței elementelor din \(A\) în \(B\)
A <-c("mere", "pere", "banane", "struguri") # fructeB <-c("lapte", "branza", "unt", "banane") # cumparaturiunion(A, B)
Este important de remarcat faptul că mulțimea vidă (i.e. \(\emptyset\)) este reprezentată în R prin intermediul unui vector de lungime zero.
A <-1:5B <-1:7C <-6:9# diferenta vidasetdiff(A, B)
integer(0)
# intersectie vidaintersect(A, C)
integer(0)
Valori speciale
Limbajul R pune la dispoziție o serie de valori speciale: NA, NaN, NULL, Inf și -Inf.
Valorile de tip NA (Not available sau Not assigned) sunt folosite cu precădere atunci când vrem să reprezentăm date lipsă , e.g. date care nu au putut fi colectate în timpul experimentului. Să presupunem că în timpul unui sondaj, patru persoane au fost întrebate ce înălțime au iar a doua persoana a refuzat să răspundă:
h <-c(168, NA, 173, 185)h
[1] 168 NA 173 185
Valorile Na sunt de mai multe tipuri, în funcție de tipul de date:
x <-c(1, NA, 2)mode(x[1])
[1] "numeric"
mode(x[2]) # NA de tip numeric
[1] "numeric"
y <-c("a", NA, "b")mode(y[1])
[1] "character"
mode(y[2]) # NA de tip caracter
[1] "character"
Pentru a determina valorile lipsă ale unui vector x putem folosi funcția is.na() care întoarce un vector logic de aceeași lungime cu vectorul inițial cu valoare de adevăr pe pozițiile unde apare NA:
is.na(c(168, NA, 173, 185))
[1] FALSE TRUE FALSE FALSE
Valorile de tip Inf și -Inf sunt folosite atunci când un număr este prea mare \(\infty\), respectiv prea mic \(-\infty\), pentru a fi reprezentat în R. Valorile numerice maxime și minime permise de R depind de arhitectura sistemului pe care este instalat R-ul, de procesor sau de compilator. Putem obține aceste valori accesând variabila .Machine (a se vedea documentația ?.Machine pentru informații suplimentare):
.Machine$double.xmax
[1] 1.797693e+308
.Machine$double.xmin
[1] 2.225074e-308
.Machine$double.eps
[1] 2.220446e-16
.Machine$double.max
[1] 1024
Valorile în afara acestor limite sunt stocate drept Inf și -Inf. Putem efectua operații matematice cu aceste valori în același mod în care efectuăm operații cu \(\infty\) și \(-\infty\):
Inf+5
[1] Inf
Inf-20
[1] Inf
Inf*3
[1] Inf
Inf* (-2)
[1] -Inf
Inf/42
[1] Inf
# Orice valoare reala impartita la infinit este 02/Inf
[1] 0
-10/-Inf
[1] 0
# O valoare reala impartita la 0 este infinit3/0
[1] Inf
-3/0
[1] -Inf
Uneori, rezultatul unui calcul poate conduce la o valoare nedefinită, care în R se exprimă prin NaN (Not a number):
Inf/Inf
[1] NaN
Inf-Inf
[1] NaN
0/0
[1] NaN
Orice operație matematică care implică valoarea NaN rezultă tot în valoarea NaN iar identificarea acestei valori se poate face prin intermediul funcției is.nan():
NaN+10
[1] NaN
NaN*5
[1] NaN
x <-c(5, 1, NaN, NA)is.nan(x)
[1] FALSE FALSE TRUE FALSE
Ultimul tip de valoare specială este NULL. Această valoare este utilizată atunci când vrem să specificăm că un obiect este vid, nu există. Spre deosebire de NA care face referire la un obiect în memorie ce poate fi modificat sau accesat, NULL nu permite acest lucru.
# Exemplificare NULL si NAx <-NULLx
NULL
length(x)
[1] 0
y <-NAy
[1] NA
length(y)
[1] 1
# NULL nu ocupa o pozitie in vector c(2, 3, NULL, NULL)
[1] 2 3
c(2, 3, NA, NA)
[1] 2 3 NA NA
Metode de indexare a vectorilor
Sunt multe situațiile în care nu vrem să efectuăm operații pe întreg vectorul ci pe o submulțime de valori ale lui selecționate în funcție de anumite proprietăți. Putem, de exemplu, să ne dorim să accesăm al 2-lea element al vectorului sau toate elementele mai mari decât o anumită valoare. Pentru aceasta vom folosi operația de indexare folosind parantezele pătrate [].
În general, sunt două tehnici principale de indexare: indexarea numerică și indexarea logică.
Indexare numerică
Atunci când folosim indexarea numerică, inserăm între parantezele pătrate un vector numeric (de numere întregi) ce corespunde poziției elementelor pe care vrem să le accesăm sub forma x[index] (x este vectorul inițial iar index este vectorul de indici). Indexarea începe cu poziția 1:
x =seq(1, 10, length.out =21) # vectorul initial x[1] # accesam primul element
[1] 1
x[c(2,5,9)] # accesam elementul de pe pozitia 2, 5 si 9
[1] 1.45 2.80 4.60
x[4:10] # accesam toate elementele dintre pozitiile 4 si 9
[1] 2.35 2.80 3.25 3.70 4.15 4.60 5.05
Putem folosi orice vector de indici atât timp cât el conține numere întregi (numerice), lungimea acestuia nu trebuie să fie egală sau mai mică cu cea a vectorului pe care îl indexăm. De exemplu, putem să accesăm elementele vectorului x și de mai multe ori:
x[c(1,1,2,2,2)]
[1] 1.00 1.00 1.45 1.45 1.45
Atunci când valoarea cu care indexăm nu corespunde unei poziții din vectorul pe care în indexăm, rezultatul va fi NA:
x[22] # vectorul are 21 de elemente
[1] NA
De asemenea dacă vrem să afișăm toate elementele mai puțin elementul de pe poziția i atunci putem folosi indexare cu numere negative. Această metodă este folositoare și în cazul în care vrem să ștergem unul sau mai multe elemente ale vectorului:
x[-5] # toate elementele mai putin cel de pe pozitia 5
A doua modalitate de indexare se face prin intermediul vectorilor logici. Atunci când indexăm cu un vector logic acesta trebuie să aibă aceeași lungime cu a vectorului pe care vrem să îl indexăm.
Să presupunem că vrem să extragem din vectorul x doar elementele care verifică o anumită proprietate, spre exemplu sunt mai mari decât 3, atunci:
x>3# un vector logic care ne arata care elemente sunt mai mari decat 3
În cazul în care indexăm cu un vector logic de lungime mai mică acesta se va recicla până ajunge la dimensiunea (lungimea) vectorului pe care îl indexăm.
Funcția which() face legătura dintre indexarea logică și cea numerică. Această funcție întoarce indicii corespunzători valorilor TRUE din vectorul logic și este folosită cu precădere atunci când suntem interesați de indicii elementelor dintr-un vector care verifică o proprietate dată.
\((4,6,3)\) și atribuiți valoarea acestuia variabilei \(a\)
\((4,6,3,4,6,3, \ldots, 4,6,3)\) unde avem \(10\) repetări ale valorii \(4\)
\((4,6,3,4,6,3, \ldots, 4,6,3,4)\) unde sunt \(11\) repetări ale valorii \(4\), \(10\) repetări ale valorii \(6\) și \(10\) repetări ale valorii \(3\)
\((4,4, \ldots, 4,6,6, \ldots, 6,3,3, \ldots, 3)\) unde \(4\) apare de \(10\) ori, \(6\) de \(15\) ori și \(3\) de \(20\) ori.
Exercițiul 2 Să presupunem că am înregistrat în fiecare zi, pe parcursul a 4 săptămâni (de Luni până Duminică), numărul de minute petrecute la telefonul mobil (convorbiri + utilizare) și am obținut următoarele valori: 106, 123, 123, 111, 125, 113, 130, 113, 114, 100, 120, 130, 118, 114, 127, 112, 121, 114, 120, 119, 127, 114, 108, 127, 131, 157, 102, 133. Ne întrebăm: care sunt zilele din săptămână în care am vorbit cel mai mult? dar cel mai puțin? dar zilele în care am vorbit mai mult de 120 de minute? (Indicație: Folosiți funcțiile rep și cat sau paste)
Exercițiul 5 Folosind funcția paste creați următorii vectori:
(“label 1”, “label 2”, …., “label 30”)
(“fn1”, “fn2”, .,, “fn30”). (Indicație: Ce face funcția paste0?)
Exercițiul 6 Executați următoarele linii de cod care crează doi vectori de lungime \(250\) obținuți prin extragerea cu întoarcere din mulțimea \(0,1, \ldots, 999\).
Exercițiul 7 Pentru vectorii \(x\) și \(y\) creați în Exercițiul 6 răspundeți la următoarele cerințe:
Alegeți valorile din \(y\) care sunt mai mari de \(600\).
Care sunt pozițiile corespunzătoare din \(y\) pentru care valorile lui \(y\) sunt mai mari de \(600\) ?
Care sunt valorile din \(x\) care corespund valorilor din \(y\) care sunt mai mari de \(600\) ?
Creați vectorul \(\left(\left|x_1-\overline{\mathbf{x}}\right|^{1 / 2},\left|x_2-\overline{\mathbf{x}}\right|^{1 / 2}, \ldots,\left|x_n-\overline{\mathbf{x}}\right|^{1 / 2}\right)\) unde \(\overline{\mathbf{x}}\) reprezintă media vectorului \(\mathbf{x}=\left(x_1, x_2, \ldots, x_n\right)\)
Câte valori din \(x\) sunt divizibile cu \(2\)?
Sortați valorile vectorului \(x\) în ordinea crescătoare a valorilor lui \(y\)
Alegeți elementele din \(y\) de pe pozițiile \(1,4,7,10,13, \ldots\).
Matrice
Matricele sunt structuri de date care extind vectorii și sunt folosite la reprezentarea datelor de același tip în două dimensiuni. Matricele sunt similare tablourilor din Excel și pot fi văzute ca vectori cu două atribute suplimentare: numărul de linii (rows) și numărul de coloane (columns).
Indexarea liniilor și a coloanelor pentru o matrice începe cu 1. De exemplu, elementul din colțul din stânga sus al unei matrice este notat cu x[1,1]. De asemenea este important de menționat că stocarea (internă) a metricelor se face pe coloane în sensul că prima oară este stocată coloana 1, apoi coloana 2, etc..
Metode de construcție
Există mai multe moduri de creare a unei matrici în R. Funcțiile cele mai uzuale sunt prezentate în tabelul de mai jos. Cum matricele sunt combinații de vectori, fiecare funcție primește ca argument unul sau mai mulți vectori (toți de același tip) și ne întoarce o matrice.
Tabelul 5: Funcții care permit crearea matricelor.
Funcție
Descriere
Exemple
cbind(a, b, c)
Combină vectorii ca și coloane într-o matrice
cbind(1:5, 6:10, 11:15)
rbind(a, b, c)
Combină vectorii ca și linii într-o matrice
rbind(1:5, 6:10, 11:15)
matrix(x, nrow, ncol, byrow)
Crează o matrice dintr-un vector x
matrix(x = 1:12, nrow = 3, ncol = 4)
Pentru a vedea ce obținem atunci când folosim funcțiile cbind() și rbind() să considerăm exemplele următoare:
x <-1:5y <-6:10z <-11:15# Cream o matrice cu x, y si z ca si coloanecbind(x, y, z)
x y z
[1,] 1 6 11
[2,] 2 7 12
[3,] 3 8 13
[4,] 4 9 14
[5,] 5 10 15
# Cream o matrice in care x, y si z sunt liniirbind(x, y, z)
[,1] [,2] [,3] [,4] [,5]
x 1 2 3 4 5
y 6 7 8 9 10
z 11 12 13 14 15
Funcția matrix() crează o matrice plecând de la un singur vector. Funcția are mai multe argumente de intrare: data – un vector cu date, nrow – numărul de linii pe care le vrem în matrice sau ncol – numărul de coloane pe care să le aibă matricea. Trebuie avut grijă ca lungimea vectorului de date să fie egală cu produsul dintre numărul de linii și numărul de coloane specificat, în caz contrar are loc fenomenul de reciclare văzut și în cazul vectorilor:
# matrice cu 5 linii si 2 coloanematrix(data =1:10,nrow =5,ncol =2)
Este important de observat modul în care un vector este convertit într-o matrice. Comportamentul implicit al R-ului este de a aloca valorile pe coloane începând din poziția 1 a vectorului și continuând pe coloane de sus în jos. Dacă se dorește schimbarea acestui mod de alocare, se poate specifica opțiunea byrow – o valoare logică care permite crearea matricei pe linii:
# aceeasi matrice cu 2 linii si 5 coloane, umpluta pe linii matrix(data =1:10,nrow =2,ncol =5,byrow =TRUE)
Operațiile uzuale cu vectori se aplică și matricelor. Pe lângă acestea avem la dispoziție și operații de algebră liniară clasice, cum ar fi determinarea dimensiunii acestora, transpunerea matricelor sau înmulțirea lor:
diag(M) # Diagonala matricei Mdim(M) # Dimensiunea matricei Mnrow(M) # Numarul de linii ale matricei Mncol(M) # Numarul de coloane ale matricei Mt(M) # TranspusacolSums(M), rowSums(M) # Suma pe coloane si suma pe linii
Determinantul și urma unei matrice se obțin folosind funcțiile det() și respectiv sum(diag())
det(A) # determinantul
[1] -12
sum(diag(A)) # urma matricei A
[1] 6
iar matricea identitate se obține folosind comanda \(I_n=\)diag(x = n):
diag(x =3)
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 1 0
[3,] 0 0 1
Metode de indexare
Metodele de indexare discutate pentru vectori se aplică și în cazul matricelor ([,]) numai că acum în loc să folosim un vector să indexăm putem să folosim doi vectori. Sintaxa are structura generală m[linii, coloane] unde linii și coloane sunt vectori cu valori întregi.
m =matrix(1:20, nrow =4, byrow =TRUE)# Linia 1m[1, ]
[1] 1 2 3 4 5
# Coloana 5m[, 5]
[1] 5 10 15 20
# Liniile 2, 3 si coloanele 3, 4m[2:3, 3:4]
[,1] [,2]
[1,] 8 9
[2,] 13 14
Indexarea logică poate fi combinată cu cea numerică:
# Elementele din coloana 3 care corespund liniilor pentru care elementele # de pe prima coloana sunt > 3m[m[,1]>3, 3]
[1] 8 13 18
Dacă dorim să adăugăm linii sau coloane la o matrice dată atunci putem să folosim funcțiile rbind() și respectiv cbind():
# adaugarea unei linii la sfarsitm1 <-rbind(m, 1:4)
Warning in rbind(m, 1:4): number of columns of result is not a multiple of
vector length (arg 2)
Este important de observat că atunci când extragem o linie sau o coloană dintr-o matrice rezultatul obținut este un vector și nu o matrice unidimensională după cum se poate vedea și în exemplul următor:
v <- m[2, ]v
[1] 6 7 8 9 10
dim(v)
NULL
Pentru a evita această reducere automată a dimensiunii, R pune la dispiziție argumentul logic drop = FALSE (implicit drop = TRUE):
\[
\mathbf{A}=\left[\begin{array}{ccc}
1 & 1 & 3 \\
5 & 2 & 6 \\
-2 & -1 & -3
\end{array}\right]
\] Verificați că \(\mathbf{A}^3=\mathbf{0}\) unde \(\mathbf{0}\) este matricea nulă de \(3 \times 3\). Înlocuiți a treia coloană a lui \(\mathbf{A}\) cu suma dintre coloana a doua și a treia.
Exercițiul 10 Creați următoarele matrice așa încât soluția să țină cont de forma particulară a matricelor (Indicație: încercați să folosiți funcția outer):
Pe lângă vectori, care au dimensiune \(1\), și matrice, care sunt structuri de date de dimensiune \(2\), R-ul pune la dispoziție și structuri de date multidimensionale. Tablourile multidimensionale (arrays) constituie un tip de structură de date care generalizează structurile de tip matrice și, ca și acestea, conțin doar date de același tip. Pentru crearea acestor structuri de date se folosește funcția array() care primește ca prin argument un vector de date iar apoi se specifică dimensiunea tabloului folosind argumentul dim =:
Observăm că am obținut un tablou tridimensional cu două straturi în care fiecare strat este format dintr-o matrice cu cinci linii și două coloane. În acest exemplu, prin argumentul dim = c(5, 2, 2) am specificat, de la stânga la dreapta, numărul de linii, numărul de coloane și respectiv straturile.
Indexarea tablourilor multidimensionale se face în manieră similară cu indexarea matricelor, numărul de indici variind în funcție de dimensiunea tabloului:
a[1, , 1] # prima linie a matricii de pe primul strat
[1] 1 6
Exerciții
Exercițiul 13 Creați un tablou multidimensional cu șase straturi astfel încât fiecare strat este o matrice de dimensiune \(4\times 2\) și care conține elemente de la \(1\) la \(48\).
Exercițiul 14 Investigați ce fac funcțiile aperm, sweep, margin.table și addmargins și prezentați câte un exemplu de utilizare din fiecare.
Liste
Spre deosebire de vectori în care toate elementele trebuie să aibă același tip de date, structura de date din R de tip listă (list) permite combinarea obiectelor de mai multe tipuri. Cu alte cuvinte, o listă poate avea de exemplu primul element un scalar, al doilea un vector, al treilea o matrice iar cel de-al patrulea element poate fi o altă listă. Tehnic listele sunt tot vectori, vectorii pe care i-am văzut anterior se numesc vectori atomici, deoarece elementele lor nu se pot diviza, pe când listele se numesc vectori recursivi.
Ca un prim exemplu să considerăm cazul unei baze de date ce face referire la studenții FMI. Pentru fiecare student, ne dorim să stocăm numele și prenumele acestuia (șir de caractere), nota la statistică (valoare numerică) și o valoare de tip logic care poate reprezenta apartenența lui în asociația studenților. Pentru crearea listei folosim funcția list():
a <-list(nume ="Popescu", prenume ="Ionel", nota_stat =9, apartenenta = T)a
List of 4
$ nume : chr "Popescu"
$ prenume : chr "Ionel"
$ nota_stat : num 9
$ apartenenta: logi TRUE
names(a) # numele listei
[1] "nume" "prenume" "nota_stat" "apartenenta"
Numele componentelor listei a (nume, prenume, nota_stat, apartenența) nu sunt obligatorii, dar cu toate acestea, pentru claritate și pentru evitarea erorilor este indicată folosirea lor. Pe de altă parte, putem crea o listă care conține aceleași elemente cu lista a dar care nu are numite componentele:
a2 <-list("Ionel", 9, T)a2
[[1]]
[1] "Ionel"
[[2]]
[1] 9
[[3]]
[1] TRUE
Putem numi componentele listei folosind funcția names():
Deoarece listele sunt vectori ele pot fi create și prin intermediul funcției vector() și putem determina numărul de componente folosind funcția length():
z <-vector(mode="list")z
list()
z[["a"]] <-3z
$a
[1] 3
length(a)
[1] 4
length(a2)
[1] 3
Indexarea listelor
Elementele unei liste pot fi accesate în diferite moduri. Dacă dorim să extragem o componentă (un element al) a listei atunci vom folosi indexarea care folosește o singură pereche de paranteze pătrate []
a[1]
$nume
[1] "Popescu"
a[2]
$prenume
[1] "Ionel"
# ce obtinem cand extragem un element al listei a ?str(a[1])
List of 1
$ nume: chr "Popescu"
În cazul în care vrem să accesăm structura de date corespunzătoare elementului i al listei vom folosi două perechi de paranteze pătrate [[]] sau în cazul în care lista are nume operatorul $ urmat de numele elementului i:
a[[1]]
[1] "Popescu"
a[[2]]
[1] "Ionel"
a$nume
[1] "Popescu"
a[["nume"]]
[1] "Popescu"
Este important de punctat diferența dintre indexarea cu o pereche de paranteze pătrate [] și respectiv două perechi de paranteze pătrate [[]]: în primul caz rezultatul este tot o listă (o sublistă a primei liste) iar în al doilea caz este o structură de date de același tip cu cea a componentei extrase:
O altă modalitate de a adăuga elemente unei liste (sau vector) este prin intermediul funcției append(). Această funcție permite adăugarea de elemente atât la începutul listei, la finalul acesteia precum și într-o poziție intermediară:
l1 <-list(a1 =matrix(1:12, 3, 4), b1 =seq(0, 1, length.out =10), c1 = letters[1:5])# adaugam la sfarsitul listei l1 primele 3 elemente ale listei z append(l1, z[1:3])
Rezultatul este un vector care are fiecare componentă denumită după elementele listei. Pentru a șterge aceste nume putem folosi funcția unname():
unname(l1u)
[1] 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 1 0
Exerciții
Exercițiul 15 Creați o listă care să conțină: un șir de lungime \(25\) ce reprezintă o diviziune echidistantă a intervalului \([-5,5]\), o matrice de dimensiune \(3\times 3\) cu elemente logice și un vector de \(20\) de litere (Indicație: verificați ce face comanda letters sau LETTERS).
Extrageți elementele de pe linia \(2\) și \(1\) din coloanele \(3\) și \(2\), în această ordine, din matricea logică a listei
Obțineți toate elementele mai mari ca \(0.5\) din vectorul cu valori între \(-5\) și \(5\)
Exercițiul 16 Ordonați componentele următoarei liste în ordine alfabetică:
l <-list(b =3, a ="Bogdan", c =c(1,2,3), f =TRUE,e =c("x","y","z"), d =37)
Data frame-uri
La nivel intuitiv, o structură de date de tip dataframe este ca o matrice, având o structură bidimensională cu linii și coloane. Cu toate acestea ea diferă de structura de date de tip matrice prin faptul că fiecare coloană poate avea tipuri de date diferite. Spre exemplu, o coloană poate să conțină valori numerice pe când o alta, valori de tip caracter sau logic. Din punct de vedere tehnic, o structură de tip data frame este o listă a cărei componente sunt vectori (atomici) de lungimi egale.
Pentru a crea un dataframe din vectori putem folosi funcția data.frame(). Această funcție funcționează similar cu funcția list() sau cbind(), diferența față de cbind() este că avem posibilitatea să dăm nume coloanelor atunci când le unim. Dată fiind flexibilitatea acestei structuri de date, majoritatea seturilor de date din R sunt stocate sub formă de dataframe (această structură de date este și cea mai des întâlnită în analiza statistică). Proprietatea de reciclare se aplică și în cazul dataframe-urilor, astfel dacă în crearea unui dataframe furnizăm vectori de lungimi diferite, vectorul/rii mai scurt/ți va/vor fi reciclat/ți până când se atinge lungimea dorită. Trebuie remarcat că lungimea vectorului mai scurt trebuie să fie un divizor al lungimii dorite altfel vom avea eroare.
Să creăm un dataframe simplu numit survey folosind funcția data.frame():
# reciclarea nu are loc - eroaresurvey <-data.frame(index =c(1, 2, 3, 4, 5),sex =c("m", "f"), age =c(99, 46, 23, 54, 23))
# reciclarea are locsurvey <-data.frame(index =c(1, 2, 3, 4, 5, 6),sex =c("m", "f"), age =c(99, 46, 23, 54, 23, 61))survey
index sex age
1 1 m 99
2 2 f 46
3 3 m 23
4 4 f 54
5 5 m 23
6 6 f 61
# clasa obiectului surveyclass(survey)
[1] "data.frame"
# un obiect de tip data.frame este derivat din clasa listmode(survey)
[1] "list"
# verificam daca este data.frame sau listis.data.frame(survey)
[1] TRUE
is.list(survey)
[1] TRUE
Funcția data.frame() prezintă un argument specific numit stringsAsFactors care permite convertirea coloanelor ce conțin elemente de tip caracter într-un tip de obiect numit factor (a se vedea secțiunea Secțiunea 1.6). Un factor este o variabilă nominală care poate lua un număr bine definit de valori. De exemplu, putem crea o variabilă de tip factor sex care poate lua doar două valori: masculin și feminin. Comportamentul implicit al funcției data.frame() (stringAsFactors = FALSE) nu transformă automat coloanele de tip caracter în factor, dar în cazul în care dorim acest lucru trebuie să includem argumentul stringsAsFactors = FALSE.
# Structura initialastr(survey)
'data.frame': 6 obs. of 3 variables:
$ index: num 1 2 3 4 5 6
$ sex : chr "m" "f" "m" "f" ...
$ age : num 99 46 23 54 23 61
survey <-data.frame(index =c(1, 2, 3, 4, 5, 6),sex =c("m", "f"), age =c(99, 46, 23, 54, 23, 61),stringsAsFactors =TRUE)# Structura de dupa str(survey)
'data.frame': 6 obs. of 3 variables:
$ index: num 1 2 3 4 5 6
$ sex : Factor w/ 2 levels "f","m": 2 1 2 1 2 1
$ age : num 99 46 23 54 23 61
R are mai multe funcții care permit vizualizarea structurilor de tip dataframe. Tabelul 6 de mai jos include câteva astfel de funcții:
Tabelul 6: Exemple de funcții necesare pentru înțelegerea structurii de tip dataframe.
Funcție
Descriere
head(x), tail(x)
Printarea primelor linii (sau ultimelor linii).
View(x)
Vizualizarea obiectului într-o fereastră nouă, tabelară.
nrow(x), ncol(x), dim(x)
Numărul de linii și de coloane.
rownames(), colnames(), names()
Numele liniilor sau coloanelor.
str(x)
Structura dataframe-ului
Comanda data() ne permite vizualizarea seturilor de date disponibile în sesiunea curentă (?data pentru mai multe detalii).
data() # vedem ce seturi de date existadata("ChickWeight")data("mtcars")
Alegem un set de date, e.g. mtcars, și apelăm funcțiile din Tabelul 6 pentru a înțelege mai bine structura acestuia:
# Alegem setul de date mtcars# ?mtcarsstr(mtcars) # structura setului de date
Vizualizarea setului de date sub formă tabelară se face prin intermediul funcției View():
View(mtcars)
Metode de indexare
Indexarea structurilor de tip dataframe se face la fel ca și indexarea listelor și a matricelor. Astfel, în primul caz, coloanele pot fi văzute ca elementele unei liste și pot fi accesate atât prin nume cât și prin indicele de poziție. Indexarea prin nume poate fi făcută atât prin folosirea parantezelor pătrate duble [[]] cât și prin operatorul $. Atunci când se folosesc parantezele duble, numele coloanei (variabilei) trebuie trecut ca un șir de caractere (folosind "" sau prin intermediul unei variabile de tip caracter) iar în cazul folosirii operatorului $ numele este trecut fără ghilimele (și nu poate fi o variabilă).
# prima coloana si primele 5 elementele mtcars[[1]][1:5] # indice
[1] 21.0 21.0 22.8 21.4 18.7
mtcars[["mpg"]][1:5] # nume
[1] 21.0 21.0 22.8 21.4 18.7
nume.var <-"mpg"# variabila de tip caracter cu numele coloanei doritemtcars[[nume.var]][1:5] # nume
[1] 21.0 21.0 22.8 21.4 18.7
mtcars$mpg[1:5] # nume
[1] 21.0 21.0 22.8 21.4 18.7
Spre deosebire de liste, structurile de tip dataframe sunt structuri de date bidimensionale (dreptunghiulare) a căror elemente pot fi accesate într-un mod similar cu modul de accesare a elementelor unei matrice, folosind doi indici (primul indice arată liniile iar al doilea coloanele).
mtcars[1:5, 1]
[1] 21.0 21.0 22.8 21.4 18.7
mtcars[1,1:4]
mpg cyl disp hp
Mazda RX4 21 6 160 110
mtcars[c(1,2),2]
[1] 6 6
La fel ca vectorii, dataframe-urile (dar și listele) pot fi indexate logic
mpg cyl disp hp drat wt qsec vs am gear carb
Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
O altă metodă de indexare este prin folosirea funcției subset().
Tabelul 7: Principalele argumente ale funcției subset().
Argument
Descriere
x
Un dataframe
subset
Un vector logic care indică liniile pe care le vrem
select
Coloanele pe care vrem să le păstrăm
Să presupunem că dorim să afișăm variabilele disp și wt din setul de date mtcars pentru acele mașini care au mpg < 12 și cyl > 6. Dacă nu am folosi funcția subset() am putea scrie:
disp wt
Cadillac Fleetwood 472 5.250
Lincoln Continental 460 5.424
Observăm că numele variabilelor ce apar în cel de-al doilea argument al funcției nu mai includ și denumirea setului de date ca și în cazul indexării logice matriceale, acest fenomen are loc deoarece acestea sunt căutate, pentru început, în setul de date.
Uneori poate fi incomod să adăugăm numele setului de date (a listei sau a dataframe-ului) la numele variabilei pe care vrem să o accesăm și din acest motiv R pune la dispoziție o serie de funcții ajutătoare: attach(), detach() și with(). De exemplu să considerăm că avem un set de date cu un nume lung pentru care vrem să creăm o nouă variabilă folosindu-ne de cele existente:
Funcția attach() permite R-ului să adauge obiectul la calea de căutare (search path) astfel acesta să fie mai ușor accesat iar funcția detach() restabilește starea inițială.
În această secțiune vom prezenta câteva metode mai avansate de manipulare a seturilor de date (a data frame-urilor).
Vom începe prin introducerea comenzii order() care permite sortarea liniilor unui dataframe în funcție de valorile coloanei de interes (am văzut în Secțiunea 1.1.2 că funcția order() întoarce pozițiile corespunzătoare ordinii). De exemplu să considerăm cazul setului de date mtcars. Vrem să afișăm primele 10 mașini în funcție de greutatea lor (crescător și descrescător):
cars_increasing <-rownames(mtcars[order(mtcars$wt),])# afisarea celor mai usoare 10 masinicars_increasing[1:10]
Funcția order() permite ordonarea după mai mult de o coloană, de exemplu dacă vrem să ordonăm mașinile după numărul de cilindrii și după greutate atunci apelăm
Sunt multe situațiile în care avem la dispoziție două sau mai multe seturi de date și am vrea să construim un nou set de date care să combine informațiile din acestea. Pentru aceasta vom folosi funcția merge(). Principalele argumente ale acestei funcții se regăsesc în tabelul de mai jos:
Tabelul 8: Argumentele funcției merge().
Argument
Descriere
x, y
Două data frame-uri ce urmează a fi unite
by
Un vector de caractere ce reprezintă una sau mai multe coloane după care se va face lipirea. De exemplu by = "id" va combina coloanele care au valori care se potrivesc într-o coloană care se numește "id". by = c("last.name", "first.name") va combina coloanele care au valori care se potrivesc în ambele coloane "last.name" și "first.name"
all
Un vector logic care indică dacă vrem să includem sau nu liniile care nu se potrivesc conform argumentului by.
Să presupunem că avem la dispoziție un set de date în care apar 5 studenți și notele pe care le-au obținut la examenul de statistică:
Scopul nostru este să creăm un singur tabel în care să regăsim notele la ambele materii:
combined_courses <-merge(x = stat_course, y = alg_course,by ="student")combined_courses
student note_stat note_alg
1 Ana 9 8
2 Gigel 5 9
3 Ionel 9 7
4 Maria 8 10
5 Vasile 7 9
O a treia funcție care joacă un rol important în manipularea data frame-urilor este funcția aggregate() care, după cum îi spune și numele, permite calcularea de funcții pe grupe de date din setul inițial. Argumentele principale ale acestei funcții sunt date în Tabelul 9 de mai jos:
Tabelul 9: Argumentele funcției aggregate().
Argument
Descriere
formula
O formulă de tipul y ~ x1 + x2 + ... unde y este variabila dependentă iar x1, x2, … sunt variabilele independente. De exemplu, salary ~ sex + age va agrega o coloană salary la fiecare combinație unică de sex și age
FUN
O funcție pe care vrem să o aplicăm lui y la fiecare nivel al variabilelor independente. E.g. mean sau max.
data
Data frame-ul care conține variabilele din formula
subset
O submulțime din data pe care vrem să le analizăm. De exemplu, subset(sex == "f" & age > 20) va restrânge analiza la femei mai învârstă de 20 de ani.
Structura generală a funcției aggregate() este
aggregate(dv ~ iv, # dv este data, iv este grupul FUN = fun, # Functia pe care vrem sa o aplicamdata = df) # setul de date care contine coloanele dv si iv
Să considerăm setul de date ChickWeight și să ne propunem să calculăm pentru fiecare tip de dietă greutatea medie:
# Fara functia aggregatemean(ChickWeight$weight[ChickWeight$Diet ==2])
[1] 122.6167
mean(ChickWeight$weight[ChickWeight$Diet ==3])
[1] 142.95
mean(ChickWeight$weight[ChickWeight$Diet ==4])
[1] 135.2627
# Cu ajutorul functiei aggregateaggregate(weight ~ Diet, # DV este weight, IV este DietFUN = mean, # calculeaza media pentru fiecare grupdata = ChickWeight) # dataframe este ChickWeight
Funcția aggregate() a întors un data.frame cu o coloană pentru variabila independentă Diet și o coloană pentru greutatea medie.
Dacă vrem să calculăm greutățile medii în funcție de dietă pentru găinile care au mai puțin de 10 săptămâni de viață atunci folosim opțiunea subset:
aggregate(weight ~ Diet, # DV este weight, IV este DietFUN = mean, # calculeaza media pentru fiecare grupsubset = Time <10, # gainile care au mai putin de 10 saptamanidata = ChickWeight) # dataframe este ChickWeight
Putem să includem de asemenea mai multe variabile independente în formula funcției aggregate(). De exemplu putem să calculăm greutatea medie a găinilor atât pentru fiecare tip de dietă cât și pentru numărul de săptămâni de la naștere:
df <-aggregate(weight ~ Diet + Time, # DV este weight, IV sunt Diet și TimeFUN = mean, # calculeaza media pentru fiecare grupdata = ChickWeight) # dataframe este ChickWeighthead(df)
Exercițiul 17 Creați un data.frame pe baza următorului tabel:
persoană
sex
simț umor
Stan
\(M\)
Ridicat
Felicia
\(F\)
Mediu
Ștefan
\(M\)
Scăzut
Radu
\(M\)
Ridicat
Ana
\(F\)
Ridicat
George
\(M\)
Mediu
Variabilele sex și simț umor sunt de tip factor (a se vedea Secțiunea 1.6).
Adăugați o coloană cu vârsta, unde vârstele sunt \(41\), \(41\), \(15\), \(100\), \(21\) și respectiv \(60\)
Reordonați coloanele după ordinea: persoană, vârstă, sex, nostim
Creați un data.frame similar pe baza următorului tabel
persoană
vârstă
sex
simț umor
Fane
42
\(M\)
Ridicat
Roberta
37
\(F\)
Mediu
Alex
19
\(M\)
Scăzut
Bogdan
35
\(M\)
Ridicat
și apoi uniți cele două seturi de date în data.frame-ul numit df
Extrageți din df acele persoane de sex feminin care au un nivel de simț al umorului mediu sau ridicat.
Exercițiul 18 Considerați setul de date mtcars. Calculați:
Greutatea medie în funcție de tipul de transmisie
Greutatea medie în funcție de numărul de cilindrii
Consumul mediu în funcție de numărul de cilindrii și tipul de transmisie
Exercițiul 19 Considerăm setul de date Seatbelts din pachetul datasets care face referire la numărul de șoferi accidentați mortal sau grav în Marea Britanie în perioada Ianuarie 1969 - Decembrie 1984.
Vizualizați setul de date. Ce observați? Transformați setul de date într-un data.frame folosind funcția as.data.frame() și stocați rezultatul în variabila dat
Creați două coloane la setul de date dat una pentru an (numită an) și alta pentru luna (numită luna) aferentă fiecărei observații.
Determinați câți șoferi au murit între 1971 și 1983. Dar între Aprilie 1970 și Mai 1980.
Creați un subset de date care conține informații despre șoferii accidentați mortal între 1975 și 1984.
Determinați numărul maxim de șoferi accidentați din luna august între 1970 și 1984.
Precizați care este diferența între numărul mediu de pasageri accidentați pe locuri din față și cel al pasagerilor de pe locurile din spate pentru fiecare an în parte.
Factori
Din punct de vedere conceptual, structurile de date de tip factor pot fi văzute ca vectori la care se adaugă o serie de informații suplimentare. În practică, aceste structuri de date sunt folosite pentru modelarea variabilelor categoriale (e.g. sex, etnie, naționalitate, culoarea ochilor, etc.), variabile care iau un număr finit de valori, și pot fi create atât din vectori numerici cât și din vectori de tip caracter. Factorii joacă un rol important în modelarea statistică din R deoarece funcțiile de modelare din R tratează în mod diferit datele de tip categorial față de cele de tip continuu. Spre exemplu în cazul modelelor liniare, tipul de model ajustat (fitted) este decis de tipul covariabilelor (variabilelor explicative): dacă acestea sunt de tip factor atunci avem ANOVA iar dacă sunt de tip numeric avem regresie.
Pentru a crea un factor se folosește funcția factor() care primește ca prim argument un vector (numeric sau de tip caracter) ce urmează să fie transformat în factor. Ceea ce caracterizează un factor în R este modul de stocare al acestuia: vectorul atomic ce urmează să fie transformat într-un factor este stocat ca un vector de numere întregi la care se adaugă un argument suplimentar levels (niveluri), o mulțime de valori de tip caracter folosite pentru ilustrarea vectorului. Astfel un factor nu include numai valorile variabilei categoriale corespunzătoare ci și diferitele niveluri (categorii) posibile ale acestei variabile (eventual și cele care nu sunt reprezentate în date).
x <-c(5, 7, 10, 7, 9)xf <-factor(x)xf
[1] 5 7 10 7 9
Levels: 5 7 9 10
str(xf)
Factor w/ 4 levels "5","7","9","10": 1 2 4 2 3
Putem observa din structura obiectului xf că acesta nu este stocat drept (5, 7, 10, 7, 9) ci mai degrabă ca (1,2,4,2,3). Vectorul (1,2,4,2,3) reprezintă modul de stocare pe niveluri din R a vectorului x. Nivelurile, dacă nu este specificat altfel, sunt date de valorile unice ale vectorului x sortate alfabetic "5","7","9","10". Astfel vectorul (1,2,4,2,3) ne spune că primul element (5) este de nivel 1 , al doilea (7) de nivel 2, al treilea (10) de nivel 4, al patrulea (7) de nivel 2 iar ultimul (9) de nivel 3. Pentru a transforma un factor într-un vector numeric (atunci când factorul a fost creat dintr-un vector numeric) nu este suficient să îl transformăm folosind funcția de conversie as.numeric:
as.numeric(xf)
[1] 1 2 4 2 3
ci trebuie să efectuăm doi pași: în primul rând transformăm factorul într-un șir de caractere (deoarece nivelurile sunt stocate drept șiruri de caractere) prin as.character() iar apoi convertim într-un vector numeric prin as.numeric(). Putem obține același lucru folosind și funcția levels():
as.numeric(as.character(xf))
[1] 5 7 10 7 9
# acelasi lucru se poate obtine si folosind functia levelsas.numeric(levels(xf)[xf])
[1] 5 7 10 7 9
Dacă dorim să schimbăm ordinea în care sunt afișate nivelurile putem adăuga argumentul levels = la funcția factor() specificând atât ordinea dorită dar și nivelurile. Același lucru se poate obține și utilizând funcția levels().
Trebuie să fim atenți atunci când folosim funcția levels(), în exemplul anterior comanda levels(sex4) <- c("B", "F") îi cere R-ului să înlocuiască primul nivel al variabilei factor sex4 în B iar al doilea în F. Dacă am fi utilizat levels(sex4) <- c("F", "B") atunci am fi inversat cele două niveluri. Mai mult, fiecare termen al unui factor este restrâns la valorile determinate de nivelurile factorului ori la NA și putem avea factori care au mai multe niveluri definite decât ceea ce se observă în date (luna Iunie nu apare în date):
luni <-c("Martie","Aprilie","Ianuarie","Noiembrie","Ianuarie","Septembrie","Octombrie","Septembrie","Noiembrie","August","Ianuarie","Noiembrie","Noiembrie","Februarie","Mai","August","Iulie","Decembrie","August","August","Septembrie","Noiembrie","Februarie","Aprilie")#fara sa specificam nivelurileluni_f <-factor(luni)table(luni_f)
luni_f
Aprilie August Decembrie Februarie Ianuarie Iulie Mai
2 4 1 2 3 1 1
Martie Noiembrie Octombrie Septembrie
1 5 1 3
luni_f
Ianuarie Februarie Martie Aprilie Mai Iunie Iulie
3 2 1 2 1 0 1
August Septembrie Octombrie Noiembrie Decembrie
4 3 1 5 1
Dacă dorim să adăugăm la un factor o valoare care nu se regăsește printre nivelurile sale atunci apare o atenționare și valoarea se înlocuiește cu NA:
luni_f[length(luni_f) +1] <-"May"
Warning in `[<-.factor`(`*tmp*`, length(luni_f) + 1, value = "May"): invalid
factor level, NA generated
luni_f
[1] Martie Aprilie Ianuarie Noiembrie Ianuarie Septembrie
[7] Octombrie Septembrie Noiembrie August Ianuarie Noiembrie
[13] Noiembrie Februarie Mai August Iulie Decembrie
[19] August August Septembrie Noiembrie Februarie Aprilie
[25] <NA>
12 Levels: Ianuarie Februarie Martie Aprilie Mai Iunie Iulie ... Decembrie
Putem menționa că funcția factor() permite și creare de factori ordonați corespunzători variabilelor ordinale (variabile calitative ale căror valori pot fi ordonate în mod natural dar pentru care nu este definită diferența dintre acestea: gradul de studii, clasa socială, gradul de satisfacție a unui serviciu, etc.) prin specificarea argumentului ordered = TRUE. În acest caz putem compara valorile prin utilizarea operatorilor logici de comparare:
[1] Martie Aprilie Ianuarie Noiembrie Ianuarie Septembrie
[7] Octombrie Septembrie Noiembrie August Ianuarie Noiembrie
[13] Noiembrie Februarie Mai August Iulie Decembrie
[19] August August Septembrie Noiembrie Februarie Aprilie
12 Levels: Ianuarie < Februarie < Martie < Aprilie < Mai < Iunie < ... < Decembrie
luni_fo[1] < luni_fo[2]
[1] TRUE
Trebuie să avem grijă atunci când dorim să concatenăm două variabile care sunt factori folosind funcția c() în versiunile de R < 4.1.0 deoarece aceasta va interpreta cei doi factori ca pe doi vectori de numere întregi și pentru a combina cei doi factori trebuie să îi convertim la valorile originale. Pentru versiunile de R > 4.1.0 funcția c() permite concatenarea factorilor (atenție la ordinea nivelurilor):
O funcție utilă în convertirea unei variabile numerice într-o variabilă de tip factor este funcția cut(). Argumentul breaks = asigură specificarea numărului de subintervale (niveluri) în care se dorește împărțirea variabilei sau a capetelor acestor intervale. Argumentul labels = permite denumirea nivelurilor variabilei factor obținute:
# intervalul de valorir <-range(mtcars$mpg)# utilizarea functiei cut cu 3 intervalecut(mtcars$mpg, breaks =3)
[1] low low low low medium low high low low low
[11] low medium medium medium medium medium medium low low low
[21] low medium medium high medium low low low high medium
[31] high low
Levels: low medium high
Exerciții
Exercițiul 20 Profesorii \(A\) și \(B\) colectează notele și sexul a \(10\) studenți fiecare și le stochează în următorii vectori:
A_note <-c("A","B","B","D","A","A","C","A","B","B")A_sex <-c(1,1,1,0,1,0,0,0,1,1) # aici 1 reprezinta sexul masculin si 0 femininB_note <-c(97,93,92,57,75,90,72,88,82,60)B_sex <-c("M","F","F","M","M","M","F","F","F","M")
Convertiți A_note într-un vector de tip factor A_note_fac cu nivelele ordonate \(A>B>C>D>F\)
Convertiți B_note într-un vector de tip factor B_note_fac cu nivelele ordonate \(A>B>C>D>F\) presupunâbd că avem următoarea corespondență
\[
\begin{array}{cc}
A & 90-100 \\
B & 80-89 \\
C & 70-79 \\
D & 60-69 \\
F & 0-59
\end{array}
\]
Convertiți A_sex într-un vector de tip factor A_sex_fac cu nivelele \(M\) și \(F\)
Convertiți B_sex într-un vector de tip factor B_sex_fac cu nivelele \(M\) și \(F\)
Combinați cei doi vectori A_note_fac și B_note_fac într-un singur vector note.fac. De asemenea, combinați vectorii A_sex_fac și B_sex_fac într-un singur vector sex.fac.