<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="hu">
	<id>https://vik.wiki/index.php?action=history&amp;feed=atom&amp;title=Sz%C3%B6vegb%C3%A1ny%C3%A1szat_-_H%C3%A1zi_feladat</id>
	<title>Szövegbányászat - Házi feladat - Laptörténet</title>
	<link rel="self" type="application/atom+xml" href="https://vik.wiki/index.php?action=history&amp;feed=atom&amp;title=Sz%C3%B6vegb%C3%A1ny%C3%A1szat_-_H%C3%A1zi_feladat"/>
	<link rel="alternate" type="text/html" href="https://vik.wiki/index.php?title=Sz%C3%B6vegb%C3%A1ny%C3%A1szat_-_H%C3%A1zi_feladat&amp;action=history"/>
	<updated>2026-05-17T21:11:43Z</updated>
	<subtitle>Az oldal laptörténete a wikiben</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>https://vik.wiki/index.php?title=Sz%C3%B6vegb%C3%A1ny%C3%A1szat_-_H%C3%A1zi_feladat&amp;diff=157301&amp;oldid=prev</id>
		<title>David14: David14 átnevezte a(z) Nobr Szövegbányászat házi feladat br Ékezetesítő /nobr lapot a következő névre: Szövegbányászat - Házi feladat</title>
		<link rel="alternate" type="text/html" href="https://vik.wiki/index.php?title=Sz%C3%B6vegb%C3%A1ny%C3%A1szat_-_H%C3%A1zi_feladat&amp;diff=157301&amp;oldid=prev"/>
		<updated>2013-02-06T11:04:52Z</updated>

		<summary type="html">&lt;p&gt;David14 átnevezte a(z) &lt;a href=&quot;/index.php?title=Nobr_Sz%C3%B6vegb%C3%A1ny%C3%A1szat_h%C3%A1zi_feladat_br_%C3%89kezetes%C3%ADt%C5%91_/nobr&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Nobr Szövegbányászat házi feladat br Ékezetesítő /nobr (a lap nem létezik)&quot;&gt;Nobr Szövegbányászat házi feladat br Ékezetesítő /nobr&lt;/a&gt; lapot a következő névre: &lt;a href=&quot;/Sz%C3%B6vegb%C3%A1ny%C3%A1szat_-_H%C3%A1zi_feladat&quot; title=&quot;Szövegbányászat - Házi feladat&quot;&gt;Szövegbányászat - Házi feladat&lt;/a&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;hu&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Régebbi változat&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;A lap 2013. február 6., 13:04-kori változata&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;hu&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(Nincs különbség)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>David14</name></author>
	</entry>
	<entry>
		<id>https://vik.wiki/index.php?title=Sz%C3%B6vegb%C3%A1ny%C3%A1szat_-_H%C3%A1zi_feladat&amp;diff=146080&amp;oldid=prev</id>
		<title>Unknown user: Új oldal, tartalma: „{{GlobalTemplate|Valaszthato|SzovBanyaszEkezetesito}}   __TOC__  ==Felhasználói útmutató==  ===Rendszerkövetelmények===  A program futtatásához .NET 2.0 Framewo…”</title>
		<link rel="alternate" type="text/html" href="https://vik.wiki/index.php?title=Sz%C3%B6vegb%C3%A1ny%C3%A1szat_-_H%C3%A1zi_feladat&amp;diff=146080&amp;oldid=prev"/>
		<updated>2012-10-22T11:47:03Z</updated>

		<summary type="html">&lt;p&gt;Új oldal, tartalma: „{{GlobalTemplate|Valaszthato|SzovBanyaszEkezetesito}}   __TOC__  ==Felhasználói útmutató==  ===Rendszerkövetelmények===  A program futtatásához .NET 2.0 Framewo…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Új lap&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{GlobalTemplate|Valaszthato|SzovBanyaszEkezetesito}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Felhasználói útmutató==&lt;br /&gt;
&lt;br /&gt;
===Rendszerkövetelmények===&lt;br /&gt;
&lt;br /&gt;
A program futtatásához .NET 2.0 Framework és minél több RAM szükséges.&lt;br /&gt;
&lt;br /&gt;
===A program használata===&lt;br /&gt;
&lt;br /&gt;
# Le kell tölteni az [origo] archívumot&lt;br /&gt;
		(http://categorizer.tmit.bme.hu/~domi/Data/Origo.zip)&lt;br /&gt;
# A &amp;#039;&amp;#039;korpusz létrehozása&amp;#039;&amp;#039; tabon meg kell adni a zip helyét, azt, hogy&lt;br /&gt;
		az első hány dokumentumot dolgozza föl, és hogy legfeljebb milyen&lt;br /&gt;
		hosszú n-gramokat gyűjtsön ki.&lt;br /&gt;
# A &amp;#039;&amp;#039;korpusz részletek&amp;#039;&amp;#039; tabon bele lehet lapozni a fába és meg lehet&lt;br /&gt;
		nézni, hogy egy konkrét n-gramot hányszor talált meg az [origo]&lt;br /&gt;
		archívumban&lt;br /&gt;
# Az &amp;#039;&amp;#039;ékezetesítés&amp;#039;&amp;#039; tabon&lt;br /&gt;
** Be lehet tölteni egy korábban előállított n-gram fát.&lt;br /&gt;
** Meg lehet nyitni illetve el lehet menteni egy szöveges&lt;br /&gt;
		  dokumentumot választott karakterkódolással.&lt;br /&gt;
** Kétféle algoritmussal lehet ékezetesíteni a szöveget.&lt;br /&gt;
** Ha a szöveg eleve ékezetes volt, a Teszt gomb hatására&lt;br /&gt;
		  kiszámolja, hogy az ékezetek törlése és az újraékezetesítés után&lt;br /&gt;
		  mekkora lesz a hibaarány. A pontosságot a következő képlettel&lt;br /&gt;
		  számolom: (eltalált magánhangzók száma) / (összes magánhangzó száma)&lt;br /&gt;
&lt;br /&gt;
===Teszt eredmények===&lt;br /&gt;
&lt;br /&gt;
Az archívum 10000 dokumentumából a legfeljebb 10 betűs n-gramokat&lt;br /&gt;
kigyűjtve, a dinamikus programozási algoritmust választva a pontosság&lt;br /&gt;
[http://magyar-irodalom.elte.hu/robert/szovegek/bazar/ A katedrális és a bazár] c. szöveg esetén&lt;br /&gt;
620 MB memóriahasználat mellett 98% volt. &amp;lt;br&amp;gt;&lt;br /&gt;
A memóriahasználat felére csökkenthető egy 3000 dokumentumból generált&lt;br /&gt;
korpusszal úgy, hogy a pontosság még mindig 97% fölött marad.&lt;br /&gt;
&lt;br /&gt;
==A program működése==&lt;br /&gt;
&lt;br /&gt;
===Korpusz előállítása és tárolása===&lt;br /&gt;
&lt;br /&gt;
A korpusznak a TMIT oldalán megtalálható [origo] archívumot választottam. A program jelenleg csak ehhez tartalmaz parsert, de a provider modellen keresztül kis erőfeszítéssel más adatforrások is illeszthetők. A 200 MB-os origo.zip több mint 100000 file-t tartalmaz, ezért úgy döntöttem, hogy nem csomagolom ki az egészet, hanem a [http://www.codeproject.com/cs/files/sharpzlib.asp zlib könyvtárral] mindig csak az éppen feldolgozandó dokumentumot bontom ki a memóriába.&lt;br /&gt;
&lt;br /&gt;
A korpusz a feldolgozott dokumentumok összes, legfeljebb k hosszú n-gramját tartalmazza, ahol k alapértéke 10. Az n-gramok egy szófában (prefix tree, [http://en.wikipedia.org/wiki/Trie trie]) vannak eltárolva annyi módosítással, hogy a gyökér gyerekei az utolsó karaktert tartalmazzák, és a fában lefele haladva visszafele tudjuk kiolvasni a kulcsokat. Egy csúcsnak legfeljebb 37 gyereke lehet. Megkülönböztetem a magyar ábécé egyjegyű betűit (26+9 karakter), a kötőjelet és a szóközt. A kis- és nagybetűket azonosnak veszem, mert elkülönítésük jelentősen megnövelné a fa méretét. Az írásjeleket szóközként kezelem.&lt;br /&gt;
&lt;br /&gt;
A fát a következőképpen ábrázolom:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;class NGramTreeNode {&lt;br /&gt;
	// kulcs (n-gram) következő karaktere&lt;br /&gt;
	public char character;&lt;br /&gt;
&lt;br /&gt;
	// n-gram előfordulásainak száma a beolvasott szövegekben&lt;br /&gt;
	public uint frequency;&lt;br /&gt;
	&lt;br /&gt;
	// milyen karakterek (karaktersorozatok) előzhetik meg az kulcsot&lt;br /&gt;
	public NGramTreeNode[] children;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A fa felépítésekor egy n-gram és összes szuffixának felvétele darabonként 1 lefelé lépést és 0 vagy 1 beszúrást jelent a fában. A csúcsok gyerekeit karakter szerint rendezve tárolom. Ezzel ugyan lineáris lesz a beszúrás ideje, cserébe a keresésé O(log(n))-re csökken. Mivel a legtöbb csúcsnak kevés gyereke van, a lineáris futási idő is elfogadható. A fa formájú tárolásnak megvan az az előnye, hogy minden n-gram ábrázolható 1 karakterrel és egy pointerrel, tehát lényegesen kisebb a memóriaigénye, mint ha egy hash táblába raknám az &amp;amp;lt;n-gram,gyakoriság&amp;amp;gt; párokat.&lt;br /&gt;
&lt;br /&gt;
A fát tömörítve mentem lemezre. Egy pár tárigényét sikerült 2,4 byte-ra leszorítani a következő kódolással:&lt;br /&gt;
* a gyakoriság nagyságrendje (2 bit)&lt;br /&gt;
** 00: egyszer fordult elő&lt;br /&gt;
** 01: legfeljebb 2^8-1-szer fordult elő&lt;br /&gt;
** 10: legfeljebb 2^16-1-szer fordult elő&lt;br /&gt;
** 11: legfeljebb 2^32-1-szer fordult elő&lt;br /&gt;
* csúcs távolsága a gyökértől (6 bit)&lt;br /&gt;
* karakter ISO-8859-2 kódolással (1 byte)&lt;br /&gt;
* karakter gyakorisága 0, 1, 2 vagy 4 byte-on&lt;br /&gt;
&lt;br /&gt;
Az [origo] archívum első 10000 dokumentumából készített korpusz 17,8 millió különböző legfeljebb 10 karakteres n-gramot tartalmaz. A fát 41 MB-on tárolható ezzel az adatábrázolással. A struktúra finomításával körülbelül további 30%-ot lehetne spórolni, de nem ez a szűk keresztmetszet, hanem a memóriahasználat, ugyanis a .NET keretrendszer egy csúcsnak átlagosan 35 byte-ot foglal a memóriában. A 17,8 millió bejegyzés több mint 600 MB-ot jelent.&lt;br /&gt;
&lt;br /&gt;
Az overheadet az objektumok pazarló tárolása okozza. Lényeges javulást csak egyedi memóriakezeléssel lehetne elérni, azaz egy nagy byte tömbben kellene tárolni az egész fát, és a fában való mozgás során minden lépésben kézzel kellene kiszámolni a következő címet. Ezzel a módszerrel becsléseim szerint harmadára lehetne visszaszorítani a memóriahasználatot.&lt;br /&gt;
&lt;br /&gt;
Alternatív megoldásként elképzelhető a fa lemezen tárolása is. A gyökérhez közeli részfát lehetne memóriában tartani csökkentve a lemezhozzáférések számát, de még a gyorsítótárazás mellett is teljesítményproblémákat vetne fel a módszer. Egy 85 KB-os szöveg ékezetesítése jelenleg 3 másodpercig tart egy 1,6 GHz-es processzort tartalmazó laptopon. Lemezolvasásokkal együtt ez az érték több nagyságrenddel nőne, ami nem elfogadható.&lt;br /&gt;
&lt;br /&gt;
===Ékezetesítő algoritmus===&lt;br /&gt;
&lt;br /&gt;
Egy a&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;a&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;...a&amp;lt;sub&amp;gt;n-1&amp;lt;/sub&amp;gt;a&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt; n-gram relatív gyakoriságát úgy definiálom, hogy legyen egyenlő az a&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;a&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;...a&amp;lt;sub&amp;gt;n-1&amp;lt;/sub&amp;gt;a&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt; és az a&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;a&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;...a&amp;lt;sub&amp;gt;n-1&amp;lt;/sub&amp;gt; gyakoriságának hányadosával. Ezzel tulajdonképpen azt adom meg, hogy az a&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;a&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;...a&amp;lt;sub&amp;gt;n-1&amp;lt;/sub&amp;gt; karaktersorozat után mekkora valószínűséggel következik a&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
====Mohó algoritmus====&lt;br /&gt;
&lt;br /&gt;
Kétféle algoritmust próbáltam ki. A mohó algoritmustól nem vártam sokat, csak azért implementáltam, mert egyszerű volt és összehasonlítási alapot adott. Az ékezetesítést a teljes indukció elve alapján végzem. Felteszem, hogy a szöveg egy prefixe már ékezetesítve van. A következő karakter ha magánhangzó, legfeljebb négyféle lehet. Mindegyik esetre megkeresem a szuffixre illeszkedő leghosszabb n-gramot és az a betűt választom, amelyik n-gramjának legnagyobb a relatív gyakorisága. Az algoritmus hatékonysága kicsit javítható, ha a relatív gyakoriságot súlyozom az n-gram hosszával.&lt;br /&gt;
&lt;br /&gt;
A mohó algoritmus problémája az, hogy azonnal dönt és csak a szavak előző karaktereit veszi figyelembe. A hatékonyság lényegesen javítható, ha csak a következő néhány karakter ismeretében hozzuk meg a döntést.&lt;br /&gt;
&lt;br /&gt;
====Dinamikus programozásos algoritmus====&lt;br /&gt;
&lt;br /&gt;
Tegyük fel, hogy k=10 karakteres n-gramokkal dolgozunk. Ekkor a program az összes lehetséges módon ékezetesíti a szöveg soron következő 10 karakterét (a&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt;, ..., a&amp;lt;sub&amp;gt;n+9&amp;lt;/sub&amp;gt;), és mindegyikhez kiszámolja a relatív gyakoriságok szorzatát. Utána eggyel jobbra csúsztatja az ablakot. Az új ablakban (a&amp;lt;sub&amp;gt;n+1&amp;lt;/sub&amp;gt;, ..., a&amp;lt;sub&amp;gt;n+10&amp;lt;/sub&amp;gt;) is veszi az összes lehetséges ékezetesítést. Az új ablak egy konkrét ékezetesítésére megkeresi a régi ablak bejegyzései közül azt, aminek az utolsó 9 karaktere megegyezik az új ablak első 9 karakterével. Egy új bejegyzéshez legfeljebb 4 régi tartozhat, mert az a&amp;lt;sub&amp;gt;n&amp;lt;/sub&amp;gt; karakternek legfeljebb négyféle ékezetes formája létezik. Az új 10-gram valószínűségét úgy kapjuk meg, hogy az illeszkedő régiek közül a legnagyobb valószínűségűt megszorozzuk a&amp;lt;sub&amp;gt;n+10&amp;lt;/sub&amp;gt; relatív gyakoriságával és egy súlyozótényezővel.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P(a_{n+1}, \dots, a_{n+k}) = \text{s\&amp;#039;ulyoz\&amp;#039;ot\&amp;#039;enyez\H{o}} \cdot \text{rel.gyak}(a_{n+k}) \cdot \max\limits_{a_n} P(a_n, \dots, a_{n+k-1}) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A feldolgozás végén a szöveg utolsó lehetséges 10-gramjai közül kiválasztjuk a legvalószínűbbet és visszakövetjük, hogy jutottunk oda. Így kapjuk meg a teljes szöveg ékezetesítését.&lt;br /&gt;
&lt;br /&gt;
====Az algoritmus hatékonyságának elemzése====&lt;br /&gt;
&lt;br /&gt;
Az algoritmusok hatékonyságát úgy mérem, hogy a szövegben lévő magánhangzók mekkora részének találja el helyesen az ékezeteit.&lt;br /&gt;
* Naiv algoritmus: sehova nem írok be ékezetet. Körülbelül 72% a találati arány.&lt;br /&gt;
* Mohó algoritmus: csak minimálisan jobb, 80-82%-os eredményt lehet vele elérni.&lt;br /&gt;
* Dinamikus programozásos algoritmus: a korpusz méretétől függően 96-98% az eredmény. Ha a szöveg sok idegen nyelvű kifejezést tartalmaz (pl. Elosztott rendszerek jegyzet), 95%-ra romlik a hatékonyság.&lt;br /&gt;
&lt;br /&gt;
====Tipikus hibák====&lt;br /&gt;
&lt;br /&gt;
* Az 1000 dokumentumos korpusznál a katedrális szót katédrálisra javította. Magyarázat: a katedrális nem szerepel egyik [origo] cikkben sem. Amikor a negyedik betűről kellene eldönteni, hogy e vagy é legyen,  a &amp;quot;kate&amp;quot; 34-szer szerepel a fában, míg a &amp;quot;katé&amp;quot; egyszer sem. Ezért a következő leghosszabb szuffixszal, az &amp;quot;até&amp;quot;-val számolok, ami 456-szor fordul elő. Ezt az eltérést az n-gram hosszával való súlyozás sem tudja kompenzálni. A 3000 dokumentumból álló korpusszal már eltalálta a helyes ékezeteket.&lt;br /&gt;
* Az átkozottul szóból átközöttül lesz. Az ok hasonló. Az átkozott szó nagyon ritkán szerepel, a között sokkal gyakrabban, ezért végül az utóbbi mellett döntött a program még akkor is, ha nem szóköz szerepel előtte. A között szónak a leggyakoribb u/ú/ü/ű betűs folytatása a közöttük, innen jön az ü.&lt;br /&gt;
&lt;br /&gt;
Kipróbáltam azt, hogy a valószínűségeket nem egyszerűen a n-gram hosszával súlyozom, hanem egy gyorsabban növekvő függvénnyel. A 2&amp;lt;sup&amp;gt;hossz&amp;lt;/sup&amp;gt; választás érezhetően javított a pontosságon, de efelett már nem volt mérhető a változás.&lt;br /&gt;
&lt;br /&gt;
===Továbbfejlesztési lehetőségek===&lt;br /&gt;
&lt;br /&gt;
* Memóriahasználat csökkentése. Hosszabb n-gramok használatához sokkal több memória kell, mert csökken a redundancia, így egyelőre nem végeztem velük teszteket.&lt;br /&gt;
* Kiértékelő függvény megváltoztata úgy, hogy elkerülje a jelenleg előforduló típushibákat.&lt;br /&gt;
* Korpusz gyorsabb betöltése lemezről.&lt;br /&gt;
&lt;br /&gt;
-- [[PallosPeter|Peti]] - 2007.01.25.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Valaszthato]]&lt;/div&gt;</summary>
		<author><name>Unknown user</name></author>
	</entry>
</feed>