Eksploracja danych (data mining) to proces odkrywania znaczacych nowych powi±zañ, wzorców i trendów poprzez przeszukiwanie du¿ych ilo¶ci danych zgromadzonych w bazach danych przy u¿yciu metod matematycznych. Tu zajmiemy siê problemem klasyfikacji, czyli jak na podstawie cech pewnych obiektów przypisaæ je do okre¶lonych klas (inaczej: jak dokonaæ podzia³u na poszczególne klasy), jak równie¿ kwesti± redukcji wymiaru. W ogólno¶ci mo¿emy wyró¿niæ dwa typu klasyfikacji: pod nadzorem (supervised learning) i bez nadzoru (unsupervised learning). W pierwszym przypadku musimy dysponowaæ pewnym zbiorem danych, w którym istniej± ju¿ dane skalsyfikowane (czyli posiadaj±ce przypisan± klasê, tzw. "próba ucz±ca"). Algorytm "uczy siê" cech zwi±zanych z obiektami, a nastêpnie korzystaj±c z takiej wiedzy, klasyfikuje nowe dane. W przypadku klasyfikacji bez nadzoru, rozdzia³ na klasy nastêpuje bez uprzedniego procesu uczenia.
Prawdopodobnie najprostsz± metod± klasyfikacji pod nadzorem jest LDA (linear discriminant analysis - liniowa analiza dyskryminacji). U jej podstaw le¿y za³o¿enie, ¿e rozk³ady zmiennych w ka¿dej klasie s± opisane wielowymiarowym rozk³adem Gaussa. Ponadto, macierze kowariancji wszystkich klas s± takie same. Mo¿na wtedy udowodniæ, ¿e klasy najlepiej rozdziela hiperp³aszczyzna (czyli prosta dla dwóch wymiarów). Zaczynamy od prostego przyk³adu dwóch klas, ka¿da z nich jest reprezntowana przez punkty wylosowane z dwuwymiarowego rozk³adu normalnego (funkcja mvrnorm(liczba_danych, wartosc_oczekiwana, macierz_kowariancji) z biblioteki MASS)
# PRZYK£AD 11.1
library(MASS)
library(ggplot2)
S <- matrix(c(3,0,0,3),2,2)
m1 <- c(2,2)
m2 <- c(-1,-1)
n1 <- 60
n2 <- 20
n <- n1 + n2
x1 <- mvrnorm(n1, m1, S)
x2 <- mvrnorm(n2, m2, S)
klasy <- c(rep("1", n1), rep("2", n2))
wsp1 <- c(x1[,1],x2[,1])
wsp2 <- c(x1[,2],x2[,2])
dataf <- data.frame(klasy, wsp1, wsp2)
theme_set(theme_bw())
ggplot(dataf) + geom_point(aes(x = wsp1, y = wsp2, color = klasy), shape = 19, size = 3)
W pakiecie R LDA jest realizowane przez funkcjê lda(), gdzie jako argumenty podajemy zale¿no¶æ pomiêdzy polami ramki danych (np. z ~ x + y). W efekcie otrzymamy warto¶ci prawdopodobieñstw a priori (czêsto¶ci klas), warto¶ci oczekiwane punktów nale¿±cych do klas a tak¿e kierunek, na który nale¿y rzutowaæ obserwacje tak, aby dokonaæ najlepszego rozdzielenia klas. Je¿eli warto¶æ tak dokonanego rzutowania danej (punktu) jest wiêksza od zera, przypisujemy go do klasy "1", w przeciwnym wypadku do klasy "2".
## Call:
## lda(klasy ~ wsp1 + wsp2, data = dataf)
##
## Prior probabilities of groups:
## 1 2
## 0.75 0.25
##
## Group means:
## wsp1 wsp2
## 1 2.253803 2.058642
## 2 -1.199486 -1.385207
##
## Coefficients of linear discriminants:
## LD1
## wsp1 -0.4044101
## wsp2 -0.4077440
proj <- as.matrix(dataf[,2:3]) %*% data.lda$scaling
dataf$proj <- proj[,1]
ggplot(dataf) + geom_point(aes(x = proj, y = 0, color = klasy), shape=21, size=5)
Oczywi¶cie "najlepsze" rozdzielenie klas nie oznacza, ¿e otrzymamy podzia³, w którym wszystkie punkty z klasy "1" faktycznie zostan± skalsyfikowane jako nale¿±ce do tej grupy - widaæ to na powy¿szym rysunku. Za pomoc± biblioteki klaR i zaimplementowanej w niej funkcji partimat() mo¿na otrzymaæ explicite prost± rozdzielaj±c± klasy, a tak¿e szybko zweryfikowaæ, które punkty zosta³y b³êdnie sklasyfikowane.
Kluczow± spraw± oprócz samej klasyfikacji jest jest skuteczno¶æ, czyli mówi±c inaczej, jak dobrze dany klasyfikator przewiduje przynale¿no¶æ do klas. W tym celu mo¿emy u¿yæ funkcji predict(), której argumentami s± klasyfikator wytrenowany na próbie ucz±cej oraz zbiór danych. Oczywi¶cie, w docelowych zastosowaniach skuteczno¶æ klasyfikatora jest sprawdzana na tzw. "próbie walidacyjnej", która powinna byæ rodzielna z prób± ucz±c±. Dla naszych potrzeb bêdziemy testowaæ klasyfikatory LDA i QDA na próbie ucz±cej, otrzymuj±c w ten sposób bardzo "optymistyczne" oszacowanie b³êdu. Interesowaæ nas bêdzie pole class zmiennej otrzymanej z dzia³ania funkcji predict, która prównamy za pomoc± polecenia table() z oryginalnymi klasami. Dla danych binarnych (tzn. dla dwóch klas) otrzymamy tzw. macierz pomy³ek (confusion matrix), której pola maj± nazwy jak na rysunku poni¿ej (numenklatura jest zwi±zana z testami medycznymi, maj±cymi na celu okre¶lenie nosicielstwa danej choroby).
sklasyfikowani jako ZDROWI | sklasyfikowani jako CHORZY | |
---|---|---|
faktycznie ZDROWI | TRUE NEGATIVE (TN) | FALSE POSITIVE (FP) |
faktycznie CHORZY | FALSE NEHATIVE (FN) | TRUE POSITIVE (TP) |
## [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [39] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 1 2 2 2 2 1 2 2 2 2 2
## [77] 1 2 2 2
## Levels: 1 2
## [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [39] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 1 2 2 2 2 1 2 2 2 2 2
## [77] 1 2 2 2
## Levels: 1 2
##
## 1 2
## 1 58 3
## 2 2 17
Aby w ³atwy sposób porównaæ poszczególne klasyfikatory (lub te¿ ich warianty) korzysta siê czêsto z nastêpuj±cych trzech wielko¶ci:
Pierwsza wielko¶æ mówi po prostu na ile dobrze algorytm przewiduje dowoln± klasê. Dwie kolejne s± prawdopodobieñstwami warunkowymi dobrej klasyfikacji, pod warunkiem, ¿e obiekt faktycznie nale¿y do danej klasy. Maj± one szczególne znaczenie, je¶li rozk³ad liczebno¶ci klas jest nierówny.
## Accuracy LDA: 0.938
## Recall LDA: 0.951
## Specifity LDA: 0.895
Jedn± z metod klasyfikacji bez nadzoru jest analiza skupieñ (klastrów), realizowana tu przez metodê k-¶rednich (k-means, w R funkcja kmeans()). Mamy do dyspozycji pewien zestaw danych, które chcieliby¶my pogrupowaæ tak, aby dane podobne do siebie znalazly siê w jednej klasie, natomiast ró¿ne w odrêbnych klasach. Podobieñstwo i ró¿nicê definiujemy poprzez odleg³o¶æ - w przypadku przez nas rozwa¿anym jest to odleg³o¶æ euklidesowa. Algorytm ma za zadanie tak rodzieliæ punkty, aby do jednego skupiska trafi³y te, które s± sobie najbli¿sze. Parametrem algorytmu jest liczba skupieñ, na która ma zostaæ podzielony zestaw danych.
# PRZYK£AD 11.6
sigma <- matrix(c(1,0,0,1),2,2)
mu1 <- c(4,4)
mu2 <- c(1,1)
mu3 <- c(4,-1)
kolory <- c(rep("orange", 30), rep("violet", 30), rep("green", 30))
clust1 <- mvrnorm(30, mu1, sigma)
clust2 <- mvrnorm(30, mu2, sigma)
clust3 <- mvrnorm(30, mu3, sigma)
all_points <- rbind(clust1, clust2, clust3)
xrange <- range(all_points[,1])
yrange <- range(all_points[,2])
xmin = xrange[1]; xmax = xrange[2]
ymin = yrange[1]; ymax = yrange[2]
par(mfrow = c(2,2))
plot(all_points, col=kolory, pch=19, cex=2, xlab="X", ylab="Y", xlim=c(xmin,xmax), ylim=c(ymin,ymax))
title("Klastry", cex.main=1.4, font=2)
cl <- kmeans(all_points, 3)
plot(all_points, col=kolory, pch=19, cex=2, xlab="X", ylab="Y", xlim=c(xmin,xmax), ylim=c(ymin,ymax))
text(all_points[,1], all_points[,2], cl$cluster, font=2)
title("Metoda 3-srednich", cex.main=1.4, font=2)
cl1 <- kmeans(all_points, 4)
plot(all_points, col=cl1$cluster, pch=19, cex=2, xlab="X", ylab="Y", xlim=c(xmin,xmax), ylim=c(ymin,ymax))
title("Metoda 4-srednich", cex.main=1.4, font=2)
cl2 <- kmeans(all_points, 5)
plot(all_points, col=cl2$cluster, pch=19, cex=2, xlab="X", ylab="Y", xlim=c(xmin,xmax), ylim=c(ymin,ymax))
title("Metoda 5-srednich", cex.main=1.4, font=2)
Jednym z zadañ eksploracji danych jest redukcja wymiaru, czyli okre¶lenie, które ze sk³adowych wektora obserwacji s± nieistotne lub te¿ jakie inne kombinacje sk³adowych mog± siê okazaæ przydatne do dalszej analizy. Standartow± metod± redukcji wymiaru jest analiza sk³adowych g³ównych (PCA - principal component analysis). Polega ona na znalezieniu nowego kierunku, który maksymalizuje wariancjê zrzutowanych na niego obserwacji. Nastêpnie szukamy kolejnego kierunku, równie¿ o jak najwiêkszej wariancji, tyle, ¿e ortogonalnego do poprzedniego etc. Okazuje siê, ¿e takie cechy odpowiadaj± wektorom w³asnym zwi±zanym z kolejnymi warto¶ciami w³asnymi (pocz±wszy od najwiêkszej). W poni¿szym przyk³adzie mamy do czynienia z "zaszumion±" relacj± y=x, alogrytm PCA (funkcja princomp()) wykrywa jako nowe kierunki wektory [1,1] i [-1,1] (pole loadings). Warto¶ci oryginalnych danych zrzutowane na nowe kierunki otrzymamy za pomoc± opcji scores, natomiast przeci±¿ona funkcja plot() prezentuje warto¶ci wariancji w kolejnych nowych kierunkach.
# PRZYK£AD 11.7
x <- seq(-5, 5, by=.1)
y <- x
eta <- runif(101, max = 1)
dzeta <- runif(101, max = 1)
x <- x + eta
y <- y + dzeta
par(mfrow = c(2,2))
plot(x, y, pch=19, xlab="Test 1", ylab="Test 3", font=2, font.lab=2, xlim=c(-5,5), ylim=c(-5,5))
abline(h=0, v=0, lwd=2, col="gray")
abline(0,1,lwd=2,col="red")
abline(0,-1,lwd=2,col="green")
text(4.5,-0.5,expression(x[1]),cex=2)
text(-0.5,4.5,expression(x[2]),cex=2)
text(4.7,4,expression(y[1]),cex=2, col="red")
text(-4.5,4,expression(y[2]),cex=2, col="green")
title("Dane", cex.main=1.4)
test <- data.frame(x, y)
test.pc <- princomp(~., cor=T, data=test)
plot(test.pc, main="")
title("Wariancja", cex.main=1.4)
plot(test.pc$scores, xlim=c(-2,2), ylim=c(-2,2), xlab="Skladowa 1", ylab="Składowa 2")
title("Skladowe", cex.main=1.4)