#!/usr/local/bin/pythonw
#coding: iso-8859-1
# Copyright © 2005 by Amos Newcombe.
# 
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along with this program.  If not, see <http://www.gnu.org/licenses/>.

'''robust statistical measures.
'''

from Statistics import Statistics
	
class Ordinal(Statistics):
	'''Collect statistics based on the ordinal characteristics of the data, most notably the median.
	
	The statistics are returned in self.lxStats: a leading sublist of [count, median, interquartile range, quartile skewness] of length cOrder+1. cOrder can be any integer or floating point number, but in no case does self.lxStats have length less than 1 or greater than 4.

	The interquartile range is 3rd quartile - 1st quartile; the quartile skewness is (3rd quartile - median) - (median - 1st quartile).
	
	Using this object has a side effect of sorting the data list passed to it. If you don't want that to happen to your original data, pass a copy: Ordinal(lxData[:]).
	'''
	
	def __init__(self, lxData=None, cOrder=2):
		Statistics.__init__(self, lxData, cOrder=cOrder)
		self['order'] = cOrder
	
	def Calculate(self):
		lxData = self.getData()
		lxData.sort()
		self['min'] = lxData[0]
		self['max'] = lxData[-1]
		cOrder = self['order']
		n = len(lxData)
		self['ordinal'] = [n]
		if cOrder < 1: return self

		xMedian = self.percentile(0.5)
		self['ordinal'].append(xMedian)
		self['median'] = xMedian
		if cOrder < 2: return self
		
		xQuartile1 = self.percentile(0.25)
		xQuartile3 = self.percentile(0.75)
		self['ordinal'].append(xQuartile3 - xQuartile1)
		self['iqrange'] = xQuartile3 - xQuartile1
		if cOrder < 3: return self
		
		self['ordinal'].append(xQuartile3 - 2*xMedian + xQuartile1)
		return self
		
	def percentile(self, p):
		'''Return the value that is a fraction p through the data.
		
		For example, percentile(0.5) is the median, and the quartiles are percentile(0.25) and percentile(0.75).
		'''
		lx = self.getData()
		n = self['ordinal'][0]
		if p == 1.: return lx[n-1]
		x = float(p) * (n-1)
		q = int(x)
		r = x - q
		return lx[q] * (1.-r) + lx[q+1] * r

if __name__ == '__main__':
	
	from random import random
	from StatTest import Test

	Test(Ordinal([random() for n in range(128)], cOrder=4), globals(), locals())
