Távoli olvasó olvas
2016-12-04 • R, distant reading, tutorialBevezetés a bevezetésbe
Az utóbbi időben igyekeztem elmélyülni a distant reading
elméletében és gyakorlatában. Az elmélet megismerése a szokásos utakon-módokon zajlik. Könyvek, tanulmányok különböző szerzők elolvasása, kijegyzetelése. Aztán cikkek, recenziók írása, előadások, szemináriumok tartása… Ja igen, néha töprengeni, mélázni sem árt a kijegyzetteken, elmondottakon. Szóval ahogy a bölcsészek csinálják.
A gyakorlat… Nyilván már egy excell-táblázat is alkalmas erre, de azért vannak ennél kifinomultabb és hajlékonyabb, illetve alkalmasabb eszközök. Még én is tanulom őket. Docendo discimus. Persze magamat tanítom – végtelen hurok.
Belevágni egyszerű: különösebb felkészülés nélkül is elő lehet venni Maciej Eder, Jan Rybicki és Mike Kestemont programcsomagját, a stylo
-t. Persze telepíteni kell hozzá az R
-t Erről nem írok, elég jó dokumentációja van, vannak tanulmányok is mellé. Stilometriára lehet használni. A stilometriának ugyanakkor nemcsak a szerzőségattribúcióban van jelentősége, vannak további lehetőségei – erről többen hosszabban írtak: Matthew L. Jockers vagy éppen a Distant readings tanulmányai – érdemes az utóbbiak magyarázatait hozzáolvasni, mert közérthetően mondják el, hogy az egyes beállítások mire jók. Magyar szövegeket is kezel, van beépített magyar stopszólistája is. A szövegeknek .txt
vagy .xml
formátumban kell lenniük.
De ha magunk akarunk távolról olvasni, akkor érdemes belevetni magunkat az R
használatába. Nekem Matthew Jockers könyve volt az útmutató. Az ő példáit alkalmazom, módosításokkal – persze most még sok sziporka nem lesz. Mondjuk ilyen „műalkotásokat” tudunk majd csinálni a „lecke” végén: Az arany ember írásjelei – nem mintha ez volna a distant reading
lényege…
1. Előfeltételek
Ebben a leírásban adottnak veszem, hogy telepítve van az R
és az RStudio
. Nem fogom elmagyarázni az egyes R
-adattípusokat (data.frame
, list
, character
stb.), ebben a részben nincs is rá szükség. Továbbá le kell még tölteni egy egyszerű java
-programot is, a magyarlanc
-ot.
2. Szövegelőkészítés
A magyarlanc
egy java
-program, amelyet a SZTE és az MTA Mesterséges Intelligencia Kutatócsoportja készített. Ingyen letölthető, de szükséges, hogy a java8 telepítve legyen. Általában fent van a gépeken. Morfológiai elemzést készít.
2.1. A magyarlanc
használata
- Miután letöltöttük, az egyszerűség kedvéért érdemes abba a könyvtárba másolni, amelyikben a feldolgozandó fájlunk van.
- Be kell hívni a parancssort/terminált és át kell menni abba a könyvtárba, ahol a
magyarlanc
található. (Ha valaki elfelejtette volna, acd
paranccsal [change directory] lehet könyvtárat váltani.) - A szövegnek
.txt
formátumban kell lennie. A [magyarlanc
] 19. századi szövegekkel is jól elbodogul, de pontosabb lesz, ha sztenderdizálva van a szöveg. Tehát ats
,tz
,cz
és társaikat normalizálni érdemes. - A futtatás egyszerű, gépeljük/másoljuk be a következő parancsot:
java -Xmx1G -jar magyarlanc-3.0.jar -mode morphparse -input in.txt -output out.txt
- A
magyarlanc
honlapján van egy részletesebb leírás arról, hogy milyen opciókat lehet bekapcsolni – én amorphparse
-ot szoktam használni.- Az
in.txt
helyén értelemszerűen a feldolgozandó szövegfájlunk neve álljon. Valójában nem kell egy könyvtárban lennie amagyarlanc
-nak a fájllal, de akkor amagyarlanc
felőli elérési utat is meg kell adni azin.txt
helyén.- Az
out.txt
a kimeneti fájl. Természetesen az elérési utat és nevet is lehet módosítani.- Így néz ki Az arany ember eleje a
magyarlanc
-cal elemezve:
- Négy oszlopot tartalmaz, amelyeket tabulátor választ el. Az első az eredeti szöveg. A második a lemmatizált (szótári) szóalak. A harmadik a szófaj*. A negyedik a morfológiai elemzés.
2.2. Beolvasás az R
-be
- Miután megnyitottuk az
RStudio
-t, állítsuk be a munkakönyvtárat.- Az aktuális munkakönyvtárat a
getwd()
paranccsal lehet lekérdezni. - Munkakönyvtárat beállítani a
setwd("konyvtareleresiutja")
paranccsal lehet vagy aSession
menüSet Working Directory
alpontjában.
- Az aktuális munkakönyvtárat a
2.2.1. A magyarlanc
-cal feldolgozott fájl betöltése
valtozo.df <- read.csv2(file = "out.txt", header = FALSE, sep = "\t", stringsAsFactors = FALSE)
- Egy
valtozo.df
nevűdata.frame
-be (praktikusan: táblázat) olvassuk be a fájlt (a<-
helyett használhatunk=
-t is).- Az első argumentum a fájl elérési útja és neve (jelen esetben a fájl a munkakönyvtárban van).
- A másodikkal azt mondjuk, hogy az első sort ne tekintse fejlécnek.
- A harmadikkal, hogy az elemeket tabulátor választja el (egy “rendes”
.csv
esetében","
-t kel írni, mivel vessző a választóelem [comma separated values
]).- A negyedikkel, hogy az azonos alakokat ne ejtse ki, hanem mindet tartsa meg. Az
R
alapesetben ugyanis az ismétlődő alakokat kiejtené.
2.2.2. Egy nem feldolgozott fájl betöltése
- Természetesen nemcsak a
magyarlanc
-cal előkészített fájlt lehet beolvasni, magát az eredeti fájlt is importálhatjuk. Mivel mint rövidesen látni fogjuk, az előkészített fájlból bármelyik oszlop tartalmát kinyerhetjük, ezért az eredeti és a lemmatizált szöveg is rendelkezésünkre áll. Ugyanakkor egy hátránya van az így előkészített fájlnak: az eredeti bekezdés- és fejezetstruktúráját nem tudjuk reprodukálni, azaz nem tudjuk az elemzés szempontjává tenni. Tehát ha erre lesz szükségünk, akkor máshogy kell a fájlt importálni:
aranyember.v <- scan("aranyember_kritikai.txt", what="character", sep="\n")
- Az első argumentum az importálandó fájlnév. Ha nincs külön elérési út megadva, akkor a munkakönyvtárban kell lennie a fájlnak.
- A második argumentum azt jelzi, hogy a fájl tartalma karaktervektorként importálandó.
- A harmadik azt az utasítást adja, hogy a fájl tartalmát
new line
elemenként, azaz bekezdésenként tárolja el.
2.3. Alapműveletek – legalábbis néhány
2.3.1. Terjedelem lekérdezése
- Ha lekérdezzük, kiderül, hogy Az arany ember-t tartalmazó fájlunknak 179705 sora és 5 oszlopa van. A karaktervektorokét máshogy kérdezzük le (
length(x)
), lásd a 3. pontnál.
> dim(valtozo.df)
[1] 179705 5
2.3.2. Elemek eltávolítása
- Ha kiíratjuk a változó elejét, akkor látjuk, hogy az ötödik oszlop valójában üres (a példában a
>
azRStudio
konzolján látszik, nem kell begépelni). Ezt akár törölhetjük is. Utána ellenőrizzük! (Ez utóbbit már nem írtam bele a példába!)
> head(valtozo.df, n = 5)
V1 V2 V3 V4 V5
1 A a DET Definite=Def|PronType=Art NA
2 SZENT szent ADJ Case=Nom|Degree=Pos|Number=Sing NA
3 BORBÁLA borbála NOUN Case=Nom|Number=Sing NA
4 I. 1. ADJ Case=Nom|NumType=Ord|Number=Sing NA
5 A a DET Definite=Def|PronType=Art NA
> valtozo.df$V5 = NULL
2.3.3. Elemek exportálása
- A változóból bármelyik oszlopot (és sort) exportálni lehet, hogy további elemzéseknek vessük alá (pl. ha a szófajok érdekelnek, vagy ha mondjuk később a morfológiai elemzések [mennyi jelen idejű ige van és mennyi múlt idejű…]). A következő két parancs a lemmatizált alakokat teszi egy egyoszlopos
data.frame
-be (mindegy, melyiket használjuk):
lemma.valtozo.df = valtozo.df[2]
lemma.valtozo.df = valtozo.df["V2"]
- Ellenőrizzük, hogy az új változónak (
lemma.valtozo.df
) hány sora és oszlopa van!- A
data.frame
típusú adatbólkaraktervektort
is csinálhatunk. Utána ellenőrizzük a hosszúságát, és kiíratjuk az első 5 elemét:
> szoveg.v = unlist(lemma.valtozo.df, use.names = FALSE)
> length(szoveg.v)
[1] 179705
> head(szoveg.v, n = 5)
[1] "a" "szent" "borbála" "1." "a"
- Mivel a táblázatunk minden sora egy-egy oszlop volt, ezért a karaktervektor hosszúsága is a szavak számát adja meg. Ugyanakkor ha közvetlenül a fájlból importáltuk a szöveget, akkor a hosszúság a bekezdések számát jelenti (feltéve, hogy a 2.2.2.-ben leírtak szerint jártunk el.)
2.3.4. Szavak (betűk), írásjelek törlése
- Ha csak a szavak érdekelnek, akkor az írásjeleket, melyek külön elemekként vannak eltárolva, törölnünk kell. Ha csak az írásjelek, akkor viszont a szavakat. Mivel a törlés úgy történik, hogy a törölt elemek üres helyként bent maradnak, ezért ezeket utóbb törölni kell. Az írásjelek törlésére két megoldást is mutatok, az egyik egy csomag (és függőségei) betöltését igényli. Az
RStudio
-ban egy többosztatú munkafelületünk van, az egyikben van egyPackages
fül, arra kell kattintani, és ott kipipálni a kívánt csomagot. Eder és munkatársaistylo
-ját is így kell betölteni – miután telepítettük. (A#
kommentáromat jelöli, nem kell beírni. A\\W
egyregex
-kifejezés, amely minden nem-karaktert kijelöl. A!=
jelentésenem egyenlő
– párja a==
, amelyegyenlő
-t jelent.)
# írásjelek törlése, be kell hívni a `tm` csomagot
szavak.v = removePunctuation(szoveg.v, preserve_intra_word_dashes = TRUE)
# alternatív módszer az eltávolításra, külön csomagot nem igényel
csakszavak.l = strsplit(szoveg.v, "\\W")
csakszavak.v = unlist(csakszavak.l)
# távolítsuk el az üres helyeket, azaz a törölt írásjelek helyét (ha a `tm` csomaggal töröltük az írásjeleket, akkor a `csakszavak.v` helyére értelemszerűen a `szavak.v` kerül)
not.blanks.v = which(csakszavak.v!="")
csakszavak.v = csakszavak.v[not.blanks.v]
- Ellenőrizzük, milyen hosszú az írásjelek nélküli
csakszoveg.v
, illetve aszavak.v
változónk! Az eredményből látni fogjuk, hogy nem teljesen azonos a hosszúságuk. Ennek az az oka, hogy az első módon történő eltávolítás során az olyan alakokat, amelyeket a lemmatizálás során amagyarlanc
elemzője így ír föl,meg+van
egy elemként őrzi meg (megvan
), addig a másik módszer két külön elemre bontja és tárolja. (A\\w
egyregex
-kifejezés, amely csak a karaktereket jelöli ki [itt egy másik online tutorial hozzá].)
# szavak törlése
csakirasjelek.l = strsplit(szoveg.v, "\\w")
csakirasjelek.v = unlist(csakirasjelek.l)
not.blanks.v = which(csakirasjelek.v!="")
csakirasjelek.v = csakirasjelek.v[not.blanks.v]
- Ennek az eljárásnak egy hibája van. Amennyiben a
magyarlanc
-cal feldolgozott anyagot használjuk, akkor megjelenik karakterként a+
, amely azonban nem a regény írásjeleinek része. Ezeket is el kell távolítani. Az eddigi példák alapján ezt könnyű megcsinálni.
2.3.5. Változó fájlként történő elmentése
- Amennyiben szükségünk van valamelyik változóra fájlként, kiírathatjuk. Jelen formájában minden szó/írásjel önálló bekezdésben lesz, ha ez zavar, akkor előtte egyetlen elembe másolhatjuk az összeset, és úgy is kiírathatjuk.
# másoljuk össze az elemeket
osszevont.csakirasjelek.v = paste(csakirasjelek.v, collapse = " ")
# írjuk ki fájlba
write(osszevont.csakirasjelek.v, file = "osszevont.csakirasjelek.txt", ncolumns = if(is.character(osszevont.csakirasjelek.v)) 1 else 5, append = FALSE, sep = " ")
Egy csomó mindent még tanulni kell. Majd máskor.
*: Nem pontos kifejezés, tudom.