|
| 1 | +# `light-curve` processing toolbox for Python |
| 2 | + |
| 3 | +The Python wrapper for Rust [`light-curve-feature`](https://github.com/light-curve/light-curve) and [`light-curve-dmdt`](https://github.com/light-curve/light-curve) packages which gives a collection of high-performant time-series feature extractors. |
| 4 | + |
| 5 | +[](https://pypi.org/project/light-curve/) |
| 6 | + |
| 7 | + |
| 8 | +[](https://results.pre-commit.ci/latest/github/light-curve/light-curve-python/master) |
| 9 | + |
| 10 | +## Installation |
| 11 | + |
| 12 | +```sh |
| 13 | +python3 -mpip install light-curve |
| 14 | +``` |
| 15 | + |
| 16 | +Minimum supported Python version is 3.6. |
| 17 | +The package is tested on Linux (x86-64, aarch64, ppc64) and macOS (x86-64). |
| 18 | +Pre-built wheels for these platforms are available on [pypi.org](https://pypi.org/project/light-curve/#files), other systems are required to have [GNU scientific library (GSL)](https://www.gnu.org/software/gsl/) v2.1+ and the [Rust](https://rust-lang.org) toolchain v1.56+ to build and install the package. |
| 19 | +You can use [`rustup` script](https://rustup.rs) to get the most recent Rust toolchain. |
| 20 | + |
| 21 | +Also could find `light-curve-python` package which is just an "alias" to the main `light-curve` package. |
| 22 | + |
| 23 | +## Feature evaluators |
| 24 | + |
| 25 | +Most of the classes implement various feature evaluators useful for light-curve based |
| 26 | +astrophysical source classification and characterisation. |
| 27 | + |
| 28 | +```python |
| 29 | +import light_curve as lc |
| 30 | +import numpy as np |
| 31 | + |
| 32 | +# Time values can be non-evenly separated but must be an ascending array |
| 33 | +n = 101 |
| 34 | +t = np.linspace(0.0, 1.0, n) |
| 35 | +perfect_m = 1e3 * t + 1e2 |
| 36 | +err = np.sqrt(perfect_m) |
| 37 | +m = perfect_m + np.random.normal(0, err) |
| 38 | + |
| 39 | +# Half-amplitude of magnitude |
| 40 | +amplitude = lc.Amplitude() |
| 41 | +# Fraction of points beyond standard deviations from mean |
| 42 | +beyond_std = lc.BeyondNStd(nstd=1) |
| 43 | +# Slope, its error and reduced chi^2 of linear fit |
| 44 | +linear_fit = lc.LinearFit() |
| 45 | +# Feature extractor, it will evaluate all features in more efficient way |
| 46 | +extractor = lc.Extractor(amplitude, beyond_std, linear_fit) |
| 47 | + |
| 48 | +# Array with all 5 extracted features |
| 49 | +result = extractor(t, m, err, sorted=True, check=False) |
| 50 | + |
| 51 | +print('\n'.join("{} = {:.2f}".format(name, value) for name, value in zip(extractor.names, result))) |
| 52 | + |
| 53 | +# Run in parallel for multiple light curves: |
| 54 | +results = amplitude.many( |
| 55 | + [(t[:i], m[:i], err[:i]) for i in range(n // 2, n)], |
| 56 | + n_jobs=-1, |
| 57 | + sorted=True, |
| 58 | + check=False, |
| 59 | +) |
| 60 | +print("Amplitude of amplitude is {:.2f}".format(np.ptp(results))) |
| 61 | +``` |
| 62 | + |
| 63 | +If you confident in your inputs you could use `sorted = True` (`t` is in ascending order) |
| 64 | +and `check = False` (no NaNs in inputs, no infs in `t` or `m`) for better performance. |
| 65 | +Note that if your inputs are not valid and are not validated by |
| 66 | +`sorted=None` and `check=True` (default values) then all kind of bad things could happen. |
| 67 | + |
| 68 | +Print feature classes list |
| 69 | +```python |
| 70 | +import light_curve as lc |
| 71 | + |
| 72 | +print([x for x in dir(lc) if hasattr(getattr(lc, x), "names")]) |
| 73 | +``` |
| 74 | + |
| 75 | +Read feature docs |
| 76 | +```python |
| 77 | +import light_curve as lc |
| 78 | + |
| 79 | +help(lc.BazinFit) |
| 80 | +``` |
| 81 | + |
| 82 | +### Experimental extractors |
| 83 | + |
| 84 | +From the technical point of view the package consists of two parts: a wrapper for [`light-curve-feature` Rust crate](https://crates.io/crates/light-curve-feature) (`light_curve_ext` sub-package) and pure Python sub-package `light_curve_py`. |
| 85 | +We use the Python implementation of feature extractors to test Rust implementation and to implement new experimental extractors. |
| 86 | +Please note, that the Python implementation is much slower for the most of the extractors and doesn't provide the same functionality as the Rust implementation. |
| 87 | +However, the Python implementation provides some new feature extractors you can find useful. |
| 88 | + |
| 89 | +You can manually use extractors from both implementations: |
| 90 | + |
| 91 | +```python |
| 92 | +import numpy as np |
| 93 | +from numpy.testing import assert_allclose |
| 94 | +from light_curve.light_curve_ext import LinearTrend as RustLinearTrend |
| 95 | +from light_curve.light_curve_py import LinearTrend as PythonLinearTrend |
| 96 | + |
| 97 | +rust_fe = RustLinearTrend() |
| 98 | +py_fe = PythonLinearTrend() |
| 99 | + |
| 100 | +n = 100 |
| 101 | +t = np.sort(np.random.normal(size=n)) |
| 102 | +m = 3.14 * t - 2.16 + np.random.normal(size=n) |
| 103 | + |
| 104 | +assert_allclose(rust_fe(t, m), py_fe(t, m), |
| 105 | + err_msg="Python and Rust implementations must provide the same result") |
| 106 | +``` |
| 107 | + |
| 108 | +This should print a warning about experimental status of the Python class |
| 109 | + |
| 110 | +## dm-dt map |
| 111 | + |
| 112 | +Class `DmDt` provides dm–dt mapper (based on [Mahabal et al. 2011](https://ui.adsabs.harvard.edu/abs/2011BASI...39..387M/abstract), [Soraisam et al. 2020](https://ui.adsabs.harvard.edu/abs/2020ApJ...892..112S/abstract)). It is a Python wrapper for [`light-curve-dmdt` Rust crate](https://crates.io/crates/light-curve-dmdt). |
| 113 | + |
| 114 | +```python |
| 115 | +import numpy as np |
| 116 | +from light_curve import DmDt |
| 117 | +from numpy.testing import assert_array_equal |
| 118 | + |
| 119 | +dmdt = DmDt.from_borders(min_lgdt=0, max_lgdt=np.log10(3), max_abs_dm=3, lgdt_size=2, dm_size=4, norm=[]) |
| 120 | + |
| 121 | +t = np.array([0, 1, 2], dtype=np.float32) |
| 122 | +m = np.array([0, 1, 2], dtype=np.float32) |
| 123 | + |
| 124 | +desired = np.array( |
| 125 | + [ |
| 126 | + [0, 0, 2, 0], |
| 127 | + [0, 0, 0, 1], |
| 128 | + ] |
| 129 | +) |
| 130 | +actual = dmdt.points(t, m) |
| 131 | + |
| 132 | +assert_array_equal(actual, desired) |
| 133 | +``` |
| 134 | + |
| 135 | +### Citation |
| 136 | + |
| 137 | +If you found this project useful for your research please cite [Malanchev et al., 2021](https://ui.adsabs.harvard.edu/abs/2021MNRAS.502.5147M/abstract) |
| 138 | + |
| 139 | +```bibtex |
| 140 | +@ARTICLE{2021MNRAS.502.5147M, |
| 141 | + author = {{Malanchev}, K.~L. and {Pruzhinskaya}, M.~V. and {Korolev}, V.~S. and {Aleo}, P.~D. and {Kornilov}, M.~V. and {Ishida}, E.~E.~O. and {Krushinsky}, V.~V. and {Mondon}, F. and {Sreejith}, S. and {Volnova}, A.~A. and {Belinski}, A.~A. and {Dodin}, A.~V. and {Tatarnikov}, A.~M. and {Zheltoukhov}, S.~G. and {(The SNAD Team)}}, |
| 142 | + title = "{Anomaly detection in the Zwicky Transient Facility DR3}", |
| 143 | + journal = {\mnras}, |
| 144 | + keywords = {methods: data analysis, astronomical data bases: miscellaneous, stars: variables: general, Astrophysics - Instrumentation and Methods for Astrophysics, Astrophysics - Solar and Stellar Astrophysics}, |
| 145 | + year = 2021, |
| 146 | + month = apr, |
| 147 | + volume = {502}, |
| 148 | + number = {4}, |
| 149 | + pages = {5147-5175}, |
| 150 | + doi = {10.1093/mnras/stab316}, |
| 151 | +archivePrefix = {arXiv}, |
| 152 | + eprint = {2012.01419}, |
| 153 | + primaryClass = {astro-ph.IM}, |
| 154 | + adsurl = {https://ui.adsabs.harvard.edu/abs/2021MNRAS.502.5147M}, |
| 155 | + adsnote = {Provided by the SAO/NASA Astrophysics Data System} |
| 156 | +} |
| 157 | +``` |
0 commit comments