Manual de R (Estadística)/El llenguatge R
Introducció
[modifica]En R es diu que tot són objectes. En R, un objecte és qualsevol cosa que es pot assignar a una variable. Això inclou constants, estructures de dades, funcions, i fins i tot gràfics. Els objectes tenen una mode
(que es descriu com s'emmagatzema l'objecte) i una class
(que diu quin tipus d'objecte és). El manual del llenguatge és pot consultar a [1].
Tipus de dades
[modifica]En R les variables es poden emmagatzemar com diferents tipus de dades o "classes" [1].
Existeixen cinc tipus de dades bàsiques (veure Tipus de variables ):
- Caràcters.
- Nombres (nombres reals).
- Enters.
- Nombres complexos.
- Lògics (Verdader / Fals).
Aquestes s'agrupen en unes classes de dades més complexes:
- Vectors: tots els elements són del mateix tipus (p. ex., tots han de ser caràcters o tots enters).
- Llistes: els elements poden ser de tipus diferents.
- Factors: s'utilitzen per representar les dades categòriques. Hom pot pensar en un factor com un vector d'enters on cada nombre té una etiqueta. Els factors poden ser ordenats o no.
- Matrius.
- Arrays. Són matrius de qualsevol nombre de dimensions.
- Taules de dades. Son matrius on les variables són de qualsevol tipus i és una estructura similar als conjunts de dades que es troben en els paquets estadístics estàndard. Les columnes són variables i les files són observacions. Una taula de dades pot tenir diferents tipus de variables (p. ex., numèriques, caràcters). Les taules de dades són les principals estructures que utilitzarà per emmagatzemar conjunts de dades. Típicament es crea quan es llegeix i s'importa un fitxer de dades.
Per saber el tipus d'un objecte determinat s'utilitza l'ordre class(<Nom d'objecte>)
.
Per tant, hi ha moltes maneres diferents per emmagatzemar les variables en R (és a dir, objectes), i cada una d'elles correspon a un tipus d'objecte diferent ("classes"). A continuació és presenten alguns dels objectes més emprats juntament amb la seva descripció i la classe corresponent [1]:
Objecte | Descricció | Tipus (Class) |
---|---|---|
Nombre Individual o lletra / paraula | Només un sol número o caràcter o paraula o frase entre cometes | Numèrica o de caràcters |
Vector | Un vector de tots números o tots caràcters | O tots nombres o tots caràcter |
Matriu | Té columnes i files - totes les entrades són de la mateixa classe | O tots nombres o tots caràcter |
Taula de dades | Igual que una matriu però columnes poden ser de diferents tipus (classes) | data.frame |
Llista | Un munt de diferents objectes tots agrupats sota un mateix nom | list |
Operadors
[modifica]Aritmètics
[modifica]X + Y : Suma
X - Y : Resta
X * Y : Multiplicació
X / Y : Divisió
X ^ Y : Potència
X %% Y: Mòdul
X %/% Y : Divisió entera
Relacionals
[modifica]X < Y
X > Y
X <= Y
X >= Y
X == Y
X != Y
Lògics
[modifica]! X Negació
X && Y
X & Y
X || Y
X | Y
Funcions
[modifica]sum(nom_variable) Ens suma tots els valors de la variable. Si volem sumar els valors de l'1 al 20 fem:
sum(c(1:20))
sort(nom_variable)
Ordena els valors d'una variable.
sqrt(nom_variable)
Arrel quadrada.
^
Potència.
mean()
Mitja aritmètica.
summary()
Fa un resum d'estadística descriptiva de la variable.
sample(nom_variable,longitud)
Agafa una mostra aleatòria de la longitud desitjada entre tots els valors de la mostra.
runif(n)
Genera una successió de n nombres aleatoris segons una llei uniforme.
rnorm()
Genera una successió de n nombres aleatoris segons una llei normal.
length()
Diu el nombre de posicions del vector.
Prod()
El producte dels elements d'un vector.
prod(c(1:20))
exp(sum(log(c(1:20))))
Seguin la classificació de Kabacoff ([2], pàg 42, 93-102), es classificaran en:
- Per treballar amb objectes de dades
- Per gestionar l'espai de treball de R
- Matemàtiques
- Estadístiques
- Probabilitats
- Per text
- Per directoris i fitxers externs
- Altres
Funcions per treballar amb objectes de dades
[modifica]Algunes de les funcions que cita Kabacoff ([2] pag. 42-43) són:
c (<Nom objecte 1er>, <Nom objecte 2n>, ...)
: combina objectes en un vector.cbind (<Nom objecte 1er>, <Nom objecte 2n>, ...)
: combina objectes en columnes.rbind (<Nom objecte 1er>, <Nom objecte 2n>, ...)
: combina objectes en files.class (<Nom objecte>)
: mostra el tipus d'objecte.head (<Nom objecte>)
: mostra la part inicial de l'objecte.tail (<Nom objecte>)
: mostra la part final de l'objecte.length (<Nom objecte>)
: mostra el nombre d'elements o de components d'un objecte.ls ()
: llista els objectes.names (<Nom objecte>)
: mostra els noms dels components d'un objecte.rm (<Nom objecte 1er>, <Nom objecte 2n>, ...)
: esborra els objectes llistats.str (<Nom objecte>)
: mostra l'estructura d'un objecte.
Funcions per gestionar l'espai de treball de R
[modifica]Algunes de les funcions que cita Kabacoff ([2] pag. 12) són:
- getwd()
- setwd("El meu directori")
- ls(): És com llistar totes les variables.
- rm(): Per esborrar una variable hem d'utilitzar l'instrucció "rm(nom_variable)".
- rm(<llista d'objectes>)
- help(options)
- options()
- history(<número>): mostra les darrers <nombre> ordres
- save(<llista d'objectes>, file="<nom de fitxer>"): desa els objectes
Funcions per les dades en R
[modifica]- c(valor, valor, ...): combina els valors (numèrics, caràcter) en un vector. La "c" és de "combine". Serveix per crear vectors.
- Exemples
-
- X = c(0,5, 0,6) # numèric
- X = c(TRUE, FALSE) ## Lògic
- X = c(T, F) ## Lògic
- X = c("a", "b") ## Caràcter
- names(<DADES>): torna els noms de les columnes de la nostra taula, és a dir, els noms de les variables.
- ncol(<DADES>): nombre de variables (nombre de columnes) d'una taula de dades.
- nrow(<DADES>): nombre de registres (nombre de files) d'una taula de dades.
Funcions que realitzen bucles
[modifica]Quan es treballa de forma interactiva, es complicat escriure bucles amb for
o while
. Existeixen unes funcions per realitzar-los de forma senzilla:
lapply
: recorre els elements d'una llista i avaluar una funció en cada un d'ells de forma consecutiva.sapply
: igual quelapply
, però intenta simplificar el resultat.apply
: aplica una funció sobre els marges d'una matriu.tapply
: aplica una funció sobre els subconjunts d'un vector.mapply
: és una versió multivariada delapply
.
És molt útil utilitzar la funció split
amb aquestes funcions, especialment amb lapply
o sapply
, ja que permet trossejar un objecte.
apply
[modifica]Tècnicament "retorna un vector o matriu o llista de valors obtinguts mitjançant l'aplicació d'una funció als marges d'una matriu o matriu". A la pràctica, és útil per calcular, p. ex., el valor mitjà o el valor màxim, de:
- Una sèrie de variables d'una taula de dades (p. ex., la mitjana o el màxim d'una sèrie de variables de cada observació o fila).
- Una variable d'una taula de dades (p. ex., la mitjana o el màxim d'una variable). Aquest cas és poc útil, ja que és més fàcil l'ordre
mean(<Nom de la variable de la taula de dades>
).
El paràmetre de la funció apply són:
- Nom de la taula de dades.
- Marge sobre el que aplicar la funció:
- 1: sobre les files.
- 2: sobre les columnes.
- c(1, 2): sobre files i columnes.
- La funció a aplicar (p. ex.,
mean
,max
,sum
o inclússort
)
Per exemple, per calcular la mitjana de les variables V1 i V2 quantitatives d'una taula de dades:
> DADES = data.frame(V1 = c(3, 7, 2, 4),
+ V2 = c(4, 2, 1, 3))
> DADES
V1 V2
1 3 4
2 7 2
3 2 1
4 4 3
> # Var nova (MIT) amb la mitjana de V1 i V2 per cada observació
> DADES$MIT = apply(DADES, 1, mean) # marge = 1: files
> DADES
V1 V2 MIT
1 3 4 3.5
2 7 2 4.5
3 2 1 1.5
4 4 3 3.5
Si existeixen valors desconeguts en el valors d'alguna de les variables, es pot fer servir l'opció na.rm = TRUE
a fi de que calculi la mitjana (o altre funció) amb la resta de valors coneguts:
> # Amb valors desconeguts
> DADES = data.frame(V1 = c(3, 7, 2, 4),
+ V2 = c(4, 2, 1, NA))
> DADES
V1 V2
1 3 4
2 7 2
3 2 1
4 4 NA
> # Var nova (MIT) amb la mitjana de V1 i V2 per cada observació
> DADES$MIT = apply(DADES, 1, mean, na.rm = TRUE) # marge = 1: files
> DADES
V1 V2 MIT
1 3 4 3.5
2 7 2 4.5
3 2 1 1.5
4 4 NA 4.0
Si només es volgués aplicar la funció a un grup de variable, es poden seleccionar pel seu nom:
> # Només unes variables
> DADES = data.frame(V1 = c(3, 7, 2, 4),
+ V2 = c(4, 2, 1, NA),
+ V3 = c(2, 5, 3, 3))
> DADES
V1 V2 V3
1 3 4 2
2 7 2 5
3 2 1 3
4 4 NA 3
> # Var nova (MIT) amb la mitjana de V1 i V2 per cada observació (excloent V3)
> DADES$MIT = apply(DADES[, c("V1", "V2")], 1, mean, na.rm = TRUE)
> DADES
V1 V2 V3 MIT
1 3 4 2 3.5
2 7 2 5 4.5
3 2 1 3 1.5
4 4 NA 3 4.0
Amb la ordre DADES[, c("V1", "V2")]
es seleccionen totes les observacions (el valor de les files està en blanc a l'ordre [ , c("V1", "V2")]
) de les variable V1 i V2.
lapply
[modifica]Processa les observacions d'una variable d'una taula de dades (o d'una llista) i avalua una funció en cada element. Sol tenir només dos arguments, una llista (que pot ser, p. ex., una taula de dades o una variable d'una taula de dades) i el nom d'una funció (que pot ser una del propi R o escrita per un mateix), encara que després pot tenir arguments addicionals (indicats a la sintaxis següent per "...
"):
lapply(<Nom de la llista>, <Nom de la funció>, ...)
# Si hi han valors desconeguts i la funció els ha d'excloure:
lapply(<Nom de la llista>, <Nom de la funció>, na.rm = TRUE, ...)
Si el primer argument no és una llista, es pot forçar que ho sigui (si és possible), amb as.list
.
En l'exemple següent, s'arrodoneix els valors de la pressió arterial diastòlica aplicant la funció round
a cada un dels valors i després es calcula la mitjana de les variables d'una taula de dades (edat i pressió arterial diastòlica):
> DADES = data.frame(EDAT = c(50, NA, 20, 18, 30),
+ PAD = c(8.3, 10.2, 7.7, 11.4, 8.6))
> DADES
EDAT PAD
1 50 8.3
2 NA 10.2
3 20 7.7
4 18 11.4
5 30 8.6
> DADES$PAD = lapply(DADES$PAD, round)
> DADES
EDAT PAD
1 50 8
2 NA 10
3 20 8
4 18 11
5 30 9
# Crear una llista amb la mitjana de les variables d'una taula de dades
# (edat i pressió arterial diastòlica):
> DADES_MI = lapply(DADES, mean, na.rm = TRUE)
> DADES_MI
$EDAT
[1] 29.5
$PAD
[1] 9.24
En el primer exemple (arrodonir els valors), el mateix resultat s'obtindria de forma més directa amb l'ordre DADES$PAD = round(DADES$PAD)
.
En el segon exemple, a la funció se li passa l'argument addicional na.rm = TRUE
, ja que la variable edat presenta un valor desconegut. Sense aquest argument, el resultat de la mitjana de l'edat seria NA
.
En el següent exemple de Computing for Data Analysis es genera un número variable de nombres aleatoris amb la funció runif
(aquesta genera tants nombres aleatoris com el nombre que se li passa com argument):
> X <- 1:4 # Llista de 4 nombres
> X
[1] 1 2 3 4
> lapply(X, runif) # Generar 4 grups de 1, 2, 3 i 4 nombres aleatoris
[[1]]
[1] 0.6403106
[[2]]
[1] 0.009495756 0.232550506
[[3]]
[1] 0.6660838 0.5142511 0.6935913
[[4]]
[1] 0.5449748 0.2827336 0.9234335 0.2923158
A la funció runif
se li passa consecutivament com argument 1, 2, 3 i 4. Per tant, primer genera un sol nombre aleatori (0.6403106), després en genera dos (0.009495756 0.232550506), després 3 (0.6660838 0.5142511 0.6935913) i, finalment, quatre. Si es volgués que els nombres aleatoris prenguessin valors entre 0,1 i 10, es poden passar aquests valors com arguments de la funció lapply
:
lapply(X, runif, min=0.1, max=10)
La funció lapply
sempre torna una llista d'elements.
sapply
[modifica]Realitza la mateixa funció que lapply
, però intenta tornar el resultat més simple possible. Per exemple [3]:
- Si el resultat és una llista en la que cada element té una longitud de 1, llavors en lloc de tornar una llista, torna un vector.
- Si el resultat és una llista en que cada element és un vector de la mateixa longitud i major de 1, la funció torna una matriu.
Exemple [3]:
# Es crea una llista amb elements de diferent longitud (4, 5, 6 i 10):
> X <- list(a = 1:4, b = rnorm(5), c = rnorm(6, 1), d = rnorm(10, 5))
> X
$a
[1] 1 2 3 4
$b
[1] -0.1703292 1.1918528 1.3658102 -0.7606006 -0.9737320
$c
[1] 2.9097989 -0.7529179 1.9556914 3.3340616 2.1016724 2.0919802
$d
[1] 5.285383 3.440272 5.855748 5.427933 4.712756 4.798824 5.900511 2.745999
[9] 4.480313 4.637082
# La funció lapply torna un llista de 4 elements de longitud 1
# (la mitjana de cada un dels elements de la llista X):
> lapply(X, mean)
$a
[1] 2.5
$b
[1] 0.1565971
$c
[1] 0.9895367
$d
[1] 5.092754
# La funció spally torna un vector de 4 elements:
> sapply(X, mean)
a b c d
2.5000000 0.1565971 0.9895367 5.0927545
# Si s'aplica la funció mean a X, dona error, ja que no es pot aplicar a llistes:
> mean(X)
[1] NA
Warning message:
In mean.default(X) : argument is not numeric or logical: returning NA
Funcions pels valors desconeguts
[modifica]- is.na()
complete.cases()
[modifica]Retorna un vector lògic amb la longitud del nombre d'observacions (files) de la taula de dades i amb al valor és TRUE
per les observacions sense valors desconeguts. Aquest vector es pot utilitzar per filtrar les observacions sense valors desconeguts:
> # Dades de 5 persones
> DADES = data.frame(INICIALS=c("PG", "GB", "NR", "IR", "NA"),
+ SEXE=c(NA, "Home", "Dona", "Dona", "Home"),
+ EDAT=c(50, NA, 20, 18, 30))
> DADES # Llistar les dades
INICIALS SEXE EDAT
1 PG <NA> 50
2 GB Home NA
3 NR Dona 20
4 IR Dona 18
5 NA Home 30
> DADES_SD = complete.cases(DADES) # Identificar casos sense valors desconeguts
> DADES_SD # Tenen tots els valors
[1] FALSE FALSE TRUE TRUE TRUE
> DADES[DADES_SD,] # Es seleccionen els casos sense valors desconeguts
INICIALS SEXE EDAT
3 NR Dona 20
4 IR Dona 18
5 NA Home 30
na.omit()
[modifica]Omet les files que contenen valors mancants.
> DADES_SD = na.omit(DADES) # Elimina observacions amb valors mancants
> DADES_SD # Llistat de les dades
INICIALS SEXE EDAT
3 NR Dona 20
4 IR Dona 18
5 NA Home 30
Funcions matemàtiques
[modifica]Funcions estadístiques
[modifica]is.na()
: valor desconegut
[modifica]Retorna TRUE si l'argument conté un valor desconegut i FALSE si no ho és:
> EDAT = NA
> EDAT
[1] NA
> is.na(EDAT)
[1] TRUE
> EDAT = 45
> EDAT
[1] 45
> is.na(EDAT)
[1] FALSE
sd
: desviació típica
[modifica]Estima la desviació típica (o desviació estàndard) d'un conjunt de dades (és a dir, l'arrel quadrada de la seva variància):
> sd(c(42,56,58))
[1] 8.717798
Funcions de probabilitats
[modifica]runif
[modifica]Genera nombres pseudo-aleatoris d'una distribució uniforme en l'interval definit per un mínim i un màxim (per omissió, de 0 a 1). Sintaxis:
runif(n, min=<valor mínim>, max=<valor màxim>)
on "n
" és el nombre de números aleatoris que es volen generar. Exemple:
> set.seed(1234) # El fixa la llavor
> runif(5) # Generar 5 nombres aleatoris entre 0 i 1
[1] 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154
> set.seed(1234) # El fixa la llavor
> runif(5, min=0.1, max=10) # Generar 5 nombres aleatoris entre 0.1 i 10
[1] 1.225664 6.260764 6.131820 6.271456 8.623062
Cada vegada que es generen nombres pseudo-aleatoris els resultats són diferents, ja que la llavor utilitzada és diferent en cada moment. Perquè els resultats siguin reproduïbles, es pot especificar explícitament la llavor, utilitzant el <codi>set.seed (<nombre>)</codi>, tal com es mostre en l'exemple anterior.
Funcions per dates i temps
[modifica]Funcions per a text
[modifica]as.character()
: Convertir a caràcter
[modifica]Converteix un tipus de variable en un caràcter:
> X = as.character(3.14) # Assigna el nombre 3,14 a la variable X
> X # Mostrar el valor de la variable X
[1] "3.14"
> class(X) # Mostrar el tipus de variable de C
[1] "character"
is.na()
: valor desconegut
[modifica]Retorna TRUE si l'argument conté un valor desconegut i FALSE si no ho és:
> SEXE = NA
> SEXE
[1] NA
> is.na(SEXE)
[1] TRUE
> SEXE = "D"
> SEXE
[1] "D"
> is.na(SEXE)
[1] FALSE
paste()
: concatenar caràcters i/o variables
[modifica]Dos valors de tipus caràcters es poden concatenar amb la funció paste:
> NOM = "Xavier"
> COGNOM = "Rull"
> paste(NOM, COGNOM)
[1] "Xavier Rull"
Si no es vol un espai entre els caràcters es pot utilitzar l'opció sep=""
:
> NOM = "Xavier"
> COGNOM = "Rull"
> paste(NOM, COGNOM, sep="")
[1] "XavierRull"
També amb variables i text. Per exemple, es pot combinar la variable XCAMIF
(el camí on estan una sèrie de funcions) i el text des.R
(el nom del fitxer on està una una funció):
> XCAMIF = "~/r/r_funcions/"
> XCAMI=paste(XCAMIF, "des.R", sep="")
> print(XCAMI)
[1] "~/r/r_funcions/des.R"
Això és útil per no tenir, p. ex., que escriure el camí on està el fitxer des.R
si aquest s'ha de carregar.
sub()
: substituir caràcter
[modifica]Si en un cap text es te, per exemple, uns punts que es volen treure (i substituir per un espai, " "), és poden fer servir les funcion sub
i gsub
. La primera substitueix només el primer punt que troba i la segona els substitueix tots. Per exemple, suposem que en una taula de dades tenim el camp NOM amb els noms amb un punt entre nom i cognom i un punt després del cognom:
> NOM = "Ian.Murdock."
> print(NOM)
[1] "Ian Murdock."
> NOM_SP = sub ("[.]", " ", NOM, ignore.case=FALSE) # Elimina el primer punt. El ignore.case no cal.
> print(NOM_SP)
[1] "Ian Murdock."
> NOM_SP = gsub("[.]", " ", NOM, ignore.case=FALSE) # Elimina tots els punts. El ignore.case no cal.
> print(NOM_SP)
[1] "Ian Murdock "
També es poden eliminar més d'un caràcter. P. ex., si en els noms hi ha un punt i una ensaïmada, es poden substituir els dos a la vegada per un espai:
> NOM = "Ian.Murdock@"
> NOM
[1] "Ian.Murdock@"
> NOM_SP = gsub("[., @]", " ", NOM, ignore.case=FALSE) # Elimina punt i @. El ignore.case no cal.
> print(NOM_SP)
[1] "Ian Murdock "
substring()
: Extreure subcaràcters
[modifica]Extreure o reemplaçar subcadenes d'un caràcter.
> substr("Qualsevol nit pot sortir el sol.", start=11, stop=13)
[1] "nit"
> substr("Qualsevol nit pot sortir el sol.", 11, 13)
[1] "nit"
Funcions per directoris i fitxers externs
[modifica]file.exists
[modifica]Per verificar si existeixen directoris i fitxers no R:
file.exists(<directori>)
file.exists(<fitxer>)
Exemples:
> file.exists("~/tmp") # Verifica si existeix el directori ~/sys/analisis/
[1] TRUE # El directori existeix.
> file.exists("~/tmp/DADES.CSV") # Verifica si existeix el fitxer DADES.CSV al directori ~/tmp/
[1] FALSE # El fitxer no existeix
És molt útil per crear un directori on es vulgui deixar els resultats, si aquest no existeix:
> CAMI_RES = "~/sys/analisis/r_proves/viquillibre/" # Camí on es volen deixar els resultats
> CAMI_RES
[1] "~/sys/analisis/r_proves/viquillibre/"
> if(!file.exists(CAMI_RES)) { dir.create(CAMI_RES,showWarnings=F) } # Verifica si existeix. El crea si no existeix
Altres tipus de funcions
[modifica]Càlcul amb funcions
[modifica]Anem a calcular la mitja aritmètica:
sum(nom_variable)/length(nom_variable)
Calculem la mitja armònica:
1/sum(1/nom_variable)/length(nom_variable)
Definició de variables
[modifica]Asignar una variable Per asignar el valor "24" a la variable "hores" usem la comanda:
hores<-24
També es pot assignar un valor amb el signe "=". La ordre seria:
hores=24
Perquè mostri el valor de la variable "hores":
hores
Igualment amb:
dies<-365 minuts<-60 segons<-60
Per tant si volem que ens faci el producte hem de posar i hem de saber que com que el resultat surt per pantalla no s'emmagatzema enlloc i per tant haurem de tornar a escriure l'ordre per tornar a calcular el resultat:
dies*hores*minuts*segons
c()
Si volem assignar els valors 7, 35 i 54 a una variable escriurem:
variable<-c(7,35,54)
Si el que volem és que ens faci una llista de l'1 al 20 ho podem aconseguir fent:
llista<-c(1:20)
Però si ho volem per posar un mateix nombre 7 unes 20 vegades fem:
mateix<-c(rep(7,20))
Càlculs amb manipulació de variables
[modifica]Si tenim una variable amb 5 posicions i fem la instrucció:
a<-c(1:5); a+5;
Ens dóna com a resultat el mateix vector però amb un cinc sumat a totes les posicions. Recordem que aquest valor no es guarda sino que simplement s'imprimeix per pantalla.
Si l'elevem al quadrat ens dóna els quadrats de cada posició.
a^2
En definitiva si fem operacions amb una variable que és un vector ens fa tantes operacions com posicions té el vector.
Matrius
[modifica]matrix(nom_variable,n_files) Expressa la variable en forma d'una matriu amb les files desitjades.
t() Ens fa la transposada d'una funció.
%*% És el simbol per poder multiplicar dues funcions.
solve() Ens calcula la matriu inversa d'una altra.
Programació
[modifica]IF
if(cond) expr if(cond) cons.expr else alt.expr
FOR
for(var in seq) expr while(cond) expr repeat expr break next
Exemples:
for(i in 1:5) print(1:i)
for(n in c(2,5,10,20,50)) {
x <- stats::rnorm(n) cat(n,":", sum(x^2),"\n")
}
f = factor(sample(letters[1:5], 10, replace=TRUE))
for( i in unique(f) ) print(i)
L'ordre system
permet executar des de dintre el R una ordre de Linux. Per exemple, per llistar el contingut del directori temporal de l'usuari:
> system("dir ~/tmp")
1202022.pdf
1309.pdf
...
Referències
[modifica]- ↑ 1,0 1,1 Data types, part 1: Ways to store variables
- ↑ 2,0 2,1 2,2 Kabacoff RI. R in action, data analysis and graphics with R. Shelter Island, NY: Manning Publications Co; 2011
- ↑ 3,0 3,1 Roger D. Peng. Computing for Data Analysis.