<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>AI Playground &#187; Web</title>
	<atom:link href="http://www.aiplayground.org/thema/web/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.aiplayground.org</link>
	<description>Thoughts on artificial intelligence, cognitive science, academia, and life in general.</description>
	<lastBuildDate>Thu, 25 Mar 2010 22:04:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Find Similar Users on del.icio.us</title>
		<link>http://www.aiplayground.org/artikel/delicious-mates/</link>
		<comments>http://www.aiplayground.org/artikel/delicious-mates/#comments</comments>
		<pubDate>Tue, 20 May 2008 14:18:18 +0000</pubDate>
		<dc:creator>Andreas</dc:creator>
				<category><![CDATA[Daten]]></category>
		<category><![CDATA[Programmieren]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.aiplayground.org/?p=294</guid>
		<description><![CDATA[Download: delicious_mates.py On the social bookmarking site del.icio.us, you can add other users to your network to see their recent bookmarks aggregated on one page. There are two kinds of people in my network: 1. Friends and 2. Users I don&#8217;t know personally, but who regularly post interesting links. People who bookmark the same things [...]]]></description>
			<content:encoded><![CDATA[<p class="abstract" style="width:547px">Download: <a href="http://www.aiplayground.org/code/delicious_mates.py">delicious_mates.py</a></p>
<p><img src="http://www.aiplayground.org/wp-content/uploads/2008/05/delicioususers2.png" alt="" title="delicioususers2" class="aligncenter size-full wp-image-296" /></p>
<p>On the social bookmarking site <a href="http://del.icio.us">del.icio.us</a>, you can add other users to your network to see their recent bookmarks aggregated on one page. There are two kinds of people in my network: 1. Friends and 2. Users I don&#8217;t know personally, but who regularly post interesting links. People who bookmark the same things that I bookmark are likely to have similar interests and are thus likely to continue bookmarking interesting things in the future. Since the information on who bookmarked what URL is public, the process of finding people with similar interests can be automated. </p>
<p>Urban Hafner <a href="http://bettong.net/articles/2005/04/02/project-idea-1-find-similar-users-of-del-icio-us">brought up this idea</a> three years ago, but I could not find an implementation. Yesterday, I wrote a short Python (2.5) script that implements the following ideas:</p>
<ol>
<li>Look at every link in your bookmarks: Who bookmarked the same page? Add these users to a list of people possibly similar to you.</li>
<li>The more bookmarks another user has in common with you, the higher your similarity.</li>
<li>The smaller the number of people who bookmarked a page, the more significant the fact that another user has this bookmark in common with you.</li>
<li>If a user has lots of bookmarks, common bookmarks are less remarkable. The percentage of common links counts.</li>
</ol>
<p>Here is what you need to do to find people whose interests are similar to yours:</p>
<ol id="download">
<li>Download <a href="http://www.aiplayground.org/code/delicious_mates.py">delicious_mates.py</a></li>
<li>Run python ./delicious_mates.py</li>
<li>Wait — this takes some time.</li>
</ol>
<p>Then, what you will see will look something like this:</p>
<pre>
<code>andreas> python ./delicious_mates.py
<strong>Your del.icio.us username?</strong> andreas.s
<strong>Your del.icio.us password?</strong>

<strong>Fetching list of bookmarks ... (485)</strong>

<strong>Fetching list of users for each bookmark ...</strong>
    1. http://en.wikipedia.org/wiki/Langton's_ant (7)
    2. http://www.nytimes.com/2008/05/13/science/13coat.html?_r=2&amp;partner=rssnyt&amp;emc=rss&amp;oref=slogin&amp;oref=login (0)
    3. http://sifter.org/~simon/journal/20080509.2.html (2)
    4. http://www.intercult.su.se/cultaptation/tournament.php (16)
    5. http://www.pnas.org/cgi/content/abstract/0801268105v1 (49)
    6. http://atlas-conferences.com/c/a/n/i/15.htm (0)
	[..]
    480. http://lifeboat.com/ex/main (129)
    481. http://prize.hutter1.net/ (137)
    482. http://www.psg.com/~dlamkins/sl/cover.html (194)
    483. http://www.idsia.ch/~juergen/ (157)
    484. http://sl4.org/wiki/ShannonInformation (1)
    485. http://www.scottaaronson.com/writings/ (13)

<strong>Finding 50 candidates from list of 49937 users ...</strong>
    rainer (42/9367) ok
    siggiB (36/1006) ok
    fhtagn (35/2471) ok
    anissimov (35/6281) ok
    jbone (41/19982) ok
    invisibleandpink (16/203) ok
    irchans (16/610) ok
    ferrouswheel (14/946) ok
	[..]
    eggywat (14/4290) ok
    Cunya (8/3133) ok
    getpost (13/9787) ok
    hannu (12/3915) ok
    lispmeister (11/2967) ok
    dean.vanniekerk (12/5873) ok
    rgrant (9/1769) ok

<strong>Top 50 del.icio.us mates:</strong>
username             weight               # common bookmarks   # total bookmarks    % common
——————————————————————————————————————————————————————————————————————————————————————————————
siggiB               54.92937             36                   1022                 3.52250
invisibleandpink     53.05635             16                   203                  7.88177
fhtagn               20.61878             36                   2474                 1.45513
irchans              15.61606             16                   611                  2.61866
fogeli               12.85109             16                   628                  2.54777
ferrouswheel         7.99177              14                   946                  1.47992
rainer               7.60971              43                   9423                 0.45633
anissimov            6.46154              34                   6309                 0.53891
pdorrell             4.10251              19                   3041                 0.62479
jefallbright         3.87392              12                   1193                 1.00587
ladro                3.76458              12                   1526                 0.78637
miguel1626           3.04347              11                   1039                 1.05871
jbone                2.62672              41                   20039                0.20460
hartmut              2.15612              9                    1316                 0.68389
asciilifeform        2.04304              10                   1581                 0.63251
tmalin               1.89627              12                   2181                 0.55021
herrmann             1.84991              21                   5410                 0.38817
jas0nm               1.82646              20                   3808                 0.52521
[..]
</code>
</pre>
<p>If you look at the script, you will find a few settings you might want to change. For each of these holds: The higher you set them, the more time it takes for the script to finish.</p>
<ul>
<li>
<pre style="display: inline">MAX_MATES</pre>
<p> is the maximum number of similar users the script suggests.</p>
</li>
<li>
<pre style="display: inline">MAX_BOOKMARKS</pre>
<p> defines how many of your bookmarks the script will look at.</p>
</li>
<li>
<pre style="display: inline">BOOKMARK_FILTER</pre>
<p> defines which types of bookmarks are analyzed. Remove
<pre style="display: inline">, "no"</pre>
<p> from
<pre style="display: inline">{"shared" : [None, "yes", "no"]}</pre>
<p> to exclude private bookmarks.</p>
</li>
<li>
<pre style="display: inline">MATE_MIN_BOOKMARKS</pre>
<p> sets a minimum for the number of bookmarks a del.icio.us user needs to have before he can be considered to be similar to you.</p>
</li>
<li>
<pre style="display: inline">MATE_MIN_COMMON</pre>
<p> sets a minimum to the number of bookmarks a user has to have in common with you to be included in the list of similar users.</p>
</li>
</ul>
<p>The script needs two Python modules, the parser <a href="http://crummy.com/software/BeautifulSoup">BeautifulSoup</a> and Michael Noll&#8217;s <a href="http://www.michael-noll.com/wiki/Del.icio.us_Python_API">del.icio.us Python API</a>. If the script does not find one of the modules, it will download the missing module to the current directory and import it from there. If you don&#8217;t like this because you believe this is a security nightmare (which it is), <strike>don&#8217;t run delicious_mates.py</strike> install the two modules beforehand.</p>
<p>Do you know some Javascript and have spare time? I would love to see the script converted into a <a href="http://johnvey.com/features/deliciousdirector/">direc.tor</a>-like bookmarklet. The need to download and run a Python script makes finding similar users more complicated than it <a href="http://www.urbandictionary.com/define.php?term=Chould">chould</a> be.</p>
<p>The feature I like best about the online bookshelf <a href="http://www.librarything.com">LibraryThing</a> is its <a href="http://www.librarything.com/unsuggester">Unsuggester</a>: Name a book you have read and it suggests those books that are least likely to be on your bookshelf. I like it because it is a means to counteract the temptation to adjust your sources of information such that whatever you read reinforces your point of view. Seeing how easy it is to give in to this temptation, is a script that makes it easier to surround yourself with like-minded people just one more sign of a general trend towards biased, largely isolated online communities?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aiplayground.org/artikel/delicious-mates/feed/</wfw:commentRss>
		<slash:comments>80</slash:comments>
		</item>
		<item>
		<title>Ein Ranking f&#252;r Lernalgorithmen</title>
		<link>http://www.aiplayground.org/artikel/ranking/</link>
		<comments>http://www.aiplayground.org/artikel/ranking/#comments</comments>
		<pubDate>Thu, 05 Apr 2007 00:39:58 +0000</pubDate>
		<dc:creator>Andreas</dc:creator>
				<category><![CDATA[Informatik]]></category>
		<category><![CDATA[Künstliche Intelligenz]]></category>
		<category><![CDATA[Programmieren]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.aiplayground.org/artikel/ranking/</guid>
		<description><![CDATA[Projektidee: Ein automatisch erstelltes und aktualisiertes Ranking von Algorithmen f&#252;r maschinelles Lernen macht Fortschritte auf dem Gebiet der allgemeinen k&#252;nstlichen Intelligenz sicht- und messbar. Das Messverfahren Lernverfahren wie rekurrente neuronale Netze, Markov-Modelle und genetische Algorithmen sollen akkurate Vorhersagen liefern. Wissenschaftliche Ver&#246;ffentlichungen sprechen davon, dass der jeweils vorgestellte Algorithmus &#8220;auf gewisse Weise&#8221; optimal ist. F&#252;r das [...]]]></description>
			<content:encoded><![CDATA[<p class="abstract">Projektidee: Ein automatisch erstelltes und aktualisiertes Ranking von Algorithmen f&#252;r maschinelles Lernen macht Fortschritte auf dem Gebiet der allgemeinen k&#252;nstlichen Intelligenz sicht- und messbar.</p>
<h2>Das Messverfahren</h2>
<p>Lernverfahren wie rekurrente neuronale Netze, Markov-Modelle und genetische Algorithmen sollen akkurate Vorhersagen liefern. Wissenschaftliche Ver&#246;ffentlichungen sprechen davon, dass der jeweils vorgestellte Algorithmus &#8220;auf gewisse Weise&#8221; optimal ist. F&#252;r das Gebiet der <a href="/artikel/agi/">allgemeinen k&#252;nstlichen Intelligenz</a> ist interessant, zu wissen, welcher Algorithmus <em>allgemein</em> am besten geeignet ist, d.h. f&#252;r die Vorhersage von Sequenzen, &#252;ber die wir lediglich wissen, dass sie von einem berechenbaren Prozess generiert wurden und dass einfache Erkl&#228;rungen wahrscheinlicher sind als komplizierte.</p>
<p>Eine Sequenz ist eine endliche oder unendliche Folge von Symbolen eines Alphabets (z.B. {0, 1}). Die meisten endlichen Sequenzen sind nicht effektiv lernbar, da kein Programm mit im Vergleich zur Sequenz kurzer Beschreibung existiert, das diese Sequenzen deterministisch ausgibt. Das hei&#223;t: Die <a href="http://en.wikipedia.org/wiki/Kolmogorov_complexity">Kolmogorov-Komplexit&#228;t</a> der meisten endlichen Sequenzen entspricht der L&#228;nge der Sequenzen. F&#252;r den Vergleich verschiedener Lernalgorithmen beschr&#228;nken wir uns auf unendliche Sequenzen mit endlich langen Erzeugerprogrammen.</p>
<p>Ein Vorhersagealgorithmus ist dann <em>allgemein</em> besser als ein anderer, wenn er lernen kann, Sequenzen mit h&#246;herer Kolmogorov-Komplexit&#228;t vorherhersagen (und beide einfache Sequenzen gleich gut vorhersagen k&#246;nnen). Praktisch jeder Algorithmus wird folgende Sequenz von sehr niedriger Komplexit&#228;t lernen k&#246;nnen:</p>
<p><code>111111111111111111111111111111111111111111...</code></p>
<p>Bei etwas h&#246;herer Komplexit&#228;t werden einige Algorithmen Probleme bekommen:</p>
<p><code>011011100101110111100010011010101111001101...</code></p>
<p>H&#228;tte man eine Datenbank, die jedes sequenzerzeugende Programm (oder jede Sequenz) sowie die Komplexit&#228;t der von jedem Programm generierten Sequenz speichert, so k&#246;nnte man f&#252;r eine Reihe von Algorithmen Tests durchf&#252;hren, um herauszufinden, in welchem Umfang und bis zu welcher Komplexit&#228;t jeder Algorithmus Sequenzen lernen kann. Mit den Ergebnissen dieser Tests lie&#223;e sich ein Ranking erstellen, das auf einen Blick verr&#228;t, welcher Algorithmus die meisten und komplexesten Sequenzen lernen kann.</p>
<p>Eine solche Datenbank ist unm&#246;glich: Es gibt unendlich viele sequenzerzeugende Programme, die Sequenzen sind unendlich lang und deren Komplexit&#228;t ist nicht algorithmisch bestimmbar.</p>
<p>Die Menge der sequenzerzeugenden Programme ist eine Teilmenge aller Programme, und diese Menge ist <em>aufz&#228;hlbar</em> unendlich. Die Kolmogorov-Komplexit&#228;t ist definiert als die L&#228;nge des k&#252;rzesten Programms, das eine Sequenz erzeugt. Generiert man alle Programme, angefangen mit dem k&#252;rzesten, so ist bekannt, ob bereits ein k&#252;rzeres Programm den gleichen Sequenzbeginn (eine festgelegte Anzahl von Zeichen, z.B. 10.000) erzeugt hat oder ob die L&#228;nge des gerade betrachteten Programms als Absch&#228;tzung der Komplexit&#228;t der erzeugten Sequenz verwendet werden kann — Absch&#228;tzung deshalb, weil nur eine endliche Anzahl der Zeichen zweier Sequenzen verglichen werden k&#246;nnen und <a href="http://de.wikipedia.org/wiki/Satz_von_Rice">nach Rice</a> nicht algorithmisch festgestellt werden kann, ob zwei Programme die gleiche Funktion berechnen.</p>
<p>Mit einigen Absch&#228;tzungen ist es m&#246;glich, Ausschnitte der beschriebenen Datenbank zu erstellen, die in der Komplexit&#228;t nach oben beschr&#228;nkt sind:</p>
<ol>
<li>Wir generieren der Reihe nach Turingmaschinen mit leerem Eingabe- bzw. Arbeitsband und nur in einer Richtung beschreibbarem Ausgabeband, angefangen mit der k&#252;rzesten.</li>
<li>Uns interessieren nur Turingmaschinen, die unendliche Sequenzen generieren:
<ul>
<li>H&#228;lt eine Turingmaschine an, so verwerfen wir diese Turingmaschine.</li>
<li>Hat eine Turingmaschine nach 10^12 Schritten noch keine 10.000 Ausgabesymbole erzeugt, so verwerfen wir diese Turingmaschine.</li>
</ul>
<p style="margin-bottom: 0">Andernfalls nehmen wir an, dass die aktuelle Turingmaschine eine der Turingmaschinen ist, die eine unendliche lange Sequenz ausgeben (Absch&#228;tzung I).</p>
</li>
<li>Wenn die ersten 10.000 Zeichen der Sequenz, die eine Turingmaschine erzeugt, noch von keiner anderen Turingmaschine erzeugt wurden, speichern wir die L&#228;nge der Beschreibung der Turingmaschine sowie die 10.000 Zeichen der Sequenz in einer Datenbank.</li>
<li>Die gespeicherte L&#228;nge entspricht in etwa der L&#228;nge der k&#252;rzesten Turingmaschine, die die Sequenz generiert und ist damit ein Ma&#223; f&#252;r die Kolmogorov-Komplexit&#228;t der Sequenz (Absch&#228;tzung II).</li>
</ol>
<p>Das wiederholen wir, bis die Datenbank &#8220;gro&#223; genug&#8221; ist. In einer 150 GB gro&#223;en Datenbank lassen sich bei 10.000 Zeichen pro Sequenzabschnitt etwa 100 Millionen unterschiedliche Sequenzabschnitte speichern. </p>
<h2>Der kritische Punkt</h2>
<p>Ist die Komplexit&#228;t der einfachsten in der Datenbank gespeicherten Sequenzen so gering, dass diese mit den meisten Vorhersagealgorithmen gelernt werden k&#246;nnen und die Komplexit&#228;t der komplexesten Sequenzen so gro&#223;, dass das Lernen der Sequenz mit aktuellen Vorhersagealgorithmen nicht mehr m&#246;glich ist?</p>
<p>Werden in dieser Datenbank &#8220;interessante&#8221; Sequenzen — Sequenzen von nichttrivialer Komplexit&#228;t — vorkommen? Oder lediglich 50 Millionen unterschiedliche, sich wiederholende Muster? Wie sieht es aus, wenn die einfachsten Sequenzen herausgefiltert und verworfen werden? Wie sieht es aus, wenn stets der Gro&#223;teil der Sequenzen verworfen wird, die von den Top 20 Algorithmen zuverl&#228;ssig vorhergesagt werden?</p>
<p>Bei zwei Bandzust&#228;nden (0 und 1) und n internen Zust&#228;nden gibt es (4*n)^(2*n) verschiedene Turingmaschinen mit einem in beide Richtungen bewegbaren Band. Die Anzahl der Turingmaschinen steigt schon bei wenigen Zust&#228;nden sehr schnell an:</p>
<p>1 interner Zustand: 16 TM<br />
2 interne Zust&#228;nde: 4096 TM <a style="color: #ccc" href="http://www.wolframscience.com/nksonline/page-1120a-text">(25 unterschiedliche)</a><br />
3 interne Zust&#228;nde: 2.985.984 TM <a style="color: #ccc" href="http://www.wolframscience.com/nksonline/page-1120a-text">(16.400 unterschiedliche)</a><br />
4 interne Zust&#228;nde: 4.294.967.296 TM<br />
5 interne Zust&#228;nde: 10.240.000.000.000 TM<br />
6 interne Zust&#228;nde: 36.520.347.436.056.576 TM<br />
7 interne Zust&#228;nde: 182.059.119.829.942.534.144 TM</p>
<p><a href="http://www.wolframscience.com/nksonline/page-79">Nach Stephen Wolfram</a> st&#246;&#223;t man auf interessantes Verhalten, sobald man Turingmaschinen mit mindestens vier internen Zust&#228;nden betrachtet. Die minimale Zahl der internen Zust&#228;nde einer Turingmaschine, die eine bestimmte Sequenz berechnet, dient als Ma&#223; f&#252;r die Komplexit&#228;t der berechneten Sequenz. Ist das Ranking brauchbar, wenn keine Turingmaschinen mit mehr als sieben internen Zust&#228;nden betrachtet werden?  Lambda Calculus, wie von <a href="http://homepages.cwi.nl/~tromp/cl/cl.html">John Tromp</a> vorgeschlagen, k&#246;nnte die bessere Wahl sein. Das Ranking k&#246;nnte sich jedoch auch damit als unbrauchbar erweisen.</p>
<h2>Beantwortete Fragen</h2>
<p>Bislang ist es schwierig, einige Fragen aus dem Bereich des maschinellen Lernens zu beantworten. L&#228;sst sich ein Ranking f&#252;r Lernalgorithmen umsetzen, so wird sich das f&#252;r folgende Fragen &#228;ndern:</p>
<p><strong>Wie sieht der aktuelle Stand der Forschung aus? Oder: Das Ranking.</strong></p>
<ol>
<li>Alle bekannteren Vorhersagealgorithmen werden in einer festgelegten Programmiersprache implementiert und zum Ranking hochgeladen.</li>
<li>Jeder Algorithmus wird mit allen oder mit einer statistisch relevanten Auswahl an Sequenzen getestet und erh&#228;lt einen Score zugeteilt, der besagt, f&#252;r wie viele Sequenzen und bis zu welcher Komplexit&#228;t der Algorithmus zuverl&#228;ssige Vorhersagen macht.</li>
<li>Ein Ranking wird erstellt, bei dem die Algorithmen mit dem h&#246;chstem Score an der Spitze stehen.</li>
</ol>
<p><strong>Wie gut ist mein Vorhersagealgorithmus?</strong></p>
<ol>
<li>Ein in einer festgelegten Programmiersprache geschriebener Algorithmus wird auf der Website des Rankings hochgeladen.</li>
<li>Der Algorithmus wird mit allen oder mit einer statistisch relevanten Auswahl an Sequenzen getestet und erh&#228;lt einen Score zugeteilt (s.o).</li>
<li>Die Leistung des Algorithmus kann dadurch mit der anderer Algorithmen verglichen werden und der Algorithmus kann in die Highscore-Liste aufgenommen werden.</li>
</ol>
<p><strong>Welcher Algorithmus ist f&#252;r mein Vorhersageproblem geeignet?</strong></p>
<ol>
<li>Sequenzen, die typisch f&#252;r das Problem sind, werden auf der Website des Rankings hochgeladen.</li>
<li>Alle Algorithmen, die am Ranking teilnehmen, werden auf die hochgeladenen Sequenzen angewendet.</li>
<li>Ein nach Korrektheit der Vorhersagen sortiertes, problem-spezifisches Ranking wird ausgegeben.</li>
</ol>
<h2>Offene Fragen</h2>
<ul>
<li>Soll die Programml&#228;nge mit in die Berechnung des Scores eines Algorithmus einbezogen werden oder soll es lediglich ein generelles Limit f&#252;r alle Programme geben?</li>
<li>Welche Limits sollen f&#252;r Laufzeit und Programml&#228;nge gesetzt werden?</li>
<li>Wie lange sollen die Sequenzabschnitte sein, die in der Datenbank gespeichert werden? 10.000 Zeichen?</li>
<li>Wie sollen die Sequenzabschnitte in Lernsequenz (die den Algorithmen pr&#228;sentiert wird) und Testsequenz (die vorherzusagen ist) aufgeteilt werden? Wie lang soll der vorherzusagende Abschnitt sein?</li>
<li>Wie wird die Vorhersage bewertet? Gelten nur komplett richtige Vorhersagen?</li>
<li>Sollen auch die k&#252;rzeren Ausgaben von anhaltenden Turingmaschinen miteinbezogen werden?</li>
<li>Ein praxistauglicher Algorithmus k&#246;nnte stark von zus&#228;tzlichen Annahmen &#252;ber seine Umgebung abh&#228;ngig sein. <em>Ideal</em> sind Vorhersage- und Komprimierungsalgorithmen nur f&#252;r jeweils eine einzige Wahrscheinlichkeitsverteilung an Eingaben. Ob ein Algorithmus, der f&#252;r die allgemeinste berechenbare Wahrscheinlichkeitsverteilung an Eingaben ideal ist, auch in der wirklichen Welt <em>brauchbar</em> ist, ist nicht gekl&#228;rt.</li>
<li>Ist es zweckm&#228;&#223;iger, probabilistische Sequenzen und Vorhersagealgorithmen statt exakter Algorithmen zuzulassen?</li>
<li>Wie wird der Score berechnet? Z&#228;hlen Sequenzen mit niedrigerer Komplexit&#228;t mehr oder weniger? Wie wird ein Vorhersagealgorithmus bewertet, der zwar komplexe Sequenzen vorhersagen kann, aber bei sehr vielen Sequenzen von niedriger Komplexit&#228;t fehlschl&#228;gt?</li>
<li>Welche Implementation eines universellen Computers ist am sinnvollsten? Turingmaschinen? Lambda Calculus?</li>
</ul>
<h2>Fazit</h2>
<p>Marcus Hutter hat in <a href="http://arxiv.org/pdf/cs.AI/0306091v1">seiner  Doktorarbeit</a> bewiesen, dass die optimale Vorgehensweise einer k&#252;nstlichen Intelligenz darin besteht, nach einer beliebigen Anzahl von Beobachtungen der Umgebung das k&#252;rzeste Programm zu finden, das diese Beobachtungen vorhersagt und anzunehmen, dass die Umgebung durch dieses Programm kontrolliert wird. Verbesserte allgemeine Vorhersagealgorithmen sind demnach mit Fortschritt auf dem Gebiet der k&#252;nstlichen Intelligenz gleichzusetzen. </p>
<p>Alles, was gemessen wird, verbessert sich. Ich schlage vor, eine Datenbank mit Sequenzabschnitten und zugeh&#246;riger (gesch&#228;tzter) Kolmogorov-Komplexit&#228;t anzulegen, diese Sequenzen von verschiedenen Lernalgorithmen vorhersagen zu lassen und den Erfolg der Algorithmen in einem Ranking sichtbar zu machen.</p>
<p>Ist diese Idee realistisch?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aiplayground.org/artikel/ranking/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Improving Django: Generic views for RESTful web services</title>
		<link>http://www.aiplayground.org/artikel/improving-django/</link>
		<comments>http://www.aiplayground.org/artikel/improving-django/#comments</comments>
		<pubDate>Fri, 23 Mar 2007 22:27:43 +0000</pubDate>
		<dc:creator>Andreas</dc:creator>
				<category><![CDATA[Informatik]]></category>
		<category><![CDATA[Programmieren]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.aiplayground.org/artikel/improving-django/</guid>
		<description><![CDATA[Django is my web programming framework of choice. The following 1.500 words describe what I would add to the core framework in order to make machine-to-machine communication (APIs) for almost every web application a matter of minutes. Abstract I suggest a general method offering a public and private API for existing Django models. New generic [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.djangoproject.com/">Django</a> is my web programming framework of choice. The following 1.500 words describe what I would add to the core framework in order to make machine-to-machine communication (APIs) for almost <em>every</em> web application a matter of minutes.<span id="more-144"></span></p>
<h2>Abstract</h2>
<p>I suggest a general method offering a public and private API for existing Django models. New generic views will simplify data retrieval and modification via different web services in a resource-centric REST architecture, providing model data in formats such as XML, JSON and YAML with very little custom code.</p>
<h2>Implementation</h2>
<p>The most widely used browsers don't support PUT and DELETE in web forms without using AJAX, therefore it is impossible to achieve a pure REST implementation. Nonetheless a more RESTful resource-centric approach makes sense: With a unique hyperlink address for every resource, resource discovery from content becomes much easier. With all resources sharing a common interface, programs written in any language can talk to Django instances in a standardized way. The partial lack of browser support for PUT and DELETE can be compensated by adding an extra hidden field to forms that carries the method information.</p>
<p>The code that tells Django which web service should be provided for which model at which URL will not to be attached to the individual model classes but will live at the view level. There are two reasons for this:</p>
<ol>
<li>REST is only one way of looking at a Django application and therefore should not be part of the underlying model.</li>
<li>There is no one-to-one mapping between resources and models. Resources have more to do with the user interface than with the underlying database structure. Sometimes it will be sufficient to apply the CRUD actions to models, but sometimes there will be the need for more complex resources (e.g. one resource that consists of several related models, service discovery). It is important to me that there is an obvious way of using both the generic views and custom developments consistently in one Django project.</li>
</ol>
<p>I will solve this by writing a general Resource class as an interface. Each method of Resource raises a Http404 exception by default. Custom resources inherit from Resource and may implement the methods __call__ (thus providing the equivalent of current view functions), create, retrieve, list, update, delete, get_create_form and get_update_form (cf. djangocollection). The ModelResource class that covers all the cases where there is a one-to-one mapping between a model and a resource inherits from the class Resource.</p>
<p>When using the ModelResource class we need to be able to set a few options:</p>
<ul>
<li>Which data should be accessible?</li>
<li>Which CRUD actions should be possible?</li>
<li>Which model fields should be visible?</li>
<li>Which type of authentication is required?</li>
<li>How should the output look like (xml, json, html, yaml, ...)?</li>
</ul>
<p>I imagine the urls.py to look like this (similar to <a href="http://groups.google.com/group/django-users/msg/aa70d857b6ad3b76?hl=en">a draft by Jacob Kaplan-Moss</a>):</p>
<div class="igBar"><span id="lpython-2"><a href="#" onclick="javascript:showPlainTxt('python-2'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">PYTHON:</span>
<div id="python-2">
<div class="python">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #0B3BC6;font-weight: bold;">from</span> mysite.<span style="color: black;">polls</span>.<span style="color: black;">models</span> <span style="color: #0B3BC6;font-weight: bold;">import</span> Poll</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #0B3BC6;font-weight: bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #0B3BC6;font-weight: bold;">import</span> *</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #0B3BC6;font-weight: bold;">from</span> django.<span style="color: black;">contrib</span> <span style="color: #0B3BC6;font-weight: bold;">import</span> restapi</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">poll_api = <span style="color: black;">&#123;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; queryset : Poll.<span style="color: black;">objects</span>.<span style="color: black;">all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>,</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; allowed_operations : <span style="color: black;">&#40;</span>restapi.<span style="color: black;">READ</span>, restapi.<span style="color: black;">UPDATE</span><span style="color: black;">&#41;</span>,</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; expose_fields : <span style="color: black;">&#40;</span><span style="color: #2B9030;">'id'</span>, <span style="color: #2B9030;">'question'</span>, <span style="color: #2B9030;">'pub_date'</span><span style="color: black;">&#41;</span>,</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; authentication_method : restapi.<span style="color: black;">APIKeyAuthentication</span>,</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; output_function : restapi.<span style="color: black;">json_response</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: black;">&#125;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #2B9030;">''</span>,</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color: black;">&#40;</span>r<span style="color: #2B9030;">'^json/polls/(?:(?P&lt;id&gt;<span style="color: #000099; font-weight: bold;">\d</span>+)/?)?(?:;(?P&lt;noun&gt;<span style="color: #000099; font-weight: bold;">\w</span>+))?/?$'</span>, <span style="color: #2B9030;">'django.contrib.restapi.ModelResource'</span>, poll_api<span style="color: black;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: black;">&#41;</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>In order for our resource implementation to be REST-friendly, each resource needs to have a unique URL. If the content format is not specified by the URL and if there is more than one content format per app, looking at the HTTP headers may be sufficient to choose which content to deliver (we could set output_format to restapi.DETECT_FORMAT).</p>
<p>The functionality of the new generic RESTful views will comprise a large part of the functionality of the current generic create_update and list_detail views. This includes the ability to supply the views with a filtered queryset, pagination, response mimetype, allow_empty, post_save_redirect and post_delete_redirect.</p>
<p>In contrast to the current generic views the ModelResource class will not use templates by default. Instead, in order to follow the DRY principle, they could call a user-supplied output function (e.g. xml_response, json_response) depending on which type of response (xml, json, ...) to return. I'm still thinking about how the most elegant solution will look like. I'll be happy to hear suggestions.</p>
<p>Another issue that still needs to be resolved is how to get authentication right. The consensus of ticket #115 seems to be that HTTP Basic Authentication over SSL is "secure enough" but that the risk of people not using SSL is quite high. Both public and private web services will be possible.</p>
<p>Web development shouldn't be monotonous. Setting up APIs can be. I'd like to automate this as far as possible without taking away the freedom to extend or replace the API with more complex solutions.</p>
<h2>Existing Code</h2>
<p>There exists a fair amount of code that might be useful for this project.</p>
<p>There is john@sneeu.com who wrote at ticket #2553:</p>
<blockquote><p>I've written a RESTful API (similar urls to the 'oldforms' Admin), it needs a bit of a tidy up, and a few more tweaks but I'm more than happy for it to be incorporated in to Django in any way.</p></blockquote>
<p>Jason Huggins mentions in the discussion of ticket #115 (Models CRUD via web services):</p>
<blockquote><p>I have a fair enough amount of code already written for this ticket. If possible, I'd like a branch in subversion set up so I can check in my code and we can start talking about real example code.</p></blockquote>
<p>Jacob Kaplan-Moss to whom the ticket is assigned may have started writing some code that can be used for both REST and RPC. He wrote:</p>
<blockquote><p>Jason (and others): if you've got code that's not attached to this ticket or to #356, #547 or #552 please attach it to this one as I'm going to try to get some work done on this Any Day Now™.</p></blockquote>
<p>More recently, Adam Smith has started working on <a href="http://code.google.com/p/django-restful-model-views/">django-restful-model-views</a> which intends to make it easier to create ReSTful Web applications with Django. In the current stage this is still more of a proof-of-concept, but the code written by Adam Smith might turn out to be a good point to start. </p>
<p>The wsgicollection-inspired project <a href="http://code.google.com/p/djangocollection/">djangocollection</a> which provides a set of generic RESTful urls for all the models of a project and a GenericCollection which uses the django generic views illustrates a few interesting and relevant ideas, too.</p>
<p>Before getting started I will talk to those who have written possibly useful code and to the Django community in order to find out how my suggested approach can be improved and how much reusable code already exists.</p>
<h2>Benefits to Django</h2>
<p>There will be a standard interface for applications to communicate with Django projects. Making it easier for Desktop applications to use Django as a server-side backend will encourage Desktop applications to use Django as a backend. Yay.</p>
<p>An API that can return data in JSON format will make AJAX integration much easier — both for the admin app and for Django users who complain about AJAX not being as easy as with competing frameworks.</p>
<p>The value of having a dead easy way to get data in and out of Django databases is obvious. Let's make extending existing applications with a fully-fledged REST API a matter of less than five minutes.</p>
<h2>Success Criteria</h2>
<ol>
<li>A few lines of code in urls.py are sufficient to make model data CRUD-accessible via XML and JSON.</li>
<li>It is possible to create custom API resources that don't correspond directly to models. These should be integrated seamlessly into the rest of the API.</li>
</ol>
<h2>Roadmap</h2>
<ol>
<li>Assess together with those who have already written similar code whether it makes sense to start from scratch. Get feedback from the community on issues such as how ModelResource should generate different output formats and how authentication should look like.</li>
<li>In-depth planning "on paper".</li>
<li>Initialize a restapi branch.</li>
<li>Implement the Resource "interface" class.</li>
<li>Implement the ModelResource class and an elegant way to return output in at least xml and json.</li>
<li>Add authentication.</li>
<li>Write and perform unit tests.</li>
<li>Prepare the code to be merged to trunk. The Django API will likely change before v1.0. Some of the things that will be improved in a possibly backwards-incompatible way and that might play a role for this project are validation, serialization and the authentication framework.</li>
</ol>
<h2>About me</h2>
<p>I'm a 21 year old bachelor student of Cognitive Science at the University of Osnabr&#252;ck in Germany. When I'm not in Osnabr&#252;ck, I live in the small town of Dinkelscherben which is located in Bavaria. After finishing school about two years ago I decided to postpone University and spent the next year developing web applications instead. At that time I had two years of Python experience. Django became — and still is — my web framework of choice.</p>
<p>During that year, I spent quite some time making sure I understood how Django works under the hood. I <a href="http://tinyurl.com/3ak29o">participated</a> in the Django discussion groups, wrote a few patches and submitted a few <a href="http://tinyurl.com/3bfb2q">tickets</a>. My largest Django project to date is the e-learning application Mindpicnic which is fairly popular in Germany.</p>
<p>I have been planning to add a RESTful API to Mindpicnic for about as long as the project exists. I'm committed to seeing this proposal become reality. I believe I would enjoy getting more involved with the Open Source community a lot. </p>
<p class="abstract">My proposal got accepted, the latest source code is available at <a href="http://code.google.com/p/django-rest-interface/">Google Code</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aiplayground.org/artikel/improving-django/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Texten mit Markov</title>
		<link>http://www.aiplayground.org/artikel/markov/</link>
		<comments>http://www.aiplayground.org/artikel/markov/#comments</comments>
		<pubDate>Mon, 14 Feb 2005 09:27:43 +0000</pubDate>
		<dc:creator>Andreas</dc:creator>
				<category><![CDATA[Programmieren]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://ai2.stuhlmueller.info/artikel/markov/</guid>
		<description><![CDATA["Evolution works through DNA-guided protein synthesis and research dollars are halving every year for the purpose is growing exponentially." -- Ray Kurzweil selbst h&#228;tte es (nun ja, fast) nicht sch&#246;ner formulieren k&#246;nnen. Und doch stammt die Zeile direkt aus dem Computer, einem einfachen Text-Generator sei Dank. Wie das genau funktioniert und was sich hinter dem [...]]]></description>
			<content:encoded><![CDATA[<p>"Evolution works through DNA-guided protein synthesis and research dollars are halving every year for the purpose is growing exponentially." -- Ray Kurzweil selbst h&#228;tte es (nun ja, fast) nicht sch&#246;ner formulieren k&#246;nnen. Und doch stammt die Zeile direkt aus dem Computer, einem einfachen Text-Generator sei Dank. Wie das genau funktioniert und was sich hinter dem Begriff Markov-Ketten verbirgt, das soll in den folgenden Abs&#228;tzen n&#228;her erl&#228;utert werden.<span id="more-21"></span></p>
<p>Zun&#228;chst stellt sich jedoch die Frage: Wozu brauche ich &#252;berhaupt einen Text-Generator? Abgesehen davon, dass die Antwort in den meisten F&#228;llen "&#252;berhaupt nicht" lauten d&#252;rfte, fallen mir spontan einige Anwendungsm&#246;glichkeiten ein (eine sinnvoller und ernstgemeinter als die andere):</p>
<ul>
<li>Reports, Aufs&#228;tze oder Facharbeiten in letzer Minute</li>
<li>T&#228;glich neue Versionen von "Alice im Wunderland" [5]</li>
<li>Spa&#223; mit Usenet-Gruppen [4]</li>
<li>Suchmaschinenspam</li>
<li>Sinnentleerte Poesie</li>
<li>Antworten auf Nigeria-Connection-Scam-Mails [6]</li>
<li>E-Mail-Antworten auch in stressigen Zeiten [6]</li>
<li>... just for fun</li>
</ul>
<h2>Das Prinzip eines Text-Generators</h2>
<p>Das Prinzip hinter solchen Generatoren ist relativ simpel: Ein Text wird zun&#228;chst daraufhin analysiert, welche W&#246;rter mit welcher Wahrscheinlichkeit auf welche anderen W&#246;rter folgen. Betrachten wir als Beispiel das Wort "die" in diesem Artikel (so weit er bis jetzt fortgeschritten ist): Mit jeweils 25% Wahrscheinlichkeit folgen die Begriffe "Antwort", "Zeile ", "andere)" und "Frage".</p>
<p>Werden diese Wahrscheinlichkeiten f&#252;r jedes Wort gespeichert, so l&#228;sst sich -- ausgehend von einem Startwort -- ein neuer Text Wort f&#252;r Wort aufbauen. F&#252;r jedes Wort wird zuf&#228;llig ein Nachfolgewort ausgew&#228;hlt; die vorher bestimmten Wahrscheinlichkeiten entsprechen dabei den Wahrscheinlichkeiten f&#252;r die Auswahl der Nachfolgew&#246;rter.</p>
<p>Im Wikipedia-Artikel zum Thema Markov-Ketten [2] wird das zun&#228;chst mit einer f&#252;r Nicht-Mathematiker abschreckenden Formel und dann folgenderma&#223;en formuliert:</p>
<blockquote><p>(..) das hei&#223;t, dass die Wahrscheinlichkeit f&#252;r den Zustand zum Zeitpunkt t+1 nur von dem Zustand zum Zeitpunkt t abh&#228;ngt. Dies bezeichnet man als Ged&#228;chtnislosigkeit oder auch Markow-Eigenschaft.</p></blockquote>
<p>Verwenden wir als Ausgangstext (wie bereits zu Beginn dieses Artikels) das "Law of Accelerating Returns" von Ray Kurzweil [3], so sieht das Ergebnis zum Beispiel folgenderma&#223;en aus:</p>
<blockquote><p>Evolution has continuously accelerated. The subsequent emergence of the first step, the first technology-creating species resulted in the environment in power and maintain a technology-creating species, the next generation's design, and of information does not the overall "power" of data from one stage of accelerating returns pertains to biological brains. # A recording information is predictable. Noise is to create new generations of other innovations).</p></blockquote>
<p>Was auf den ersten Blick interessant aussehen mag, entpuppt sich bei genauerem Hinsehen als v&#246;lliger Unsinn. </p>
<h2>Der Markov-Algorithmus</h2>
<p>Wie wird das Modell der Markov-Ketten nun konkret als Algorithmus umgesetzt? Ein kurzes Script in der Programmiersprache Python [1] soll uns hier als Beispiel dienen.</p>
<p>Zun&#228;chst wird die Textdatei <em>markov.txt</em> eingelesen und Wort f&#252;r Wort in einer Liste gespeichert:<br />
<code>#!/usr/bin/python<br />
# -*- coding: cp1252 -*-<br />
from random import random<br />
&nbsp;<br />
f = open(&#39;markov.txt&#39;)<br />
TextIn = f.read()<br />
f.close()<br />
&nbsp;<br />
TextIn = TextIn.replace(&#39;&#92;n&#39;, &#39; &#39;)<br />
TextIn = TextIn.split(&#39; &#39;)<br />
TextIn = [n for n in TextIn if n not in &#39;&#39;]<br />
</code></p>
<p>Jetzt steht die Analyse des Textes an: F&#252;r jedes vorkommende Wort speichern wir in <em>WortDict</em>, wie oft welche anderen W&#246;rter direkt auf dieses Wort folgen:<br />
<code>WortDict = {}<br />
&nbsp;<br />
for w in range(len(TextIn)-1):<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (TextIn[w] != &#39;&#39;):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if not WortDict.has_key(TextIn[w]):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WortDict[TextIn[w]] = {}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if not WortDict[TextIn[w]].has_key(TextIn[w+1]):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WortDict[TextIn[w]][TextIn[w+1]] = 1.0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WortDict[TextIn[w]][TextIn[w+1]] += 1.0<br />
</code></p>
<p>Die Anzahl des Aufeinanderfolgens bestimmter W&#246;rter wird in Wahrscheinlichkeiten umgerechnet:<br />
<code>for (Wort, NextDict) in WortDict.items():<br />
&nbsp;&nbsp;&nbsp;&nbsp;# Gesamtzahl n&#228;chster W&#246;rter berechnen<br />
&nbsp;&nbsp;&nbsp;&nbsp;TotalCount = 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;for (NextWort, Count) in NextDict.items():<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TotalCount += Count<br />
&nbsp;&nbsp;&nbsp;&nbsp;# Zahl f&#252;r jedes n&#228;chste Wort durch Gesamtzahl teilen<br />
&nbsp;&nbsp;&nbsp;&nbsp;for (NextWort, Count) in NextDict.items():<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WortDict[Wort][NextWort] = WortDict[Wort][NextWort]/TotalCount<br />
</code></p>
<p>Schlie&#223;lich k&#246;nnen wir einen neuen Text mit einer dem Ausgangstext &#228;hnlichen Wahrscheinlichkeitsverteilung der Wortfolgen erstellen. <em>CurWort</em> legt fest, mit welchem Wort der Text beginnen soll, <em>LenText</em> die maximale Anzahl an W&#246;rtern. Zur Auswahl des jeweils n&#228;chsten Wortes werden die Einzel-Wahrscheinlichkeiten f&#252;r s&#228;mtliche M&#246;glichkeiten als Aufteilung des Bereichs [0;1] gesehen und festgestellt, wo in diesem Bereich sich die Zufallszahl x befindet. Der so gew&#228;hlte Bereich legt das n&#228;chste Wort fest.<br />
<code>CurWort = &#39;Evolution&#39;<br />
LenText = 30<br />
Text = CurWort<br />
&nbsp;<br />
for n in range(200):<br />
&nbsp;&nbsp;&nbsp;&nbsp;x = random()<br />
&nbsp;&nbsp;&nbsp;&nbsp;ProbSum = 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;for (NextWort, Prob) in WortDict[CurWort].items():<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (x >= ProbSum) and (x < ProbSum+Prob):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Text += " " + NextWort<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CurWort = NextWort<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProbSum += Prob<br />
&nbsp;<br />
# Ausgabe des Textes bis zum letzen Punkt.<br />
print Text[:Text.rfind(&#39;.&#39;)+1]<br />
</code></p>
<h2>Beispiele f&#252;r generierte Texte</h2>
<p>Was k&#246;nnte ein solcher Markov-Prozess nun mit inhaltlich wertvollen Texten wie der Cyberkultur-Reihe [7] des franz&#246;sischen Philosophen Pierre Lévy anstellen? Na, zum Beispiel das:</p>
<blockquote><p>Die Verbindung von virtuellen Welten, durch die Bildschirme. Dann entdeckte ich, da&#223; die Computernetze zugunsten der modernen Demokratie gek&#228;mpft ... und institutionalisiert, die Papierseiten mit der Verteilung ausgehend von allem in dem Cyberspace mehr aus einer Totalit&#228;t, deren Kommunikationspraxis konnte eine kulturelle Universum an ihren Hervorbringungen haben wir uns in den Seiten anderer Dokumente verbindet, weil er ist, neue Verkaufsargumente. Symmterisch dazu verdammt, den traditionellen Medien legitimiert wird? Diejenigen, die bestehenden Infrastrukturen zu schaffen, Information darstellt, sollte gem&#228;&#223; dem begrenzten Programm der gro&#223;en Menge von Gruppen, Beziehungsstile zwischen den Cyberspace beeinflussen.</p></blockquote>
<p>Je k&#252;rzer der Text, um so mehr wird das Ergebnis dem Ausgangstext &#228;hneln. Versuchen wir es f&#252;r etwas kreativere Textgestaltung deshalb mit Kants im Textformat ganze 1.2 MB einnehmender "Kritik der reinen Vernunft":</p>
<blockquote><p>Der hypothetische Urteil vom Gegenstande wei&#223;, die Gesetzgebung erforderlich ist. Es besteht das Verm&#246;gen vorkommt, Unterarten, unter den Dingen vorhergeht, darin von der Frage: ob man sie die allererst m&#246;glich sei, aus irgendeiner Grundkraft, soviel gepriesener und k&#252;nftigen Zeit existieren. Woran erkennt die Unabh&#228;ngigkeit von der des intelligiblen Charakter haben, wie es ihm unterworfen ist. Denn der au&#223;er mir f&#252;r Erscheinungen keine bestimmten Erfahrung hineinbringt, m&#252;ssen mir etwas vorstellen, da&#223; die mir immer sein, niemals etwas Unm&#246;gliches, und die transzendentale &#196;sthetik*.</p></blockquote>
<p>Alles klar?</p>
<p>Wer das gerne mit eigenen Texten versuchen m&#246;chte, kann entweder direkt mit der Python-Datei spielen [8] oder sich an der Online-Version von Elje.net [9] versuchen.</p>
<p>[1] <a href="http://python.org/">The Python Programming Language</a><br />
[2] <a href="http://de.wikipedia.org/wiki/Markow-Kette">Wikipedia: Markow-Kette</a><br />
[3] <a href="http://www.kurzweilai.net/articles/art0610.html?printable=1">Kurzweil’s Law (aka "the law of accelerating returns")</a><br />
[4] <a href="http://en.wikipedia.org/wiki/Mark_V_Shaney">Markov-Texte im Usenet: Mark V Shaney</a><br />
[5] <a href="http://www.eblong.com/zarf/markov/">Fun with Markov Chains</a><br />
[6] <a href="http://www.doctornerve.org/nerve/pages/interact/markfun.htm">Fun things to do with a Markov Process</a><br />
[7] <a href="http://www.heise.de/tp/r4/artikel/2/2044/1.html">Telepolis: Cyberkultur</a><br />
[8] <a href="http://www.aiplayground.org/markov.py">AI Playground Download: Markov.py</a><br />
[9] <a href="http://www.elje.net/markov/">Elje.net: Markov Text Generator</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.aiplayground.org/artikel/markov/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Die Verbreitung von Ideen</title>
		<link>http://www.aiplayground.org/artikel/memetik/</link>
		<comments>http://www.aiplayground.org/artikel/memetik/#comments</comments>
		<pubDate>Sat, 29 Jan 2005 09:25:58 +0000</pubDate>
		<dc:creator>Andreas</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[Zukunft]]></category>

		<guid isPermaLink="false">http://ai2.stuhlmueller.info/artikel/memetik/</guid>
		<description><![CDATA[Seit wann wird im Internet die Idee einer k&#252;nstlichen Intelligenz diskutiert? Wie hat sich das Interesse an neuronalen Netzen entwickelt? Und wann kam eigentlich der Begriff Singularit&#228;t auf? Eine einfache M&#246;glichkeit solche Fragen zu kl&#228;ren besteht darin, die Usenet-Diskussionen der letzten 25 Jahre nach diesen Themen zu durchsuchen und die Ergebnisse grafisch darzustellen. Ein paar [...]]]></description>
			<content:encoded><![CDATA[<p>Seit wann wird im Internet die Idee einer k&#252;nstlichen Intelligenz diskutiert? Wie hat sich das Interesse an neuronalen Netzen entwickelt? Und wann kam eigentlich der Begriff  Singularit&#228;t auf? Eine einfache M&#246;glichkeit solche Fragen zu kl&#228;ren besteht darin, die Usenet-Diskussionen der letzten 25 Jahre nach diesen Themen zu durchsuchen und die Ergebnisse grafisch darzustellen.<span id="more-20"></span></p>
<p>Ein paar Worte zur Vorgehensweise: Googles Usenet-Archiv, Google Groups [1], erlaubt es, die Suche auf bestimmte Zeitr&#228;ume einzuschr&#228;nken. Mit einem kurzen Script, z.B. in der Programmiersprache Python [2], kann so f&#252;r jedes Jahr zwischen 1980 und 2005 eine Suche nach einem bestimmten Begriff durchgef&#252;hrt und die Anzahl der Suchergebnisse gespeichert werden. Stellt man die Suchergebnis-Zahlen nun als Diagramm dar, so l&#228;sst sich die zeitliche Entwicklung der Popularit&#228;t eines Themas recht deutlich ablesen.</p>
<p>Um aussagekr&#228;ftigere Ergebnisse zu erhalten wurden zum Teil mehrere Suchen pro Thema durchgef&#252;hrt -- etwa f&#252;r einen englischen und den entsprechenden deutschen Begriff -- und die Anzahl der Suchergebnisse dann addiert.</p>
<p>Die Ergebnisse des Experiments (ein Klick auf die Grafik &#246;ffnet eine Version in h&#246;herer Aufl&#246;sung):</p>
<h2>K&#252;nstliche Intelligenz</h2>
<p>Suchbegriffe: "K&#252;nstliche Intelligenz" und "Artificial Intelligence".<br />
  <a href="http://www.aiplayground.org/img/artificial-intelligence-kuenstliche-intelligenzhigh.gif"><img src="http://www.aiplayground.org/img/artificial-intelligence-kuenstliche-intelligenzlow.gif" alt="Usenet-Graph k&#252;nstliche Intelligenz" width="400" height="225" border="0" class="illu" /></a></p>
<h2>Nanotechnologie</h2>
<p>Suchbegriffe: "Nanotech" und "Nanotechnology".</p>
<p>  <a href="http://www.aiplayground.org/img/nanotech-nanotechnologyhigh.gif"><img src="http://www.aiplayground.org/img/nanotech-nanotechnologylow.gif" alt="Usenet-Graph Nanotechnologie" width="400" height="228" border="0" class="illu" /></a></p>
<h2>Neuronale Netze</h2>
<p>Suchbegriffe: "Neural Network", "Neural Networks", "Neural Net", "Neural Nets", "Neuronale Netze".<br />
  <a href="http://www.aiplayground.org/img/neural-net-nets-network-networks-neuronale-netzehigh.gif"><img src="http://www.aiplayground.org/img/neural-net-nets-network-networks-neuronale-netzelow.gif" alt="Usenet-Graph Neuronale Netze" width="400" height="227" border="0" class="illu" /></a></p>
<h2>Singularit&#228;t</h2>
<p>Suchbegriffe: "Singularity" und "Singularit&#228;t".</p>
<p>  <a href="http://www.aiplayground.org/img/singularity-singularitaethigh.gif"><img src="http://www.aiplayground.org/img/singularity-singularitaetlow.gif" alt="Usenet-Graph Singularit&#228;t" width="400" height="223" border="0" class="illu" /></a></p>
<h2>&#220;bersicht</h2>
<p><span style="color: #1618FB">Nanotechnologie</span> - <span style="color: #FF3535">Singularit&#228;t</span> -  <span style="color: #2DFF2C">K&#252;nstliche Intelligenz</span> -  <span style="color: #0EFDFC">Neuronale Netze</span><br />
<a href="http://www.aiplayground.org/img/allehigh.gif"><img src="http://www.aiplayground.org/img/allelow.gif" alt="Usenet-Graph &#220;bersicht" width="400" height="218" border="0" class="illu" /></a><br />
Nat&#252;rlich lassen sich Newsgroups auch nach den Namen von Personen durchsuchen. Versuchsweise habe ich die Popularit&#228;t des einflussreichen Science-Fiction-Autors Vernor Vinge und des Singularit&#228;tsaktivisten Eliezer Yudkowsky im Laufe der Zeit analysiert:</p>
<h2>Vernor Vinge</h2>
<p>  <a href="http://www.aiplayground.org/img/vernor-vingehigh.gif"><img src="http://www.aiplayground.org/img/vernor-vingelow.gif" alt="Usenet-Graph Vernor Vinge" width="400" height="224" border="0" class="illu" /></a></p>
<h2>Eliezer Yudkowsky</h2>
<p>  <a href="http://www.aiplayground.org/img/eliezer-yudkowskyhigh.gif"><img src="http://www.aiplayground.org/img/eliezer-yudkowskylow.gif" alt="Usenet-Graph Eliezer Yudkowsky" width="400" height="227" border="0" class="illu" /></a><br />
[1] <a href="http://groups.google.com">Google Groups</a><br />
[2] <a href="http://python.org">The Python Programming Language</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.aiplayground.org/artikel/memetik/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Web APIs</title>
		<link>http://www.aiplayground.org/artikel/google-apis/</link>
		<comments>http://www.aiplayground.org/artikel/google-apis/#comments</comments>
		<pubDate>Sat, 18 Dec 2004 09:16:36 +0000</pubDate>
		<dc:creator>Andreas</dc:creator>
				<category><![CDATA[Google]]></category>
		<category><![CDATA[Programmieren]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://ai2.stuhlmueller.info/artikel/google-apis/</guid>
		<description><![CDATA[Google ist ein Ph&#228;nomen: Die Suchmaschine kennt mehr als 8 Milliarden Webseiten. Dazu kommen mehr als 845 Millionen Usenet-Postings. Googles Infrastruktur umfasst inzwischen mehr als 250.000 Server. Nirgendwo anders wird eine gr&#246;&#223;ere Menge an Daten verarbeitet und per Website der &#214;ffentlichkeit zug&#228;nglich gemacht. Inzwischen d&#252;rfen nicht mehr nur Menschen, sondern auch Maschinen auf den Datenschatz [...]]]></description>
			<content:encoded><![CDATA[<p>Google ist ein Ph&#228;nomen: Die Suchmaschine kennt mehr als 8 Milliarden Webseiten. Dazu kommen mehr als 845 Millionen Usenet-Postings. Googles Infrastruktur umfasst inzwischen mehr als 250.000 Server. Nirgendwo anders wird eine gr&#246;&#223;ere Menge an Daten verarbeitet und per Website der &#214;ffentlichkeit zug&#228;nglich gemacht. Inzwischen d&#252;rfen nicht mehr nur Menschen, sondern auch Maschinen auf den Datenschatz zugreifen: Das Zauberwort hei&#223;t "Web Services".<span id="more-13"></span></p>
<p>Im letzten Teil der "Daten, Daten, Daten"-Serie [1] wurde das Konzept der Web Services vorgestellt. Zur Erinnerung:</p>
<blockquote><p>Was f&#252;r uns Menschen Websites sind, das sind f&#252;r Computer Web Services - Internet-Dienste, die in der Regel von gr&#246;&#223;eren Firmen wie Amazon, Google oder eBay angeboten werden und Unmengen an Informationen in (vornehmlich) maschinenlesbaren Formaten liefern.</p>
<p>Im Gegensatz zu den meisten Websites werden die Informationen bei Web Services als XML-Dateien abgerufen. XML (Extensible Markup Language) ist "ein Standard zur Erstellung strukturierter, maschinen- und menschenlesbarer Dateien." [2]</p>
<p>Diese XML-Dateien werden &#252;ber das SOAP-Protokoll (Simple Object Access Protocol) vom Server abgerufen und lokal weiterverarbeitet. Erfreulicherweise bleibt es dem Software-Entwickler dabei oft erspart, sich mit den Hintergr&#252;nden von SOAP, XML und Co zu befassen, wenn bereits Module f&#252;r die Programmiersprache und den Web Service der Wahl existieren.</p></blockquote>
<p>F&#252;r die Google-API trifft das zu. Ob Visual Basic .Net [3], PHP [4] oder Python [5]: F&#252;r die Einbindung der API braucht es nicht mehr als ein paar Zeilen Code. Wie schon im Artikel &#252;ber die Amazon Web Services verwende ich auch hier zur Demonstration der M&#246;glichkeiten wieder Python, da der Code vergleichsweise einfach zu lesen ist und mit PyGoogle [5] ein exzellentes Modul f&#252;r die API existiert.</p>
<p>Doch was ist mit der Google-API [6] m&#246;glich, welche Daten stellt Google bereit? Neben Suchergebnissen in maschinenlesbarer Form sind die zwischengespeicherten Cache-Seiten, die Google von fast jeder Website erstellt, sowie Googles Rechtschreibkorrektur aufrufbar.</p>
<p>Die Suchergebnisse sind dabei der interessanteste Part. Sie enthalten unter anderem die Anzahl der Resultate f&#252;r eine bestimmte Anfrage (estimatedTotalResultsCount), die Zeit, die die Suche in Anspruch nahm (searchTime) und die einzelnen gefundenen Seiten mit URL, Titel (title), Ausschnitt aus der Seite (snippet), Dateigr&#246;&#223;e (cachedSize) und Kategorie (directoryCategory).</p>
<p>Ein Beispiel sagt mehr als tausend Worte, also versuchen wir uns an folgender Fragestellung: Welches der Jahre 1985-2009 wird am h&#228;ufigsten im Internet erw&#228;hnt? Und wie oft wurde es im Vergleich zu den anderen Jahren erw&#228;hnt? Unser Beispielprogramm soll also Suchvorg&#228;nge nach den Phrasen "year 1985", "year 1986", ..., "year 2009" durchf&#252;hren und jeweils die Anzahl der Gesamtsuchergebnisse ausgeben.</p>
<p>In Python sieht das folgenderma&#223;en aus:<code>import google, sys<br />
google.setLicense(&#39;YourLicenseKey&#39;)<br />
&nbsp;<br />
for k in range(1985,2010):<br />
&nbsp;&nbsp;&nbsp;&nbsp;try:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gData = google.doGoogleSearch(&#39;&#92;&#39;year &#39; + &#92;<br />
str(k)+&#39;&#92;&#39;&#39;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print k, &#92;<br />
str(gData.meta.estimatedTotalResultsCount).rjust(10)<br />
&nbsp;&nbsp;&nbsp;&nbsp;except:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &#39;Fehler:&#39;, sys.exc_info()[0]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</code></p>
<p>Ist das PyGoogle-Modul installiert und ein g&#252;ltiger Lizenz-Schl&#252;ssel angegeben (kann unter [8] angefordert werden), so wird das Programm der Reihe nach die Phrasen-Suchen auf&#252;hren und die Suchergebnisse ausgeben:<code>1985&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;117000<br />
1986&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;111000<br />
1987&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;126000<br />
1988&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;136000<br />
1989&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;148000<br />
1990&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;216000<br />
(...)<br />
2003&nbsp;&nbsp;&nbsp;&nbsp;2100000<br />
2004&nbsp;&nbsp;&nbsp;&nbsp;2840000<br />
2005&nbsp;&nbsp;&nbsp;&nbsp;1280000<br />
2006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;149000<br />
2007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;65400<br />
2008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;40100<br />
2009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;21400</code></p>
<p>Das Jahr 2004 wird also zurzeit am h&#228;ufigsten erw&#228;hnt, etwas &#246;fters als das Jahr 2000. Nat&#252;rlich lassen sich aus der Google-API gewonnene Daten auch graphisch darstellen:<br />
<img class="illu" src="http://www.aiplayground.org/img/google-api-years.gif" alt="Google Web API Statistik: Years"><br />
Ein weiteres Beispiel: Wir interessieren uns f&#252;r alle Websites mit .de-Domain, die in den Top-50 Suchergebnissen f&#252;r das Stichwort "Neuronale Netze" auftauchen. Eine alphabetisch sortierte Liste der Webadressen soll ausgegeben werden, wobei keine Domain doppelt vorkommen soll. Mit der Google-API kein Problem:<code>import google, sys<br />
&nbsp;<br />
google.setLicense(&#39;YourLicenseKey&#39;)<br />
Results = []<br />
&nbsp;<br />
for k in range(0,50,10):<br />
&nbsp;&nbsp;&nbsp;&nbsp;try:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gData = &#92;<br />
google.doGoogleSearch(&#39;neuronale netze&#39;,k,10)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for n in gData.results:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Results.append(n.URL)<br />
&nbsp;&nbsp;&nbsp;&nbsp;except:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &#39;Fehler:&#39;, sys.exc_info()[0]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;<br />
Results = [n[7:n.find(&#39;/&#39;,7)] &#92;<br />
for n in Results if (n.find(&#39;.de&#39;) != -1)]<br />
Results = [n for i,n &#92;<br />
in enumerate(Results) if n not in Results[:i]]<br />
&nbsp;<br />
Results.sort()<br />
for n in Results:<br />
&nbsp;&nbsp;&nbsp;&nbsp;print n</code></p>
<p>Das Python-Programm f&#252;hrt 5 Suchvorg&#228;nge mit jeweils 10 Ergebnissen aus und f&#252;gt f&#252;r jede URL eines Suchergebnisses der "Results"-Liste einen neuen Eintrag hinzu. Tritt ein Fehler auf (z.B. keine Internetverbindung verf&#252;gbar), so bricht das Programm ab und gibt eine entsprechende Fehlermeldung aus.</p>
<p>Nachdem die Ergebnisse erfolgreich abgerufen wurden, wird die "Results"-Liste auf die Eintr&#228;ge eingegrenzt, bei denen ".de" in der URL vorkommt. Gleichzeitig wird das "http://" am Anfang sowie der Verzeichnisstrang am Ende der URL entfernt.</p>
<p>In der n&#228;chsten Zeile des Programms werden s&#228;mtliche doppelten "Results"-Eintr&#228;ge gel&#246;scht, danach sortiert und per "print" angezeigt. Die Ausgabe des Programms sieht dann in etwa so aus:<br />
<code>fuzzy.cs.uni-magdeburg.de<br />
home.zait.uni-bremen.de<br />
itb.biologie.hu-berlin.de<br />
rfhs8012.fh-regensburg.de<br />
www-lehre.inf.uos.de<br />
www-ra.informatik.uni-tuebingen.de<br />
www.andreas-mielke.de<br />
www.artifin.de<br />
www.documanager.de<br />
www.faes.de<br />
(...)<br />
www.medi-informatik.de<br />
www.neuro.ct-webspace.de<br />
www.physik.uni-regensburg.de<br />
www.vdi.de<br />
wwwhni.uni-paderborn.de<br />
wwwmath.uni-muenster.de<br />
wwwuser.gwdg.de</code></p>
<p>Nat&#252;rlich l&#228;sst sich die Google-API auch hervorragend zum Zwecke der Suchmaschinen-Analyse und Optimierung (Search Engine Optimization, SEO) verwenden. Das n&#228;chste Beispielprogramm dieses Artikels soll anhand der ersten 50 Suchergebnisse f&#252;r den Begriff "SEO" feststellen, welchen Wert Google auf das Vorkommen des Suchbegriffes in Titel und URL legt bzw. bei welchem Anteil der Suchergebnisse der Suchbegriff in Titel/URL vorkommt.</p>
<p>Der Python-Quellcode ist weitgehend selbsterkl&#228;rend:<br />
<code>import google, sys<br />
&nbsp;<br />
google.setLicense(&#39;YourLicenseKey&#39;)<br />
InTitle = 0<br />
InURL = 0<br />
KeyWord = &#39;python&#39;<br />
NumResults = 50<br />
&nbsp;<br />
for k in range(0,NumResults,10):<br />
&nbsp;&nbsp;&nbsp;&nbsp;try:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gData = google.doGoogleSearch(KeyWord,k,10)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for n in gData.results:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m = n.URL.lower()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (m.find(KeyWord) != -1):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InURL += 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m = n.title.lower()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (m.find(KeyWord) != -1):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InTitle += 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;except:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &#39;Fehler:&#39;, sys.exc_info()[0]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;<br />
print &#39;Keyword: &#39;,KeyWord<br />
print &#39;Keyword in URL: &#39;,InURL,&#39;von&#39;,NumResults, &#92;<br />
&#39;(&#39;, float(InURL)/float(NumResults)*100, &#39;% )&#39;<br />
print &#39;Keyword in Titel: &#39;,InTitle,&#39;von&#39;,NumResults, &#92;<br />
&#39;(&#39;, float(InTitle)/float(NumResults)*100, &#39;% )&#39;</code><br />
Nachdem eine Suchergebnis-Liste mit 10 Ergebnissen geladen wurde, werden f&#252;r jedes Element URL und Titel in Kleinbuchstaben umgewandelt und nach dem Schl&#252;sselwort durchsucht. Wird es gefunden, so werden die Variablen InURL bzw. InTitle um 1 erh&#246;ht. Vor das Programm endet, werden die Variablen als ganze Zahlen sowie als Prozentzahlen ausgegeben. Konkret sieht das so aus:<br />
<code>Keyword:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;seo<br />
Keyword in URL:&nbsp;&nbsp;&nbsp;&nbsp;33 von 50 ( 66.0 % )<br />
Keyword in Titel:&nbsp;&nbsp;37 von 50 ( 74.0 % )<br />
&nbsp;<br />
Keyword:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;search<br />
Keyword in URL:&nbsp;&nbsp;&nbsp;&nbsp;14 von 50 ( 28.0 % )<br />
Keyword in Titel:&nbsp;&nbsp;25 von 50 ( 50.0 % )<br />
&nbsp;<br />
Keyword:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;python<br />
Keyword in URL:&nbsp;&nbsp;&nbsp;&nbsp;27 von 50 ( 54.0 % )<br />
Keyword in Titel:&nbsp;&nbsp;42 von 50 ( 84.0 % )<br />
</code><br />
Erweiterungen sind durchaus denkbar. Das Programm k&#246;nnte beispielsweise die Prozentzahlen f&#252;r die ersten 50 Suchergebnisse mit denen der Suchergebnisse 50-100 vergleichen und auf Unterschiede &#252;berpr&#252;fen. Weiterhin w&#228;re es denkbar, dass ganze Wortlisten automatisch abgearbeitet werden und die Ergebnisse in einer mit Tabellenkalkulationsprogrammen lesbaren (CSV-)Datei gespeichert werden.</p>
<p>Die Analyse von mehr als 20 hochfrequentierten Suchw&#246;rtern ergab folgenden Graph, die X-Achse gibt dabei die Nummer der Suchergebnis-Seite an:<br />
<img class="illu" src="http://www.aiplayground.org/img/google-api-competitive.gif" alt="Graph Competitive Keywords"><br />
Die meisten Seiten, die in den Top-200 f&#252;r so hart umk&#228;mpfte Schl&#252;sselw&#246;rter wie "advertising", "business", "estate", "software" oder "marketing" vorkommen, haben das entsprechende Keyword im Titel. Den Unterschied kann die Verwendung von Keywords in der URL machen: Hier unterscheiden sich die Top-20 vom Rest.</p>
<p>Zum Vergleich der Graph, der sich bei der Analyse 20 weniger begehrter Keywords wie zum Beispiel "singularity", "tschebyschew" oder "backpropagation" ergab:<br />
<img class="illu" src="http://www.aiplayground.org/img/google-api-noncompetitive.gif" alt="Graph Noncompetitive Keywords"><br />
Als Demonstration der M&#246;glichkeiten der Google-API zur Suchmaschinenanalyse sollte das gen&#252;gen. Was hier an Code vorgestellt wurde, ist das Ergebnis von 15 Minuten Arbeit -- mit etwas gr&#246;&#223;erem Zeitaufwand sind die M&#246;glichkeiten schier unbegrenzt.</p>
<p>Zum Abschluss noch der Quellcode f&#252;r ein Programm, das vor allem f&#252;r Website-Betreibern von Nutzen ist: Ein Ranking-Checker. Das Programm &#228;hnelt dem zuvor beschriebenen Analyse-Programm, &#252;berpr&#252;ft aber anstatt des Vorkommens des Suchworts in URL/Titel das Vorkommen der eigenen URL in den Suchergebnissen. So l&#228;sst sich schnell feststellen, auf welcher Position der Suchergebnis-Seiten die eigene Website f&#252;r bestimmte Keywords zu finden ist.<br />
<code>import google, sys<br />
&nbsp;<br />
google.setLicense(&#39;YourLicenseKey&#39;)<br />
KeyWord = &#39;singularitaet&#39;<br />
MySite = &#39;aiplayground.org&#39;<br />
NumResults = 100<br />
ResFound = 0<br />
&nbsp;<br />
for k in range(0,NumResults,10):<br />
&nbsp;&nbsp;&nbsp;&nbsp;try:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gData = google.doGoogleSearch(KeyWord,k,10)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rc = 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for n in gData.results:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rc += 1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m = n.URL.lower()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (m.find(MySite) != -1) and (ResFound == 0):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ResFound = k+rc<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;except:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &#39;Fehler:&#39;, sys.exc_info()[0]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;<br />
print &#39;Website:  &#39;,MySite<br />
print &#39;Keyword:  &#39;,KeyWord<br />
print &#39;Position: &#39;,ResFound</code>Die Variable "k" gibt dabei jeweils die aktuelle Seite der Suchergebnisse an (10, 20, 30, ...), die Variable "rc" die Position auf dieser Seite (1, 2, 3, ...). Wird die eigene Website in der URL eines Suchergebnisses gefunden, so wird die Gesamt-Position, d.h. die Summe aus "k" und "rc", in der Variablen "ResFound" abgespeichert, weitere Suchvorg&#228;nge abgebrochen und die Position auf dem Bildschirm ausgegeben.</p>
<p>Ein Ablauf des Programms kann zum Beispiel so aussehen:<br />
<code>Website:   aiplayground.org<br />
Keyword:   singularitaet<br />
Position:  52</code>Die Verwendung dieses Ranking-Checkers ist allerdings nur begrenzt hilfreich: Google verwendet f&#252;r die API einen anderen, nicht ganz so umfangreichen Index an Websites als f&#252;r die Suchergebnisse, die auf Google.com zur&#252;ckgegeben werden. Wer sein genaues Ranking erfahren will und das nicht per Hand tun will, ist also gezwungen, die Suchergebnisse direkt von Googles HTML-Seiten einzulesen.</p>
<p>[1] <a href="http://www.aiplayground.org/artikel/amazon-data/">Daten, Daten, Daten: Amazon Web Services</a><br />
[2] <a href="http://de.wikipedia.org/wiki/XML">Wikipedia: XML</a><br />
[3] <a href="http://msdn.microsoft.com/library/en-us/dv_vstechart/html/vbtchaccessinggooglewithvb.asp">Google APIs und VB.Net</a><br />
[4] <a href="http://blog.outer-court.com/archive/2003_06_22_index.html">Google APIs und PHP</a><br />
[5] <a href="http://pygoogle.sourceforge.net/">Google APIs und Python: PyGoogle</a><br />
[6] <a href="http://www.google.com/apis/">Google Web APIs</a><br />
[7] <a href="https://www.google.com/accounts/NewAccount?continue=http://api.google.com/createkey&#038;followup=http://api.google.com/createkey">Google Web APIs LicenseKey anfordern</a><br />
[8] <a href="http://www.technologyreview.com/articles/05/01/issue/ferguson0105.asp?p=5">Google: Mehr als 250.000 Server</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.aiplayground.org/artikel/google-apis/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Memecodes: Die Evolution von Websites</title>
		<link>http://www.aiplayground.org/artikel/memecodes/</link>
		<comments>http://www.aiplayground.org/artikel/memecodes/#comments</comments>
		<pubDate>Thu, 18 Nov 2004 09:06:50 +0000</pubDate>
		<dc:creator>Andreas</dc:creator>
				<category><![CDATA[Evolution]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://ai2.stuhlmueller.info/artikel/memecodes/</guid>
		<description><![CDATA[Websites werden von Menschenhand gestaltet. Sie existieren, weil Menschen die darauf zu findenden Informationen verbreiten m&#246;chten oder ein anderes Ziel damit verfolgen. Doch muss das so sein? Was passiert, wenn Informationen sich evolution&#228;r ausbreiten und der Inhalt einer Website sich ohne menschliches Zutun selbst&#228;ndig ver&#228;ndern kann? Im Februar 2004 setzte Philipp Lenssen [1] ein Experiment [...]]]></description>
			<content:encoded><![CDATA[<p>Websites werden von Menschenhand gestaltet. Sie existieren, weil Menschen die darauf zu findenden Informationen verbreiten m&#246;chten oder ein anderes Ziel damit verfolgen. Doch muss das so sein? Was passiert, wenn Informationen sich evolution&#228;r ausbreiten und der Inhalt einer Website sich ohne menschliches Zutun selbst&#228;ndig ver&#228;ndern kann?<span id="more-8"></span></p>
<p>Im Februar 2004 setzte Philipp Lenssen [1] ein Experiment auf, um genau das auszuprobieren.</p>
<p>Zu diesem Zweck generierte er per Algorithmus 5.000 Seiten mit zuf&#228;lligen Wortsequenzen als digitalem DNA-Ersatz und stellte sie unter dem Projektnamen "Memecodes" ins Netz [2]. Diese Seiten, die neben einer zuf&#228;lligen Auswahl von W&#246;rterbuch-Eintr&#228;gen auch Satzzeichen, Bindew&#246;rter, einige bekannte Markennamen sowie die Namen ber&#252;hmter Pers&#246;nlichkeiten enthalten, wurden bald darauf von Suchmaschinen besucht und in deren Index aufgenommen.</p>
<p>Wenn nun ein Besucher &#252;ber Google eine der Seiten aufruft, z&#228;hlt diese als im Sinne der Evolution erfolgreich und darf Nachkommen erzeugen: Per Datenbank wird eine neue, zuf&#228;llig ver&#228;nderte Version dieser Seite erstellt und auf der Memecodes-Startseite verlinkt. Diese Seite wartet nun darauf, erst von Suchmaschinen indiziert zu werden, dann von einem Besucher angeklickt zu werden und wiederum eine Nachfolgeseite zu erschaffen -- so schlie&#223;t sich der Kreis.</p>
<p>Wird eine Seite lange Zeit von keinem Besucher aufgerufen, so "stirbt sie", d.h. sie wird gel&#246;scht. Die Suchanfragen der Suchmaschinen-Benutzer entsprechen demnach der Nahrung in nat&#252;rlichen &#214;kosystemen.</p>
<p>Nach einer Weile ist zu erwarten, dass sich mehr und mehr Seiten auf bestimmte &#246;kologische Nischen konzentrieren, indem sie Wortkombinationen enthalten, die im Internet noch kaum abgedeckt sind. Nur bei solchen Wortkombinationen erscheinen die Memecodes-Seiten unter den ersten Suchergebnissen, und nur solche Seiten "&#252;berleben".</p>
<p>Je l&#228;nger das Experiment l&#228;uft, umso interessanter das Ergebnis. Bleibt es lange genug bestehen, so k&#246;nnten sich aus dem Haufen zusammengew&#252;rfelter Zufallss&#228;tze mit der Zeit sogar bedeutungstragende Inhalte entwickeln.</p>
<p>Seit Beginn des Experiments sind neun Monate vergangen, und einige der Seiten k&#246;nnen bereits auf 4 Generationen an Vorfahren zur&#252;ckblicken. Ein Blick auf die Statistik der Suchanfragen [3], die zu den Memecodes-Seiten f&#252;hrten, zeigt unter anderem folgende Wortkombinationen -- die Zahl vorweg gibt die Anzahl der Suchanfragen an:<br />
<code>63 sphagnum esplanade lyrics<br />
62 marshmallow blowgun<br />
56 lockout buster<br />
48 WWW£¬5757£¬MY ¡£COM<br />
44 feel the wrath of salivating mushroom (...)<br />
43 shush bikini<br />
40 seagull sandwich riddle<br />
34 caftan marocain<br />
33 sandboy revelation<br />
33 incubus torrent<br />
32 labial infusion<br />
32 girdle.us<br />
29 reticulated stingray<br />
24 Sphagnum Esplanade lyrics<br />
24 lockout buster schematic diagram<br />
</code></p>
<p>Vorl&#228;ufiges Fazit: Die Idee, Webseiten durch Evolution zu erzeugen ist der n&#228;heren Betrachtung wert, das Prinzip der Evolution als Bestandteil von Algorithmen sowieso und das Experiment zeigt auch schon erste Erfolge. Doch auch der Nachteil von auf Evolution basierenden Verfahren zeigt sich hier: Sie brauchen sehr viel Zeit. Nicht umsonst sind zwischen dem Auftauchen der ersten einzelligen Lebewesen und dem der ersten Menschen etwa 3.5 Milliarden Jahre vergangen.</p>
<p>[1] <a href="http://blog.outer-court.com">Google Blogoscoped</a><br />
[2] <a href="http://memecodes.outer-court.com">Memecodes</a><br />
[3] <a href="http://memecodes.outer-court.com/stats.html">Memecodes Statistiken</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.aiplayground.org/artikel/memecodes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
