Commits

Michele Lacchia committed ff183bf

Initial commit

  • Participants

Comments (0)

Files changed (11)

+syntax: glob
+.git
+.gitignore
+*.pyc
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	-rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pyst.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pyst.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/pyst"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pyst"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	make -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."

doc/_themes/emerile/static/default.css_t

+/**
+ * Sphinx stylesheet -- default theme
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+    font-family: {{ theme_bodyfont }};
+    font-size: 100%;
+    background-color: {{ theme_footerbgcolor }};
+    color: #000;
+    margin: 0;
+    padding: 0;
+}
+
+div.document {
+    background-color: {{ theme_sidebarbgcolor }};
+}
+
+div.documentwrapper {
+    float: left;
+    width: 100%;
+}
+
+div.bodywrapper {
+    margin: 0 0 0 230px;
+}
+
+div.body {
+    background-color: {{ theme_bgcolor }};
+    color: {{ theme_textcolor }};
+    padding: 0 20px 30px 20px;
+}
+
+{%- if theme_rightsidebar|tobool %}
+div.bodywrapper {
+    margin: 0 230px 0 0;
+}
+{%- endif %}
+
+div.footer {
+    color: {{ theme_footertextcolor }};
+    width: 100%;
+    padding: 9px 0 9px 0;
+    text-align: center;
+    font-size: 75%;
+}
+
+div.footer a {
+    color: {{ theme_footertextcolor }};
+    text-decoration: none;
+}
+
+div.related {
+    background-color: {{ theme_relbarbgcolor }};
+    line-height: 30px;
+    color: {{ theme_relbartextcolor }};
+}
+
+div.related a {
+    color: {{ theme_relbarlinkcolor }};
+    border-bottom: #89c912 1px dotted;
+}
+
+div.related a:hover {
+	color: #89c912;
+    text-decoration: none;
+}
+
+div.sphinxsidebar {
+    {%- if theme_stickysidebar|tobool %}
+    top: 30px;
+    bottom: 0;
+    margin: 0;
+    position: fixed;
+    overflow: auto;
+    height: auto;
+    {%- endif %}
+    {%- if theme_rightsidebar|tobool %}
+    float: right;
+    {%- if theme_stickysidebar|tobool %}
+    right: 0;
+    {%- endif %}
+    {%- endif %}
+}
+
+{%- if theme_stickysidebar|tobool %}
+/* this is nice, but it it leads to hidden headings when jumping
+   to an anchor */
+/*
+div.related {
+    position: fixed;
+}
+
+div.documentwrapper {
+    margin-top: 30px;
+}
+*/
+{%- endif %}
+
+div.sphinxsidebar h3 {
+    font-family: {{ theme_headfont }};
+    color: {{ theme_sidebartextcolor }};
+    font-size: 1.4em;
+    font-weight: normal;
+    margin: 0;
+    padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+    color: {{ theme_sidebartextcolor }};
+}
+
+div.sphinxsidebar h4 {
+    font-family: {{ theme_headfont }};
+    color: {{ theme_sidebartextcolor }};
+    font-size: 1.3em;
+    font-weight: normal;
+    margin: 5px 0 0 0;
+    padding: 0;
+}
+
+div.sphinxsidebar p {
+    color: {{ theme_sidebartextcolor }};
+}
+
+div.sphinxsidebar p.topless {
+    margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+    margin: 10px;
+    padding: 0;
+    color: {{ theme_sidebartextcolor }};
+}
+
+div.sphinxsidebar a {
+    color: {{ theme_sidebarlinkcolor }};
+    border-bottom: #89c912 1px dotted;
+}
+
+div.sphinxsidebar a:hover {
+	color: #89c912;
+    text-decoration: none;
+}
+
+div.sphinxsidebar input {
+    border: 1px solid {{ theme_sidebarlinkcolor }};
+    font-family: sans-serif;
+    font-size: 1em;
+    background:#f9f9f9;
+    -webkit-border-radius:4px;
+	-moz-border-radius:4px;
+	border-radius:4px;
+}
+
+
+/*input.textbox, input#s
+{
+	border:#ccc 1px solid;
+	
+	font:1em Georgia, Serif;
+	padding:5px;
+	width:135px;
+	height:10px;
+
+}
+* /
+
+/* -- body styles ----------------------------------------------------------- */
+/*li {
+	list-style-image:url(bullets.gif);
+}*/
+a {
+    color: {{ theme_linkcolor }};
+    text-decoration: none;
+    border-bottom: #89c912 1px dotted;
+}
+
+a:hover {
+	color: #89c912;
+    text-decoration: none;
+}
+
+div.body p, div.body dd, div.body li {
+    text-align: justify;
+    line-height: 130%;
+}
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+    font-family: {{ theme_headfont }};
+    background-color: {{ theme_headbgcolor }};
+    font-weight: normal;
+    color: {{ theme_headtextcolor }};
+    border-bottom: 1px solid #ccc;
+    margin: 20px -20px 10px -20px;
+    padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+    color: {{ theme_headlinkcolor }};
+    font-size: 0.8em;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+}
+
+a.headerlink:hover {
+    background-color: {{ theme_headlinkcolor }};
+ 	color: #89c912;
+    text-decoration: none;
+}
+
+div.body p, div.body dd, div.body li {
+    text-align: justify;
+    line-height: 130%;
+}
+
+div.admonition p.admonition-title + p {
+    display: inline;
+}
+
+div.admonition p {
+    margin-bottom: 5px;
+}
+
+div.admonition pre {
+    margin-bottom: 5px;
+}
+
+div.admonition ul, div.admonition ol {
+    margin-bottom: 5px;
+}
+
+div.note {
+    background-color: #eee;
+    border: 1px solid #ccc;
+}
+
+div.seealso {
+    background-color: #ffc;
+    border: 1px solid #ff6;
+}
+
+div.topic {
+    background-color: #eee;
+}
+
+div.warning {
+    background-color: #ffe4e4;
+    border: 1px solid #f66;
+}
+
+p.admonition-title {
+    display: inline;
+}
+
+p.admonition-title:after {
+    content: ":";
+}
+
+pre {
+    padding: 5px;
+    background-color: {{ theme_codebgcolor }};
+    color: {{ theme_codetextcolor }};
+    line-height: 150%;
+    border: 1px solid #ac9;
+    border-left: none;
+    border-right: none;
+}
+
+tt {
+    background-color: #ecf0f3;
+    padding: 0 1px 0 1px;
+    font-size: 0.95em;
+}
+
+.warning tt {
+    background: #efc2c2;
+}
+
+.note tt {
+    background: #d6d6d6;
+}

doc/_themes/emerile/theme.conf

+[theme]
+inherit = basic
+stylesheet = default.css
+pygments_style = sphinx
+
+[options]
+rightsidebar = true
+stickysidebar = false
+
+footerbgcolor    = #62949d
+footertextcolor  = #ffffff
+sidebarbgcolor   = #48443d
+sidebartextcolor = #ffffff
+sidebarlinkcolor = #ffffff
+relbarbgcolor    = #6b7162
+relbartextcolor  = #dbeabb
+relbarlinkcolor  = #ffffff
+bgcolor          = #ffffff
+textcolor        = #000000
+headbgcolor      = #89c912
+headtextcolor    = #ffffff
+headlinkcolor    = #ffffff
+linkcolor        = #000000
+codebgcolor      = #eeeeee
+codetextcolor    = #333333
+
+bodyfont = sans-serif
+headfont = Lucida Grande, Verdana, Arial, Sans-serif
+# -*- coding: utf-8 -*-
+#
+# pyst documentation build configuration file, created by
+# sphinx-quickstart on Sun Dec 19 14:10:28 2010.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.pngmath', 'sphinx.ext.viewcode']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'pyst'
+copyright = u'2010, Michele Lacchia'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.1'
+# The full version, including alpha/beta/rc tags.
+release = '0.1a'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'haiku'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+html_theme_path = ['_themes']
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'pystdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'pyst.tex', u'pyst Documentation',
+   u'Michele Lacchia', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'pyst', u'pyst Documentation',
+     [u'Michele Lacchia'], 1)
+]
+.. pyst documentation master file, created by
+   sphinx-quickstart on Sun Dec 19 14:10:28 2010.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to pyst's documentation!
+================================
+
+pyst is a Python module that provides over 50 statistical functions, including:
+
+    * Univariate statistic
+        * arithmetic mean, harmonic mean, geometric mean, quadratic mean;
+        * running averages, trimmed mean, weighted mean, circular mean;
+        * mode, median, quantiles and quartiles;
+        * deciles, percentiles, absolute deviation;
+        * standard deviation (sample and population), variance (sample and population);
+        * central moments, standardized moments, raw moments;
+        * skewness and kurtosis;
+
+    * Multivariate statistic
+        * Q-correlation coefficient;
+        * Pearson's correlation coefficient (sample and population);
+
+    and others.
+
+Contents
+--------
+
+.. toctree::
+   :maxdepth: 2
+   :numbered:
+
+   univariate.rst
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+	set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+	:help
+	echo.Please use `make ^<target^>` where ^<target^> is one of
+	echo.  html       to make standalone HTML files
+	echo.  dirhtml    to make HTML files named index.html in directories
+	echo.  singlehtml to make a single large HTML file
+	echo.  pickle     to make pickle files
+	echo.  json       to make JSON files
+	echo.  htmlhelp   to make HTML files and a HTML help project
+	echo.  qthelp     to make HTML files and a qthelp project
+	echo.  devhelp    to make HTML files and a Devhelp project
+	echo.  epub       to make an epub
+	echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+	echo.  text       to make text files
+	echo.  man        to make manual pages
+	echo.  changes    to make an overview over all changed/added/deprecated items
+	echo.  linkcheck  to check all external links for integrity
+	echo.  doctest    to run all doctests embedded in the documentation if enabled
+	goto end
+)
+
+if "%1" == "clean" (
+	for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+	del /q /s %BUILDDIR%\*
+	goto end
+)
+
+if "%1" == "html" (
+	%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+	goto end
+)
+
+if "%1" == "dirhtml" (
+	%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+	goto end
+)
+
+if "%1" == "singlehtml" (
+	%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+	goto end
+)
+
+if "%1" == "pickle" (
+	%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the pickle files.
+	goto end
+)
+
+if "%1" == "json" (
+	%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can process the JSON files.
+	goto end
+)
+
+if "%1" == "htmlhelp" (
+	%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+	goto end
+)
+
+if "%1" == "qthelp" (
+	%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pyst.qhcp
+	echo.To view the help file:
+	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pyst.ghc
+	goto end
+)
+
+if "%1" == "devhelp" (
+	%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished.
+	goto end
+)
+
+if "%1" == "epub" (
+	%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The epub file is in %BUILDDIR%/epub.
+	goto end
+)
+
+if "%1" == "latex" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "text" (
+	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The text files are in %BUILDDIR%/text.
+	goto end
+)
+
+if "%1" == "man" (
+	%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The manual pages are in %BUILDDIR%/man.
+	goto end
+)
+
+if "%1" == "changes" (
+	%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.The overview file is in %BUILDDIR%/changes.
+	goto end
+)
+
+if "%1" == "linkcheck" (
+	%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+	goto end
+)
+
+if "%1" == "doctest" (
+	%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+	goto end
+)
+
+:end

doc/univariate.rst

+.. currentmodule:: pyst
+
+Univariate statistics
+=====================
+
+.. contents:: Table of contents
+
+Currently :mod:`pyst` offers these functions:
+
+Averages
+--------
+
+.. autofunction:: mean
+
+.. autofunction:: weighted_mean
+
+.. autofunction:: harmonic_mean
+
+.. autofunction:: geo_mean
+
+.. autofunction:: quadratic
+
+.. autofunction:: running_average(data, m=mean)
+
+.. autofunction:: trimmed_mean(data, p, m=mean)
+
+
+Central tendancy
+----------------
+
+.. autofunction:: mode
+
+.. autofunction:: median(data)
+
+.. autofunction:: midrange
+
+.. autofunction:: midhinge
+
+.. autofunction:: trimean
+
+
+Order statistic
+---------------
+
+.. autofunction:: quantile(data, p, m=0)
+
+.. autofunction:: quartiles(data, m=1)
+
+.. autofunction:: decile
+
+.. autofunction:: percentile
+
+.. autofunction:: hinges
+
+
+Spread
+------
+
+.. autofunction:: pstdev
+
+.. autofunction:: stdev
+
+.. autofunction:: pvariance
+
+.. autofunction:: variance
+
+.. autofunction:: iqr
+
+.. autofunction:: idr
+
+.. autofunction:: range
+
+.. autofunction:: adev(data, m=mean)
+
+.. autofunction:: adev1(data, m=mean, e=1)
+
+.. autofunction:: md
+
+.. autofunction:: rmd
+
+.. autofunction:: m_d
+
+.. autofunction:: mad
+
+
+Moments
+-------
+
+.. autofunction:: moment
+
+.. autofunction:: s_moment
+
+.. autofunction:: r_moment
+
+.. autofunction:: skewness
+
+.. autofunction:: kurtosis
+
+.. autofunction:: quartile_skewness
+
+.. autofunction:: pearson_skewness
+
+.. autofunction:: pearson_mode_skewness

pyst/__init__.py

Empty file added.
+#!/usr/bin/env python
+
+from __future__ import division
+import math
+import operator
+import functools
+import collections
+
+class StatsError(ValueError):
+    '''Raised when pyst have to throw an error'''
+
+def _root(n, k):
+    return n ** (1 / k)
+
+def _bin_coeff(n, k):
+    return math.factorial(n) / (math.factorial(n - k) * math.factorial(k))
+
+def _sorted(func):
+    @functools.wraps(func)
+    def wrapper(data, *args, **kwargs):
+        return func(sorted(data), *args, **kwargs)
+    return wrapper
+
+def _split(func):
+    @functools.wraps(func)
+    def wrapper(xdata, ydata=None):
+        if ydata is None:
+            xdata, ydata = zip(*xdata)
+        n = len(xdata)
+        if n != len(ydata):
+            raise StatsError('xdata and ydata must have the same length')
+        if n == 0:
+            raise StatsError('xdata and ydata cannot be empty')
+        return func(xdata, ydata, n)
+    return wrapper
+
+def _two_pass(data): ## two-pass algorithm
+    m = mean(data)
+    return sum((d - m) ** 2 for d in data)
+
+def _sp(data1, data2):
+    mx, my = mean(data1), mean(data2)
+    return sum((x - mx) * (y - my) for x, y in zip(data1, data2))
+
+def sum(data):
+    return math.fsum(data)
+
+## Others
+
+def afreq(data):
+    return [data.count(d) for d in set(data)]
+
+def rfreq(data):
+    n = len(data)
+    return map(lambda i: i / n, afreq(data))
+
+## Averages
+
+def mean(data):
+    '''
+    Returns the arithmetic mean of *data*.
+    The mean is the sum of the data divided by the number of data.
+    It is usually called *the average*::
+
+        >>> mean([1, -4, 32, 5, 3, 1]) # doctest: +ELLIPSIS
+        6.333333...
+    '''
+
+    n = len(data)
+    if n == 0:
+        raise StatsError('no mean defined for empty data sets')
+    return sum(data) / n
+
+def weighted_mean(data, weights=None):
+    dt = list(set(data))
+    if weights is None:
+        weights = map(lambda i: data.count(i), dt)
+    if len(data) != len(weights) or (len(data), len(weights)) == (0, 0):
+        raise StatsError('data and weights must have the same length and cannot be empty')
+    return sum(map(lambda i: i[0] * i[1], zip(dt, weights))) / sum(weights)
+
+def geo_mean(data):
+    '''
+    Returns the geometric mean of *data*.
+    The geometric mean is the n-th root of the product of the data.
+    It is usually used for averaging exponential growth rates::
+
+        >>> d = [1, .244, 12, 53]
+        >>> geo_mean(d) # doctest: +ELLIPSIS
+        3.5294882...
+    '''
+
+    return _root(reduce(operator.mul, data), len(data))
+
+def quadratic(data):
+    '''
+    Returns the quadratic mean of *data*.
+    The quadratic mean is the square root of the arithmetic mean of the squares
+    of the data. It is usually used when the data vary from negative to positive::
+
+        >>> d = [1, -23, 24, -2, 42, -2]
+        >>> quadratic(d) # doctest: +ELLIPSIS
+        21.9012937...
+    '''
+
+    return math.sqrt(mean([d ** 2 for d in data]))
+
+def harmonic_mean(data):
+    '''
+    Returns the harmonic mean of *data*.
+    The harmonic mean is the reciprocal of the arithmetic mean of the reciprocals
+    of the data. It is usually used for averaging rates::
+
+        >>> d = [1, 2, -5, 2, 0.2]
+        >>> harmonic_mean(d) # doctest: +ELLIPSIS
+        0.73529411...
+        >>> d = [1, -24, .2, 0]
+        >>> harmonic_mean(d)
+        Traceback (most recent call last):
+          File "<pyshell#4>", line 1, in <module>
+            harmonic_mean(d)
+          File "pyst.py", line 97, in harmonic_mean
+            return len(data) / sum(1 / d for d in data)
+          File "pyst.py", line 43, in sum
+            return math.fsum(data)
+          File "pyst.py", line 97, in <genexpr>
+            return len(data) / sum(1 / d for d in data)
+        ZeroDivisionError: float division
+    '''
+
+    return len(data) / sum(1 / d for d in data)
+
+def running_average(data, m=mean):
+    '''
+    Iterates over *data* yielding the running average.
+
+    :param m: a function that compute the average
+    :rtype: generator expression
+
+    Examples::
+
+        >>> d = [1, -32, 42, -3, 42]
+        >>> for i in running_average(d): print i # doctest: +ELLIPSIS
+        1.0
+        -15.5
+        3.66666...
+        2.0
+        10.0
+        >>> list(running_average(d, harmonic_mean)) # doctest: +ELLIPSIS
+        [1.0, 2.06451612..., 3.022488755..., 6.06772009..., 7.320261437...]
+        >>> list(running_average(d, quadratic)) # doctest: +ELLIPSIS
+        [1.0, 22.6384628..., 30.49043565..., 26.4480623..., 30.20595967...]
+    '''
+
+    for i in xrange(1, len(data) + 1):
+        s = data[:i]
+        yield m(s)
+
+@ _sorted
+def trimmed_mean(data, p, m=mean):
+    '''
+    Returns the trimmed mean of *data*.
+    A trimmed mean is calculated by discarding a certain percentage of the
+    lowest and the highest scores and then computing the mean of the remaining scores.
+
+    :param p: the rate to discard
+    :param m: a function that accept an argument. After the data trimming, the remaining score will be passed to this function, default to ``mean``
+    :rtype: float
+
+    Some examples::
+
+        >>> d = [1, 23, 3, 19, 45, 1003]
+        >>> mean(d)
+        182.33333333333334
+        >>> trimmed_mean(d, 0)
+        182.33333333333334
+        >>> trimmed_mean(d, 20)
+        22.5
+        >>> trimmed_mean(d, 25)
+        22.5
+        >>> trimmed_mean(d, 40)
+        22.5
+        >>> trimmed_mean(d, 70)
+        21.0
+        >>> trimmed_mean(d, 100) ## the median
+        21.0
+        >>> trimmed_mean(d, 20, harmonic_mean) # doctest: +ELLIPSIS
+        8.85611348...
+        >>> trimmed_mean(d, 20, quadratic) # doctest: +ELLIPSIS
+        27.0370116...
+        >>> trimmed_mean(d, 20, geo_mean) # doctest: +ELLIPSIS
+        15.5848921...
+    '''
+
+    n = len(data)
+    if not n:
+        raise StatsError('no trimmed mean defined for empty data set')
+    if p == 0:
+        return m(data)
+    me = median(data)
+    c = n / 2 - 1
+    i = int(math.ceil(c * p / 100))
+    d = data[i:-i]
+    if not d:
+        return me
+    return m(d)
+
+def circular_mean(data, deg=False):
+    if deg:
+        data = map(math.radians, data)
+    n = len(data)
+    th = math.atan2(math.fsum(math.sin(d) for d in data) / n, math.fsum(math.cos(d) for d in data) / n)
+    if deg:
+        th = math.degrees(th)
+    return th
+
+###############################
+## Measures of central tendancy
+
+def mode(data):
+    data = sorted((data.count(d), d) for d in set(data))
+    n = len(data)
+    if n == 0:
+        raise StatsError('no mode defined for empty data sets')
+    if n > 1 and data[-1][0] == data[-2][0]:
+        raise StatsError('no distinct mode')
+    return data[-1][1]
+
+@ _sorted
+def median(data):
+    n = len(data)
+    if n == 0:
+        raise StatsError('no median defined for empty data sets')
+    if n & 1:
+        return data[(n + 1) // 2 - 1]
+    return (data[n // 2 - 1] + data[n // 2]) / 2
+
+def md(data): ## mean difference
+    n = len(data)
+    return sum(abs(j - i) for i in data for j in data) / (n * (n - 1))
+
+def rmd(data):
+    return md(data) / mean(data)
+
+def range(data):
+    if len(data) == 0:
+        raise StatsError('no range defined for empty data sets')
+    return abs(max(data) - min(data))
+
+def midrange(data):
+    if len(data) == 0:
+        raise StatsError('no midrange defined for empty data sets')
+    return (max(data) + min(data)) / 2
+
+@ _sorted
+def quantile(data, p, m=0):
+    '''
+    Returns the *p*-th quantile of *data*.
+
+    :param integer m: the method to use, it can be a number from 0 to 9
+    :rtype: an element of *data*
+
+    ======  ======================================================
+    Method  Description
+    ======  ======================================================
+    0
+    1
+    2
+    3
+    4
+    5
+    6
+    7
+    8
+    9
+    ======  ======================================================
+
+    '''
+
+    def _compute(h):
+        return data[int(math.floor(h) - 1)] + (h - math.floor(h)) * (data[int(math.floor(h))] - data[int(math.floor(h) - 1)])
+    def r1():
+        if p == 0:
+            return data[0]
+        h = n * p + .5
+        i = int(math.ceil(h - .5) - 1)
+        if i < 0:
+            return data[0]
+        return data[i]
+    def r2():
+        if p == 0:
+            return data[0]
+        if p == 1:
+            return data[-1]
+        h = n * p + .5
+        i, j = int(math.ceil(h - .5) - 1), int(math.floor(h + .5) - 1)
+        if i < 0 or j < 0:
+            return data[0]
+        return (data[i] + data[j]) / 2
+    def r3(): ##! does not give h = (N + 1) / 2 when p = 1/2
+        if p < .5 / n:
+            return data[0]
+        h = n * p
+        return data[int(max(1, round(h)) - 1)]
+    def r4(): ##! does not give h = (N + 1) / 2 when p = 1/2
+        if p < 1 / n:
+            return data[0]
+        if p == 1:
+            return data[-1]
+        h = n * p
+        return _compute(h)
+    def r5():
+        if p < .5 / n:
+            return data[0]
+        if p >= (n - .5) / n:
+            return data[-1]
+        h = n * p + .5
+        return _compute(h)
+    def r6():
+        if p < 1 / (n + 1):
+            return data[0]
+        if p >= n / (n + 1):
+            return data[-1]
+        h = (n + 1) * p
+        return _compute(h)
+    def r7():
+        if p == 1:
+            return data[-1]
+        h = (n - 1) * p + 1
+        return _compute(h)
+    def r8():
+        if p < (2 / 3) / (n + 1/3):
+            return data[0]
+        if p >= (n - 1 / 3) / (n + 1 / 3):
+            return data[-1]
+        h = (n + 1 / 3) * p + 1 / 3
+        return _compute(h)
+    def r9():
+        if p < (5 / 8) / (n + 1 / 4):
+            return data[0]
+        if p >= (n - 3 / 8) / (n + 1 / 4):
+            return data[-1]
+        h = (n + 1 / 4) * p + 3 / 8
+        return _compute(h)
+    def unknown():
+        if p < (3 / 2) / (n + 2):
+            return data[0]
+        if p >= (n + 1 / 2) / (n + 2):
+            return data[-1]
+        h = (n + 2) * p - .5
+        return _compute(h)
+
+    n = len(data)
+    methods = [r1, r2, r3, r4, r5, r6, r7, r8, r9, unknown]
+    return methods[m]()
+
+@ _sorted
+def parametrized_quantile(data, p, scheme):
+    n = len(data)
+    a, b, c, d = scheme
+    if n < 2:
+        raise StatsError('need at least 2 elements to split data into quantiles')
+    x = a + (n + b) * p
+    i, ii = map(int, (math.ceil(x), math.floor(x)))
+    return data[i] + (data[ii] - data[i]) * (c + d * math.modf(x)[0])
+
+@ _sorted
+def quartiles(data, m=1):
+    '''
+    Returns the quantiles Q1, Q2 and Q3, where one quarter of the data is below Q1, two quarters below Q2 and three quarters below Q3.
+    The exact values Q1, Q2 and Q3 depend on the method (default to 1):
+
+    ======  ============================================================
+    Method  Description
+    ======  ============================================================
+    0       Standard method (1)
+    1       Method used by Minitab software (2)
+    2       Tukey's method, the median is included in the two halves (3)
+    3       Method recommended by Moore and McCabe
+    4       Method recommended by Mendenhall and Sincich (4)
+    5       Method recommended by Freund and Perles (2) (5)
+    ======  ============================================================
+
+    Notes:
+
+    (1) Compute the first quartile Q1 with ``n / 4`` and Q3 with ``3n / 4``
+    (2) Uses linear interpolation between items
+    (3) Equivalent to Tukey's hinges H1, M, H2
+    (4) Ensure that value returned are always data points
+    (5) For compatibility with Microsoft Excel and OpenOffice, use this method
+    '''
+
+    n = len(data)
+    if n < 3:
+        raise StatsError('need at least 3 items')
+    methods = [[(n / 4, n * 3 / 4), (n / 4, n * 3 / 4)], ## Standard method
+               [((n + 1) / 4, (3*n + 3) / 4), ((n + 1) / 4, (3*n + 3) / 4)], ## Minitab's method
+               [((n + 2) / 4, (3*n + 2) / 4), ((n + 3) / 4, (3*n + 1) / 4)], ## Tukey's method
+               [((n + 2) / 4, (3*n + 2) / 4), ((n + 1) / 4, (3*n + 3) / 4)], ## Moore and McCabe
+               [map(round, ((n + 1) / 4, (3*n + 3) / 4)), map(round, ((n + 1) / 4, (3*n + 3) / 4))], ## Mendenhall and Sincich
+               [((n + 3) / 4, (3*n + 1) / 4), ((n + 3) / 4, (3*n + 1) / 4)]] ## Freund and Perles
+    q1, q3 = map(math.ceil, methods[m][n & 1])
+    return (data[int(q1 - 1)], median(data), data[int(q3 - 1)])
+
+def hinges(data):
+    return quartiles(data, 2)
+
+def midhinge(data):
+    h1, _, h3 = hinges(data)
+    return (h1 + h3) / 2
+
+def trimean(data):
+    q1, q2, q3 = hinges(data)
+    return (q1 + 2*q2 + q3) / 4
+
+def decile(data, d, m=0):
+    if not 0 <= d <= 10:
+        raise StatsError('d must be between 0 and 10')
+    return quantile(data, d / 10, m)
+
+def percentile(data, p, m=0):
+    if not 0 <= p <= 100:
+        raise StatsError('p must be between 0 and 100')
+    return quantile(data, p / 100, m)
+
+def iqr(data, m=0):
+    q1, _, q3 = quartiles(data, m)
+    return abs(q3 - q1)
+
+def idr(data, m=0): ## Inter-decile range
+    d1, d9 = decile(data, 0, m), decile(data, 9, m)
+    return d1 - d9
+
+def adev(data, m=median): ## absolute deviation
+    '''
+    Returns the absolute deviation from the point *m*.
+
+    :param list data: the data
+    :param m: can be either a callable object or a number. If it is a callable the absolute deviation will be computed from ``m(data)`` (it must be a number)
+    :type m: number or callable
+    :rtype: a list of numbers
+
+    Some examples::
+
+        >>> data = [1, 2, 3, 4, 5]
+        >>> adev(data, data[0]) ## Absolute deviation from the first point
+        [0, 1, 2, 3, 4]
+        >>> adev(data, data[-1]) ## Absolute deviation from the last point
+        [4, 3, 2, 1, 0]
+        >>> adev(data) ## Absolute deviation from the median
+        [2, 1, 0, 1, 2]
+        >>> adev(data, mean) ## Absolute deviation from the arithmetic mean
+        [2.0, 1.0, 0.0, 1.0, 2.0]
+        >>> adev(data + [1], mode) ## Absolute deviation from the mode
+        [0, 1, 2, 3, 4, 0]
+        >>> adev(data, harmonic_mean) ## Absolute deviation from the harmonic mean # doctest: +ELLIPSIS
+        [1.18978102..., 0.18978102..., 0.81021897..., 1.81021897..., 2.81021897...]
+    '''
+
+    try:
+        c = m(data)
+    except TypeError:
+        c = m
+    return [abs(d - c) for d in data]
+
+def adev1(data, m=median, e=1):
+    '''
+    Like :func:`adev`, but raise each element to *e* and after the sum take the *e*-th root::
+
+        >>> data = [1, 2, 3, 4, 5]
+        >>> adev1(data, data[0], 2) # doctest: +ELLIPSIS
+        5.47722557...
+
+    Equivalent to::
+
+        >>> adev(data, data[0]) ## Absolute deviation from the first point
+        [0, 1, 2, 3, 4]
+        >>> sum(map(lambda i: i ** 2, adev(data, data[0]))) ** (1. / 2) # doctest: +ELLIPSIS
+        5.47722557...
+
+    other examples::
+
+        >>> adev1(data, data[0], 9) # doctest: +ELLIPSIS
+        4.03312218...
+        >>> sum(map(lambda i: i ** 9, adev(data, data[0]))) ** (1. / 9) # doctest: +ELLIPSIS
+        4.03312218...
+        >>> adev1(data, median, 9) # doctest: +ELLIPSIS
+        2.16058784...
+        >>> sum(map(lambda i: i ** 9, adev(data, median))) ** (1. / 9) # doctest: +ELLIPSIS
+        2.16058784...
+    '''
+
+    try:
+        c = m(data)
+    except TypeError:
+        c = m
+    return _root(sum(abs(d - c) ** e for d in data), e)
+
+def m_d(data): ## mean absolute deviation
+    return mean(adev(data, mean))
+
+def mad(data): ## median absolute deviation
+    return median(adev(data))
+
+#####################
+## Measures of spread
+
+def stdev(data):
+    '''
+    Returns the sample standard deviation of *data*::
+
+        >>> d = [1, 2, 3, 3, 5, 5, 5, 8]
+        >>> stdev(d) # doctest: +ELLIPSIS
+        2.20389...
+    '''
+
+    m = mean(data)
+    n = len(data)
+    if n < 2:
+        raise StatsError('standard deviation requires at leas 2 elements')
+    return math.sqrt(sum((d - m) ** 2for d in data) / (n - 1))
+
+def pstdev(data):
+    '''
+    Returns the population standard deviation of *data*::
+
+        >>> d = [1, 2, 3, 3, 5, 5, 5, 8]
+        >>> pstdev(d) # doctest: +ELLIPSIS
+        2.06155...
+    '''
+    m = mean(data)
+    n = len(data)
+    if n < 2:
+        raise StatsError('standard deviation requires at leas 2 elements')
+    return math.sqrt(sum(((d - m) ** 2 for d in data)) / n)
+
+def pvariance(data): ## population variance
+    n = len(data)
+    if n < 2:
+        raise StatsError('variance requires at leas 2 elements')
+    return _two_pass(data) / n
+
+def variance(data): ## sample variance
+    n = len(data)
+    if n < 2:
+        raise StatsError('variance requires at leas 2 elements')
+    return _two_pass(data) / (n - 1)
+
+def sterrmean(s, n, N=None):
+    if N is not None and N < n:
+        raise StatsError('the population cannot be smaller than the sample')
+    if n < 0:
+        raise StatsError('the sample size cannot be negative')
+    if s < 0.0:
+        raise StatsError('standard deviation cannot be negative')
+    if n == 0:
+        if N == 0:
+            return float('nan')
+        else:
+            return float('+inf')
+    st = s / math.sqrt(n)
+    if N is not None:
+        return st * math.sqrt((N - n) / (N - 1))
+    return st
+
+################
+## Other moments
+
+def moment(data, k): ## Central moment
+    if k == 0:
+        return 1.
+    if k == 1:
+        return 0.
+    m = mean(data)
+    return sum((d - m) ** k for d in data) / len(data)
+
+def s_moment(data, k): ## Standardized moment 
+    return moment(data, k) / (stdev(data) ** k)
+
+def r_moment(data, k): ## Raw moment
+    m = mean(data)
+    if k == 1:
+        return m
+    return sum(_bin_coeff(k, n) * moment(data, n) * m ** (k - n) for n in xrange(k + 1))
+
+def skewness(data):
+    return moment(data, 3) / (moment(data, 2) ** (3 / 2))
+
+def kurtosis(data): ## kurtosis coeff, excess kurtosis
+    b = moment(data, 4) / (moment(data, 2) ** 2)
+    return b, b - 3
+
+def quartile_skewness(q1, q2, q3): # or bowley skewness
+    return (q1 - 2*q2 + q3) / (q3 - q1)
+
+def pearson_mode_skewness(m, mo, s):
+    if s == 0:
+        return float('nan') if m == mo else float('+inf')
+    if s > 0:
+        return (m - mo) / s
+    raise StatsError('standard deviation cannot be negative')
+
+def pearson_skewness(m, mo, me, s):
+    if s < 0:
+        raise StatsError('standard deviation cannot be negative')
+    return (3 * (m - mo) / s, 3 * (m - me) / s)
+
+###########################
+## Indexes and coefficients
+
+def pcv(data): ## coefficient of variation of a population
+    return pstdev(data) / mean(data)
+
+def cv(data): ## coefficient of variation of a sample
+    return stdev(data) / mean(data)
+
+def id(data): ## Index of dispersion
+    return variance(data) / mean(data)
+
+def gini(data):
+    '''
+    Returns the Gini coefficient, a number between ``0`` and ``(n - 1) / n``.
+    It is ``0`` when all the data are equal, and it is ``(n - 1) / n`` when all the data are different::
+
+        >>> d = [1, 2, 3, 4]
+        >>> gini(d)
+        0.75
+        >>> d = [1, 1, 2, 2, 3, 3]
+        >>> gini(d) # doctest: +ELLIPSIS
+        0.666666...
+        >>> d = [1, 1, 2, 2]
+        >>> gini(d)
+        0.5
+        >>> d = [1, 1, 1, 1]
+        >>> gini(d)
+        0.0
+    '''
+
+    if len(data) == 0:
+        raise StatsError('no Gini coefficient defined for empty data set')
+    return 1 - sum(map(lambda i: i ** 2, rfreq(data)))
+
+def gini1(data):
+    '''
+    Returns the normalized Gini coefficient, a number between 0 and 1. It is 0
+    when all the data are equal and 1 when all the data are different::
+
+        >>> d = [1, 2, 3, 4]
+        >>> gini1(d)
+        1.0
+        >>> d = [1, 2, 3, 4, 5, 1, 3, 4, 6, 7, 2]
+        >>> gini1(d) # doctest: +ELLIPSIS
+        0.92727272...
+        >>> d = [1]
+        >>> gini1(d)
+        0.0
+        >>> gini([])
+        Traceback (most recent call last):
+          File "<pyshell#1>", line 1, in <module>
+            gini([])
+          File "pyst.py", line 559, in gini
+            raise StatsError('no Gini coefficient defined for empty data set')
+        StatsError: no Gini coefficient defined for empty data set
+    '''
+
+    n = len(data)
+    if n == 1:
+        return 0.
+    return gini(data) * n / (n - 1)
+
+def shannon(data):
+    '''
+    Returns the Shannon index of *data*, a number between ``0`` and ``ln n``.
+    It is ``0`` when all the data are equal
+
+        
+    '''
+
+    if len(data) == 0:
+        raise StatsError('no Shannon index defined for empty data set')
+    return - sum(r * math.log(r) for r in rfreq(data))
+
+def shannon1(data):
+    n = len(data)
+    if n == 1:
+        return 0.
+    return shannon(data) / math.log(n)
+
+## Other functions
+
+def z_score(x, m, s):
+    return (x - m) / s
+
+## Multivariate
+
+@ _split
+def pcov(xdata, ydata, n):
+    sp = _sp(xdata, ydata)
+    return sp / n
+
+@ _split
+def cov(xdata, ydata, n):
+    sp = _sp(xdata, ydata)
+    return sp / (n - 1)
+
+@ _split
+def qcorr(xdata, ydata, n):
+    ac = bd = s = 0
+    xmed, ymed = median(xdata), median(ydata)
+    for x, y in zip(xdata, ydata):
+        if (x > xmed and y > ymed) or (x < xmed and y < ymed):
+            ac += 1
+        elif (x > xmed and y < ymed) or (x < xmed and y > ymed):
+            bd += 1
+        else:
+            s += 1
+    return (ac - bd) / (n - s)
+
+@ _split
+def pcorr(xdata, ydata, n):
+    sx, sy, sxy, sx2, sy2 = sum(xdata), sum(ydata), \
+                            sum(x * y for x, y in zip(xdata, ydata)), \
+                            sum(x**2 for x in xdata), sum(y**2 for y in ydata)
+    return (sxy - sx * sy / n) / math.sqrt((sx2 - sx ** 2 / n) * (sy2 - sy ** 2 / n))
+
+@ _split
+def corr(xdata, ydata, n):
+    mx, sx = mean(xdata), stdev(xdata)
+    my, sy = mean(ydata), stdev(ydata)
+    return sum(z_score(x, mx, sx) * z_score(y, my, sy) for x, y in zip(xdata, ydata)) / n
+
+
+##################################################################################
+############# Still in development ###############################################
+##################################################################################
+
+
+if __name__ == '__main__':
+    import doctest
+    doctest.testmod()

pyst/test_pyst.py

+from __future__ import division
+
+import py
+from pyst import *
+
+class TestAverages(object):
+    def test_mean(self):
+        assert mean([1, 2, 3, 4]) == 2.5
+        assert mean([0]) == 0
+        with py.test.raises(StatsError):
+            mean([])
+
+    def test_weighted_mean(self):
+        assert weighted_mean([1, 2, 3, 4]) == mean([1, 2, 3, 4])
+        assert weighted_mean([1, 2, 3, 4], [1, 3, 2, 1]) == mean([1, 2, 2, 2, 3, 3, 4])
+        with py.test.raises(StatsError):
+            weighted_mean([], [1])
+            weighted_mean([], [])
+
+    def test_harmonic_mean(self):
+        assert harmonic_mean([0.25, 0.5, 1.0, 1.0]) == .5
+        assert harmonic_mean([1]) == 1
+        assert harmonic_mean([1] * 100) == 1
+        with py.test.raises(ZeroDivisionError):
+            harmonic_mean([1, 2, 3, 0])
+            harmonic_mean([0])
+            harmonic_mean([])
+
+    def test_geo_mean(self):
+        assert geo_mean([1.0, 2.0, 6.125, 12.25]) == 3.5
+        assert geo_mean([2, 8]) == 4
+        assert geo_mean([1]) == 1
+        assert geo_mean([0]) == 0
+        with py.test.raises(TypeError):
+            geo_mean([])
+
+    def test_quadratic(self):
+        assert quadratic([2, 2, 4, 5]) == 3.5
+        assert quadratic([-2, 2, 4, -5]) == 3.5
+        assert quadratic([2, -2, 4, 5]) == 3.5
+        assert quadratic([-2, 2, -4, 5]) == 3.5
+        with py.test.raises(StatsError):
+            quadratic([])
+
+    def test_running_average(self):
+        pass
+
+    def test_trimmed_mean(self):
+        pass
+
+
+class TestCentralTendancy(object):
+    def test_mode(self):
+        assert mode([0, -42, 24, 24, 2, 1, 4]) == 24
+        with py.test.raises(StatsError):
+            mode([])
+            mode([1, 2, 3, 4])
+
+    def test_median(self):
+        assert median([1, 2, -4]) == 1
+        assert median([-4, -1, 4, -7]) == -2.5
+        with py.test.raises(StatsError):
+            median([])
+
+    def test_midrange(self):
+        assert midrange([2.0, 4.5, 7.5]) == 4.75
+        with py.test.raises(StatsError):
+            midrange([])
+
+    def test_midhinge(self):
+        assert midhinge([1, 1, 2, 3, 4, 5, 6, 7, 8, 8]) == 4.5
+        with py.test.raises(StatsError):
+            midhinge([])
+
+    def test_trimean(self):
+        assert trimean([1, 1, 3, 5, 7, 9, 10, 14, 18]) == 6.75
+        assert trimean([0, 1, 2, 3, 4, 5, 6, 7, 8]) == 4
+        d = xrange(100)
+        assert trimean(d) == (median(d) + midhinge(d)) / 2
+        with py.test.raises(StatsError):
+            trimean([])
+
+
+class TestOrderStatistic(object):
+    def test_quantile(self):
+        pass
+
+    def test_quartiles(self):
+        pass
+
+    def test_decile(self):
+        d = xrange(11)
+        for i in xrange(11):
+            assert decile(d, i) == d[i]
+        d = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
+        assert decile(d, 7) == 14
+        with py.test.raises(IndexError):
+            decile([], 1)
+
+    def test_percentile(self):
+        d = xrange(101)
+        for i in xrange(101):
+            assert percentile(d, i) == d[i]
+        d = xrange(1, 201)
+        assert percentile(d, 7) == 15
+        assert percentile(d, 7, 2) == 14
+        with py.test.raises(IndexError):
+            percentile([], 1)
+
+    def test_hinges(self):
+        assert hinges(xrange(9)) == (2, 4, 6)
+        assert hinges([2, 4, 6, 8, 10, 12, 14, 16, 18]) == (6, 10, 14)
+        with py.test.raises(StatsError):
+            hinges([])
+
+
+class TestSpread(object):
+    def test_stdev(self):
+        assert stdev([1, 2, 3, 4, 5, 6]) == 1.8708286933869707
+        with py.test.raises(StatsError):
+            stdev([])
+            stdev([1])
+
+    def test_pstdev(self):
+        assert pstdev([2, 4, 4, 4, 5, 5, 7, 9]) == 2
+        with py.test.raises(StatsError):
+            pstdev([])
+            pstdev([1])
+
+    def test_variance(self):
+        pvariance([1, 2, 3, 4, 5, 6]) == 2.9166666666666666
+        with py.test.raises(StatsError):
+            pvariance([])
+            pvariance([1])
+
+    def test_pvariance(self):
+        assert pvariance([2, 4, 4, 4, 5, 5, 7, 9]) == 4
+        with py.test.raises(StatsError):
+            pvariance([])
+            pvariance([1])
+
+    def test_iqr(self):
+        d = xrange(102, 119, 2)
+        for i in xrange(6):
+            assert iqr(d, i) in (8, 10)
+
+    def test_idr(self):
+        assert idr(xrange(11)) == -9
+        with py.test.raises(IndexError):
+            idr([])
+
+    def test_range(self):
+        assert range([1, 2]) == 1
+        assert range([1, -42, 4, 64, 4, -4]) == 106
+        with py.test.raises(StatsError):
+            range([])
+
+    def test_adev(self):
+        d = [1, 2, 3, 4, 5]
+        assert adev(d, d[0]) == [0, 1, 2, 3, 4]
+        assert adev(d, d[-1]) == [4, 3, 2, 1, 0]
+        assert adev(d) == [2, 1, 0, 1, 2]
+        assert adev(d + [6]) == [2.5, 1.5, .5, .5, 1.5, 2.5]
+        assert adev(d, mean) == [2, 1, 0, 1, 2]
+        with py.test.raises(StatsError):
+            adev(d, mode)
+            adev([])
+
+    def test_adev1(self):
+        d = [1, 2, 3, 4, 5]
+        assert adev1(d, d[0], 2) == (30 ** .5)
+        assert adev1(d, d[0], 2) == adev1(d, d[-1], 2)
+        assert adev1(d, e=2) == (10 ** .5)
+        with py.test.raises(StatsError):
+            adev1(d, mode)
+            adev1([])
+
+    def test_md(self):
+        d = [1, 2, 3, 4]
+        assert md(d) == 20 / 12
+
+    def test_rmd(self):
+        pass
+
+    def test_m_d(self):
+        pass
+
+    def test_mad(self):
+        assert mad([1, 1, 2, 2, 4, 6, 9]) == 1
+        with py.test.raises(StatsError):
+            mad([])
+
+
+class TestMoments(object):
+    def test_moment(self):
+        d = xrange(1, 6)
+        assert moment(d, 0) == 1
+        assert moment(d, 1) == 0
+        assert moment(d, 2) == 2
+        assert moment(d, 3) == 0
+
+    def test_standardized_moment(self):
+        pass
+
+    def test_raw_moment(self):
+        pass
+
+    def test_skewness(self):
+        d, d1 = [1, 2, 3, 4, 5], [5, 4, 3, 2, 1]
+        assert skewness(d) == skewness(d1) == 0
+
+    def test_kurtosis(self):
+        pass
+
+    def test_quartile_skewness(self):
+        pass
+
+    def test_pearson_skewness(self):
+        pass
+
+    def test_pearson_mode_skewness(self):
+        pass
+
+
+class TestOthers(object):
+    def test_afreq(self):
+        assert afreq([1, 1, 2, 3, 4]) == [2, 1, 1, 1]
+        assert afreq([]) == []
+
+    def test_rfreq(self):
+        assert rfreq([1, 1, 2, 3, 4]) == [.4, .2, .2, .2]
+        assert rfreq([]) == []