Lista je generički vektor koji sadrži druge objekte.
n <- c(2, 3, 5)
s <- c("aa", "bb", "cc", "dd", "ee")
b <- c(TRUE, FALSE, TRUE, FALSE, FALSE)
lst <- list(n, s, b) # lst sadrzi kopije od n, s, b
lst[1] #niz n
## [[1]]
## [1] 2 3 5
lst[2] #niz s
## [[1]]
## [1] "aa" "bb" "cc" "dd" "ee"
Na ovaj način dobijamo kopije prvog, odnosno drugog člana liste
Međutim ako hoćemo da direktno pristupimo članu liste koristimo [[ ]]
lst[[1]]
## [1] 2 3 5
Tada možemo da mijenjamo sadržaj liste
lst[[2]]<-c("a","b")
lst[[2]][1]<-"c"
brojevi<-1:12
slova<-letters[1:12]
df<-data.frame(brojevi,slova)
df
## brojevi slova
## 1 1 a
## 2 2 b
## 3 3 c
## 4 4 d
## 5 5 e
## 6 6 f
## 7 7 g
## 8 8 h
## 9 9 i
## 10 10 j
## 11 11 k
## 12 12 l
df$brojevi
## [1] 1 2 3 4 5 6 7 8 9 10 11 12
df$slova
## [1] a b c d e f g h i j k l
## Levels: a b c d e f g h i j k l
names(df)<-c("kolona1", "kolona2")
attach(df)
kolona1 # inace bismo pristupali sa df$kolona1
## [1] 1 2 3 4 5 6 7 8 9 10 11 12
df[,2]
## [1] a b c d e f g h i j k l
## Levels: a b c d e f g h i j k l
df[1]
## kolona1
## 1 1
## 2 2
## 3 3
## 4 4
## 5 5
## 6 6
## 7 7
## 8 8
## 9 9
## 10 10
## 11 11
## 12 12
Neki primjeri baza podataka.
data("AirPassengers")
AirPassengers
## Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 1949 112 118 132 129 121 135 148 148 136 119 104 118
## 1950 115 126 141 135 125 149 170 170 158 133 114 140
## 1951 145 150 178 163 172 178 199 199 184 162 146 166
## 1952 171 180 193 181 183 218 230 242 209 191 172 194
## 1953 196 196 236 235 229 243 264 272 237 211 180 201
## 1954 204 188 235 227 234 264 302 293 259 229 203 229
## 1955 242 233 267 269 270 315 364 347 312 274 237 278
## 1956 284 277 317 313 318 374 413 405 355 306 271 306
## 1957 315 301 356 348 355 422 465 467 404 347 305 336
## 1958 340 318 362 348 363 435 491 505 404 359 310 337
## 1959 360 342 406 396 420 472 548 559 463 407 362 405
## 1960 417 391 419 461 472 535 622 606 508 461 390 432
summary(AirPassengers)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 104.0 180.0 265.5 280.3 360.5 622.0
Funkcionalima ćemo ovdje zvati funkcije koje primaju funkciju kao argument i vraćaja vektor kao izlaz. Jednostavan primjer funkcionala: funkcija koju kreiramo treba da vrati vrijednosti funkcije koja je proslijedjena kao argument u datim tačkama iz uniformne raspodjele.
funkcional <- function(f) {
f(runif(1000))
}
funkcional(mean)
## [1] 0.4916365
funkcional(sum)
## [1] 472.7689
funkcional(var)
## [1] 0.08020371
Tri funkcionala koja se najčešće koriste su: lapply()
, apply()
i tapply()
.
Česta upotreba funkcionala je zamjena za for
petlje, za koje važi da rade sporo u R-u. Nije uvijek slučaj da će upotreba funkcionala proizvesti najbrži kod, ali se preporučuje zbog jednostavnijeg zapisa koda, lakšeg uočavanja problema i razvijanja alata koji se koriste da riješe široku klasu problema.
lapply
lapply2 <- function(x, f) {
out <- vector("list", length(x))
for (i in seq_along(x)) {
out[[i]] <- f(x[[i]])
}
out
}
Primjer
# Pravimo neke podatke pomocu slucajnih brojeva
l <- replicate(20, runif(sample(1:10,1)),simplify = F) # simplify=F ce nam dati podatke u obliku liste
# Hocemo da dobijemo vektor duzina svakog od 20 elemenata ove liste
# Resenje sa for petljom
out<- vector("list", length(l))
for( i in seq_along(l)){
out[[i]] <- length(l[[i]])
}
unlist(out) # unlist nam daje jednostavniju verziju liste u vidu vektora koji sadrzi njene podatke
## [1] 9 9 7 1 6 10 8 2 3 9 7 9 9 6 2 9 4 5 2 10
# mogli smo da pozovemo i samo `out`
# Resenje sa lapply
unlist(lapply(l,length))
## [1] 9 9 7 1 6 10 8 2 3 9 7 9 9 6 2 9 4 5 2 10
Kako je “data frame” takodje lista, lapply()
je korisna kada hoćemo nešto da radimo sa svakom kolonom.
# Baza `mtcars`
mtcars
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
## Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
## Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
## Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
## Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
## Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
## Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
## Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
## Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
## Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
## Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
## Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
## Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
## AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
## Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
## Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
## Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
## Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
## Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
## Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
# Primjer1: zanima nas koje klasi su podaci u svakoj koloni
unlist(lapply(mtcars,class))
## mpg cyl disp hp drat wt qsec
## "numeric" "numeric" "numeric" "numeric" "numeric" "numeric" "numeric"
## vs am gear carb
## "numeric" "numeric" "numeric" "numeric"
# Primjer2: želimo da podijelimo svaku kolonu sa srednjom vr.
mtcars[]<-lapply(mtcars, function(x) x/mean(x))
# mtcars
lapply
koje na izlazu daju vektore: sapply
i vapply
df <- data.frame(x=1:10, y=letters[1:10])
sapply(df,class) # "pogadja tip podataka na izlazu"
## x y
## "integer" "factor"
vapply(df, class, character(1)) # "tip izlaza se zadaje kao argument"
## x y
## "integer" "factor"
apply
i tapply
za data frame i matriceapply(X, MARGIN, FUN, ...)
Argumenti:
X
- matrica
MARGIN
- odredjuje indeks za dio matrice na koji treba da bude primijenjena funkcija, npr. 1-za vrste, 2-za kolone
FUN
-sumarna funkcija
… ostali opcioni argumenti koji se odnose na funkciju FUN
Jednostavan primjer:
a <- matrix(runif(20), ncol = 4, nrow = 5)
a
## [,1] [,2] [,3] [,4]
## [1,] 0.01152352 0.2374907 0.7183384 0.89700779
## [2,] 0.03050023 0.6147648 0.5692699 0.97480502
## [3,] 0.47331415 0.5809281 0.2923093 0.47602682
## [4,] 0.99749332 0.1770159 0.1526841 0.55353065
## [5,] 0.19500236 0.5529109 0.6784285 0.05839393
apply(a,1,mean) # racunamo srednju vrijednost po vrstama
## [1] 0.4660901 0.5473350 0.4556446 0.4701810 0.3711839
apply(a,2,mean) # racunamo srednju vrijednost po kolonama
## [1] 0.3415667 0.4326221 0.4822060 0.5919528
apply(a, c(1,2), function(x) x^2) # kvadriramo sve elemente matrice
## [,1] [,2] [,3] [,4]
## [1,] 0.0001327914 0.05640182 0.51601004 0.804622984
## [2,] 0.0009302639 0.37793580 0.32406827 0.950244828
## [3,] 0.2240262844 0.33747746 0.08544471 0.226601535
## [4,] 0.9949929237 0.03133462 0.02331244 0.306396175
## [5,] 0.0380259221 0.30571048 0.46026526 0.003409851
Funkcija apply
nema argument simplify
pa ne možemo da zadamo koji tip izlaza želimo. To znači da ako je koristimo unutar neke druge funkcije treba biti oprezan kojeg tipa su ulazni podaci.
sweep
x<-matrix(rnorm(20,0,10), nrow = 4)
x
## [,1] [,2] [,3] [,4] [,5]
## [1,] 4.662218 -7.73986414 6.606557 -14.6390696 33.549287
## [2,] 7.337004 -5.43866058 5.239908 3.3166891 -7.932929
## [3,] -6.924635 -0.09918982 12.609025 -0.9345136 2.746065
## [4,] -22.594851 12.09370682 -14.541598 -7.7727668 11.940250
x1<-sweep(x,1,apply(x,1,min),'-')
x1
## [,1] [,2] [,3] [,4] [,5]
## [1,] 19.30129 6.899205 21.245626 0.000000 48.18836
## [2,] 15.26993 2.494269 13.172838 11.249619 0.00000
## [3,] 0.00000 6.825445 19.533660 5.990121 9.67070
## [4,] 0.00000 34.688558 8.053253 14.822084 34.53510
x2<-sweep(x,1,apply(x,1,max),'/')
x2
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.1389662 -0.230701301 0.1969209 -0.43634518 1.0000000
## [2,] 1.0000000 -0.741264491 0.7141755 0.45204951 -1.0812219
## [3,] -0.5491808 -0.007866573 1.0000000 -0.07411466 0.2177857
## [4,] -1.8683148 1.000000000 -1.2024104 -0.64271169 0.9873111
outer
* pravi matricu tako što primjenjuje zadatu funkciju na više različitih vektora koji su joj proslijeđeni kao argumenti
outer(1:3, 1:10,"*")
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 1 2 3 4 5 6 7 8 9 10
## [2,] 2 4 6 8 10 12 14 16 18 20
## [3,] 3 6 9 12 15 18 21 24 27 30
outer(rep(1,3),rep(1,4),"-")
## [,1] [,2] [,3] [,4]
## [1,] 0 0 0 0
## [2,] 0 0 0 0
## [3,] 0 0 0 0
tapply
# Pravimo vektor tako da prvih 10 pacijenata (grupa A) ima puls u skladu sa normalnom (70,10/3) raspodjelom a za drugih 12 (grupa B) ima srednju vrijednost vecu za 5
pulse <- round(rnorm(22,70,10/3))+rep(c(0,5),c(10,12))
pulse
## [1] 69 69 70 73 73 74 66 71 76 72 78 70 74 76 77 73 76 74 73 73 75 73
group <- rep(c("A","B"),c(10,12))
tapply(pulse, group, length)
## A B
## 10 12
tapply(pulse, group, mean)
## A B
## 71.30000 74.33333
# ako zadamo simplify=F vraca listu
t<-tapply(pulse, group, sd)
t
## A B
## 2.907844 2.188122
t[[1]]
## [1] 2.907844
t[[2]]
## [1] 2.188122