xsl-list
[Top] [All Lists]

Re: Statistics - Calculating Standard Deviation

2003-06-12 08:55:24

I'd like to be able to calculate the standard deviation of a set of
numbers - much as sun() does.
I've had a look at various websites, extensions etc, and cannot find
anything.
Does anyone know if such functionality is available (and if so - where I
can get it from:)) or should I write my own?

Using FXSL one would write something like this:


<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:ext="http://exslt.org/common";
 xmlns:stdAccum="f:fxsl__stdAccum"
 exclude-result-prefixes="ext stdAccum"

 
 <xsl:import href="foldl.xsl"/>
 <xsl:import href="sqrt.xsl"/>
 
 <xsl:output method="text"/>

  <xsl:template match="/">
   <xsl:call-template name="stdDev">
     <xsl:with-param name="pNums" select="/*/*"/>
   </xsl:call-template>
  </xsl:template>
  
  <xsl:template name="stdDev">
    <xsl:param name="pNums" select="/.."/>
    
    <xsl:variable name="vCount" select="count($pNums)"/>
    
    <xsl:if test="not($vCount > 1)">
      <xsl:message terminate="yes">
      Error[stdDev]: Sample should have at least two numbers
      </xsl:message>
    </xsl:if>
   
    <xsl:variable name="vMean" select="sum($pNums) div $vCount"/>
    
    <xsl:variable name="vrtfParams">
      <mean><xsl:value-of select="$vMean"/></mean>
      <accum>0</accum>
    </xsl:variable>
    
    <xsl:variable name="stdFun" select="document('')/*/stdAccum:*[1]"/>
    
    <xsl:variable name="vsumSQ-Devs">
      <xsl:call-template name="foldl">
        <xsl:with-param name="pFunc" select="$stdFun"/>
        <xsl:with-param name="pA0" select="ext:node-set($vrtfParams)/*"/>
        <xsl:with-param name="pList" select="$pNums"/>
      </xsl:call-template>
    </xsl:variable>
    
    <xsl:call-template name="sqrt">
      <xsl:with-param name="N" 
      select="ext:node-set($vsumSQ-Devs)/accum div ($vCount - 1)"/>
      <xsl:with-param  name="Eps" select="0.00001"/>
    </xsl:call-template>
  </xsl:template>
  
  <stdAccum:stdAccum/>
  <xsl:template match="stdAccum:*">
    <xsl:param name="arg1" select="/.."/> <!-- pA0 -->
    <xsl:param name="arg2"/> <!--Current list-element -->
    
    <mean><xsl:value-of select="$arg1[self::mean]"/></mean>
    <accum>
      <xsl:value-of 
      select="$arg1[self::accum]
             + 
              ($arg2 - $arg1[self::mean]) * ($arg2 - $arg1[self::mean])"/>
    </accum>
  </xsl:template>
</xsl:stylesheet>


When the above transformation is applied on this source.xml:

<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>10</num>
</nums>

The result is:

3.0276503541537023


With MSXML4 + Exslt this takes 9-10 milliseconds on a 800MHz PC.


Hope this helped.




=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL

__________________________________
Do you Yahoo!?
Yahoo! Calendar - Free online calendar with sync to Outlook(TM).
http://calendar.yahoo.com

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list