* Selectie en groepering van data. * Samenstellen van lijst met labels voor de selectie/groepering. * Conversie van data. * Lijst van labels met locaties. Uit alle data moet een selectie gemaakt worden. Bijvoorbeeld, bij fonetische vergelijking moeten alle items met lexicale varianten verwijderd worden, en alle items waar de fonetische transcriptie niet beschikbaar is. Bij lexicale vergelijking moeten alle items verwijderd worden waar de lexicale info ontbreekt. Dan zijn er nog allerlei selecties mogelijk, zoals op soort informant, periode, veldwerker. Bij LAMSAS staan sommige van deze gegevens in de bestanden met transcripties, andere gegevens staan in een apart bestand met gegevens over de informanten. Groepering, bijvoorbeeld in LAMSAS. Voor elk woord kunnen er meerdere varianten beschikbaar zijn voor één informant of locatie. Er zijn 1162 informanten in de LAMSAS database, maar voor het item 'frost' zijn er 2967 records. Deze moeten dus samengevoegd worden. (Het Levenshtein-programma laat een variabel aantal strings toe per locatie.) Voor LAMSAS was het wenselijk de data nog meer samen te voegen, per gemeenschap (483). Hiervoor is gebruik gemaakt van de "Informant ID Number (informid)" in de database, waarin de eerste letters gevolgd door de eerste cijfers de gemeenschap aangeven. (Alleen de letters geven de staat aan.) Er moet een bestand gemaakt worden met daarin een lijst van genummerde labels. Elk label staat voor een (gegroepeerde) locatie in de selectie. Conversie van de data op basis van de selectie en groepering naar de bestanden die door het Levenshtein-programma worden ingelezen. Data moet gegroepeerd worden per woord. Dit is gelukkig al het geval bij de LAMSAS-data. Andere datasets zijn gegroepeerd per plaats/informant. Omdat het om grote hoeveelheden data gaat (219062 records in 151 bestanden voor LAMSAS) zie ik geen andere werkbare methode dan dat selectie, groepering en conversie gebeurt door middel van scripts. Ik zal enkele voorbeelden geven voor LAMSAS. Een record in de LAMSAS-database bestaat uit een vast aantal velden gescheiden door komma's. Sommige velden kunnen tussen quotes staan. In de velden kunnen quotes staan, voorafgegaan door een escape: \" Voorbeeld: "bottom land",NY3A,401,O,N,"\"none here¢"," ",bµ«`ñ°m$ìáº{°}nd,MS,5 Ik heb een kort Flex-programma geschreven die records splitst in velden gescheiden door tabs, en quotes en escapes verwijdert. Het resultaat is simpel te verwerken in een Perl-script: %Start _quote %% "\"" { BEGIN _quote; } \\. { putchar (yytext [1]); } "," { putchar ('\t'); } <_quote>"\"" { BEGIN INITIAL; } <_quote>\n { putchar ('\n'); BEGIN INITIAL; } (Tekens die niet matchen blijven onveranderd.) Het volgende is een Perl-script voor simpele, fonetische vergelijking, gegroepeerd per gemeenschap, voor alle data: #!/usr/local/bin/perl $| = 1; # De originele data staat in de bestanden ../raw/*.raw opendir (DIR, '../raw'); while (defined ($infile = readdir (DIR))) { next if ($infile !~ /\.raw$/); print "$infile\n"; $outfile = $infile; $outfile =~ s/raw$/fon/; # Elk bestand is genoemd naar het hoofdwoord (de belangrijkste lexicale # variant). Spaties in het woord zijn een underscore in de bestandsnaam. # Uit de bestandsnaam wordt dus het hoofdwoord afgeleid. $word = $infile; $word =~ s/\.raw$//; $word =~ s/_/ /g; $word = lc $word; # Reset van uitvoer voor nieuw bestand %out = (); open (IN, "../split ../raw/$infile | ../sortdiac|"); while () { chomp; # Het Flex-programma heeft het meeste werk gedaan van het opsplitsen in # velden zonder quotes. Dit Perl-script hoeft alleen nog maar te # splitsen op tabs. @item = split /\t/; # De lexicale variant staat in veld 0. Als na verwijdering van extra # tekens het woord niet gelijk is aan het afgeleide hoofdwoord, dan # wordt dit record overgeslagen $item[0] =~ s/[^-. a-zA-Z]//g; next if ($word ne (lc $item[0])); # Veld 7 bevat de fonetische transcriptie. Het record wordt overgeslagen # als de fonetische transcriptie ontbreekt. next if ($item[7] eq ''); # Uit veld 1 wordt de locatie afgeleid, de eerste letters + cijfers. Als # deze ontbreken dan wordt het record overgeslagen. Anders wordt een regel # met de transcriptie toegevoegd aan de uitvoer van deze locatie. if ($item[1] =~ /^[A-Z]+[0-9]+/) { $ii = $&; $out{$ii} .= "- $item[7]\n"; } } close IN; # Als alle records zijn verwerkt dan wordt de gegroepeerde data weggeschreven. open (OUT, ">../fon483/$outfile"); foreach $key (sort keys %out) { print OUT ": $key\n$out{$key}"; } close OUT; } Hier is een ander voorbeeld. In dit geval wordt fonetische data geselecteerd, gegroepeerd per gemeenschap, alleen met Lowman als veldwerker. De gegevens van de veldwerker zitten in een apart bestand "../informants": #!/usr/local/bin/perl $| = 1; open (IN, '../split ../informants|'); while () { @i = split /\t/; $fw[$i[0]] = $i[5]; } close IN; opendir (DIR, '../raw'); while (defined ($infile = readdir (DIR))) { next if ($infile !~ /\.raw$/); print "$infile\n"; $outfile = $infile; $outfile =~ s/raw$/fon/; $word = $infile; $word =~ s/\.raw$//; $word =~ s/_/ /g; $word = lc $word; %out = (); open (IN, "../split ../raw/$infile | ../sortdiac|"); while () { chomp; @item = split /\t/; next if ($fw[$item[9]] ne 'L'); $item[0] =~ s/[^-. a-zA-Z]//g; next if ($word ne (lc $item[0])); next if ($item[7] eq ''); if ($item[1] =~ /^[A-Z]+[0-9]+/) { $ii = $&; $out{$ii} .= "- $item[7]\n"; } } close IN; open (OUT, ">../fonlowman/$outfile"); foreach $key (sort keys %out) { print OUT ": $key\n$out{$key}"; } close OUT; } Hier is een vrij complex voorbeeld. In dit geval worden lexicale varianten gebruikt, gegroepeerd per gemeenschap, maar alle varianten die minder dan .12 keer voorkomen van het aantal van de hoofdvariant worden weggelaten. #!/usr/local/bin/perl # selectie: minimumpercentage # vorm: strings # bestanden met maar 1 variant: nee $percent = .12; $dir = '../lex'; opendir (DIR, '../raw'); @files = readdir (DIR); closedir (DIR); for $infile (sort @files) { next if ($infile !~ /\.raw$/); print "$infile\n"; %wrds = (); %useit = (); $word = $infile; $word =~ s/\.raw$//; $word =~ s/_/ /g; $word = lc $word; open (IN, "../split ../raw/$infile|"); while () { chomp; @item = split /\t/; next if ($item[0] eq 'NR' || $item[0] eq 'NA' || $item[0] eq '-0-' || $item[0] =~ /^\s*$/ || $item[0] =~ /\?\?/ || $item[0] !~ /[a-zA-Z]/ ); $item[0] =~ s/[^-. a-zA-Z]//g; $wrds{lc($item[0])}++; } close IN; $min = $percent * $wrds{$word}; foreach $w (sort keys %wrds) { if ($wrds{$w} >= $min) { $useit{$w} = 1; } } $outfile = $infile; $outfile =~ s/raw$/lex/; if (scalar keys %useit < 2) { unlink "$dir/$outfile"; next; } %out = (); open (IN, "../split ../raw/$infile|"); while () { chomp; @item = split /\t/; $wrd = lc $item[0]; $wrd =~ s/[^-. a-z]//g; next unless ($useit{$wrd} > 0); if ($item[1] =~ /^[A-Z]+[0-9]+/) { $out{$&} .= "- $wrd\n"; } } close IN; open (OUT, ">$dir/$outfile"); foreach $key (sort keys %out) { $val = $out{$key}; @i = split /\n/, $val; chomp @i; $id = 1; for ($j = 1; $j <= $#i; $j++) { if ($i[$j] ne $i[$j - 1]) { $id = 0; last; } } $val = "$i[0]\n" if ($id); print OUT ": $key\n$val"; } close OUT; } Dan zijn er nog complexere bewerkingen, bijvoorbeeld waarin de strings die vergeleken worden moeten worden geconverteerd, en het maken van een bestand met gewichten voor de verschillende indel-waarden. Bovenstaande laat wel zien dat je dit werk niet kunt doen met een point-and-clickinterface. Ook al maak je gebruik van een database-programma, dan nog zul je een query-taal moeten gebruiken. De complexiteit ontstaat doordat je met meerdere invoerbestanden werkt, meerdere uitvoerbestanden (bij LAMSAS met een 1-op-1-relatie, maar complex als de data per plaats is geordend), doordat je selecties moet maken op basis van gegevens in de invoerbestanden, maar soms ook op basis van combinaties met gegevens uit andere bestanden (bijvoorbeeld: naam van de veldwerker), doordat je de gegevens op de gewenste manier moet samenvoegen (bijvoorbeeld per gemeenschap), en doordat je het resultaat moet omzetten naar de syntaxis die begrepen wordt door het Levenshtein-programma. En dit alles moet gecombineerd worden in een enkele stap. Voor wie de handigheid heeft dit te kunnen doen is de rest een peuleschil. Andere bestanden die de gebruiker zelf zal moeten maken: Bestand met genummerde labels. Nodig voor het Levenshtein-programma. Dit bestand kan verschillen per selectie en groepering van de data. Voor het berekenen van de local incoherence en het tekenen van kaarten moet een bestand met coördinaten gemaakt worden. Voor het tekenen van kaarten zijn nog nodig: - een configuratiebestand - de juiste posities voor de labels in het coördinatenbestand dat ook gebruikt wordt bij het bereken van de local incoherence (als je labels wilt afdrukken op de kaarten) Dit zijn gegevens die met proberen moeten worden afgestemd. Voor het maken van de overige bestanden zijn programma's aanwezig die het voor je kunnen doen. Het gaat dus om allemaal zeer complexe voorbewerkingen, die sterk afhangen van de vorm van de beschikbare data en de wensen van de gebruiker. Complexe bewerkingen waarvoor alleen een algemene programmeeromgeving te gebruiken is. De software is een collectie losse utility's die in zo'n omgeving aangeroepen kunnen worden, net naar wat je nodig hebt. Als je eenmaal de invoer in de juiste vorm hebt is het gebruik van de software vrij eenvoudig. Van Levenshtein-meting tot het maken van dendrogrammen en kaarten: het is een kwestie van het kiezen van het juiste programma. Tussentijdse handmatige bewerking van de data is niet meer nodig. Het grootste probleem is dan weten welk programma je moet gebruiken. Het gebruik van de software bevat dus drie fasen: 1. Voorbewerking, selectie, groepering, en conversie van de data, en het maken van enkele andere bestanden met gegevens (labels, coördinaten, set-up voor tekenen van kaarten). Hiervoor is geen werkhandleiding te geven, omdat dit afhangt van de situatie. Ik kan niet meer doen dan het geven van een beschrijving van de syntaxis van de bestanden, en enkele voorbeelden van het gewenste resultaat laten zien. 2. Gebruik van de software zelf. Hiervoor zijn de manuals en een uitgewerkte handleiding (tutorial). Beiden zouden ongetwijfeld verbeterd kunnen worden. Vooral de syntaxis van de manuals zal vreemd zijn voor iemand die nooit met Unix werkt. Een groot deel van de software kan ook gebruikt worden voor andere doeleinden dan dialectonderzoek. 3. Verdere verwerking van de gegevens met andere software. Er is een interface voor R, en twee programma's die de resultaten omzetten in een vrij algemeen bestandsformaat. Een interface voor S-Plus zou misschien nog wenselijk zijn. Heel ambitieus zou een interface met GIS-software zijn, zoals GRASS. Maar het gebruik van zulke software eist sowieso veel ervaring. Ook zou gedacht kunnen worden aan integratie gebruik van andere softwarepakketten voor onderzoek en visualisatie van dialecten.