├── .gitignore ├── MANIFEST.in ├── astroML_addons ├── __init__.py ├── setup.py └── periodogram.pyx ├── Makefile ├── setup.py └── README.rst /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.pyc 3 | 4 | MANIFEST -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.rst 2 | recursive-include astroML_addons *.py *.pyx *.c -------------------------------------------------------------------------------- /astroML_addons/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['periodogram'] 2 | __version__ = '0.3-git' 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PYTHON ?= python 2 | NOSETESTS ?= nosetests 3 | 4 | SOURCES = Makefile setup.py README.rst astroML_addons 5 | 6 | VERSION = 0.2-git 7 | 8 | all: build install test 9 | 10 | build: 11 | $(PYTHON) setup.py build 12 | 13 | install: 14 | $(PYTHON) setup.py install 15 | 16 | clean: 17 | $(PYTHON) setup.py clean 18 | 19 | inplace: 20 | $(PYTHON) setup.py build_ext -i 21 | -------------------------------------------------------------------------------- /astroML_addons/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | def configuration(parent_package='', top_path=None): 4 | import numpy 5 | from numpy.distutils.misc_util import Configuration 6 | 7 | config = Configuration('astroML_addons', parent_package, top_path) 8 | libraries = [] 9 | if os.name == 'posix': 10 | libraries.append('m') 11 | 12 | config.add_extension('periodogram', 13 | sources=['periodogram.c'], 14 | include_dirs=[numpy.get_include()], 15 | libraries=libraries) 16 | 17 | return config 18 | 19 | if __name__ == '__main__': 20 | from numpy.distutils.core import setup 21 | setup(**configuration(top_path='').todict()) 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy 3 | from numpy.distutils.core import setup 4 | 5 | DESCRIPTION = "Performance add-ons for the astroML package" 6 | LONG_DESCRIPTION = open('README.rst').read() 7 | NAME = "astroML_addons" 8 | AUTHOR = "Jake VanderPlas" 9 | AUTHOR_EMAIL = "vanderplas@astro.washington.edu" 10 | MAINTAINER = "Jake VanderPlas" 11 | MAINTAINER_EMAIL = "vanderplas@astro.washington.edu" 12 | URL = 'http://astroML.github.com' 13 | DOWNLOAD_URL = 'http://github.com/astroML/astroML' 14 | LICENSE = 'BSD' 15 | 16 | # import partial version of the package for version info 17 | import astroML_addons 18 | VERSION = astroML_addons.__version__ 19 | 20 | def configuration(parent_package='', top_path=None): 21 | if os.path.exists('MANIFEST'): 22 | os.remove('MANIFEST') 23 | 24 | from numpy.distutils.misc_util import Configuration 25 | config = Configuration(None, parent_package, top_path) 26 | 27 | # Avoid non-useful msg: 28 | # "Ignoring attempt to set 'name' (from ... " 29 | config.set_options(ignore_setup_xxx_py=True, 30 | assume_default_configuration=True, 31 | delegate_options_to_subpackages=True, 32 | quiet=True) 33 | 34 | config.add_subpackage('astroML_addons') 35 | 36 | return config 37 | 38 | setup(configuration=configuration, 39 | name=NAME, 40 | version=VERSION, 41 | description=DESCRIPTION, 42 | long_description=LONG_DESCRIPTION, 43 | author=AUTHOR, 44 | author_email=AUTHOR_EMAIL, 45 | maintainer=MAINTAINER, 46 | maintainer_email=MAINTAINER_EMAIL, 47 | url=URL, 48 | download_url=DOWNLOAD_URL, 49 | license=LICENSE, 50 | classifiers=[ 51 | 'Development Status :: 4 - Beta', 52 | 'Environment :: Console', 53 | 'Intended Audience :: Science/Research', 54 | 'License :: OSI Approved :: BSD License', 55 | 'Natural Language :: English', 56 | 'Programming Language :: Python :: 2.6', 57 | 'Topic :: Scientific/Engineering :: Astronomy'], 58 | ) 59 | -------------------------------------------------------------------------------- /astroML_addons/periodogram.pyx: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | cimport numpy as np 3 | 4 | cimport cython 5 | 6 | cdef extern from "math.h": 7 | double sin(double) 8 | double cos(double) 9 | double atan(double) 10 | 11 | DTYPE = np.float64 12 | ctypedef np.float64_t DTYPE_t 13 | 14 | ITYPE = np.int32 15 | ctypedef np.int32_t ITYPE_t 16 | 17 | def lomb_scargle(t, y, dy, omega, generalized=True, 18 | subtract_mean=True, significance=None): 19 | """ 20 | (Generalized) Lomb-Scargle Periodogram with Floating Mean 21 | 22 | Parameters 23 | ---------- 24 | t : array_like 25 | sequence of times 26 | y : array_like 27 | sequence of observations 28 | dy : array_like 29 | sequence of observational errors 30 | omega : array_like 31 | frequencies at which to evaluate p(omega) 32 | generalized : bool 33 | if True (default) use generalized lomb-scargle method 34 | otherwise, use classic lomb-scargle. 35 | subtract_mean : bool 36 | if True (default) subtract the sample mean from the data before 37 | computing the periodogram. Only referenced if generalized is False. 38 | significance : None or float or ndarray 39 | if specified, then this is a list of significances to compute 40 | for the results. 41 | 42 | Returns 43 | ------- 44 | p : array_like 45 | Lomb-Scargle power associated with each frequency omega 46 | z : array_like 47 | if significance is specified, this gives the levels corresponding 48 | to the desired significance (using the Scargle 1982 formalism) 49 | 50 | Notes 51 | ----- 52 | The algorithm is based on reference [1]_. The result for generalized=False 53 | is given by equation 4 of this work, while the result for generalized=True 54 | is given by equation 20. 55 | 56 | Note that the normalization used in this reference is different from that 57 | used in other places in the literature (e.g. [2]_). For a discussion of 58 | normalization and false-alarm probability, see [1]_. 59 | 60 | To recover the normalization used in Scargle [3]_, the results should 61 | be multiplied by (N - 1) / 2 where N is the number of data points. 62 | 63 | References 64 | ---------- 65 | .. [1] M. Zechmeister and M. Kurster, A&A 496, 577-584 (2009) 66 | .. [2] W. Press et al, Numerical Recipies in C (2002) 67 | .. [3] Scargle, J.D. 1982, ApJ 263:835-853 68 | """ 69 | t = np.asarray(t, dtype=DTYPE, order='C') 70 | y = np.asarray(y, dtype=DTYPE, order='C') 71 | dy = np.asarray(dy) * np.ones_like(y) 72 | omega = np.asarray(omega, dtype=DTYPE, order='C') 73 | 74 | assert t.ndim == 1 75 | assert y.ndim == 1 76 | assert dy.ndim == 1 77 | assert omega.ndim == 1 78 | assert t.shape == y.shape 79 | assert y.shape == dy.shape 80 | 81 | p_omega = np.zeros(omega.shape, dtype=DTYPE, order='C') 82 | 83 | # the generalized method takes care of offset automatically, 84 | # while the classic method requires centered data. 85 | if (not generalized) and subtract_mean: 86 | # compute MLE for mean in the presence of noise. 87 | w = 1. / dy ** 2 88 | y = y - np.dot(w, y) / np.sum(w) 89 | 90 | if generalized: 91 | _generalized_lomb_scargle(t, y, dy, omega, p_omega) 92 | else: 93 | _standard_lomb_scargle(t, y, dy, omega, p_omega) 94 | 95 | if significance is not None: 96 | N = t.size 97 | M = 2 * N 98 | z = (-2.0 / (N - 1.) 99 | * np.log(1 - (1 - np.asarray(significance)) ** (1. / M))) 100 | return p_omega, z 101 | else: 102 | return p_omega 103 | 104 | 105 | @cython.cdivision(True) 106 | @cython.boundscheck(False) 107 | @cython.wraparound(False) 108 | cdef _standard_lomb_scargle(np.ndarray[DTYPE_t, ndim=1, mode='c'] t, 109 | np.ndarray[DTYPE_t, ndim=1, mode='c'] y, 110 | np.ndarray[DTYPE_t, ndim=1, mode='c'] dy, 111 | np.ndarray[DTYPE_t, ndim=1, mode='c'] omega, 112 | np.ndarray[DTYPE_t, ndim=1, mode='c'] p_omega): 113 | cdef ITYPE_t N_freq = omega.shape[0] 114 | cdef ITYPE_t N_obs = t.shape[0] 115 | 116 | cdef unsigned int i, j 117 | cdef DTYPE_t w, omega_t, sin_omega_t, cos_omega_t, tan_2omega_tau 118 | cdef DTYPE_t S2, C2, tau, Y, wsum, YY, YCtau, YStau, CCtau, SStau 119 | 120 | for i from 0 <= i < N_freq: 121 | # first pass: determine tau 122 | S2 = 0 123 | C2 = 0 124 | for j from 0 <= j < N_obs: 125 | w = 1. / dy[j] 126 | w *= w 127 | 128 | omega_t = omega[i] * t[j] 129 | sin_omega_t = sin(omega_t) 130 | cos_omega_t = cos(omega_t) 131 | 132 | S2 += 2 * w * sin_omega_t * cos_omega_t 133 | C2 += w - 2 * w * sin_omega_t * sin_omega_t 134 | 135 | tan_2omega_tau = S2 / C2 136 | tau = atan(tan_2omega_tau) 137 | tau *= 0.5 138 | tau /= omega[i] 139 | 140 | wsum = 0 141 | Y = 0 142 | YY = 0 143 | YCtau = 0 144 | YStau = 0 145 | CCtau = 0 146 | SStau = 0 147 | 148 | # second pass: compute the power 149 | for j from 0 <= j < N_obs: 150 | w = 1. / dy[j] 151 | w *= w 152 | wsum += w 153 | 154 | omega_t = omega[i] * (t[j] - tau) 155 | sin_omega_t = sin(omega_t) 156 | cos_omega_t = cos(omega_t) 157 | 158 | Y += w * y[j] 159 | YY += w * y[j] * y[j] 160 | YCtau += w * y[j] * cos_omega_t 161 | YStau += w * y[j] * sin_omega_t 162 | CCtau += w * cos_omega_t * cos_omega_t 163 | SStau += w * sin_omega_t * sin_omega_t 164 | 165 | Y /= wsum 166 | YY /= wsum 167 | YCtau /= wsum 168 | YStau /= wsum 169 | CCtau /= wsum 170 | SStau /= wsum 171 | 172 | p_omega[i] = (YCtau * YCtau / CCtau + YStau * YStau / SStau) / YY 173 | 174 | 175 | @cython.cdivision(True) 176 | @cython.boundscheck(False) 177 | @cython.wraparound(False) 178 | cdef _generalized_lomb_scargle(np.ndarray[DTYPE_t, ndim=1, mode='c'] t, 179 | np.ndarray[DTYPE_t, ndim=1, mode='c'] y, 180 | np.ndarray[DTYPE_t, ndim=1, mode='c'] dy, 181 | np.ndarray[DTYPE_t, ndim=1, mode='c'] omega, 182 | np.ndarray[DTYPE_t, ndim=1, mode='c'] p_omega): 183 | cdef ITYPE_t N_freq = omega.shape[0] 184 | cdef ITYPE_t N_obs = t.shape[0] 185 | 186 | cdef unsigned int i, j 187 | cdef DTYPE_t w, omega_t, sin_omega_t, cos_omega_t, tan_2omega_tau 188 | cdef DTYPE_t S, C, S2, C2, tau, Y, wsum, YY 189 | cdef DTYPE_t Stau, Ctau, YCtau, YStau, CCtau, SStau 190 | 191 | for i from 0 <= i < N_freq: 192 | # first pass: determine tau 193 | wsum = 0 194 | S = 0 195 | C = 0 196 | S2 = 0 197 | C2 = 0 198 | for j from 0 <= j < N_obs: 199 | w = 1. / dy[j] 200 | w *= w 201 | wsum += w 202 | 203 | omega_t = omega[i] * t[j] 204 | sin_omega_t = sin(omega_t) 205 | cos_omega_t = cos(omega_t) 206 | 207 | S += w * sin_omega_t 208 | C += w * cos_omega_t 209 | 210 | S2 += 2 * w * sin_omega_t * cos_omega_t 211 | C2 += w - 2 * w * sin_omega_t * sin_omega_t 212 | 213 | S2 /= wsum 214 | C2 /= wsum 215 | S /= wsum 216 | C /= wsum 217 | 218 | S2 -= (2 * S * C) 219 | C2 -= (C * C - S * S) 220 | 221 | tan_2omega_tau = S2 / C2 222 | tau = atan(tan_2omega_tau) 223 | tau *= 0.5 224 | tau /= omega[i] 225 | 226 | Y = 0 227 | YY = 0 228 | Stau = 0 229 | Ctau = 0 230 | YCtau = 0 231 | YStau = 0 232 | CCtau = 0 233 | SStau = 0 234 | 235 | # second pass: compute the power 236 | for j from 0 <= j < N_obs: 237 | w = 1. / dy[j] 238 | w *= w 239 | 240 | omega_t = omega[i] * (t[j] - tau) 241 | sin_omega_t = sin(omega_t) 242 | cos_omega_t = cos(omega_t) 243 | 244 | Y += w * y[j] 245 | YY += w * y[j] * y[j] 246 | Ctau += w * cos_omega_t 247 | Stau += w * sin_omega_t 248 | YCtau += w * y[j] * cos_omega_t 249 | YStau += w * y[j] * sin_omega_t 250 | CCtau += w * cos_omega_t * cos_omega_t 251 | SStau += w * sin_omega_t * sin_omega_t 252 | 253 | Y /= wsum 254 | YY /= wsum 255 | Ctau /= wsum 256 | Stau /= wsum 257 | YCtau /= wsum 258 | YStau /= wsum 259 | CCtau /= wsum 260 | SStau /= wsum 261 | 262 | YCtau -= Y * Ctau 263 | YStau -= Y * Stau 264 | CCtau -= Ctau * Ctau 265 | SStau -= Stau * Stau 266 | 267 | YY -= Y * Y 268 | 269 | p_omega[i] = (YCtau * YCtau / CCtau + YStau * YStau / SStau) / YY 270 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. -*- mode: rst -*- 2 | 3 | ============== 4 | AstroML addons 5 | ============== 6 | This package contains addon code for the astroML package, available at 7 | http://github.com/astroML/astroML. 8 | 9 | AstroML is a Python module for machine learning and data mining 10 | built on numpy, scipy, scikit-learn, and matplotlib, 11 | and distributed under the 3-Clause BSD license. 12 | It contains a growing library of statistical and machine learning 13 | routines for analyzing astronomical data in python, loaders for several open 14 | astronomical datasets, and a large suite of examples of analyzing and 15 | visualizing astronomical datasets. 16 | 17 | This project was started in 2012 by Jake VanderPlas to accompany the book 18 | *Statistics, Data Mining, and Machine Learning in Astronomy* by 19 | Zeljko Ivezic, Andrew Connolly, Jacob VanderPlas, and Alex Gray. 20 | 21 | Core and Addons 22 | =============== 23 | The project is split into two components. The core ``astroML`` library is 24 | written in python only, and is designed to be very easy to install for 25 | any users, even those who don't have a working C or fortran compiler. 26 | A companion library, ``astroML_addons``, can be optionally installed for 27 | increased performance on certain algorithms. Every algorithm 28 | in ``astroML_addons`` has a pure python counterpart in the 29 | core ``astroML`` implementation, but the ``astroML_addons`` library 30 | contains faster and more efficient implementations in compiled code. 31 | Furthermore, if ``astroML_addons`` is installed on your system, the core 32 | ``astroML`` library will import and use the faster routines by default. 33 | 34 | The reason for this split is the ease of use for newcomers to Python. If the 35 | prerequisites are already installed on your system, the core ``astroML`` 36 | library can be installed and used on any system with little trouble. The 37 | ``astroML_addons`` library requires a C compiler, but is also designed to be 38 | easy to install for more advanced users. See further discussion in 39 | "Development", below. 40 | 41 | 42 | Important Links 43 | =============== 44 | - HTML documentation: http://astroML.github.com 45 | - Source-code repository: http://github.com/astroML/astroML 46 | - Issue Tracker: http://github.com/astroML/astroML/issues 47 | - Mailing List: https://groups.google.com/forum/#!forum/astroml-general 48 | 49 | 50 | Installation 51 | ============ 52 | 53 | This package uses distutils, which is the default way of installing python 54 | modules. **Before installation, make sure your system meets the prerequisites 55 | listed in Dependencies, listed below.** 56 | 57 | Core 58 | ---- 59 | To install the core ``astroML`` package in your home directory, use:: 60 | 61 | pip install astroML 62 | 63 | The core package is pure python, so installation should be straightforward 64 | on most systems. To install from source, refer to http://github.com/astroML/ 65 | 66 | Addons 67 | ------ 68 | The ``astroML_addons`` package requires a working C/C++ compiler for 69 | installation. It can be installed using:: 70 | 71 | pip install astroML_addons 72 | 73 | To install from source, use:: 74 | 75 | python setup_addons.py install 76 | 77 | You can specify an arbitrary directory for installation using:: 78 | 79 | python setup.py install --prefix='/some/path' 80 | 81 | To install system-wide on Linux/Unix systems:: 82 | 83 | python setup.py build 84 | sudo python setup.py install 85 | 86 | 87 | Dependencies 88 | ============ 89 | There are three levels of dependencies in astroML. *Core* dependencies are 90 | required for the core ``astroML`` package. *Add-on* dependencies are required 91 | for the performance ``astroML_addons``. *Optional* dependencies are required 92 | to run some (but not all) of the example scripts. Individual example scripts 93 | will list their optional dependencies at the top of the file. 94 | 95 | Core Dependencies 96 | ----------------- 97 | The core ``astroML`` package requires the following: 98 | 99 | - Python_ version 2.6.x - 2.7.x 100 | (astroML does not yet support python 3.x) 101 | - Numpy_ >= 1.4 102 | - Scipy_ >= 0.7 103 | - Scikit-learn_ >= 0.10 104 | - Matplotlib_ >= 0.99 105 | - PyFITS_ >= 3.0. 106 | PyFITS is a python reader for Flexible Image Transport 107 | System (FITS) files, based on cfitsio. Several of the dataset loaders 108 | require pyfits. 109 | 110 | This configuration matches the Ubuntu 10.04 LTS release from April 2010, 111 | with the addition of scikit-learn. 112 | 113 | To run unit tests, you will also need nose >= 0.10 114 | 115 | Add-on Dependencies 116 | ------------------- 117 | The fast code in ``astroML_addons`` requires a working C/C++ compiler. 118 | 119 | Optional Dependencies 120 | --------------------- 121 | Several of the example scripts require specialized or upgraded packages. 122 | These requirements are listed at the top of the particular scripts 123 | 124 | - Scipy_ version 0.11 added a sparse graph submodule. 125 | The minimum spanning tree example requires scipy >= 0.11 126 | 127 | - PyMC_ provides a nice interface for Markov-Chain Monte Carlo. Several astroML 128 | examples use pyMC for exploration of high-dimensional spaces. The examples 129 | were written with pymc version 2.2 130 | 131 | - HEALPy_ provides an interface to 132 | the HEALPix pixelization scheme, as well as fast spherical harmonic 133 | transforms. 134 | 135 | Development 136 | =========== 137 | This package is designed to be a repository for well-written astronomy code, 138 | and submissions of new routines are encouraged. After installing the 139 | version-control system Git_, you can check out 140 | the latest sources from GitHub_ using:: 141 | 142 | git clone git://github.com/astroML/astroML.git 143 | 144 | or if you have write privileges:: 145 | 146 | git clone git@github.com:astroML/astroML.git 147 | 148 | Contribution 149 | ------------ 150 | We strongly encourage contributions of useful astronomy-related code: 151 | for `astroML` to be a relevant tool for the python/astronomy community, 152 | it will need to grow with the field of research. There are a few 153 | guidelines for contribution: 154 | 155 | General 156 | ~~~~~~~ 157 | Any contribution should be done through the github pull request system (for 158 | more information, see the 159 | `help page `_ 160 | Code submitted to ``astroML`` should conform to a BSD-style license, 161 | and follow the `PEP8 style guide `_. 162 | 163 | Documentation and Examples 164 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 165 | All submitted code should be documented following the 166 | `Numpy Documentation Guide`_. This is a unified documentation style used 167 | by many packages in the scipy universe. 168 | 169 | In addition, it is highly recommended to create example scripts that show the 170 | usefulness of the method on an astronomical dataset (preferably making use 171 | of the loaders in ``astroML.datasets``). These example scripts are in the 172 | ``examples`` subdirectory of the main source repository. 173 | 174 | Add-on code 175 | ~~~~~~~~~~~ 176 | We made the decision early-on to separate the core routines from 177 | high-performance compiled routines. 178 | This is to make sure that installation of the core 179 | package is as straightforward as possible (i.e. not requiring a C compiler). 180 | 181 | Contributions of efficient compiled code to ``astroML_addons`` is encouraged: 182 | the availability of efficient implementations of common algorithms in python 183 | is one of the strongest features of the python universe. The preferred 184 | method of wrapping compiled libraries is to use 185 | `cython `_; other options (weave, SWIG, etc.) are 186 | harder to build and maintain. 187 | 188 | Currently, the policy is that any efficient algorithm included in 189 | ``astroML_addons`` should have a duplicate python-only implementation in 190 | ``astroML``, with code that selects the faster routine if it's available. 191 | (For an example of how this works, see the definition of the ``lomb_scargle`` 192 | function in ``astroML/periodogram.py``). 193 | This policy exists for two reasons: 194 | 195 | 1. it allows novice users to have all the functionality of ``astroML`` without 196 | requiring the headache of complicated installation steps. 197 | 2. it serves a didactic purpose: python-only implementations are often easier 198 | to read and understand than equivalent implementations in C or cython. 199 | 3. it enforces the good coding practice of avoiding premature optimization. 200 | First make sure the code works (i.e. write it in simple python). Then 201 | create an optimized version in the addons. 202 | 203 | If this policy proves especially burdensome in the future, it may be revisited. 204 | 205 | .. _Numpy Documentation Guide: https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt 206 | 207 | Authors 208 | ======= 209 | 210 | Package Author 211 | -------------- 212 | * Jake Vanderplas http://jakevdp.github.com 213 | 214 | Code Contribution 215 | ----------------- 216 | * Morgan Fouesneau https://github.com/mfouesneau 217 | * Julian Taylor http://github.com/juliantaylor 218 | 219 | 220 | .. _Python: http://www.python.org 221 | .. _Numpy: http://www.numpy.org 222 | .. _Scipy: http://www.scipy.org 223 | .. _Scikit-learn: http://scikit-learn.org 224 | .. _Matplotlib: http://matplotlib.org 225 | .. _PyFITS: http://www.stsci.edu/institute/software_hardware/pyfits 226 | .. _PyMC: http://pymc-devs.github.com/pymc/ 227 | .. _HEALPy: https://github.com/healpy/healpy> 228 | .. _Git: http://git-scm.com/ 229 | .. _GitHub: http://www.github.com 230 | --------------------------------------------------------------------------------