Статистички софтвер 1: Базе података

Стефан Малбашић, Математички факултет, Универзитет у Београду

Базе података (матрица података)

База података (енг. Data frame) је листа вектора исте дужине, тако да су елементи са истим индексом врсте повезани. Подсећа на матрицу у којој су у једној врсти подаци о једном елементу узорка (субјекту у експерименту).

  • Креирање базе података простим навођењем свих елемената расврстаних по одређеним критеријумима.
dataframe1 <- data.frame (
  Name = c("Juan", "Alcaraz", "Simantha"),
  Age = c(22, 15, 19),
  Vote = c(TRUE, FALSE, TRUE)
)
dataframe1
##       Name Age  Vote
## 1     Juan  22  TRUE
## 2  Alcaraz  15 FALSE
## 3 Simantha  19  TRUE
class(dataframe1)
## [1] "data.frame"
str(dataframe1)
## 'data.frame':    3 obs. of  3 variables:
##  $ Name: chr  "Juan" "Alcaraz" "Simantha"
##  $ Age : num  22 15 19
##  $ Vote: logi  TRUE FALSE TRUE
  • Креирање базе података из постојећих података, нпр. спајањем два вектора.
brojevi <- 1:12
slova <- letters[1:12]
d <- data.frame(brojevi, slova)
d
##    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
  • Приступање елементима преко $.
d$brojevi
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12
d$slova
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l"
  • Приликом креирања базе колонама можемо доделити имена различита од ових, а можемо их и накнадно изменити.
d <- data.frame(br = brojevi, sl = slova)
names(d) <- c("kol1", "kol2")

Функција attach

Функција attach примењена на базу података омогућава нам да приступамо елементима без навођења имена базе. За поништавање функције attach користи се функција detach.

attach(d)
kol1
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12
kol2
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l"
detach(d)

Индексирање база података

Из базе података можемо извући податке преко $ или преко матричне репрезентације.

d[1,2] # ili d$kol2[1]
## [1] "a"
d[1,] # vraca prvu vrstu
##   kol1 kol2
## 1    1    a
d[,1] # vraca prvu kolonu
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12
d[1] # vraca data frame koji sadzi prvu kolonu d
##    kol1
## 1     1
## 2     2
## 3     3
## 4     4
## 5     5
## 6     6
## 7     7
## 8     8
## 9     9
## 10   10
## 11   11
## 12   12
  • Условна селекција у бази података
d[d$kol1 < 10,] # Baza podatakа koja sadrzi vrednost <10 u prvoj koloni
##   kol1 kol2
## 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
d[d$kol1 < 10 & d$kol1 %% 2 == 0,]# + parne vrednosti
##   kol1 kol2
## 2    2    b
## 4    4    d
## 6    6    f
## 8    8    h

Груписање база података

  • Вертикално груписање база података помоћу функције rbind.
dataframe1 <- data.frame (
  Name = c("Juan", "Alcaraz"),
  Age = c(22, 15)
)

dataframe2 <- data.frame (
  Name = c("Yiruma", "Bach"),
  Age = c(46, 89)
)

updated <- rbind(dataframe1, dataframe2)
updated
##      Name Age
## 1    Juan  22
## 2 Alcaraz  15
## 3  Yiruma  46
## 4    Bach  89
  • Хоризонтално груписање база података помоћу функције cbind.
dataframe1 <- data.frame (
  Name = c("Juan", "Alcaraz"),
  Age = c(22, 15)
)

dataframe2 <- data.frame (
  Hobby = c("Tennis", "Piano")
)

updated <- cbind(dataframe1, dataframe2)
updated
##      Name Age  Hobby
## 1    Juan  22 Tennis
## 2 Alcaraz  15  Piano

Додавање и брисање вектора у базу података

У R-у постоје уграђене базе, као на пример sleep.

data(sleep) # ucitava bazu sleep u tekuci session u R-u
sleep # ispisuje
##    extra group ID
## 1    0.7     1  1
## 2   -1.6     1  2
## 3   -0.2     1  3
## 4   -1.2     1  4
## 5   -0.1     1  5
## 6    3.4     1  6
## 7    3.7     1  7
## 8    0.8     1  8
## 9    0.0     1  9
## 10   2.0     1 10
## 11   1.9     2  1
## 12   0.8     2  2
## 13   1.1     2  3
## 14   0.1     2  4
## 15  -0.1     2  5
## 16   4.4     2  6
## 17   5.5     2  7
## 18   1.6     2  8
## 19   4.6     2  9
## 20   3.4     2 10
cbind(sleep, seq(20,1,-1)) # dodajemo kolonu brojeva 20,19,18,...1
##    extra group ID seq(20, 1, -1)
## 1    0.7     1  1             20
## 2   -1.6     1  2             19
## 3   -0.2     1  3             18
## 4   -1.2     1  4             17
## 5   -0.1     1  5             16
## 6    3.4     1  6             15
## 7    3.7     1  7             14
## 8    0.8     1  8             13
## 9    0.0     1  9             12
## 10   2.0     1 10             11
## 11   1.9     2  1             10
## 12   0.8     2  2              9
## 13   1.1     2  3              8
## 14   0.1     2  4              7
## 15  -0.1     2  5              6
## 16   4.4     2  6              5
## 17   5.5     2  7              4
## 18   1.6     2  8              3
## 19   4.6     2  9              2
## 20   3.4     2 10              1
rbind(sleep, c(2.0,1,1)) # isto tako mozemo dodati i vrstu
##    extra group ID
## 1    0.7     1  1
## 2   -1.6     1  2
## 3   -0.2     1  3
## 4   -1.2     1  4
## 5   -0.1     1  5
## 6    3.4     1  6
## 7    3.7     1  7
## 8    0.8     1  8
## 9    0.0     1  9
## 10   2.0     1 10
## 11   1.9     2  1
## 12   0.8     2  2
## 13   1.1     2  3
## 14   0.1     2  4
## 15  -0.1     2  5
## 16   4.4     2  6
## 17   5.5     2  7
## 18   1.6     2  8
## 19   4.6     2  9
## 20   3.4     2 10
## 21   2.0     1  1
sleep$ID <- NULL # brisanje kolone ID iz baze
sleep
##    extra group
## 1    0.7     1
## 2   -1.6     1
## 3   -0.2     1
## 4   -1.2     1
## 5   -0.1     1
## 6    3.4     1
## 7    3.7     1
## 8    0.8     1
## 9    0.0     1
## 10   2.0     1
## 11   1.9     2
## 12   0.8     2
## 13   1.1     2
## 14   0.1     2
## 15  -0.1     2
## 16   4.4     2
## 17   5.5     2
## 18   1.6     2
## 19   4.6     2
## 20   3.4     2
  • Ако хоћемо да трансформишемо неку од колона користимо функцију transform.
transform(sleep, abs.extra=abs(extra)) # u novoj koloni abs.extra da nam ispisuje aps. vrednosti kolone extra
##    extra group abs.extra
## 1    0.7     1       0.7
## 2   -1.6     1       1.6
## 3   -0.2     1       0.2
## 4   -1.2     1       1.2
## 5   -0.1     1       0.1
## 6    3.4     1       3.4
## 7    3.7     1       3.7
## 8    0.8     1       0.8
## 9    0.0     1       0.0
## 10   2.0     1       2.0
## 11   1.9     2       1.9
## 12   0.8     2       0.8
## 13   1.1     2       1.1
## 14   0.1     2       0.1
## 15  -0.1     2       0.1
## 16   4.4     2       4.4
## 17   5.5     2       5.5
## 18   1.6     2       1.6
## 19   4.6     2       4.6
## 20   3.4     2       3.4
  • За приказ основних дескриптивних статистика о бази користимо функцију summary.
data(InsectSprays) # jos jedna ugradjena baza - InsectSprays
InsectSprays 
##    count spray
## 1     10     A
## 2      7     A
## 3     20     A
## 4     14     A
## 5     14     A
## 6     12     A
## 7     10     A
## 8     23     A
## 9     17     A
## 10    20     A
## 11    14     A
## 12    13     A
## 13    11     B
## 14    17     B
## 15    21     B
## 16    11     B
## 17    16     B
## 18    14     B
## 19    17     B
## 20    17     B
## 21    19     B
## 22    21     B
## 23     7     B
## 24    13     B
## 25     0     C
## 26     1     C
## 27     7     C
## 28     2     C
## 29     3     C
## 30     1     C
## 31     2     C
## 32     1     C
## 33     3     C
## 34     0     C
## 35     1     C
## 36     4     C
## 37     3     D
## 38     5     D
## 39    12     D
## 40     6     D
## 41     4     D
## 42     3     D
## 43     5     D
## 44     5     D
## 45     5     D
## 46     5     D
## 47     2     D
## 48     4     D
## 49     3     E
## 50     5     E
## 51     3     E
## 52     5     E
## 53     3     E
## 54     6     E
## 55     1     E
## 56     1     E
## 57     3     E
## 58     2     E
## 59     6     E
## 60     4     E
## 61    11     F
## 62     9     F
## 63    15     F
## 64    22     F
## 65    15     F
## 66    16     F
## 67    13     F
## 68    10     F
## 69    26     F
## 70    26     F
## 71    24     F
## 72    13     F
summary(InsectSprays)
##      count       spray 
##  Min.   : 0.00   A:12  
##  1st Qu.: 3.00   B:12  
##  Median : 7.00   C:12  
##  Mean   : 9.50   D:12  
##  3rd Qu.:14.25   E:12  
##  Max.   :26.00   F:12
  • Испис првих 6 редова (обично се користи за веће базе)
head(InsectSprays) 
##   count spray
## 1    10     A
## 2     7     A
## 3    20     A
## 4    14     A
## 5    14     A
## 6    12     A

Учитавање података

  • Учитавање табеле као базе податка: read.table("putanja/ime_fajla.txt", header = T), где header = T значи да прву врсту не посматра као податке, већ као заглавље табеле/базе података.

Прво правимо текстуални фајл са табелом. На пример, копирамо део базе cars у неки фајл. Треба водити рачуна да working directory буде локација где је фајл или у позиву функције навести целу путању.

cars
##    speed dist
## 1      4    2
## 2      4   10
## 3      7    4
## 4      7   22
## 5      8   16
## 6      9   10
## 7     10   18
## 8     10   26
## 9     10   34
## 10    11   17
## 11    11   28
## 12    12   14
## 13    12   20
## 14    12   24
## 15    12   28
## 16    13   26
## 17    13   34
## 18    13   34
## 19    13   46
## 20    14   26
## 21    14   36
## 22    14   60
## 23    14   80
## 24    15   20
## 25    15   26
## 26    15   54
## 27    16   32
## 28    16   40
## 29    17   32
## 30    17   40
## 31    17   50
## 32    18   42
## 33    18   56
## 34    18   76
## 35    18   84
## 36    19   36
## 37    19   46
## 38    19   68
## 39    20   32
## 40    20   48
## 41    20   52
## 42    20   56
## 43    20   64
## 44    22   66
## 45    23   54
## 46    24   70
## 47    24   92
## 48    24   93
## 49    24  120
## 50    25   85
baza <- read.table("cars.txt", header = T)
head(baza) 
##   speed dist
## 1     4    2
## 2     4   10
## 3     7    4
## 4     7   22
## 5     8   16
## 6     9   10

Функција read.table подразумева да је сепаратор празно поље. Ако хоћемо да сепаратор буде зарез користимо функцију read.csv, а ако хоћемо да сепаратор буде TAB, тада користимо функцију read.delim.

read.csv("cars_zarezi.txt", header = T)
##     X speed dist
## 1   1     4    2
## 2   2     4   10
## 3   3     7    4
## 4   4     7   22
## 5   5     8   16
## 6   6     9   10
## 7   7    10   18
## 8   8    10   26
## 9   9    10   34
## 10 10    11   17
## 11 11    11   28
## 12 12    12   14
## 13 13    12   20
## 14 14    12   24
## 15 15    12   28
  • Писање табеле/базе података у фајл: write.table(data, fajl, sep = "\t"), где је data`` типаdata.frameили матрица. Ако није, аутоматски ће се конвертовати. Параметарsep``` означава како ће бити раздвојени подаци у оквиру врсте у новом фајлу.
write.table(baza, "fajl1.txt", sep = "\t")
write.table(baza, "fajl2.txt", sep = "   SEPARATOR   ")
  • Функција scan

Користи се за учтавање података: scan(file, what, nmax, sep), где је what тип података, nmax је максималан број карактера који хоћемо да учитамо, а sep је сепаратор.

s <- scan("C:/Users/Stefan Malbasic/Desktop/cars.txt", what = character(), nmax=30) # skeniracemo tekstualni fajl cars.txt
is.vector(s) # dobija se vektor sa skeniranim podacima
## [1] TRUE
s
##  [1] "speed" "dist"  "1"     "4"     "2"     "2"     "4"     "10"    "3"    
## [10] "7"     "4"     "4"     "7"     "22"    "5"     "8"     "16"    "6"    
## [19] "9"     "10"    "7"     "10"    "18"    "8"     "10"    "26"    "9"    
## [28] "10"    "34"    "10"

Ако желимо да не учитава реч по реч, него ред по ред, користимо функцију readLines.

readLines("C:/Users/Stefan Malbasic/Desktop/cars.txt")
##  [1] "   speed dist" "1      4    2" "2      4   10" "3      7    4"
##  [5] "4      7   22" "5      8   16" "6      9   10" "7     10   18"
##  [9] "8     10   26" "9     10   34" "10    11   17" "11    11   28"
## [13] "12    12   14" "13    12   20" "14    12   24" "15    12   28"

Генерално: write(podaci, "fajl", ncolumns = ..., append = T/F, sep = " ")

x <- 1:120
write(x, "fajl.txt", sep=" ", ncolumns = 12)

Пакети

Пакет је колекција R- функција, које се односе на један појам, повезани су. На пример, пакет за графику, пакет функција и база за линеарну регресију, пакет узорака из неког истраживања … Са R-ом долази сет стандардних пакета, а остали се могу преузети са http://cran.r-project.org/.

Поступак за инсталирање пакета је install.packages("ime_paketa"), пакет се инсталира директно са интернета или скинути пакет у zip формату са сајта, па tools--install packages---.

Када је пакет инсталиран учитава се са library(ime_paketa) и тада су нам на располагању његове функције, базе података и остало.

На пример, пакет PASWR (paket probability and statistics with R) садржи корисне функције и базе података за вероватноћу и статистику.

# install.packages("PASWR")
library(PASWR) 
data(Aggression) # kada je paket ucitan, bazu ucitavamo sa data(BAZA)
Aggression
##    violence noviolence
## 1        35         26
## 2        30         28
## 3        15         16
## 4        20         16
## 5        25         16
## 6        14         16
## 7        37         32
## 8        26         24
## 9        36         30
## 10       40         33
## 11       35         20
## 12       20         19
## 13       16         19
## 14       21         10
## 15       17          7
## 16       15         17

Ако нећемо да учитамо цео пакет, можемо учитати само неку од база без претходног позива library.

data(Aggression, package = "PASWR")

У овом пакету има и корисних статистичких тестова. На пример, тест који проверава хипотезу о средњој вредности узорка из нормалне расподеле (\(H_0\) је да је средња вредност 0).

x <- rnorm(100)
z.test(x, sigma.x = 1) # navodimo uzorak, kao i pretpostavljenu standardnu devijaciju raspodele 
## 
##  One Sample z-test
## 
## data:  x
## z = -0.2644, p-value = 0.7915
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##  -0.2224360  0.1695568
## sample estimates:
##   mean of x 
## -0.02643965
  • Када завршавамо са радом
detach("package:PASWR")

Уграђени пакети у R``-у:base, datasets, utils, graphics```, и многи други.

  • За приказ неког пакета
help(datasets)
library(help = "datasets")
help("airquality") # odavde vidimo imena baza, jedna od njih sadrzi podatke o vazduhu iz Njujorka
data(airquality)
head(airquality)
summary(airquality)
  • Промена типа података
#as.ime_tipa(x)
x <- rnorm(5)
as.matrix(x)
##             [,1]
## [1,]  0.57422261
## [2,]  1.48932477
## [3,] -0.79125084
## [4,]  2.12861883
## [5,] -0.06483478
as.character(x)
## [1] "0.574222611369814"   "1.48932477490835"    "-0.791250836591693" 
## [4] "2.12861882728485"    "-0.0648347809175958"
z <- as.character(x)
is.character(z)
## [1] TRUE

Може да конвертује бројеве у одговарајуће карактере, али обрнуто НЕ може!

z <- c("wef",'wdf')
as.numeric(z)
## Warning: NAs introduced by coercion
## [1] NA NA

Могуће је конвертовати и између сложенијих типова

as.list(x)
## [[1]]
## [1] 0.5742226
## 
## [[2]]
## [1] 1.489325
## 
## [[3]]
## [1] -0.7912508
## 
## [[4]]
## [1] 2.128619
## 
## [[5]]
## [1] -0.06483478
as.data.frame(x)
##             x
## 1  0.57422261
## 2  1.48932477
## 3 -0.79125084
## 4  2.12861883
## 5 -0.06483478
m <- matrix(1:10, ncol = 5)
as.list(m)
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 2
## 
## [[3]]
## [1] 3
## 
## [[4]]
## [1] 4
## 
## [[5]]
## [1] 5
## 
## [[6]]
## [1] 6
## 
## [[7]]
## [1] 7
## 
## [[8]]
## [1] 8
## 
## [[9]]
## [1] 9
## 
## [[10]]
## [1] 10
lista <- list("a", "b", "c")
as.matrix(lista) 
##      [,1]
## [1,] "a" 
## [2,] "b" 
## [3,] "c"
lista <- list(matrix(1:4, ncol = 2), c("a", "v"), 1) # iz liste u matricu ako su tipovi elemenata liste razliciti
as.matrix(lista) # dobijemo matricu ali su podaci prikazani na drugaciji nacin
##      [,1]       
## [1,] integer,4  
## [2,] character,2
## [3,] 1

Графичко приказивање података

  • Најједноставнији график
x <- seq(2, 16, 1)
y <- c(5, 6, 5, 9, 3, 11, 6, 15, 19, 5, 7, 14, 8, 12, 1)
plot(x,y)

Додатна подешавања при цртању графика

  • главни и споредни наслов, називи оса: main, sub, xlab, ylab

  • дужину оса можемо и експлицитно навести параметрима xlim и ylim

  • додавање тачака на график points

  • додавање текста на график text

  • линије и текст се могу додати у оквиру позива функцијеplot или их можемо накнадно додати

  • За убацивање линије на постојећи график користи се функција abline која црта график функције \(y=a+bx\).

  • Ако је агрумент \(h=...\) или \(v=...\), црта хоризонталну, односно вертикалну линију са датом координатом.

plot(x, y, main = "Main title", sub = "Subtitle", xlab = "x-osa", ylab = "y-osa")

plot(x, y, xlim = c(0, 30), ylim = c(0, 30))
points(25, 25) # zadajemo koordinate tacke koju dodajemo
text(3, 3, "ubaceni tekst") # zadajemo koordinate i tekst koji se ispisuje 
abline(0, 1) # dobili smo grafik f-je y=x
abline(h = 20)
abline(v = 20) # isto kao da smo napisali i abline(h = 20, v = 20)

Ако хоћемо да график буде веома сложен, често је добра идеја да на почетк изоставимо све елементе и после их појединачно додајемо.

plot(x, y, type = "n", xlab = "", ylab = "", axes = F) # Ne crta ose, ne obelezava ih, type="n" znaci da se tacke izostavljaju
points(x, y) # dodaje sve tacke na grafik
axis(1) # dodaje prvu osu
axis(2, at = seq(0, 20, 5)) # dodaje drugu osu, ali je obelezava na mestima naznacenim vektorom seq(..)
box() # dodaje okvir
title(main = "Glavni naslov", sub = "Podnaslov", xlab = "x-osa", ylab = "y-osa") 

  • График функције \(f(x)=x^3\)
x <- seq(-2, 2, 0.01)
plot(x, x^3, type = "l", main = "y=x^3", xlab = "x-osa", ylab = "y-osa", col = "blue")

curve(x^3, from = -2, to = 2, col = "blue", main = "y=x^3", xlab = "x-osa", ylab = "y-osa")

  • Функција par се користи за напреднија подешавања свих графичких параметара. Нека од ових подешавања могу и преко plot функције. Разлика је што их функција par трајно подешава, док се не врате на старо. Неке од опција су боја, дељина линије, тип линије, подела оса, величина графика, подела на више површина, итд.
par(col = "blue", bg = "yellow") # menjanje boje grafika
y <- x^3
plot(x, y)

par(col = "black", bg="white")

Дељење платна за цртање

Параметар mfrow означава колико се графика одједном може налазити на платну. То је вектор димензијa

par(mfrow = c(1,2)) # platno se deli na jednu vrstu i dve kolone (dva grafika jedan pored drugog)
plot(x, y)
plot(y, x)

# vracamo sve na default
par(mfrow = c(1, 1), col="black", bg="white")
plot(x, y)

  • Комбиновање више графика један преко другог
x1 <- rnorm(20) #  grafici uzorka normalne raspodele
par(mfrow = c(2,2)) 
plot(x1, type = "p", main = "points", ylab = "y-osa", xlab = "x-osa", col = "red")
plot(x1, type = "l", main = "lines", ylab = "y-osa", xlab = "x-osa", col = "orange")
plot(x1, type = "b", main = "both", ylab = "y-osa", xlab = "x-osa", col = "blue")
plot(x1, type = "o", main = "both overplot", ylab = "y-osa", xlab = "x-osa", col = "green")

Хистограм и функција густине

data(faithful) 
attach(faithful)
hist(eruptions, seq(1.6, 5.2, 0.2), prob = T, col = "orange")
lines(density(eruptions))

BOXPLOT

data(InsectSprays)
attach(InsectSprays)
boxplot(count ~ spray, data = InsectSprays, col = "lightgray")
means <- tapply(count, spray, mean)
points(means, col = "red", pch = 18)

boxplot(count ~ spray, data = InsectSprays, horizontal = T, col = "lightblue")

BARPLOT

VADeaths
##       Rural Male Rural Female Urban Male Urban Female
## 50-54       11.7          8.7       15.4          8.4
## 55-59       18.1         11.7       24.3         13.6
## 60-64       26.9         20.3       37.0         19.3
## 65-69       41.0         30.9       54.6         35.1
## 70-74       66.0         54.3       71.1         50.0
barplot(VADeaths)

barplot(t(VADeaths), col = gray(c(0.25, 0.5, 0.75, 1)))

barplot(t(VADeaths), beside = TRUE)

DOTCHART - тачкасти дијаграм

dotchart(VADeaths, xlab = "Broj umrlih na 1000 ljudi", main = "Stopa smrtnosti u Virdziniji")

PIECHART - питице

par(mfrow = c(2,2))
pie.sales <- c(0.12, 0.3, 0.26, 0.16, 0.04, 0.12)
names(pie.sales) <- c("Blueberry", "Cherry", "Apple",
                      "Boston Cream", "Other", "Vanilla")
pie(pie.sales, main = "Obicna pitica")
pie(pie.sales, col = gray(seq(0.4, 0.9, length = 6)), clockwise = TRUE, main = "Nijanse sive")
pie(pie.sales, col = rainbow(6), clockwise = TRUE, main = "Boje duge")
library(plotrix)
pie3D(pie.sales, main = "3D pitica")

Пакет lattice

# install.packages("lattice")
library(lattice) 
data(mtcars)
attach(mtcars)
# kreiramo faktore 
gear.f <- factor(gear, levels = c(3, 4, 5), labels = c("3gears","4gears","5gears")) 
cyl.f <- factor(cyl, levels = c(4, 6, 8), labels = c("4cyl", "6cyl", "8cyl")) 
# gustina
densityplot(~mpg, main = "Density Plot", xlab = "Miles per Gallon")

# gustina po faktorima
densityplot(~mpg|cyl.f, main = "Density Plot by Number of Cylinders", xlab = "Miles per Gallon")

# gustina po faktorima 
densityplot(~mpg|cyl.f, main = "Density Plot by Numer of Cylinders", xlab = "Miles per Gallon", layout = c(1, 3))