Mérési segédlet: az R rövid bemutatása

Az R-ről

Az R egy erősen funkcionális nyelv, ill. környezet statisztikai számításokhoz és grafikus ábrázoláshoz. Az R környezet egy ingyenes, komplett rendszer, amely könnyen kiterjeszthető, bővíthető. Többek között az alábbi feladatokhoz nyújt megoldást:

  • Hatékony adatkezelés- és tárolás.
  • Adatelemzési eszközök.
  • Egyszerű és hatékony programozási nyelv, amely lehetővé teszi feltételek, ciklusok, függvények alkalmazását.
  • Operátorok vektor- ill. mátrixműveletek végrehajtására.

Az R letölthető a http://www.r-project.org/* oldalról. Egy részletesebb leírás a nyelvről elérhető a http://cran.r-project.org/doc/manuals/r-release/R-intro.html* oldalon, ami alapján ez a bevezető is készült.

Az R indítása, bezárása, a munkafolyamat adatai

A mérés során UNIX rendszer alatt használjuk az R-t. Az R-beli számításokhoz, elemzésekhez tartozó adatok egy working directory-ba kerülnek mentésre. Célszerű egy adott problémához tartozó számításokhoz egyetlen working directory-t használni, míg egy másik, teljesen különálló feladatnak új working directory-t létrehozni.

Az R indításához indítsunk el egy terminált, lépjünk abba a könyvtárba, amit working directory-ként szeretnénk használni, majd adjuk ki az R parancsot. Ekkor elindul az R. (A working directory automatikusan az a könyvtár lesz, ahonnan az R-t indítottuk.) Az indítás után egy parancssoros felületet látunk, ahol R parancsok megadásával elkezdhetünk dolgozni. Az R-beli parancssor a UNIX-os parancssorhoz hasonlóan kezelhető. (Fel-le nyilakkal lehet navigálni a korábbi parancsok között, tab-bal ki lehet egészíteni a parancsokat stb.)

Az R bezárásához adjuk ki a q() parancsot. Ekkor a program felteszi a kérdést, hogy szeretnénk-e menteni a munkafolyamathoz tartozó adatokat. Az elmentett adatok az R következő indításánál ismét rendelkezésre fognak állni. (Ha a megfelelő könyvtárból indítjuk az R-t.)

R-ben a parancsokat pontosvesszővel vagy új sorral zárhatjuk le.

Commentet #-tel írhatunk, a # utáni rész a sor végéig comment lesz.

Az elemi parancsok lehetnek kifejezések (expressions) vagy hozzárendelések (assignments). Kifejezések esetén a kifejezés kiértékelődik, és az eredmény kiíródik (alapesetben a képernyőre). Hozzárendelés esetén egy kifejezés értékét hozzárendeljük egy változóhoz. Ekkor a kifejezés értéke nem íródik ki automatikusan a kimenetre.

A source() függvény segítségével egy szöveges fájlba írt R parancsokat hajthatunk végre:

source("r_elemzes.r")

Help (súgó)

Az R rendelkezik egy beépített súgóval, amely a UNIX rendszereken használatos man parancshoz hasonlóan működik. A parancsokhoz tartozó help oldalak leírják a parancs funkcióját, paramétereit, visszatérési értékét és egyéb hasznos információkat. Használata: ha pl. az átlagszámításra alkalmas mean() függvény leírását szeretnénk megtekinteni, adjuk ki az alábbi parancsot:

?mean

A help-ből a q billentyűvel léphetünk ki.

Vectorok

Az R-beli adatstruktúrákat objektumoknak nevezzük. A legegyszerűbb adatstruktúra a vector. Egy vector minden eleme azonos típusú, így ezeket atomi struktúráknak nevezik. Az atomi struktúrákon belül is megkülöböztethetünk különböző típusokat. A legfontosabb atomi típusok: numeric (integer vagy double), logical, character. Vectorokat a c() függvénnyel hozhatunk létre, pl. egy x nevű 3 elemű numeric vector változót az alábbi módon hozhatunk létre:

x <- c(10.5, 3.6, 23.4)

A <- operátor a hozzárendelés (assignment) operátor, amely értéket rendel egy változóhoz. (Használható helyette az = jel is, ill. használható a másik irányban is: ->.)

Vectorokkal végezhetünk aritmetikai műveleteket. Ekkor a műveletek a vectorok megfelelő elemein egyesével végrehajtódnak. Ha a műveletben szereplő vectorok nem ugyanolyan hosszúak, akkor az eredmény a műveletben szereplő leghosszabb vectorral megegyező hosszúságú lesz, és a számításkor a rövidebb vectorok értékei ciklikusan újra felhasználásra kerülnek, amíg el nem érik a leghosszabb vector hosszát. Pl.:

x <- c(2,3,4)
y <- c(10,11)
x + y + 1
## [1] 13 15 15

Néhány függvény vectorok tulajdonságainak meghatározására:

-min, max: legkisebb, ill. legnagyobb elem értéke,
-length: a vector hossza,
-sum: a vector elemeinek összege,
-mean: átlag,
-var: variancia,
-summary: összefoglaló statisztikákat ad a vectorról (minimum, maximum, kvartilisek, medián, átlag, hiányzó értékek száma).

Logikai vectorok

A numerikus vectorokhoz hasonlóan az R-ben kezelhetünk logikai (logical) vectorokat, amelyeknek háromféle eleme lehet: TRUE, FALSE, NA, ahol az NA a hiányzó értéknek (not available) felel meg. Logikai vectorokat feltételekkel hozhatunk létre, pl.:

x <- 20 > 10
x
## [1] TRUE
x <- c(20>10, 1>10)
x
## [1]  TRUE FALSE

Az alapvető logikai operátorok a következők: <, <=, >, >=, ==, !=. Továbbá ha c1 és c2 logikai vectorok, akkor c1 & c2 az elemenkénti és kapcsolatnak felel meg, c1 | c2 az elmenkénti vagy kapcsolatot jelenti, ill. !c1 az elemenkénti negálást jelenti.

Hiányzó adatok

Vectorok (ill. más objektumok) tartalmazhatnak nem ismert, hiányzó adatokat. A hiányzó adatokat jelképező elemek értéke NA (not available). Minden NA értéken végrehajtott művelet eredménye szintén NA.

Az is.na(x) függvény egy logikai vectorral tér vissza, amelynek egy eleme pontosan akkor TRUE, ha az x vector megfelelő eleme NA értékű:

z <- c(1,2,3,NA)
ind <- is.na(z)
ind
## [1] FALSE FALSE FALSE  TRUE

Figyelem: az x == NA kifejezés eredménye egy x-szel megegyező hosszúságú vector, ami kizárólag NA értékeket tartalmaz. (Mivel minden NA értéken végrehajtott művelet értéke szintén NA.)

Indexelés, adathalmazok részhalmazai

Egy vector elemeinek kiválaszthatjuk egy részhalmazát egy index vector segítségével, amelyet szögletes zárójelek között kell megadni a vector után. Az index vector négyféle típusú lehet:

  • Logikai vector: azon elemek kerülnek kiválasztásra a vectorból, amelyeknek megfelelő elemek TRUE értékűek az index vectorban. (Ha az index vector hossza rövidebb, mint a kiválasztandó elemeket tartalmazó vector, akkor az index vector elemei periodikusan újra felhasználásra kerülnek.) Pl.:
x <- c(1, 2, 3, 4, 5, NA)
x[c(TRUE, FALSE)]
## [1] 1 3 5
  • Pozitív egészeket tartalmazó vector: ekkor az index vector elemeinek megfelelő indexű elemek kerülnek kiválasztásra. (Az indexelés 1-gyel kezdődik, nem 0-val.) Pl.:
x[c(1, 4, 6)]
## [1]  1  4 NA
  • Negatív egészeket tartalmazó vector: ekkor az index vector a kizárandó elemek indexeit tartalmazza a kiválasztandó elemek helyett. Pl.:
x[c(-1, -4, -6)]
## [1] 2 3 5
  • Karakter stringeket tartalmazó vector: az objektumok rendelkezhetnek egy ún. names attribútummal, amellyel neveket adhatunk az egyes elemeknek. Ekkor a neveket használhatjuk indexelésre is: az index vector által tartalmazott neveknek megfelelő elemek kerülnek kiválasztásra. Pl.:
names(x) <- c("a", "b", "c", "d", "e", "f")
x[c("a", "d", "e")]
## a d e 
## 1 4 5

Egy részhalmaz-kiválasztás (indexelés) szerepelhet egy értékhozzárendelés bal oldalán is. Ekkor csak a kiválasztott elemek értékeire vonatkozik az értékadás. Pl.:

x[is.na(x)] <- 0
x
## a b c d e f 
## 1 2 3 4 5 0

A példában az x változó összes hiányzó értékét 0-val helyettesítjük.

Egyéb típusok

A vector mellett további típusokat is használhatunk R-ben. Ezek közül a fontosabbak:

  • Mátrixok: többdimenziós vektorok. Valójában vektorok, amelyeket 2 vagy több indexszel indexelhetünk.

  • Factorok: a factorok lehetőségeket biztosítanak kategorikus változók kezelésére. (Azaz olyan változók kezelésére, amelyek csak véges sok értéket vehetnek fel.)

  • Listák: a vectorhoz hasonló típus, azonban egy listában az egyes elemek különböző típusúak is lehetnek.

  • Data frame-ek: a data frame-ek mátrixszerű struktúrák, melyekben az egyes oszlopok különböző típusúak lehetnek. Sok esetben egy data frame sorai az egyes entitásoknak, elemeknek felelnek meg, míg az oszlopok az entitások egy-egy tulajdonságát, jellemzőjét írják le. A data frame-ek igen gyakran használatosak az R-beli adatelemzések során.

  • Függvények: az R függvényei maguk is objektumok, amelyeket a munkafolyamat adatai között tárolhatunk, így az R könnyen kiterjeszthető új funkciókkal.

Objektumok alaptípusa (type) és osztálya (class)

Az objektumok (alap)típusát a typeof() függvénnyel kérdezhetjük le. Az objektumokat átkonvertálhatjuk más típusra is, azonban az ilyen esetekben körültekintően kell eljárni, mivel a nem megfelelő konverzió adatvesztéshez vezethet. A konverzióra az as függvények szolgálnak. Pl. az atomi típusokra való konvertálásra az as.numeric(), as.logical(), as.character() stb. függvények. (De nem csak az atomi típusokra érhetőek el a konverziós függvények!)

A class() függvény segítségével meghatározhatjuk, hogy milyen osztályba tartozik egy objektum. A class() függvény egy absztrakt típust ad vissza, amely az objektum viselkedését határozza meg. ha különböző műveleteket hajtunk velük végre. Az osztálytípusok lehetővé teszik generikus függvények alkalmazását, melyek más és más módon viselkednek attól függően, hogy milyen class-hez tartozik a függvénynek átadott paraméter. A class() függvény sok esetben megegyezik a typeof()-fal, azonban nem mindig. A typeof() azt jelzi, hogy a memóriában, milyen módon tárolódik az adott objektum, míg a class() egy absztrakt típust ad meg, amely az objektumnak egy attribútuma. Pl.: egy data frame esetében a class() függvény data.frame-mel fog visszatérni, míg a typeof() függvény list-tel, mivel a data frame-ek valójában listaként kerülnek tárolásra a memóriában.

Factorok

A factorok speciális típusú vector változók, melyek egy diszkrét osztályozást, csoportosítást valósítanak meg. Azaz factorokat olyan változók leírására alkalmazunk, amelyek véges sok számú diszkrét értéket vehetnek fel. R-ben egyaránt lehetőség van rendezett (ordered) és rendezetlen (unordered) factorok használatára.

Factorokat a factor() függvénnyel hozhatunk létre. A factor különböző lehetséges értékeit a levels() függvénnyel érhetjük el.

Pl. tfh. van egy vectorunk, amely egy kísérletünk alanyainak nemét tartalmazza:

nemek <- c("fiu", "lany", "fiu", "fiu", "lany", "lany", "lany", "fiu")
nemek <- factor(nemek)
nemek
## [1] fiu  lany fiu  fiu  lany lany lany fiu 
## Levels: fiu lany
levels(nemek)
## [1] "fiu"  "lany"

Data frame-ek

A data frame-ek mátrixszerű objektumok, melyeknek az egyes oszlopai különböző típusúak lehetnek, azonban az egy oszlopon belüli elemek mindig azonos típusúak. A data frame-ek valójában listaként kerülnek tárolásra. Sok esetben a data frame sorait entitásoknak feleltethetjük meg, míg oszlopait az entitások tulajdonságainak. Az oszlopok névvel rendelkeznek, melyeket a names() függvénnyel érhetünk el. A sorok számát az nrow() függvénnyel határozhatjuk meg.

A data frame-eket a vectorokhoz hasonlóan indexelhetjük, azonban mivel mátrixszerű struktúrájúak, ezért két indexet kell alkalmaznunk vesszővel elválasztva. Amennyiben elhagyunk egy indexvectort, akkor az indexvectornak megfelelő dimenzióban minden érték kiválasztásra kerül. Az első index a sorokat jelenti, míg a második az oszlopokat. A hagyományos szögletes zárójelek mellett a $ jelet is alkalmazhatjuk egy adott oszlop teljes kijelöléséhez. Néhány példa:

emberek <- data.frame(kor=c(45,50,34), nem=c("fiu","fiu","lany"), magassag=c(178, 184, 165))
emberek
##   kor  nem magassag
## 1  45  fiu      178
## 2  50  fiu      184
## 3  34 lany      165
names(emberek)
## [1] "kor"      "nem"      "magassag"
nrow(emberek)
## [1] 3
emberek[,]
##   kor  nem magassag
## 1  45  fiu      178
## 2  50  fiu      184
## 3  34 lany      165
emberek$kor
## [1] 45 50 34
emberek[3,1]
## [1] 34
emberek$kor[3]
## [1] 34
emberek[,c("kor","nem")]
##   kor  nem
## 1  45  fiu
## 2  50  fiu
## 3  34 lany
emberek[1,]
##   kor nem magassag
## 1  45 fiu      178

Oszlop hozzáadása, törlése

Új oszlopot az alábbi módon adhatunk hozzá egy data frame-hez:

emberek$tomeg <- c(78, 82, 56)
emberek
##   kor  nem magassag tomeg
## 1  45  fiu      178    78
## 2  50  fiu      184    82
## 3  34 lany      165    56

Egy oszlopot az oszlop NULL-ra állításával törölhetünk:

emberek$tomeg <- NULL
names(emberek)
## [1] "kor"      "nem"      "magassag"

Data frame létrehozása fájlból való adatbeolvasással

A data frame-ek létrehozásának egyik egyszerű és gyakori módja a fájlban tárolt adatok beolvasása a megfelelő függvénnyel. Táblázatosan tárolt adatok beolvasására szolgál a read.table() függvény, ill. annak egyéb változatai. A mérésen használt adatokat egy .csv fájlból kell beolvasni, amihez célszerű a read.csv() függvényt használni. (Ez a függvény valójában a read.table() függgvényt hívja, pusztán a paraméterek alapértelmezett értékeiben különbözik a két függvény.)

A plot() függvény

Az egyik leggyakrabban használt függvény ábrák megjelenítésére a plot() függvény. Ez egy generikus függvény: a viselkedése az első paraméter típusától (class-étől) függ.

Ha x és y vectorok, akkor a plot(x, y) függvényhívás egy scatterploton fogja ábrázolni az y értékeket az x értékek függvényében.

Ha x egy numerikus vector, akkor a plot(x) függvény a vector értékeit az index függvényében ábrázolja.

Ha f egy factor típusú változó, y pedig numerikus vector, akkor a plot(f) függvény oszlopdiagramon (barplot-on) ábrázolja f-et, míg a plot(f, y) az f factor minden osztályához (level-éhez) tartozó y értékeket egy-egy boxplot-on ábrázolja.

A fenti példákon kívül a plot() függvény még számos egyéb módon alkalmazható, ill. a megfelelő paraméterbeállításokkal az ábrák egyes tulajdonságai továbbfinomíthatóak.

Statisztikai modellek R-ben

Az R-ben a statisztikai modellek létrehozása általában egy ún. formula alapján történik. A formula megadja a statisztikai modellben a célváltozót, ill. a célváltozó meghatározására felhasznált magyarázó változókat.

Természetesen minden típusú statisztikai modell esetén más és más módon kerül felhasználásra a megadott formula. Pl.: az lm() függvény segítségével lineáris regressziós modellt hozhatunk létre a paraméterben megadott formula alapján, a randomForest() függvénnyel (randomForest package-ből) random forest modellt hozhatunk létre a megadott formula alapján és így tovább. Vagyis a formula a modellekben felhasznált változókat határozza meg, nem a modell típusát. A különböző típusú modellek létrehozásához pedig különböző függvényeket alkalmazunk.

Az alábbiakban néhány egyszerű példán keresztül mutatjuk be a formulák felépítését:

  • y ~ x vagy y ~ x + 1: az y célváltozót az x változó segítségével, ill. egy konstans bias értékkel való eltolással magyarázzuk. Az első változatban a bias érték implicit módon jelenik meg, míg a másodikban explicite megadtuk a formulában. A két eset azonos.

  • y ~ 0 + x vagy y ~ x - 1 vagy y ~ -1 + x: az y változót kizárólag az x változóval magyarázzuk, bias nélkül.

  • y ~ x1 + x2: az y változót az x1 és x2 változóval (és az implicit bias értékkel) magyarázzuk.

Példa: egy lineáris regressziós modell létrehozása:

lin_model <- lm(y ~ x1 + x2, data=dataset)

A fenti példában az lm() függvény segítségével egy lineáris regressziós modellt hozunk létre az y változó becslésére az x1 és x2 változók (és egy bias érték) segítségével. Az y, x1, x2 változók a dataset nevű data frame változó egy-egy oszlopának felelnek meg. Az lm() függvény visszatérési értéke egy illesztett lm típusú (class-ű) modell változó, amely leírja a létrehozott modell tulajdonságait, és lehetővé teszi a létrehozott modell alkalmazását későbbi példákon.

Függvények

Az R nyelv lehetővé teszi a felhasználók számára saját függvények (függvény típusú objektumok) definiálását. A függvények lehetővé teszik az R nyelv kiegészítését új funkciókkal, így az egyik legalapvetőbb és legfontosabb komponensei az R nyelvnek. Az R rendszer legtöbb függvénye (pl.: mean(), var() stb.) szintén R nyelven van megírva, így hasonlóak a felhasználók által definiált függvényekhez. (Azonban vannak rendszerfüggvények, amelyek C-ben vagy Fortran nyelven kerültek implementálásra.)

Az alábbi példa egy derékszögű háromszög átfogójának hosszának kiszámítására alkalmas függvényt definiál. A függvénynek két paramétere van, amelyek a befogók hosszát adják meg.

atfogo <- function(a,b){
        c <- sqrt(a^2 + b^2)
        c
}

A függvény visszatérési értéke a függvényen belül utoljára végrehajtott utasítás értéke lesz. A fenti példában így a c változó értékével fog visszatérni a függvény. A visszatérésre használható a return() függvény is.

A függvények paraméterei rendelkezhetnek alapértelmezett értékkel is, melyet a függvény definiálásakor a paraméterlistában a parameter_name=default_value módon adhatunk meg. Ha egy paraméter rendelkezik alapértelmezett értékkel, akkor a függvény hívásakor elhagyható az adott paraméter, és ekkor az alapértelmezett értékkel kerül meghívásra a függvény.

A paramétereket két alapvető módon adhatjuk meg a függvények számára: pozíció szerint vagy név szerint. Az alábbi példában először pozíció alapján történik a paraméterek megadása, majd név szerinti megadással hajtjuk végre ugyanazt a függvényhívást:

atfogo(5, 6)
## [1] 7.81025
atfogo(b=6, a=5)
## [1] 7.81025

Ahogy a példából is látható, név szerinti paramétermegadás esetén bármilyen sorrendben megadhatjuk a paramétereket, míg pozíció szerinti megadás esetén a függvény definiálásakor meghatározott sorrendben kell megadni a paramétereket. A két paramétermegadási módot kombinálni is lehet: a paraméterek kezdődhetnek pozíció szerinti megadással, majd utánuk következhetnek név szerint megadott paraméterek is. (Továbbá lehetőség van részleges név alapján történő paramétermegadásra. Ekkor a paraméterek teljes nevének megadása helyett pusztán az első részét adjuk meg, úgy hogy az már egyértelműen meghatározza az egyik paramétert. Azonban ez a módszer kevésbé átlátható kódot eredményez, így nem alkalmazzák gyakran.)

R package-ek

Az R függvényei package-ekben, csomagokban vannak tárolva. Egy package tartalma csak akkor érhető el, ha a package be van töltve. Az installált package-eket a library() függvénnyel listázhatjuk ki paraméterek nélkül. Egy package betöltéséhez szintén a library() függvényt alkalmazhatjuk paraméterként megadva a már korábban installált package nevét. Pl.:

library(randomForest)

Leadandó anyagok

A mérés során jegyzőkönyvet kell készíteni az elvégzett feladatokról. A jegyzőkönyv tartalmazza a mérést végző hallgatók nevét, neptunkódját, a mérés helyét és idejét, ill. az elvégzett feladatok megoldását. A jegyzőkönyvben a feladatok megoldásánál szerepeljenek az adott feladat megoldásához használt R kódok, valamint a kimenetük releváns része is, ami hozzájárult a feladat megoldásához, a következtetések levonásához. (Irreleváns, ill. nagyon hosszú kimenetek ne kerüljenek a jegyzőkönyvbe.) A jegyzőkönyv mellett a feladatok megoldására írt R kódokat külön is be kell adni egyetlen nevű fájlban. Fontos, hogy a fájlban ne legyen hibás kód, vagyis futtatni lehessen az összes feladat megoldását a paranccsal.

Feladatok

A feladatok megoldásához szükséges .csv fájlt a tantárgy weboldaláról lehet letölteni. Emellett szükséges, hogy a mérési számítógépen telepítve legyen az R a randomForest csomaggal együtt.

Bevezető

A feladatok során a Humans of New York (https://www.facebook.com/humansofnewyork*) nevű nyilvános Facebook-oldal adatait fogjuk elemezni. A vizsgálatokhoz egy, az oldal postjait tartalmazó adathalmazt fogunk felhasználni. Az adathalmaz egy .csv* fájlban áll rendelkezésre, amely az oldal postjait tartalmazza 2014.12.14-étől visszamenőleg.

A mérés végigvezet néhány tipikus részfeladaton, problémán, amely egy adathalmaz elemzése során előfordulhat.

A mérés során a következő feladatot járjuk körbe nagy vonalakban. A Facebookról nyilvánosan elérhető adatok alapján (amelyek már rendelkezésre állnak a mérési melléklet .csv fájljában) próbáljunk minél pontosabb predikciós eljárásokat létrehozni a postokra érkező like-ok számának előrejelzésére a postok írásának időpontjában! Azaz megpróbáljuk előrejelezni a postokra, hogyha kikerülnének a Facebook-oldalra, akkor feltehetőleg mennyi like érkezne rájuk.

1. feladat: Az adatok megismerése

1.1 Olvassuk be az adatokat!

Az adatokat egy data frame típusú változóba olvassuk be. Ügyeljünk arra, hogy a data frame változói (oszlopai) megfelelő típusúak legyenek. Azaz a message és a link változók ne factorok legyenek, hanem character típusúak, ugyanakkor a type változó legyen factor!

1.2 Válaszoljunk az alábbi kérdésekre

  • Milyen nevű változók szerepelnek a beolvasott data frame-ben?

  • Hány post adatait tartalmazza az adathalmaz?

  • Hány különböző post-típus van az adathalmazban? Melyek ezek a típusok?

  • Oszlopdiagramon ábrázoljuk az egyes posttípusok gyakoriságát!

  • Adjuk meg a postokra érkezett like-ok számának főbb jellemzőit (minimum, maximum, átlag, medián, kvartilisek)! Ábrázoljuk a postokra érkezett like-ok számát hisztogramon! (Segítség: hist().)

  • Összesen hány like érkezett a legutóbbi 100 postra? (A postok időben rendezetten vannak a .csv fájlban, azonban figyeljünk a rendezettség irányára!)

  • Hány post tartalmaz linket?

  • Hány post tartalmaz linket? Milyen összefüggést látunk a “type” és a “link” változók között?

  • A legalább 10 like-kal rendelkező status-ok közül melyiknek van a legkevesebb hozzászólása? Adjuk meg ezen post id-ját, ill. a hozzászólásainak számát! (Segítség: which().)

2. feladat: Adathalmazok létrehozása

2.1 Adatok szűrése

Szűrjük ki a postokat tartalmazó adathalmazból azokat a postokat, amelyek az adathalmaz összegyűjtésének időpontjában még kevesebb, mint 5 napja léteztek. Az adathalmaz összegyűjtésének időpontját tekintsük az adathalmazban szereplő legfrissebb post idejével megegyezőnek. Hozzunk létre egy új data frame változót a kiszűrt postok eltávolításával! (Azaz az új változóba kizárólag az 5 napnál ,,idősebb’’ postok kerüljenek.)

Segítség: a dátumok kezeléséhez használjuk az alábbi függvényt, amely az adathalmaz created_time nevű változóját numerikus változóvá alakítja át, amely az 1970. jan. 1-je óta eltelt másodperceket jelzi:

getNumericTimeFromCreatedTimeField <- function(created_times){
        if (is.null(created_times)){
                NULL
        } else {
                as.numeric(strptime(created_times,format="%Y-%m-%dT%H:%M:%S"))
        }
}

2.2 Tanuló és teszt adathalmazok létrehozása

A szűrt adathalmazunkat osszuk két részre. A postok időrendben legkorábbi 70%-a alkossa a tanuló adathalmazt, míg a maradék része a tesztadathalmazt. A tanuló- és teszthalmazt mentsük el egy-egy új változóba. (A postok eleve időrendben rendezettek a bemeneti .csv fájlban, így sorrendezni nem kell őket, azonban figyeljünk a rendezettség irányára.) (Segítség: round().)

3. feladat: Új változók létrehozása

Hozzunk létre új változókat a tanuló- és a tesztadathalmazban. Mindegyik változó létrehozásához írjunk külön függvényt, amelynek egyetlen bemeneti paramétere az adatokat tartalmazó data frame változó, visszatérési értéke pedig a bemenetként kapott data frame új oszloppal kiegészített változata legyen.

A létrehozandó változók:

  • Eltelt napok száma:
    Egy egész típusú változó, ami megmutatja, hogy adott referenciadátumtól számítva hány nap telt el az adott postig. (Segítség: getNumericTimeFromCreatedTimeField() (lásd: korábbi feladat) vagy as.Date().)

  • Hét napja:
    Egy factor típusú változó, amelynek értéke megmutatja, hogy a hét melyik napján írták az adott postot. (Segítség: weekdays(), as.Date().)

  • Message hossza:
    A message változó hossza karakterekben. Ahol a message változó értéke NA, ott az új változó értéke 0 legyen. (Segítség: nchar().)

  • Napszak órában:
    Szintén egy factor típusú változó, amely azt jelzi, hogy a postot milyen napszakban írák. A napokat 4 napszakra osztjuk: 00-06: éjjel, 06-12: reggel: 12-18: délután, 18-00: este. (Segítség: ne konvertáljuk az adatot idő/dátum típussá, használjuk a substr() függvényt. Ügyeljünk a helyes típusra az értékek összehasonlításánál!)

  • Van-e link:
    Bináris factor változó, melynek értéke jelzi, hogy van-e link megadva az adott posthoz. (Ne logikai típusú legyen, hanem factor!)

4. feladat: Modellezés

Ebben a feladatban a tanuló- és a tesztadathalmaz felhasználásával modelleket építünk a postokra érkező like-ok számának predikciójára. Ügyeljünk arra, hogy a modelleket leíró formulában csak olyan változókat használjunk fel magyarázó változóként, amelyek relevánsak, továbbá rendelkezésre állnak már a post írásának időpontjában. Azaz pl.: a megosztások vagy commentek számát nem használhatjuk fel predikcióra, hiszen ezeket a változókat nem ismerjük a post írásának időpontjában. (De ezek mellett ne használjuk fel a nyilvánvalóan irreleváns változókat sem.) Mely változók kerültek így a modellek magyarázó változói közé? Az alábbi modelltípusokat próbáljuk ki:

4.1 feladat: Lineáris regresszió

A predikció a magyarázó változóknak egy lineáris kombinációjaként áll elő. (Segítség: lm().)

4.2 feladat: Random forest

A random forest egy döntési fákon alapuló modell, amely több döntési fát épít fel, majd a kimenetet az egyes döntési fák predikciójának átlaga adja. (Segítség: randomForest() a randomForest package-ből.)

4.3 feladat: Factor változók kezelése a lineáris regressziós modellben

A modellillesztő lépések a modelleket leíró objektummal térnek vissza. Vizsgáljuk meg az lm() függvény által létrehozott modellben az egyes változók együtthatóit: hogyan kezelte a függvény a factor típusú változókat?

5. feladat: Modellek értékelése

5.1 Hibafüggvény definiálása

A modelleink összehasonlításához meg kell határoznunk valamilyen mértéket, amely alapján minősíthetjük a modellek teljesítményét. A mérés során az átlagos négyzetes hibát használjuk a modellek összehasonlítására. Írjunk egy függvényt az átlagos négyzetes hiba kiszámítására! A függvénynek két paramétere legyen: az egyik a valódi értékeket tartalmazó numerikus vector, míg a második paraméter a predikciókat tartalmazó vector. (Vagyis a két paraméter hossza meg kell, hogy egyezzen.)

5.2 Modellek összehasonlítása

Hasonlítsuk össze a tesztadathalmaz elemeire adott predikciók alapján a modelljeink teljesítményét! (Segítség: predict().) A két modell mellett számítsuk ki, milyen eredményt ér el egy egyszerű átlagot számító eljárás, amely egy konstans értéket, a tanító adathalmaz postjaira érkezett like-ok számának átlagát jósolja minden jövőbeli postra. (Segítség: rep().)

Sikerült-e az átlaghoz képest jobb eredményt elérni a modelleinkkel? A három eljárás közül melyik adta a legpontosabb, ill. a legkevésbé pontos predikciókat? Hogyan lehetne szignifikánsan továbbjavítani a modelljeink teljesítményét?

Függelék

Adatok gyűjtése

Az adathalmaz összegyűjtése az Rfacebook package segítségével történt, így a kódok futtatásához először telepíteni kell a csomagot. Az adatok gyűjtése a 0.4-es verziójú csomaggal és 3.1.2-es verziójú R-rel történt. Az adatok összegyűjtéséhez az alábbi kódot futtattuk:

library(Rfacebook)

token <- "CAACEdEose0cBALAInDsI2tW1ZArG9QPl1ZChTFKDINieKa12eYZBL1zc1bL6146F7JGFMZADhUZCy0S2POeD6tuVXWwtkPUqurWtSepEKrzZCpqGPouRxSs3sJMw884rNxNIE2RykOVy8MyVsMLXIOjkvUQvZBVNltwLWpjlwpRNfPgo5toJZChLXdjNBRVsQ665Hea2SuviQKCUaJiU6t7K"

getPageData <- function(pagename, token, n){
        go <- T
        while(go){
                tryCatch({
                        print("try")
                        pageData <- getPage(pagename, token, n = n)
                        go <- F
                        print("success")
                        },
                        error = function(err){
                                print(paste("error", err))
                                go <- T        
                        })
        }
        pageData
}
pageData <- getPageData("humansofnewyork", token, n = 30000)
write.csv(pageData, file="../data/pageData_HumansOfNewYork.csv", row.names=F)

Fontos, hogy ha futtatni szeretnénk a fenti kódot, akkor a token változónak egy érvényes Facebook access tokent kell tartalmaznia, melyet legegyszerűbb módon a https://developers.facebook.com/tools/explorer/* oldalon szerezhetünk. Továbbá a Facebook API változásai miatt az Rfacebook* package egyes metódusai nem működnek tökéletesen, erre figyelni kell a package használatakor. Így pl. a getPage() függvény is néha leállt hibával, így többször kellett futtatni, amíg egyszer le nem futott sikeresen.