pyrolite 0.0.14__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__init__.py +10 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/_version.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/alteration.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/classification.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/compositions.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/geochem.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/melts.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/norm.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/normalisation.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/plot.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/_version.py +21 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/alteration.py +66 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/classification.py +222 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__init__.py +9 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/aggregate.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/codata.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/impute.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/renorm.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/aggregate.py +391 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/codata.py +266 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/impute.py +82 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/renorm.py +40 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/compositions.py +524 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_CFB_Dataset_List.csv +42 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_Convergent_Dataset_List.csv +42 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OBFB_Dataset_List.csv +5 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OIB_Dataset_List.csv +49 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OceanicPlateau_Dataset_List.csv +18 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/contents.json +1 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/__pycache__/env.cpython-35.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/__pycache__/env.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/env.py +1063 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Ba.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Bs.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.F.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O3.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Pc.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Ph.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.R.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S3.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.T1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.T2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U1.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U2.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U3.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.modelfields +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.nan.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.none.modelfield +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/aphanitic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/gabbroic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/peralkalinity.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/phaneritic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/ultramafic.clsf.gz +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/CH_PalmeONeill2014.csv +95 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DDMM_WorkmanHart2005.csv +105 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DMM_WorkmanHart2005.csv +105 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DM_SaltersStrake2004.csv +95 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/EDMM_WorkmanHart2005.csv +105 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/PM_PalmeONeill2014.csv +95 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/timescale/geotimescale_spans.csv +180 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/geochem.py +821 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/melts.py +92 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__init__.py +10 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/db.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/ions.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/mineral.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/sites.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/db.py +88 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/ions.py +78 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/mineral.py +587 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/sites.py +134 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/norm.py +224 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/normalisation.py +204 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/plot.py +514 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__init__.py +13 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/__init__.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/database.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/env.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/general.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/georoc.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/math.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/melts.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/multip.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/multiprocessing.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/pd.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/plot.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/skl.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/spatial.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/text.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/time.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/wfs.cpython-36.pyc +0 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/database.py +88 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/env.py +81 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/general.py +266 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/georoc.py +444 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/math.py +371 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/melts.py +397 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/multip.py +29 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/multiprocessing.py +29 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/pd.py +214 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/plot.py +345 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/skl.py +847 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/spatial.py +91 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/text.py +207 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/time.py +224 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/wfs.py +10 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/PKG-INFO +61 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/SOURCES.txt +83 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/dependency_links.txt +1 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/requires.txt +47 -0
- ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from sympy.solvers.solvers import nsolve
|
|
3
|
+
from sympy import symbols, var
|
|
4
|
+
from functools import partial
|
|
5
|
+
import scipy
|
|
6
|
+
import logging
|
|
7
|
+
from copy import copy
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def is_numeric(obj):
|
|
15
|
+
attrs = ["__add__", "__sub__", "__mul__", "__truediv__", "__pow__"]
|
|
16
|
+
return all(hasattr(obj, attr) for attr in attrs)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@np.vectorize
|
|
20
|
+
def round_sig(x, sig=2):
|
|
21
|
+
"""Round a number to a certain number of significant figures."""
|
|
22
|
+
where_nan = ~np.isfinite(x)
|
|
23
|
+
x = copy(x)
|
|
24
|
+
if hasattr(x, "__len__"):
|
|
25
|
+
x[where_nan] = np.finfo(np.float).eps
|
|
26
|
+
vals = np.round(x, sig - np.int(np.floor(np.log10(np.abs(x)))) - 1)
|
|
27
|
+
vals[where_nan] = np.nan
|
|
28
|
+
return vals
|
|
29
|
+
else:
|
|
30
|
+
try:
|
|
31
|
+
return np.round(x, sig - np.int(np.floor(np.log10(np.abs(x)))) - 1)
|
|
32
|
+
except (ValueError, OverflowError): # nan or inf is passed
|
|
33
|
+
return x
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def significant_figures(n, unc=None, max_sf=20, rtol=1e-20):
|
|
37
|
+
"""Get number of significant digits for a number, given an uncertainty."""
|
|
38
|
+
if not hasattr(n, "__len__"):
|
|
39
|
+
if np.isfinite(n):
|
|
40
|
+
if unc is not None:
|
|
41
|
+
mag_n = np.floor(np.log10(np.abs(n)))
|
|
42
|
+
mag_u = np.floor(np.log10(unc))
|
|
43
|
+
if not np.isfinite(mag_u) or not np.isfinite(mag_n):
|
|
44
|
+
return np.nan
|
|
45
|
+
sf = int(max(0, int(1.0 + mag_n - mag_u)))
|
|
46
|
+
else:
|
|
47
|
+
sf = min(
|
|
48
|
+
[
|
|
49
|
+
ix
|
|
50
|
+
for ix in range(max_sf)
|
|
51
|
+
if np.isclose(round_sig(n, ix), n, rtol=rtol)
|
|
52
|
+
]
|
|
53
|
+
)
|
|
54
|
+
return sf
|
|
55
|
+
else:
|
|
56
|
+
return 0
|
|
57
|
+
else: # this isn't working
|
|
58
|
+
n = np.array(n)
|
|
59
|
+
_n = n.copy()
|
|
60
|
+
mask = np.isclose(n, 0.0) # can't process zeros
|
|
61
|
+
_n[mask] = np.nan
|
|
62
|
+
if unc is not None:
|
|
63
|
+
mag_n = np.floor(np.log10(np.abs(_n)))
|
|
64
|
+
mag_u = np.floor(np.log10(unc))
|
|
65
|
+
sfs = np.nanmax(
|
|
66
|
+
np.vstack(
|
|
67
|
+
[np.zeros(mag_n.shape), (1.0 + mag_n - mag_u).astype(np.int)]
|
|
68
|
+
),
|
|
69
|
+
axis=0,
|
|
70
|
+
).astype(np.int)
|
|
71
|
+
else:
|
|
72
|
+
rounded = np.vstack([_n] * max_sf).reshape(max_sf, *_n.shape)
|
|
73
|
+
indx = np.indices(rounded.shape)[0] # get the row indexes for no. sig figs
|
|
74
|
+
rounded = round_sig(rounded, indx)
|
|
75
|
+
sfs = np.nanargmax(np.isclose(rounded, _n, rtol=rtol), axis=0)
|
|
76
|
+
sfs[np.isnan(sfs)] = 0
|
|
77
|
+
return sfs
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def most_precise(arr):
|
|
81
|
+
"""Get the most precise element from an array."""
|
|
82
|
+
arr = np.array(arr)
|
|
83
|
+
if np.isfinite(arr).any().any():
|
|
84
|
+
precision = significant_figures(arr)
|
|
85
|
+
if arr.ndim > 1:
|
|
86
|
+
return arr[range(arr.shape[0]), np.nanargmax(precision, axis=-1)]
|
|
87
|
+
else:
|
|
88
|
+
return arr[np.nanargmax(precision, axis=-1)]
|
|
89
|
+
else:
|
|
90
|
+
return np.nan
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def equal_within_significance(arr, equal_nan=False, rtol=1e-15):
|
|
94
|
+
"""
|
|
95
|
+
Test whether elements within an array are equal to the precision of the
|
|
96
|
+
least precise.
|
|
97
|
+
"""
|
|
98
|
+
arr = np.array(arr)
|
|
99
|
+
|
|
100
|
+
if arr.ndim == 1:
|
|
101
|
+
if not np.isfinite(arr).all():
|
|
102
|
+
return equal_nan
|
|
103
|
+
else:
|
|
104
|
+
precision = significant_figures(arr)
|
|
105
|
+
min_precision = np.nanmin(precision)
|
|
106
|
+
rounded = round_sig(arr, min_precision * np.ones(arr.shape, dtype=int))
|
|
107
|
+
return np.isclose(rounded[0], rounded, rtol=rtol).all()
|
|
108
|
+
else: # ndmim =2
|
|
109
|
+
equal = equal_nan * np.ones(
|
|
110
|
+
arr.shape[0], dtype=bool
|
|
111
|
+
) # mean for rows containing nan
|
|
112
|
+
if np.isfinite(arr).all(axis=1).any():
|
|
113
|
+
non_nan_rows = np.isfinite(arr).all(axis=1)
|
|
114
|
+
|
|
115
|
+
precision = significant_figures(arr[non_nan_rows, :])
|
|
116
|
+
min_precision = np.nanmin(precision, axis=1)
|
|
117
|
+
precs = np.repeat(min_precision, arr.shape[1]).reshape(
|
|
118
|
+
arr[non_nan_rows, :].shape
|
|
119
|
+
)
|
|
120
|
+
rounded = round_sig(arr[non_nan_rows, :], precs)
|
|
121
|
+
equal[non_nan_rows] = np.apply_along_axis(
|
|
122
|
+
lambda x: (x == x[0]).all(), 1, rounded
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
return equal
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def signify_digit(n, unc=None, leeway=0, low_filter=True):
|
|
129
|
+
"""
|
|
130
|
+
Reformats numbers to contain only significant_digits. Uncertainty can be provided to
|
|
131
|
+
digits with relevant precision.
|
|
132
|
+
|
|
133
|
+
Note: Will not pad 0s at the end or before floats.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
if np.isfinite(n):
|
|
137
|
+
if np.isclose(n, 0.0):
|
|
138
|
+
return n
|
|
139
|
+
else:
|
|
140
|
+
mag_n = np.floor(np.log10(np.abs(n)))
|
|
141
|
+
sf = significant_figures(n, unc=unc) + int(leeway)
|
|
142
|
+
if unc is not None:
|
|
143
|
+
mag_u = np.floor(np.log10(unc))
|
|
144
|
+
else:
|
|
145
|
+
mag_u = 0
|
|
146
|
+
round_to = sf - int(mag_n) - 1 + leeway
|
|
147
|
+
if round_to <= 0:
|
|
148
|
+
fmt = int
|
|
149
|
+
else:
|
|
150
|
+
fmt = lambda x: x
|
|
151
|
+
sig_n = round(n, round_to)
|
|
152
|
+
if low_filter and sig_n == 0.0:
|
|
153
|
+
return np.nan
|
|
154
|
+
else:
|
|
155
|
+
return fmt(sig_n)
|
|
156
|
+
else:
|
|
157
|
+
return np.nan
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def orthagonal_basis(X: np.ndarray):
|
|
161
|
+
"""
|
|
162
|
+
Generate a set of orthagonal basis vectors.
|
|
163
|
+
|
|
164
|
+
Parameters
|
|
165
|
+
---------------
|
|
166
|
+
X : np.ndarray
|
|
167
|
+
Array from which the size of the set is derived.
|
|
168
|
+
"""
|
|
169
|
+
D = X.shape[1]
|
|
170
|
+
# D-1, D Helmert matrix, exact representation of ψ as in Egozogue's book
|
|
171
|
+
H = scipy.linalg.helmert(D, full=False)
|
|
172
|
+
return H[::-1]
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def on_finite(X, f):
|
|
176
|
+
"""
|
|
177
|
+
Calls a function on an array ignoring np.nan and +/- np.inf. Note that the
|
|
178
|
+
shape of the output may be different to that of the input.
|
|
179
|
+
|
|
180
|
+
Parameters
|
|
181
|
+
---------------
|
|
182
|
+
X : np.ndarray
|
|
183
|
+
Array on which to perform the function.
|
|
184
|
+
"""
|
|
185
|
+
ma = np.isfinite(X)
|
|
186
|
+
return f(X[ma])
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def nancov(X, method="replace"):
|
|
190
|
+
"""
|
|
191
|
+
Generates a covariance matrix excluding nan-components. Done on a
|
|
192
|
+
column-column/pairwise basis. The result Y may not be a positive definite matrix.
|
|
193
|
+
|
|
194
|
+
Parameters
|
|
195
|
+
---------------
|
|
196
|
+
X: np.ndarray
|
|
197
|
+
Input array for which to derive a covariance matrix.
|
|
198
|
+
method: str, 'row_exclude' | 'replace'
|
|
199
|
+
Method for calculating covariance matrix.
|
|
200
|
+
'row_exclude' removes all rows which contain np.nan before calculating
|
|
201
|
+
the covariance matrix. 'replace' instead replaces the np.nan values with
|
|
202
|
+
the mean before calculating the covariance.
|
|
203
|
+
|
|
204
|
+
"""
|
|
205
|
+
if method == "rowexclude":
|
|
206
|
+
Xnanfree = X[np.all(np.isfinite(X), axis=1), :].T
|
|
207
|
+
# assert Xnanfree.shape[1] > Xnanfree.shape[0]
|
|
208
|
+
# (1/m)X^T*X
|
|
209
|
+
return np.cov(Xnanfree)
|
|
210
|
+
else:
|
|
211
|
+
X = np.array(X, ndmin=2, dtype=float)
|
|
212
|
+
X -= np.nanmean(X, axis=0) # [:, np.newaxis]
|
|
213
|
+
cov = np.empty((X.shape[1], X.shape[1]))
|
|
214
|
+
cols = range(X.shape[1])
|
|
215
|
+
for n in cols:
|
|
216
|
+
for m in [i for i in cols if i >= n]:
|
|
217
|
+
fn = np.isfinite(X[:, n])
|
|
218
|
+
fm = np.isfinite(X[:, m])
|
|
219
|
+
if method == "replace":
|
|
220
|
+
X[~fn, n] = 0
|
|
221
|
+
X[~fm, m] = 0
|
|
222
|
+
fact = fn.shape[0] - 1
|
|
223
|
+
c = np.dot(X[:, n], X[:, m]) / fact
|
|
224
|
+
else:
|
|
225
|
+
f = fn & fm
|
|
226
|
+
fact = f.shape[0] - 1
|
|
227
|
+
c = np.dot(X[f, n], X[f, m]) / fact
|
|
228
|
+
cov[n, m] = c
|
|
229
|
+
cov[m, n] = c
|
|
230
|
+
return cov
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def OP_constants(xs, degree=3, tol=10 ** -14):
|
|
234
|
+
"""
|
|
235
|
+
For constructing orthagonal polynomial functions of the general form:
|
|
236
|
+
y(x) = a_0 + a_1 * (x - β) + a_2 * (x - γ_0) * (x - γ_1) +
|
|
237
|
+
a_3 * (x - δ_0) * (x - δ_1) * (x - δ_2)
|
|
238
|
+
Finds the parameters (β_0), (γ_0, γ_1), (δ_0, δ_1, δ_2).
|
|
239
|
+
|
|
240
|
+
These parameters are functions only of the independent variable x.
|
|
241
|
+
"""
|
|
242
|
+
xs = np.array(xs)
|
|
243
|
+
x = var("x")
|
|
244
|
+
params = []
|
|
245
|
+
for d in range(degree):
|
|
246
|
+
ps = symbols("{}0:{}".format(chr(945 + d), d))
|
|
247
|
+
logger.debug("Generating {} DIM {} equations for {}.".format(d, d, ps))
|
|
248
|
+
if d:
|
|
249
|
+
eqs = []
|
|
250
|
+
for _deg in range(d):
|
|
251
|
+
q = 1
|
|
252
|
+
if _deg:
|
|
253
|
+
q = x ** _deg
|
|
254
|
+
for p in ps:
|
|
255
|
+
q *= x - p
|
|
256
|
+
eqs.append(q)
|
|
257
|
+
|
|
258
|
+
sums = []
|
|
259
|
+
for q in eqs:
|
|
260
|
+
sumq = 0.0
|
|
261
|
+
for xi in xs:
|
|
262
|
+
sumq += q.subs(dict(x=xi))
|
|
263
|
+
sums.append(sumq)
|
|
264
|
+
|
|
265
|
+
guess = np.linspace(np.nanmin(xs), np.nanmax(xs), d + 2)[1:-1]
|
|
266
|
+
result = nsolve(sums, ps, list(guess), tol=tol)
|
|
267
|
+
params.append(tuple(result))
|
|
268
|
+
else:
|
|
269
|
+
params.append(()) # first parameter
|
|
270
|
+
return params
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def lambda_poly(x, ps):
|
|
274
|
+
"""
|
|
275
|
+
Polynomial lambda_n(x) given parameters ps with len(ps) = n.
|
|
276
|
+
|
|
277
|
+
Parameters
|
|
278
|
+
-----------
|
|
279
|
+
x: np.ndarray
|
|
280
|
+
X values to calculate the function at.
|
|
281
|
+
ps: tuple
|
|
282
|
+
Parameter set tuple. E.g. parameters (a, b) from f(x) = (x-a)(x-b).
|
|
283
|
+
"""
|
|
284
|
+
if not isinstance(x, np.ndarray):
|
|
285
|
+
x = np.array(x)
|
|
286
|
+
result = np.ones(len(x))
|
|
287
|
+
for p in ps:
|
|
288
|
+
result = result * (x - p)
|
|
289
|
+
return result.astype(np.float)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def lambda_min_func(ls, ys, arrs, power=2.0):
|
|
293
|
+
cost = np.abs(np.dot(ls, arrs) - ys) ** power
|
|
294
|
+
cost[np.isnan(cost)] = 0.0 # can't change nans - don't penalise them
|
|
295
|
+
return cost
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def lambdas(
|
|
299
|
+
arr: np.ndarray,
|
|
300
|
+
xs=np.array([]),
|
|
301
|
+
params=None,
|
|
302
|
+
guess=None,
|
|
303
|
+
degree=5,
|
|
304
|
+
costf_power=2.0,
|
|
305
|
+
residuals=False,
|
|
306
|
+
min_func=lambda_min_func,
|
|
307
|
+
):
|
|
308
|
+
"""
|
|
309
|
+
Parameterises values based on linear combination of orthagonal polynomials
|
|
310
|
+
over a given set of x values.
|
|
311
|
+
"""
|
|
312
|
+
if np.isnan(arr).any(): # With missing data, the method can't be used.
|
|
313
|
+
x = np.nan * np.ones(degree)
|
|
314
|
+
res = np.nan * np.ones(degree)
|
|
315
|
+
else:
|
|
316
|
+
guess = guess or np.exp(np.arange(degree) + 2)
|
|
317
|
+
params = params or OP_constants(xs, degree=degree)
|
|
318
|
+
|
|
319
|
+
fs = np.array([lambda_poly(xs, pset) for pset in params])
|
|
320
|
+
|
|
321
|
+
result = scipy.optimize.least_squares(
|
|
322
|
+
min_func, guess, args=(arr, fs, costf_power) # , method='Nelder-Mead'
|
|
323
|
+
)
|
|
324
|
+
x = result.x
|
|
325
|
+
res = result.fun
|
|
326
|
+
if residuals:
|
|
327
|
+
return x, res
|
|
328
|
+
else:
|
|
329
|
+
return x
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def lambda_poly_func(lambdas: np.ndarray, params=None, pxs=None, degree=5):
|
|
333
|
+
"""
|
|
334
|
+
Expansion of lambda parameters back to the original space. Returns a
|
|
335
|
+
function which evaluates the sum of the orthaogonal polynomials at given
|
|
336
|
+
x values.
|
|
337
|
+
|
|
338
|
+
Parameters
|
|
339
|
+
------------
|
|
340
|
+
lambdas: np.ndarray
|
|
341
|
+
Lambda values to weight combination of polynomials.
|
|
342
|
+
params: list of tuples
|
|
343
|
+
Parameters for the orthagonal polynomial decomposition.
|
|
344
|
+
pxs: np.ndarray
|
|
345
|
+
x values used to construct the lambda values.*
|
|
346
|
+
degree: int
|
|
347
|
+
Degree of the orthagonal polynomial decomposition.*
|
|
348
|
+
|
|
349
|
+
* (only needed if parameters are not supplied)
|
|
350
|
+
"""
|
|
351
|
+
if params is None and pxs is not None:
|
|
352
|
+
params = OP_constants(pxs, degree=degree)
|
|
353
|
+
elif params is None and pxs is None:
|
|
354
|
+
msg = """Must provide either x values to construct parameters,
|
|
355
|
+
or the parameters themselves."""
|
|
356
|
+
raise AssertionError(msg)
|
|
357
|
+
|
|
358
|
+
def lambda_poly_f(xarr):
|
|
359
|
+
"""
|
|
360
|
+
Calculates the sum of decomposed polynomial components
|
|
361
|
+
at given x values.
|
|
362
|
+
|
|
363
|
+
Parameters
|
|
364
|
+
-----------
|
|
365
|
+
xarr: np.ndarray
|
|
366
|
+
X values at which to evaluate the function.
|
|
367
|
+
"""
|
|
368
|
+
arrs = np.array([lambda_poly(xarr, pset) for pset in params])
|
|
369
|
+
return np.dot(lambdas, arrs)
|
|
370
|
+
|
|
371
|
+
return lambda_poly_f
|