ready to roll version of newspaper article topic classifier

Thomas Michael Hagen <[email protected]> Wed, 6 May 2009 17:10:57 +0200
Newsgroups gmane.mail.spam.crm114
Message-ID <[email protected]>
i'm on my fifth version now, after a lot of work, and a lot of
valuable input from this list.

eight people in my department are now going to train the classifier by
categorizing about a thousand articles each.

here is the core of the program they are using:

i hope this can be of use to some, and i always love harsh feedback :)


:try-to-classify: (:article:)
{
    #THE CLASSIFICATION HALF:
    {
	{
	    isolate (:stats:)
	    classify <osbf microgroom> [:article:] \
		    (bus.cfc cli.cfc con.cfc cul.cfc dom.cfc \
		    eco.cfc edu.cfc ene.cfc ent.cfc env.cfc \
		    for.cfc hea.cfc loc.cfc pol.cfc sci.cfc \
		    spo.cfc tec.cfc tra.cfc wor.cfc | unc.cfc out.cfc) (:stats:)
	    match (:: :class-conc:) [:stats:] /(...)\.cfc/ #perhaps pick the
top 3 cats, and tag article with all 3 (if above some threshold)
	    { #classify succeeded, checking pR:
		match (:: :pR:) [:stats:] /Best match.*: (.*)  \nTotal/
		output /pR::*:pR:. /
		eval /:@::*:pR: > 30:/ #play around with this number
		output /Classify succeeded as ':*:class-conc:'\n/
		return
	    }
	    output /Classification NOT confident! Please classify:\n\n/
	}
	alius
	{
	    output /Classify failed! Please classify:\n\n/
	}
    }
    #compare a low conf answer with the result of try-to-learn here,
and use it if they are the same
    isolate (:conc-file:) /:*:class-conc:.cfc/
    isolate (:interaction:) /:*:class-conc::*:article::*:stats:/
    call /:interact:/ [:*:interaction:] #asking the user for the right topic
    { #if the answer was right, use that answer, and refute fram all
other categories:
	match [:user-feedback:] /^y$/
	isolate (:user-feedback:) /:*:class-conc:/
	isolate (:refute-args:) /:*:conc-file::*:article:/
	call /:refute:/ [:*:refute-args:]
    }
    #THE LEARNING HALF:
    isolate (:user-feedback-conc-file:) /:*:user-feedback:.cfc/
    isolate (:count:) /7/
    isolate (:print-p:) /1/
    { # entering the training loop
	learn <osbf microgroom> (:*:user-feedback-conc-file:) [:article:]
	{
	    match [:print-p:] /1/
	    output /\nLearning as :*:user-feedback-conc-file:...\n/
	    isolate (:print-p:) /0/
	}
	isolate (:stats2:)
	{ #reclassifying to check improvement:
	    classify <osbf microgroom> [:article:]	\
		    (bus.cfc cli.cfc con.cfc cul.cfc dom.cfc \
		    eco.cfc edu.cfc ene.cfc ent.cfc env.cfc \
		    for.cfc hea.cfc loc.cfc pol.cfc sci.cfc \
		    spo.cfc tec.cfc tra.cfc wor.cfc | unc.cfc out.cfc) (:stats2:)
	    isolate (:pR2:) #here, you assume it ends up with the same cat as
before. what if it doesn't?
	    match (:: :pR2:) [:stats2:] /Best match.*: (.*)  \nTotal/
	    isolate (:improvement:)
	    eval (:improvement:) /:@:(:*:pR2: - :*:pR:):/
	    output /imp::*:improvement:\n/
	    eval /:@::*:improvement: > 3:/
	    eval /:@::*:pR2: > 10:/ #play around with this number too
	    output /Succesfully learned! Moving on\n/
	    return
	}
	eval (:count:) /:@::*:count: - 1:/
	{
	    eval /:@::*:count: > 0:/
	    liaf
	}
	alius
	{
	    output /Didn't improve enough; reinforcing your answer...\n/
	    call /:refute:/ [:*:refute-args:]
	}
    }
    return /:*:user-feedback:/
}

insert interact.crm

:refute: (:aargh:) # here, we train OUT of all the incorrect classes
{
    output /Reinforcing correct answer...\n/
    {
	match (:: :conc-ffile: :aarticle:) [:aargh:] /(...\.cfc)(.*)/
	isolate (:cfc-files:) /bus.cfc cli.cfc con.cfc cul.cfc dom.cfc
eco.cfc edu.cfc ene.cfc ent.cfc env.cfc for.cfc hea.cfc loc.cfc
pol.cfc sci.cfc spo.cfc tec.cfc tra.cfc wor.cfc unc.cfc out.cfc /
	{ #first instance:
	    match (:: :cfc-file:) /(.*?\.cfc) / [:cfc-files:]
	    {
		match <absent> /:*:conc-ffile:/ [:cfc-file:]
		learn <osbf microgroom refute> (:*:cfc-file:)  [:aarticle:]
	    }
	    { #next instances:
		match <fromnext> (:: :cfc-file:) /(.*?\.cfc) / [:cfc-files:]
		{
		    match <absent> /:*:conc-ffile:/ [:cfc-file:]
		    learn <osbf microgroom refute> (:*:cfc-file:)  [:aarticle:]
		}
		liaf
	    }
	}
	return
    }
    output /Match missed in refute!\n/
    return
}

------------------------------------------------------------------------------
The NEW KODAK i700 Series Scanners deliver under ANY circumstances! Your
production scanning environment may not be a perfect world - but thanks to
Kodak, there's a perfect scanner to get the job done! With the NEW KODAK i700
Series Scanner you'll get full speed at 300 dpi even with all image 
processing features enabled. http://p.sf.net/sfu/kodak-com