R-tahák

Z ωικι.matfyz.cz
Přejít na: navigace, hledání

Vytvořeno na základě zápisků ze cvičení k Úvodu do strojového učení, ZS 2008/9 -- Tuetschek 16:20, 24 Jan 2009 (CET)

Základní příkazy

Nápověda:

  • > ?func  # nápověda pro funkci func

Potlačení chyb:

  • try( ... )  # nezastaví program, když se stane chyba
  • Debugging: Debugging in R

Objekty, paměť

Úplně všechno v R je objekt.

  • summary(obj)   # Použít pro zjištění něčeho o libovolném objektu
  • str(obr)  # zjištění typu objektu (jiná informace
  • ls()  # seznam všech objektů
  • ls.str()  # zavolá str() na všechny existující objekty
  • rm(object)  # smaže objekt object
    • rm(list=ls())  # smaže úplně všechny objekty

Zavřu-li nějaký příkaz do závorek, vytiskne se jeho výsledek na výstup.

Počty

Ovládání:

  • ls  # použitím jména funkce bez závorek se vypíše její zdroják, nezavolá se
  • m <- 15  # přiřazovací příkaz, nepoužívat =, je to obsolete!
  • a <- c(10,12, 16, pi)  # vytvoření vektoru pomocí funkce c() (konkatenace)
  • b <- (1:8)*3  # sekvence čísel, může jít i pozpátku: c <- (8:1)/2 - 3
  • R nemá ternární operátor (?), operátor ? je nápověda
    • Místo ternárního operátoru se dá použít x <- if (condition){ value1 }else{ value2 };

Funkce s jedním argumentem, do kterého dám c(..) mi vrátí c(..) s výsledky pro každý člen původního vektoru. Všechny početní operace jsou totiž definovány na vektorech. S vektory se dá počítat všelijak. Dát ale pozor na sčítání vektorů různé délky, R si kratší z nich zacyklí a nevydá žádný warning.

  • w <- x/2 + 1  # a x je vektor
  • y <- x + w * rnorm(x)
  • predict == test# je vektor hodnot TRUE a FALSE, podle toho, jestli se shodují hodnoty na stejných pozicích

Vnější vztahy

Pracovní adresář (pro čtení, zápis souborů) -- vždycky je nějaký nastaven:

  • getwd()  # zjištění
  • setwd()  # nastavení

Volání příkazů operačního systému:

  • system("ls")

R-balíčky = knihovny: soubory funkcí, struktura: použít v Unixu locate, pak 00Index.html. Základní knihovna se jmenuje base.

  • library(MASS)  # nahrání knihovny MASS do paměti, umožní používat funkce v ní obsažené
  • installed.packages()  # seznam všech nainstalovaných balíčků, co můžu nahrát do paměti
  • available.packages()  # seznam všech balíčků, které se dají stáhnout
  • download.packages(pkgs="e1071", destdir=getwd())  # stažení balíčku e1071 do aktuálního adresáře
    • Stáhne se pod Windows ve formátu ZIP, pod Unixem v TGZ
  • install.packages(pkgs="e1071_1.5-18.tgz", lib.loc=getwd(), repos = NULL)  # instalace balíčku do aktuálního adresáře (nebo adresáře libloc; v pkgs je celá cesta k nim), repos = NULL znamená, že se instalace provádí offline, šlo by instalovat i přímo z CRAN mirroru.
  • library(e1071,lib.loc=getwd())  # nahrání separátně nainstalované knihovny z nějakého adresáře

Před uzavřením R je možné uložit všechny objekty v paměti, ale lepší je to nedělat, ať mám opakovatelné pokusy.

Funkce

# definice funkce, v názvech se slova zpravidla oddělují tečkou
foo.bar <- function( x, y=2 ) # můžu dát iniciální hodnoty parametrů
{
    # komentář
    return ( x ^ y ) # návratová hodnota: závorky nutné!
}

Přímá editace funkce z prostředí R se provádí příkazem edit(func).

Statistika

Generátor náhodných čísel -- iniciální nastavení:

  • set.seed(123)  # pozor, některé hodnoty jsou vhodnější než jiné

Distribuce pravděpodobnosti

Pro každou distribuci je v R několik funkcí, které se starají o generování apod., mají spec. prefixy (první znak názvu):

  • r  # generování náhodných vzorků, je tu opravdu dobrý generátor náh. čísel (tedy používat tohle!)
    • První parametr je číslo (požadovaný počet vzorků), nebo vektor (počet vzorků = délka vektoru)
  • d  # funkce hustoty pravděpodobnosti (pro každý bod mám "něco jako" pravděpodobnost, suma přes $ \mathbb{R} $ dává 1)
  • p  # kumulativní distribuční funkce
  • q  # kvantilová distribuční funkce

Distribuce

  • -norm  # normální rozdělení
  • -unif  # rovnoměrné rozdělení
  • -binom  # binomické rozdělení
  • -multinom  # multinomické rozdělení

Testování parametrů rozdělení pro náhodný výběr (v proměnné x)

  • mean(x)  # střední hodnota
  • var(x)  # rozptyl

Regrese

Vytvoření modelu lineární regrese:

  • fm <- lm( y ~ x, data= ... )  # na základě data framu, který má sloupce y a x, vytvořím model lin. regrese, kde y závisí na x
    • Proměnná, která je závislá, musí být spojitá, ostatní se převedou na spojité, pokud jsou kategoriální
  • fm <- lm( y ~ ., data= ... )  # model, kde y závisí na všech ostatních sloupcích data framu

Predikce modelu a testování:

  • trainedModel <- lm(y ~ ., data=train)  # vytvoření modelu
  • prediction <- predict.lm(trainedModel, data=test)  # vytvoření predikce, dá se pak porovnávat s výsledky testování

Lokální polynomická regrese:

  • model <- loess(y ~ x, data=train)  # vytvoření modelu (má spoustu dalších parametrů)
  • predict  # predikce nemá vlastní funkci, používá se standardní pro všechno

Operace s daty

I/O

Načtení dat ze souboru:

  • read.csv(filename, header=TRUE, sep=",")  # načte data z CSV souboru, sep je oddělovač polí, pokud je header=TRUE, první řádek se bere jako hlavička

Převody datových typů

Vytváření jednoho datového typu z jiného:

  • c()  # konkatenace vektorů / prvků do jednoho vektoru
  • dummy <- data.frame(x,y,w)  # vytvoření data framu, vektory x,y,w budou jeho sloupce.
    • Jedná se o kopírování, původní proměnné můžu zahodit
  • matrix(data, cols, rows)  # vytvoření matice o dané šířce a výšce z vektoru
    • Matici vytvoří i když délka dat není rovna cols*rows, ale vydá warning
  • rbind(col1, col2, col3)  # vytvoří matici z dat, která budou jejími sloupci
  • cbind(row1, row2, row3)  # totéž s řádky
  • l <- list(..); vector <- unlist(l);  # vytvoření seznamu z vektoru a převod zpět (seznam může obsahovat vektory a seznamy, vektor je jednorozměrný)
  • factor(data, levels=c(...), labels=c(...))  # vytvoření faktoru = enumu (levels -- udávám přípustné hodnoty, všechny další jsou hozeny na <NA>; labels -- udaným úrovním můžu dát jména, pokud chci).
    • levels(my.factor)  # ukáže jména všech hodnot faktoru
    • levels(my.factor) <- c("a","b","c")  # do jmen hodnot faktoru lze i zapisovat

Informace o matici nebo data frame:

  • ncol(dummy); length(dummy[1,])  # počet sloupců
  • nrow(dummy)  # počet řádků

Explicitní konverze:

  • as.-matrix, data.frame, vector, factor  # podle toho, na co chci konvertovat

Dělení dat

Výběr dat z matice nebo data frame:

  • dummy[1,3]  # 3. sloupec, 1. řádek (1 element)
  • dummy[1,]  # první řádek (výsledek je jednořádkový data frame)
  • dummy[,-1]  # vše až na první sloupec (výsledek je data frame)
  • dummy[,1]  # první sloupec (výsledek je vektor)
  • indices <- c(1,3,5,7); dummy[indices,];  # vybrání jen některých řádků (můžu např. použít funkci sample), můžu i přímo zadat vektor
  • dummy[[column]]  # vybere z data framu sloupec, který má název rovný hodnotě proměnné column (název se dá získat např. pomocí names)

Vytváření dat

Generování vzorků:

  • x <- seq(start, finish, step)  # vytvoří vektor, který obsahuje čísla od start do finish s krokem step. Zavolám-li seq(1,20,5), dostanu čísla 1 6 11 16.
  • sample(x, length, ...)  # vybírání náhodných vzorků -- z vektoru x vyberu length vzorků
    • defaultní hodnota length je délka x, tedy vytváří náhodnou permutaci daného vektoru
    • je-li x ne vektor, ale číslo, bere se vektor čísel od 1 do x.
  • indices <- sample(39)[1:25]; train <- data[indices,];  # vybrání náhodné podmnožiny, aby se zabránilo hierarchii v datech

Použití funkce na celý vektor / matici:

  • apply(dummy, 1, mean)  # použití funkce mean (jde definovat i vlastní bezejmenná funkce a přímo napsat do parametru) na řádky (prostř. hodnota = 1) / sloupce (2) data framu
  • lapply(vector, func)  # použití funkce na všechny prvky vektoru, vrací vždy seznam
  • sapply(vector, func)  # to samé, ale když dostane vektor, vrátí vektor

Převody charakteru dat

Data atributů, se kterými pracuji, jsou buď spojitá (continuous) nebo kategoriální (categorical, disktrétní). Některé modely, algoritmy atd. pracují jen s jedním typem.

Převod kategoriálních atributů na spojité: mám-li např. atribut color se 3 hodnotami: red, blue, black, potom vytvořím 3 atributy: f-blue, f-black, f-red a dávám jim hodnoty 0 a 1. To, že je vždy 1 jen jeden, vůbec nevadí - sice to enormně zvětšuje dimenzi (počet atributů), ale to v praxi často vůbec nevadí (jen pozor na Curse of dimensionality).

Převod spojitých na kategoriální: např. vyrobím kategoriální parametr se 4 hodnotami excellent, good, average, bad ~ např. 4, 3, 2, 1 -- ale musím si pořád pamatovat, že to je jenom kódování a např. průměr nebo medián nemá moc smysl (v praxi ale často funguje). Jak přesně rozdělit data je otázka praxe, musíme o datech něco vědět, aby dělení mělo smysl. Funkce na dělení:

  • categ <- cut(continuous.data, c(-Inf,5,20,Inf), labels=c("low", "mid", "high") )  # pozor, velikost vektoru s hranicemi musí být o 1 větší než velikost vektoru s názvy jednotlivých levelů
    • Pokud nedodám názvy levelů, vyrobí si R pochybné svoje s popisem intervalů, ze kterých hodnoty pocházejí
  • quantile(continuous.data, c(0,0.2,0.4,0.6,0.8,1))  # Pro dělení podle pravděpodobností padnutí do nějakého intervalu, defaultní je c(0,0.25,0.50,0.75,1).

Některé modely předpokládají určité vlastnosti dat (např. standardní normální rozdělení apod.). Měly by se upravit trénovací data a podle nich upravit stejně i testovací:

  • x <- scale(data, center=TRUE, scale=TRUE)  # vycentruje všechny sloupce matice kolem průměru a vyškáluje: vydělí jejich kvadratickým průměrem (použít pro trénovací data)
    • pokud jsou center a scale čísla, použijí se přímo na odečtení / vydělení (použít pro testovací data)
    • pokud jsou hodnoty FALSE necentruje se a/nebo se neškáluje
  • attr(x, "scaled:center")  # jediný možný přístup k center a scale spočítaných na trénovacích datech, která se pak mohou použít pro testovací data

Výpisy

  • paste("a", "b", "c", sep="")  # slepování stringů
  • gettextf("Insert a string here:%s", string.data)  # vkládání stringů do nějakého vzorce
    • %s je string, %d integer (%x hexadecimálně), %f je double (%e v plovoucí čárce a %g se rozhoduje, jestli použít normální nebo plovoucí čárku), procento se píše %%.

Grafy, kreslení

Histogram:

  • truehist(x, nbins=25)  # nbins určuje počet "přihrádek"

Graf:

  • plot(x, y1); lines(x, y2); ...  # první a další proměnná (čára) do grafu
    • parametr type je informace o druhu čar / bodů: b bod a čára, l jen čára, p jen body
    • u libovolných čar lty je druh (plná, čárkovaná, tečkovaná, čerchovaná ...), col je barva, pch je písmeno, které se použije jako bod, pokud type je nastaveno na b.
    • nastavení min. a max. hodnoty u obou os: xlim=c(min,max), ylim

Grafické zobrazení distribuce:

  • dd <- kde2d(x,y)  # kde2d je z knihovny MASS, 2-rozměrná funkce hustoty
  • contour(dd)  # dvourozměrná hustota ve "vrstevnicích"
  • image(dd)  # barevný obrázek téhož

Výstup do souboru:

  • png("output.png"); plot(x); dev.off();  # otevře PNG, zapíše požadovaný graf a zavře
  • pdf("output.pdf");  # totéž s PDF, výstup se dá potom importovat do Inkscape a dál editovat (a např. uložit jako EPS a vložit do TeXového zdrojáku)

Metody strojového učení

Rozhodovací stromy

Rpart (funguje na kategoriální proměnné):

  • library(rpart)  # nachází se v knihovně rpart (součástí std. balíčku R).
  • decision.tree <- rpart(y ~ feat1 + feat2, train.data)  # vytvoření rozhodovacího stromu
  • prediction <- predict(decision.tree, test.data, type="class")  # predikce podle testovacích dat; kdyby nebyl nastavený parametr type, potom by vracelo matici pravděpodobností klasifikace pro jednotlivé typy

Trees

  • Funguje i na spojité proměnné, dělí vždy na dvě skupiny a kde dělit se rozhoduje podle maximálního snížení nějakého koeficientu přes všechna možná dělení.
  • library(tree)  # součástí knihovny tree, kterou je nutné si nainstalovat
  • model <- tree(y ~ ., train)  # natrénování, vytvoření stromu; interakce atributů jsou zakázané
    • split  # kritérium dělení (co se má co nejvíce snížit -- deviance / gini)
  • Predikce stejná jako pro Rpart.

K-nn

K-nn funguje jen na spojité proměnné, je nutné tedy převést kategoriální data.

  • library(class)  # k-nn algoritmus se nachází v knihovně class (součást standardního balíčku R)
  • predict <- knn(train, test, cl.train, k, use.all)  # samotný algoritmus
    • train a test jsou trénovací a testovací data bez klasifikací (sloupce s výslednými proměnnými)
    • cl.train je sloupec klasifikací pro trénovací data
    • k je parametr k, tj. počet vzorků, které se mají použít
    • use.all -- pokud je více vzorků ve stejné vzdálenosti, mají se použít všechny, nebo jen vybraných max. k?
  • Rovnou vrací vektor předpovězených klasifikací pro testovací data.

Naive Bayes

Je součásti knihovny e1071, pracuje se spojitými proměnnými i kategoriálními daty:

  • library(e1071)  # nutné ji mít nainstalovanou
  • model <- naiveBayes(y ~ ., train)  # natrénování modelu, nelze používat interakce featur!
  • test1 <- test; test1$y <- NULL; predict(model, test1);  # predikce, sloupec s výslednými hodnotami testovacích dat se pro použití ve funkci predict musí vyhodit, aby to fungovalo.

SVM

Je součástí knihovny e1071, pracuje se spojitými proměnnými

  • library(e1071)  # nutné ji mít nainstalovanou
  • model <- svm(y ~ ., train, type="C-classification", kernel="linear", cost=100)  # natrénování
    • type používat jen C-classification
    • kernel máme i radial (s parametrem gamma (měřítko)) nebo polynomial (s parametrem gamma (měřítko), coef0 (posun) a degree (stupeň polynomu))
    • cost je váha penalizací (slack variables)
  • predict(model, test)  # predikce
  • Funguje i na víc kategorií než + a -.

Testy úspěšnosti

  • mean(predict == test);  # accuracy
  • table(predict, test);  # vytvoří confusion matrix (kontingenční tabulku s počtem jednotlivých hodnot)
precision <- function( real, predict ){

    tp <- 0; fp <- 0;

    for(i in 1:length(real)){
	if (predict[i] == 1){
	    if (real[i] == 1) tp <- tp + 1
	    else fp <- fp + 1;
	}
    }
    return ( tp / (tp + fp));
}

recall <- function( real, predict ){

    tp <- 0; fn <- 0;

    for(i in 1:length(real)){
	if (real[i] == 1){
	    if (predict[i] == 1) tp <- tp + 1
	    else fn <- fn + 1;
	}
    }
    return ( tp / (tp + fn));  
}

f.measure <- function( real, predict ){

    r <- recall( real, predict )
    p <- precision( real, predict )

    return ( 2 * p * r / ( p + r ) );
}

Help