Ten zeszyt służy jako wstęp do korzystania z biblioteki emuR do analizy korpusów mowy w języku R.
Zaczniemy od załadowania biblioteki emuR:
library(emuR)
Attaching package: ‘emuR’
The following object is masked from ‘package:base’:
norm
Po ściągnięciu i rozpakowaniu archiwum z tego linku: http://mowa.clarin-pl.eu/korpusy/clarin-small.zip
Zakładając, że jesteśmy w katalogu, gdzie rozpakowano powyższe archiwum, możemy wczytać naszą bazę:
db <- load_emuDB('clarin', verbose = FALSE)
Uwaga: argument verbose
jest tu potrzebny tylko do poprawnego wyświetlania w tym zeszycie - normalnie nie jest potrzebny.
W pamięci znalazła się zmienna o nazwie db
, ale w tej postaci nie można wiele z niej wyczytać. Biblioteka emuR zawiera specjalne funkcje do wyświetlania zawartości bazy.
Możemy, na przykład, wyświetlić listę sesji:
list_sessions(db)
Albo poszczególnych paczek:
list_bundles(db)
Możemy obejrzeć hierarchię opisującą naszą bazę:
list_levelDefinitions(db)
Możemy też uruchomić specjalny intefejs webowy do przeglądania i edycji całej bazy:
serve(db)
Navigate your browser to the EMU-webApp URL: http://ips-lmu.github.io/EMU-webApp/ (should happen automatically)
Server connection URL: ws://localhost:17890
To stop the server press 'clear' button in the EMU-webApp or close/reload the webApp in your browser.
emuR websocket service established
emuR websocket service closed
[1] FALSE
Ale przede wszystkim możemy wykonywać specjalne kwerendy do wyszukiwania konkrentnych segmentów w bazie.
Poszukajmy wszystkich samogłosek dla mówcy nagranego w sesji SES0100:
segs=query(db,'Phoneme=a|e|i|I|o|u', sessionPattern = "SES0100")
Otrzymujemy listę segmentów, która zawiera mnóstwo ciekawych informacji. Spójrzmy na jej srtukturę:
str(segs)
Classes ‘emuRsegs’, ‘emusegs’ and 'data.frame': 1689 obs. of 16 variables:
$ labels : chr "o" "e" "a" "o" ...
$ start : num 4410 4670 4850 5470 5590 ...
$ end : num 4490 4790 4990 5550 5720 ...
$ utts : chr "SES0100:rich001" "SES0100:rich001" "SES0100:rich001" "SES0100:rich001" ...
$ db_uuid : chr "604e8448-241d-11e7-9cad-507b9d83c0f9" "604e8448-241d-11e7-9cad-507b9d83c0f9" "604e8448-241d-11e7-9cad-507b9d83c0f9" "604e8448-241d-11e7-9cad-507b9d83c0f9" ...
$ session : chr "SES0100" "SES0100" "SES0100" "SES0100" ...
$ bundle : chr "rich001" "rich001" "rich001" "rich001" ...
$ start_item_id : int 753449 753452 753454 753458 753460 753463 753467 753472 753474 753478 ...
$ end_item_id : int 753449 753452 753454 753458 753460 753463 753467 753472 753474 753478 ...
$ level : chr "Phoneme" "Phoneme" "Phoneme" "Phoneme" ...
$ start_item_seq_idx: int 9 12 14 18 20 23 27 32 34 38 ...
$ end_item_seq_idx : int 9 12 14 18 20 23 27 32 34 38 ...
$ type : chr "SEGMENT" "SEGMENT" "SEGMENT" "SEGMENT" ...
$ sample_start : int 70560 74720 77600 87520 89440 94400 140800 149280 152320 166400 ...
$ sample_end : int 71840 76640 79840 88800 91520 97280 142400 151360 156320 170720 ...
$ sample_rate : int 16000 16000 16000 16000 16000 16000 16000 16000 16000 16000 ...
- attr(*, "query")= chr "Phoneme=a|e|i|I|o|u"
- attr(*, "type")= chr "segment"
- attr(*, "database")= chr "clarin"
Z powyższej tabelki można wyczytać dużo ciekawych informacji i pisać własne programy, które je przetworzą, ale emuR posiada narzędzia, które nam jeszcze bardziej ułatwią życie.
Czasami baza danych zawiera już przetworzone dane (tak jak w tym przypadku), ale czasami trzeba użyć biblioteki wrassp do przeliczenia informacji z korpusu. W każdym przypadku używamy poniższego polecenia.
Następujące polecenie wylicza (wczytuje z dysku) formanty dla wszystkich segmentów. Argument cut
jest kolejnym udogodnieniem, gdyż dla każdego segmentu zwraca tylko jedną wartość, znajdującą się dokładnie pośrodku każdego segmentu. Argument consistentOutputType
jest potrzebny do ułatwienia pracy z wynikową tabelką jaką zwraca to polecenie:
td <- get_trackdata(db, seglist = segs, ssffTrackName = 'Formants', cut=0.5,
consistentOutputType = FALSE, verbose = FALSE)
td
Tak jak widać, powyższa tabelka zawiera dokładnie tyle samo elementów co tabelka segmentów. Niestety, informacje o samogłosce i jej formantach są w dwóch różnych tabelkach. Połączymy je zatem w nowej tabelce i nazwiemy bardziej intuicyjnie:
dane <- data.frame(vowel=segs$labels, F1=td$fm1, F2=td$fm2)
dane
Mamy tutaj tylko jeden mały problem. Algorytmy aproksymacji formantów czasami zawodzą, a w takich sytuacjach najczęściej wpisują jakąś przewidywalną wartość - w tym przypadku 0. Część znalezionych formantów ma wartość 0, więc warto je usunąć z naszej listy przed narysowaniem. Użyjemy do tego wygodnej biblioteki dplyr:
library(dplyr)
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
dane <- filter(dane,F1>0 & F2>0)
W tej chwili straciliśmy ok. 3% danych, ale mamy pewność, że nie ma w nich “śmieci”.
Teraz można już rysować zawartość stworzonej tabelki używając funkcji plot
, ale są sposoby dobre i lepsze. Otóż, ktoś stworzył świetną bibliotekę do wyświetlania fonemów w przestrzeni 2D i warto z niej skorzystać:
library(phonR)
Rysowanie używając tej biblioteki jest trywialne:
plotVowels(dane$F1,dane$F2,dane$vowel)
Ale przy odrobinie czytania dokumentacji i ustawiania argumentów, można uzyskać bardzo ładne rysunki:
plotVowels(dane$F1, dane$F2,
vowel = dane$vowel,
var.col.by = dane$vowel,
plot.tokens = TRUE,
pch.tokens = dane$vowel,
plot.means = TRUE,
pch.means = dane$vowel,
cex.tokens = 1.2,
alpha.tokens = 0.4,
cex.means = 4,
ellipse.line = TRUE,
pretty = TRUE)