<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Random Hacks: Tag Probability</title>
    <link>http://www.randomhacks.net/articles/tag/Probability?tag=Probability</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Technology and Other Fun Stuff</description>
    <item>
      <title>Probability monads at Hac 07 II</title>
      <description>&lt;p&gt;From October 5-7, I&amp;#8217;ll be at the &lt;a href="http://www.haskell.org/haskellwiki/Hac_2007_II"&gt;Haskell Hackathon in Freiburg&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ll be working on probability monads, attempting to turn my &lt;a href="http://www.randomhacks.net/articles/2007/04/19/robot-localization-particle-system-monad"&gt;various blog articles&lt;/a&gt; into a real Haskell library.&lt;/p&gt;

&lt;p&gt;Some resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.randomhacks.net/darcs/probability/"&gt;Control.Monad.Probability source code&lt;/a&gt;: This is the as-yet-unreconstructed code from my blog posts.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.randomhacks.net/darcs/probability-monads/probability-monads.pdf"&gt;Draft paper on probability monads&lt;/a&gt;: This paper explains the theory, and it has terser implementations of some ideas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you were a peer reviewer, or gave me feedback on the paper, my humble thanks&amp;#8211;and apologies. I haven&amp;#8217;t had a chance to revise the paper yet, and so your feedback is not yet included.&lt;/p&gt;

&lt;p&gt;See you at the Hackathon!&lt;/p&gt;</description>
      <pubDate>Tue, 02 Oct 2007 07:50:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:1603ed79-bdc5-4bf1-aafd-33c8c29bb6de</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/10/02/probability-monads-at-hac-07-ii</link>
      <category>Haskell</category>
      <category>Math</category>
      <category>Monads</category>
      <category>Probability</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/509</trackback:ping>
    </item>
    <item>
      <title>Freiburg in October: Scheme, Dylan, and probability monads</title>
      <description>&lt;p&gt;Good morning! I&amp;#8217;ll be in Freiburg for several events this October, including &lt;a href="http://cufp.galois.com/"&gt;CUFP&lt;/a&gt; and the &lt;a href="http://haskell.org/haskellwiki/Hac_2007_II"&gt;Haskell Hackathon&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;Commercial Users of Functional Programming (CUFP)&lt;/h4&gt;

&lt;p&gt;On October 4th, I&amp;#8217;ll be speaking at &lt;a href="http://cufp.galois.com/"&gt;CUFP &amp;rsquo;07&lt;/a&gt;, describing the use of Scheme in a real-world multimedia engine. Some likely topics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How we switched to Scheme (and why refactoring is your friend).&lt;/li&gt;
&lt;li&gt;How our artists learned to program in Scheme (it&amp;#8217;s all about the tools).&lt;/li&gt;
&lt;li&gt;The tension between functional programming and objects: Can we have both?&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Dylan Beer Night&lt;/h4&gt;

&lt;p&gt;Once upon a time, I dreamt of &lt;a href="http://www.cs.dartmouth.edu/reports/abstracts/TR2001-404/"&gt;generic functions&lt;/a&gt; and built RPMs for &lt;a href="http://web.archive.org/web/19990125095755/http://www.gwydiondylan.org/"&gt;Gwydion Dylan&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some current and former Dylan hackers are hoping to meet in Freiburg, most likely on October 4th. If you&amp;#8217;re at ICFP or one of the workshops, we&amp;#8217;d love to hear from you.&lt;/p&gt;

&lt;h4&gt;Haskell Hackathon&lt;/h4&gt;

&lt;p&gt;I&amp;#8217;ll be at the &lt;a href="http://haskell.org/haskellwiki/Hac_2007_II"&gt;Haskell Hackathon&lt;/a&gt; from Friday to Sunday.&lt;/p&gt;

&lt;p&gt;Perhaps it&amp;#8217;s time to whip &lt;a href="http://www.randomhacks.net/darcs/probability/"&gt;Control.Monad.Probability&lt;/a&gt; into shape?&lt;/p&gt;</description>
      <pubDate>Tue, 18 Sep 2007 12:36:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:b660e303-82af-41f0-8576-ad58b8fb8cc0</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/09/18/freiburg-in-october</link>
      <category>Scheme</category>
      <category>Dylan</category>
      <category>Haskell</category>
      <category>Monads</category>
      <category>Probability</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/506</trackback:ping>
    </item>
    <item>
      <title>Robot localization using a particle system monad</title>
      <description>&lt;p&gt;&lt;b&gt;Refactoring Probability Distributions:&lt;/b&gt;
&lt;a href="http://www.randomhacks.net/articles/2007/02/21/refactoring-probability-distributions" title="PerhapsT"&gt;part 1&lt;/a&gt;, &lt;a href="http://www.randomhacks.net/articles/2007/02/21/randomly-sampled-distributions" title="Random sampling"&gt;part 2&lt;/a&gt;, &lt;a href="http://www.randomhacks.net/articles/2007/02/22/bayes-rule-and-drug-tests" title="Bayes' rule"&gt;part 3&lt;/a&gt;, &lt;a href="http://www.randomhacks.net/articles/2007/03/03/smart-classification-with-haskell" title="Bayesian classification"&gt;part 4&lt;/a&gt;, &lt;b&gt;part 5&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Welcome to the 5th (and final) installment of &lt;i&gt;Refactoring Probability
Distributions!&lt;/i&gt;  Today, let&amp;#8217;s begin with an example from 
&lt;a href="http://seattle.intel-research.net/people/jhightower/pubs/fox2003bayesian/fox2003bayesian.pdf" title="Fox and colleagues, 2003"&gt;Bayesian Filters for Location Estimation&lt;/a&gt; (PDF), an excellent paper by Fox and colleagues.&lt;/p&gt;

&lt;p&gt;In their example, we have a robot in a hallway with 3 doors.  Unfortunately, we don&amp;#8217;t know &lt;i&gt;where&lt;/i&gt; in the hallway the robot is located:&lt;/p&gt;

&lt;p style="text-align: center"&gt;&lt;img
src="http://www.randomhacks.net/files/robot-door-1.png" title="Robot at
first door" /&gt;&lt;/p&gt;

&lt;p&gt;The vertical black lines are &amp;#8220;particles.&amp;#8221;  Each particle represents a
possible location of our robot, chosen at random along the hallway.  At
first, our particles are spread along the entire hallway (the top
row of black lines). Each particle begins life with a weight of 100%, represented by the height of the black line.&lt;/p&gt;

&lt;p&gt;Now imagine that our robot has a &amp;#8220;door sensor,&amp;#8221; which currently tells us that
we&amp;#8217;re in front of a door. This allows us to rule out any particle which is located &lt;i&gt;between&lt;/i&gt; doors. &lt;/p&gt;

&lt;p&gt;So we multiply the weight of each particle by 100% (if it&amp;#8217;s in front of a door) or 0% (if it&amp;#8217;s between doors), which gives us the lower row of particles. If our sensor was less accurate, we might use 90% and 10%, respectively.&lt;/p&gt;

&lt;p&gt;What would this example look like in Haskell?  We &lt;i&gt;could&lt;/i&gt; build a
giant list of particles (with weights), but that would require us to do a
lot of bookkeeping by hand.  Instead, we use a &lt;a href="http://www.randomhacks.net/articles/2007/03/12/monads-in-15-minutes" title="Monads in 15 minutes"&gt;monad&lt;/a&gt; to hide all the
details, allowing us to work with a single particle at a time.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;localizeRobot&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;WPS&lt;/span&gt; &lt;span class='conid'&gt;Int&lt;/span&gt;
&lt;span class='varid'&gt;localizeRobot&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
  &lt;span class='comment'&gt;-- Pick a random starting location.&lt;/span&gt;
  &lt;span class='comment'&gt;-- This will be our first particle.&lt;/span&gt;
  &lt;span class='varid'&gt;pos1&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;uniform&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='keyglyph'&gt;..&lt;/span&gt;&lt;span class='num'&gt;299&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
  &lt;span class='comment'&gt;-- We know we're at a door.  Particles&lt;/span&gt;
  &lt;span class='comment'&gt;-- in front of a door get a weight of&lt;/span&gt;
  &lt;span class='comment'&gt;-- 100%, others get 0%.&lt;/span&gt;
  &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='varid'&gt;doorAtPosition&lt;/span&gt; &lt;span class='varid'&gt;pos1&lt;/span&gt;
    &lt;span class='keyword'&gt;then&lt;/span&gt; &lt;span class='varid'&gt;weight&lt;/span&gt; &lt;span class='num'&gt;1&lt;/span&gt;
    &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;span class='varid'&gt;weight&lt;/span&gt; &lt;span class='num'&gt;0&lt;/span&gt;
  &lt;span class='comment'&gt;-- ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What happens if our robot drives forward?&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2007/04/19/robot-localization-particle-system-monad"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Thu, 19 Apr 2007 20:43:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:d14628b2-732e-4b87-934f-c6373df35a5c</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/04/19/robot-localization-particle-system-monad</link>
      <category>Haskell</category>
      <category>Math</category>
      <category>Monads</category>
      <category>Probability</category>
      <category>Robots</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/399</trackback:ping>
    </item>
    <item>
      <title>Smart classification using Bayesian monads in Haskell</title>
      <description>&lt;p&gt;&lt;small&gt;(Refactoring Probability Distributions: &lt;a href="http://www.randomhacks.net/articles/2007/02/21/refactoring-probability-distributions"&gt;part 1&lt;/a&gt;, &lt;a href="http://www.randomhacks.net/articles/2007/02/21/randomly-sampled-distributions"&gt;part 2&lt;/a&gt;,
&lt;a href="http://www.randomhacks.net/articles/2007/02/22/bayes-rule-and-drug-tests"&gt;part 3&lt;/a&gt;, &lt;b&gt;part 4&lt;/b&gt;)&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;The world is full of messy classification problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;Is this order fraudulent?&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;It this e-mail a spam?&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;What blog posts would Rachel find interesting?&amp;#8221;&lt;/li&gt;
&lt;li&gt;&amp;#8220;Which intranet documents is Sam looking for?&amp;#8221;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In each case, we want to classify something: Orders are either valid or
fraudulent, messages are either spam or non-spam, blog posts are either
interesting or boring.  Unfortunately, most software is &lt;i&gt;terrible&lt;/i&gt; at
making these distinctions.  For example, why can&amp;#8217;t my RSS reader go out and
track down the 10 most interesting blog posts every day?&lt;/p&gt;

&lt;p&gt;Some software, however, &lt;i&gt;can&lt;/i&gt; make these distinctions.
Google figures out when I want to watch a movie, and shows me &lt;a href="http://www.google.com/search?q=cinema+boston"&gt;specialized
search results&lt;/a&gt;.  And most e-mail clients can identify spam with over
99% accuracy.  But the vast majority of software is dumb, incapable of
dealing with the messy dilemmas posed by the real world.&lt;/p&gt;

&lt;p&gt;So where can we learn to improve our software?&lt;/p&gt;

&lt;p&gt;Outside of Google&amp;#8217;s shroud
of secrecy, the most successful classifiers are spam filters.  And most modern
spam filters are inspired by Paul Graham&amp;#8217;s essay &lt;a href="http://www.paulgraham.com/spam.html"&gt;A Plan for Spam&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So let&amp;#8217;s go back to the source, and see what we can learn.  As it turns out, we can formulate a lot of the ideas in &lt;a href="http://www.paulgraham.com/spam.html"&gt;A Plan
for Spam&lt;/a&gt; in a straightforward fashion using a &lt;a href="http://www.randomhacks.net/articles/2007/02/22/bayes-rule-and-drug-tests"&gt;Bayesian
monad&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Functions from distributions to distributions&lt;/h3&gt;

&lt;p&gt;Let&amp;#8217;s begin with spam filtering.  By convention, we divide messages into
&amp;#8220;spam&amp;#8221; and &amp;#8220;ham&amp;#8221;, where &amp;#8220;ham&amp;#8221; is the stuff we want to read.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;data&lt;/span&gt; &lt;span class='conid'&gt;MsgType&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;Spam&lt;/span&gt; &lt;span class='keyglyph'&gt;|&lt;/span&gt; &lt;span class='conid'&gt;Ham&lt;/span&gt;
  &lt;span class='keyword'&gt;deriving&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Show&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Eq&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Enum&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Bounded&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;#8217;s assume that we&amp;#8217;ve just received a new e-mail.  Without even looking
at it, we know there&amp;#8217;s a certain chance that it&amp;#8217;s a spam.  This gives us
something called a &amp;#8220;prior distribution&amp;#8221; over &lt;code&gt;MsgType&lt;/code&gt;.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;bayes&lt;/span&gt; &lt;span class='varid'&gt;msgTypePrior&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='conid'&gt;Spam&lt;/span&gt; &lt;span class='num'&gt;64.2&lt;/span&gt;&lt;span class='varop'&gt;%&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='conid'&gt;Ham&lt;/span&gt; &lt;span class='num'&gt;35.8&lt;/span&gt;&lt;span class='varop'&gt;%&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But what if we know that the first word of the message is &amp;#8220;free&amp;#8221;?  We can
use that information to calculate a new distribution.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;bayes&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;hasWord&lt;/span&gt; &lt;span class='str'&gt;"free"&lt;/span&gt; &lt;span class='varid'&gt;msgTypePrior&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='conid'&gt;Spam&lt;/span&gt; &lt;span class='num'&gt;90.5&lt;/span&gt;&lt;span class='varop'&gt;%&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='conid'&gt;Ham&lt;/span&gt; &lt;span class='num'&gt;9.5&lt;/span&gt;&lt;span class='varop'&gt;%&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The function &lt;code&gt;hasWord&lt;/code&gt; takes a string and a probability
distribution, and uses them to calculate a new probability distribution:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;hasWord&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;String&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;FDist'&lt;/span&gt; &lt;span class='conid'&gt;MsgType&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt;
           &lt;span class='conid'&gt;FDist'&lt;/span&gt; &lt;span class='conid'&gt;MsgType&lt;/span&gt;
&lt;span class='varid'&gt;hasWord&lt;/span&gt; &lt;span class='varid'&gt;word&lt;/span&gt; &lt;span class='varid'&gt;prior&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
  &lt;span class='varid'&gt;msgType&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;prior&lt;/span&gt;
  &lt;span class='varid'&gt;wordPresent&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt;
    &lt;span class='varid'&gt;wordPresentDist&lt;/span&gt; &lt;span class='varid'&gt;msgType&lt;/span&gt; &lt;span class='varid'&gt;word&lt;/span&gt;
  &lt;span class='varid'&gt;condition&lt;/span&gt; &lt;span class='varid'&gt;wordPresent&lt;/span&gt;
  &lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='varid'&gt;msgType&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code is based on the Bayesian monad from &lt;a href="http://www.randomhacks.net/articles/2007/02/22/bayes-rule-and-drug-tests"&gt;part 3&lt;/a&gt;.  As before,
the &amp;ldquo;&lt;code&gt;&amp;lt;-&lt;/code&gt;&amp;#8221; operator selects a single item from a probability
distribution, and &amp;#8220;condition&amp;#8221; asserts that an expression is true.  The
actual Bayesian inference happens behind the scenes (handy, that).&lt;/p&gt;

&lt;p&gt;If we have multiple pieces of evidence, we can apply them one at a time.
Each piece of evidence will update the probability distribution produced by
the previous step:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;hasWords&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;     &lt;span class='varid'&gt;prior&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;prior&lt;/span&gt;
&lt;span class='varid'&gt;hasWords&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;w&lt;/span&gt;&lt;span class='conop'&gt;:&lt;/span&gt;&lt;span class='varid'&gt;ws&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varid'&gt;prior&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
  &lt;span class='varid'&gt;hasWord&lt;/span&gt; &lt;span class='varid'&gt;w&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;hasWords&lt;/span&gt; &lt;span class='varid'&gt;ws&lt;/span&gt; &lt;span class='varid'&gt;prior&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The final distribution will combine everything we know:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;bayes&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;hasWords&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='str'&gt;"free"&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='str'&gt;"bayes"&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt; &lt;span class='varid'&gt;msgTypePrior&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='conid'&gt;Spam&lt;/span&gt; &lt;span class='num'&gt;34.7&lt;/span&gt;&lt;span class='varop'&gt;%&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='conid'&gt;Ham&lt;/span&gt; &lt;span class='num'&gt;65.3&lt;/span&gt;&lt;span class='varop'&gt;%&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This technique is known as the &lt;a href="http://en.wikipedia.org/wiki/Naive_Bayes_classifier"&gt;naive Bayes classifier&lt;/a&gt;.  Looked at from the right angle, it&amp;#8217;s surprisingly simple.&lt;/p&gt;

&lt;p&gt;(Of course, the naive Bayes classifier assumes that all of our evidence is independent.  In theory, this is a pretty big assumption. In practice, it &lt;a href="http://www.cs.unb.ca/profs/hzhang/publications/FLAIRS04ZhangH.pdf"&gt;works better than you might think&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;But this still leaves us with a lot of questions: How do we keep track of
our different classifiers?  How do we decide which ones to apply?  And do
we need to fudge the numbers to get reasonable results?&lt;/p&gt;

&lt;p&gt;In the following sections, I&amp;#8217;ll walk through various aspects of Paul
Graham&amp;#8217;s &lt;a href="http://www.paulgraham.com/spam.html"&gt;A Plan for Spam&lt;/a&gt;, and show how to generalize it.  If you
want to follow along, you can download the code using Darcs:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_sh "&gt;darcs get http://www.randomhacks.net/darcs/probability&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2007/03/03/smart-classification-with-haskell"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Sat, 03 Mar 2007 09:02:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:46da7ba0-d82a-40a5-bdac-d730e4f7073b</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/03/03/smart-classification-with-haskell</link>
      <category>Haskell</category>
      <category>Math</category>
      <category>Monads</category>
      <category>Probability</category>
      <category>Spam</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/322</trackback:ping>
    </item>
    <item>
      <title>Bayes' rule in Haskell, or why drug tests don't work</title>
      <description>&lt;p&gt;Part 3 of Refactoring Probability Distributions.&lt;br /&gt;
&lt;small&gt;(Part 1: &lt;a href="http://www.randomhacks.net/articles/2007/02/21/refactoring-probability-distributions"&gt;PerhapsT&lt;/a&gt;,
Part 2: &lt;a href="http://www.randomhacks.net/articles/2007/02/21/randomly-sampled-distributions"&gt;Sampling functions&lt;/a&gt;)&lt;/small&gt;&lt;/p&gt;

&lt;blockquote&gt;
    &lt;p&gt;&lt;i&gt;A very senior Microsoft developer who moved to Google told
    me that Google works and thinks at a higher level of abstraction than
    Microsoft. &amp;#8220;Google uses Bayesian filtering the way Microsoft uses the if
    statement,&amp;#8221; he said.&lt;/i&gt; -&lt;a href="http://www.joelonsoftware.com/oldnews/pages/October2005.html"&gt;Joel Spolsky&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I really love this quote, because it&amp;#8217;s &lt;a href="http://weblog.raganwald.com/archives/2005_10_01_archive.html"&gt;insanely provocative&lt;/a&gt;
to any language designer.  What &lt;i&gt;would&lt;/i&gt; a programming language look
like if Bayes&amp;#8217; rule were as simple as an &lt;code&gt;if&lt;/code&gt; statement?&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s start with a toy problem, and refactor it until Bayes&amp;#8217; rule is baked
right into our programming language.&lt;/p&gt;

&lt;p&gt;Imagine, for a moment, that we&amp;#8217;re in charge of administering drug tests for
a small business.  We&amp;#8217;ll represent each employee&amp;#8217;s test results (and drug use) as follows:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;data&lt;/span&gt; &lt;span class='conid'&gt;Test&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;Pos&lt;/span&gt; &lt;span class='keyglyph'&gt;|&lt;/span&gt; &lt;span class='conid'&gt;Neg&lt;/span&gt;
  &lt;span class='keyword'&gt;deriving&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Show&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Eq&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='keyword'&gt;data&lt;/span&gt; &lt;span class='conid'&gt;HeroinStatus&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;User&lt;/span&gt; &lt;span class='keyglyph'&gt;|&lt;/span&gt; &lt;span class='conid'&gt;Clean&lt;/span&gt;
  &lt;span class='keyword'&gt;deriving&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Show&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Eq&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Assuming that 0.1% of our employees have used heroin recently, and that our test is 99%
accurate, we can model the testing process as follows:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;drugTest1&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Dist&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt; &lt;span class='keyglyph'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;HeroinStatus&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Test&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;span class='varid'&gt;drugTest1&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
  &lt;span class='varid'&gt;heroinStatus&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;percentUser&lt;/span&gt; &lt;span class='num'&gt;0.1&lt;/span&gt;
  &lt;span class='varid'&gt;testResult&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt;
    &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='varid'&gt;heroinStatus&lt;/span&gt; &lt;span class='varop'&gt;==&lt;/span&gt; &lt;span class='conid'&gt;User&lt;/span&gt;
      &lt;span class='keyword'&gt;then&lt;/span&gt; &lt;span class='varid'&gt;percentPos&lt;/span&gt; &lt;span class='num'&gt;99&lt;/span&gt;
      &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;span class='varid'&gt;percentPos&lt;/span&gt; &lt;span class='num'&gt;1&lt;/span&gt;
  &lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;heroinStatus&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;testResult&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='comment'&gt;-- Some handy distributions.&lt;/span&gt;
&lt;span class='varid'&gt;percentUser&lt;/span&gt; &lt;span class='varid'&gt;p&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;percent&lt;/span&gt; &lt;span class='varid'&gt;p&lt;/span&gt; &lt;span class='conid'&gt;User&lt;/span&gt; &lt;span class='conid'&gt;Clean&lt;/span&gt;
&lt;span class='varid'&gt;percentPos&lt;/span&gt; &lt;span class='varid'&gt;p&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;percent&lt;/span&gt; &lt;span class='varid'&gt;p&lt;/span&gt; &lt;span class='conid'&gt;Pos&lt;/span&gt; &lt;span class='conid'&gt;Neg&lt;/span&gt;

&lt;span class='comment'&gt;-- A weighted distribution with two elements.&lt;/span&gt;
&lt;span class='varid'&gt;percent&lt;/span&gt; &lt;span class='varid'&gt;p&lt;/span&gt; &lt;span class='varid'&gt;x1&lt;/span&gt; &lt;span class='varid'&gt;x2&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt;
  &lt;span class='varid'&gt;weighted&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;x1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;p&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;x2&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='num'&gt;100&lt;/span&gt;&lt;span class='comment'&gt;-&lt;/span&gt;&lt;span class='varid'&gt;p&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code is based our &lt;a href="http://www.randomhacks.net/articles/2007/02/21/randomly-sampled-distributions"&gt;FDist monad&lt;/a&gt;, which is in turn based on
&lt;a href="http://web.engr.oregonstate.edu/~erwig/pfp/"&gt;PFP&lt;/a&gt;.  Don&amp;#8217;t worry if it seems slightly mysterious; you can think of the
&amp;ldquo;&lt;code&gt;&amp;lt;-&lt;/code&gt;&amp;#8221; operator as choosing an element from a probability
distribution.&lt;/p&gt;

&lt;p&gt;Running our drug test shows every possible combination of the two
variables:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;exact&lt;/span&gt; &lt;span class='varid'&gt;drugTest1&lt;/span&gt;
&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;User&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='conid'&gt;Pos&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='num'&gt;0.1&lt;/span&gt;&lt;span class='varop'&gt;%&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;
 &lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;User&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='conid'&gt;Neg&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='num'&gt;0.0&lt;/span&gt;&lt;span class='varop'&gt;%&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;
 &lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Clean&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='conid'&gt;Pos&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='num'&gt;1.0&lt;/span&gt;&lt;span class='varop'&gt;%&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;
 &lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Clean&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt;&lt;span class='conid'&gt;Neg&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='num'&gt;98.9&lt;/span&gt;&lt;span class='varop'&gt;%&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you look carefully, we have a problem.  Most of the employees who test
positive are actually clean!  Let&amp;#8217;s tweak our code a bit, and try to zoom
in on the positive test results.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2007/02/22/bayes-rule-and-drug-tests"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Thu, 22 Feb 2007 18:11:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:fffdc914-d289-4ac8-bde5-7bbb02451aeb</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/02/22/bayes-rule-and-drug-tests</link>
      <category>Haskell</category>
      <category>Math</category>
      <category>Monads</category>
      <category>Probability</category>
      <category>Recommended</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/306</trackback:ping>
    </item>
    <item>
      <title>Refactoring probability distributions, part 2: Random sampling</title>
      <description>&lt;p&gt;In &lt;a href="http://www.randomhacks.net/articles/2007/02/21/refactoring-probability-distributions"&gt;Part 1&lt;/a&gt;, we cloned &lt;a href="http://web.engr.oregonstate.edu/~erwig/pfp/"&gt;PFP&lt;/a&gt;, a library for computing with probability distributions. PFP represents a distribution as a list of possible values, each with an associated probability.&lt;/p&gt;

&lt;p&gt;But in the real world, things aren&amp;#8217;t always so easy.  What if we wanted to pick  a random number between 0 and 1? Our previous implementation would break, because there&amp;#8217;s an infinite number of values between 0 and 1&amp;#8212;they don&amp;#8217;t exactly fit in a list.&lt;/p&gt;

&lt;p&gt;As it turns out, Sungwoo Park and colleagues found &lt;a href="http://citeseer.ist.psu.edu/752237.html"&gt;an elegant solution&lt;/a&gt; to this problem. They represented probability distributions as sampling functions, resulting in something called the &amp;lambda;&lt;sub&gt;&amp;#x25EF;&lt;/sub&gt; calculus. (I have no idea how to pronounce this!)&lt;/p&gt;

&lt;p&gt;With a little bit of hacking, we can use their sampling functions as a drop-in replacement for PFP.&lt;/p&gt;

&lt;h3&gt;A common interface&lt;/h3&gt;

&lt;p&gt;Since we will soon have two ways to represent probability distributions, we need to define a common interface.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;type&lt;/span&gt; &lt;span class='conid'&gt;Weight&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;Float&lt;/span&gt;

&lt;span class='keyword'&gt;class&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Functor&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Monad&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='conid'&gt;Dist&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt; &lt;span class='keyword'&gt;where&lt;/span&gt;
  &lt;span class='varid'&gt;weighted&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;a&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Weight&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt; &lt;span class='varid'&gt;a&lt;/span&gt;

&lt;span class='varid'&gt;uniform&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Dist&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt; &lt;span class='keyglyph'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='varid'&gt;a&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt; &lt;span class='varid'&gt;a&lt;/span&gt;
&lt;span class='varid'&gt;uniform&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;weighted&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='keyglyph'&gt;\&lt;/span&gt;&lt;span class='varid'&gt;x&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;x&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The function &lt;code&gt;uniform&lt;/code&gt; will create an equally-weighted distribution from a list of values. Using this API, we can represent a two-child family as follows:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;data&lt;/span&gt; &lt;span class='conid'&gt;Child&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;Girl&lt;/span&gt; &lt;span class='keyglyph'&gt;|&lt;/span&gt; &lt;span class='conid'&gt;Boy&lt;/span&gt;
  &lt;span class='keyword'&gt;deriving&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Show&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Eq&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Ord&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='varid'&gt;child&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Dist&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt; &lt;span class='keyglyph'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt; &lt;span class='conid'&gt;Child&lt;/span&gt;
&lt;span class='varid'&gt;child&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;uniform&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;Girl&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Boy&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;

&lt;span class='varid'&gt;family&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Dist&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt; &lt;span class='keyglyph'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;d&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='conid'&gt;Child&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;span class='varid'&gt;family&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
  &lt;span class='varid'&gt;child1&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;child&lt;/span&gt;
  &lt;span class='varid'&gt;child2&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;child&lt;/span&gt;
  &lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='varid'&gt;child1&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='varid'&gt;child2&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, we need to implement this API two different ways: Once with lists, and a second time with sampling functions.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2007/02/21/randomly-sampled-distributions"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Wed, 21 Feb 2007 23:53:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:48ce73c7-a197-4909-af77-6da8d71db1a8</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/02/21/randomly-sampled-distributions</link>
      <category>Haskell</category>
      <category>Math</category>
      <category>Monads</category>
      <category>Probability</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/302</trackback:ping>
    </item>
    <item>
      <title>Refactoring probability distributions, part 1: PerhapsT</title>
      <description>&lt;p&gt;(Warning: This article is a bit more technical than most of my stuff. It assumes prior knowledge of monads and monad transformers.)&lt;/p&gt;

&lt;p&gt;Martin Erwig and Steve Kollmansberger wrote &lt;a href="http://web.engr.oregonstate.edu/~erwig/pfp/"&gt;PFP&lt;/a&gt;, a really sweet Haskell library for computing with probabilities. To borrow their example:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;die&lt;/span&gt; &lt;span class='keyglyph'&gt;::&lt;/span&gt; &lt;span class='conid'&gt;Dist&lt;/span&gt; &lt;span class='conid'&gt;Int&lt;/span&gt;
&lt;span class='varid'&gt;die&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;uniform&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='keyglyph'&gt;..&lt;/span&gt;&lt;span class='num'&gt;6&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If we roll a die, we get the expected distribution of results:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;&amp;gt; die
1  16.7%
2  16.7%
3  16.7%
4  16.7%
5  16.7%
6  16.7%&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you haven&amp;#8217;t seen PFP before, I strongly encourage you to &lt;a href="http://web.engr.oregonstate.edu/~erwig/pfp/"&gt;check it out&lt;/a&gt;.  You can use it to solve all sorts of probability puzzles.&lt;/p&gt;

&lt;p&gt;Anyway, I discovered an interesting way to implement PFP using &lt;a href="http://uebb.cs.tu-berlin.de/~magr/pub/Transformers.en.html"&gt;monad transformers&lt;/a&gt;.  Here&amp;#8217;s what it looks like:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;type&lt;/span&gt; &lt;span class='conid'&gt;Dist&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;PerhapsT&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='varid'&gt;uniform&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;weighted&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='keyglyph'&gt;\&lt;/span&gt;&lt;span class='varid'&gt;x&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;x&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='num'&gt;1&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In other words, &lt;code&gt;Dist&lt;/code&gt; can be written by adding some semantics to the standard list monad.&lt;/p&gt;

&lt;h3&gt;Perhaps: A less specific version of Maybe&lt;/h3&gt;

&lt;p&gt;First, let&amp;#8217;s define a simple probability type:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;newtype&lt;/span&gt; &lt;span class='conid'&gt;Prob&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;P&lt;/span&gt; &lt;span class='conid'&gt;Float&lt;/span&gt;
  &lt;span class='keyword'&gt;deriving&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Eq&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Ord&lt;/span&gt;&lt;span class='layout'&gt;,&lt;/span&gt; &lt;span class='conid'&gt;Num&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;

&lt;span class='keyword'&gt;instance&lt;/span&gt; &lt;span class='conid'&gt;Show&lt;/span&gt; &lt;span class='conid'&gt;Prob&lt;/span&gt; &lt;span class='keyword'&gt;where&lt;/span&gt;
  &lt;span class='varid'&gt;show&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;P&lt;/span&gt; &lt;span class='varid'&gt;p&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;show&lt;/span&gt; &lt;span class='varid'&gt;intPart&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='str'&gt;"."&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='varid'&gt;show&lt;/span&gt; &lt;span class='varid'&gt;fracPart&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='str'&gt;"%"&lt;/span&gt;
    &lt;span class='keyword'&gt;where&lt;/span&gt; &lt;span class='varid'&gt;digits&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;round&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='num'&gt;1000&lt;/span&gt; &lt;span class='varop'&gt;*&lt;/span&gt; &lt;span class='varid'&gt;p&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
          &lt;span class='varid'&gt;intPart&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;digits&lt;/span&gt; &lt;span class='varop'&gt;`div`&lt;/span&gt; &lt;span class='num'&gt;10&lt;/span&gt;
          &lt;span class='varid'&gt;fracPart&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;digits&lt;/span&gt; &lt;span class='varop'&gt;`mod`&lt;/span&gt; &lt;span class='num'&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Thanks to the &lt;code&gt;deriving (Num)&lt;/code&gt; declaration, we can treat &lt;code&gt;Prob&lt;/code&gt; like any other numeric type.&lt;/p&gt;

&lt;p&gt;We can now define &lt;code&gt;Perhaps&lt;/code&gt;, which represents a value with an associated probability:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='keyword'&gt;data&lt;/span&gt; &lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='varid'&gt;a&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='varid'&gt;a&lt;/span&gt; &lt;span class='conid'&gt;Prob&lt;/span&gt;
  &lt;span class='keyword'&gt;deriving&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Show&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, this is just a generalization of Haskell&amp;#8217;s built-in &lt;code&gt;Maybe&lt;/code&gt; type, which treats a value as either present (probability 1) or absent (probability 0). All we&amp;#8217;ve added is a range of possibilities in between: &lt;code&gt;Perhaps x 0.5&lt;/code&gt; represents a 50% chance of having a value.&lt;/p&gt;

&lt;p&gt;Note that there&amp;#8217;s one small trick here: When the probability of a value is 0, we may not actually know it!  But because Haskell is a lazy language, we can write:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='varid'&gt;undefined&lt;/span&gt; &lt;span class='num'&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We&amp;#8217;ll need a convenient way to test for this case, to make sure we don&amp;#8217;t try to use any undefined values:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;neverHappens&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;Perhaps&lt;/span&gt; &lt;span class='keyword'&gt;_&lt;/span&gt; &lt;span class='num'&gt;0&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;True&lt;/span&gt;
&lt;span class='varid'&gt;neverHappens&lt;/span&gt; &lt;span class='keyword'&gt;_&lt;/span&gt;             &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So &lt;code&gt;Perhaps&lt;/code&gt; is just like &lt;code&gt;Maybe&lt;/code&gt;. As it turns out, they&amp;#8217;re both monads, and they both have an associated monad transformer.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2007/02/21/refactoring-probability-distributions"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Wed, 21 Feb 2007 08:06:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:d54b7853-2d74-4a8e-96f3-b0c0c47c4c2b</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/02/21/refactoring-probability-distributions</link>
      <category>Haskell</category>
      <category>Monads</category>
      <category>Math</category>
      <category>Probability</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/297</trackback:ping>
    </item>
    <item>
      <title>Probabilistic Functional Programming is cool</title>
      <description>&lt;p&gt;Syntaxfree is &lt;a href="http://syntaxfree.wordpress.com/2007/02/09/some-probabilistic-text-generation/"&gt;hacking&lt;/a&gt; on Martin Erwig&amp;#8217;s &lt;a href="http://web.engr.oregonstate.edu/~erwig/pfp/"&gt;probability monad&lt;/a&gt;. This is one of the coolest monads out there&amp;#8212;it allows you to trivially solve all kinds of probability problems.&lt;/p&gt;

&lt;p&gt;Mikael Johansson has a &lt;a href="http://blog.mikael.johanssons.org/archive/2007/02/response-to-heath-raftery/"&gt;good example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope to write a bit more about probability monads soon. There&amp;#8217;s already a long post sitting on my hard drive, and some more ideas that I&amp;#8217;m still trying to puzzle out.&lt;/p&gt;

&lt;p&gt;In the meantime, I&amp;#8217;d like to recommend &lt;a href="http://homepages.cwi.nl/~jve/HR/"&gt;The Haskell Road to Logic, Maths and  Programming&lt;/a&gt;.  There&amp;#8217;s an &lt;a href="http://arxiv.org/abs/cs.PL/0512096"&gt;excellent review&lt;/a&gt; available.  &lt;/p&gt;</description>
      <pubDate>Sat, 10 Feb 2007 16:14:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:b66c19ba-06b7-4b30-8755-51ebf45214c6</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/02/10/pfp-is-cool</link>
      <category>Haskell</category>
      <category>Math</category>
      <category>Monads</category>
      <category>Probability</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/292</trackback:ping>
    </item>
    <item>
      <title>Fromberger spam filtering paper</title>
      <description>    &lt;p&gt;Michael Fromberger has
  written a &lt;a href='http://thayer.dartmouth.edu/~sting/sw/perl/bayes-spam.pdf'&gt;nice
  formal analysis&lt;/a&gt; (PDF) of Paul Graham's &lt;a href='http://www.paulgraham.com/spam.html'&gt;Plan for Spam&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Mon, 30 Sep 2002 00:00:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:d75e1da2-a676-4b8d-89d3-4754b254c925</guid>
      <author>Eric</author>
      <link>http://www.randomhacks.net/articles/2002/09/30/fromberger-spam-filtering-paper</link>
      <category>Spam</category>
      <category>Probability</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/40</trackback:ping>
    </item>
    <item>
      <title>Bayesian Whitelisting: Finding the Good Mail Among the Spam</title>
      <description>    &lt;p&gt;The biggest challenge with spam filtering is reducing false
    positives--that is, finding the good mail among the spam.  Even the
    best spam filters occasionally mistake legitimate e-mail for spam.  For
    example, in some &lt;a href='/stories/2002/09/22/trainable-spam-filter-testing' title='How To Test a Trainable Spam Filter'&gt;recent
    tests&lt;/a&gt;, &lt;a href='http://bogofilter.sourceforge.net/'&gt;&lt;code&gt;bogofilter&lt;/code&gt;&lt;/a&gt;
    processed 18,000 e-mails with only 34 false positives.  Unfortunately,
    several of these false positives were urgent e-mails from former
    clients.  This unpleasant mistake wasn't necessary--the most important
    of these false positives could have been avoided with an automatic
    whitelisting system.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2002/09/29/bayesian-whitelisting"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Sun, 29 Sep 2002 00:00:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:4e3b83e6-1f2a-48d4-9f65-5e691ab45838</guid>
      <author>Eric</author>
      <link>http://www.randomhacks.net/articles/2002/09/29/bayesian-whitelisting</link>
      <category>Spam</category>
      <category>Hacks</category>
      <category>Python</category>
      <category>Recommended</category>
      <category>Probability</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/38</trackback:ping>
    </item>
  </channel>
</rss>
