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,847 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from functools import partial
|
|
4
|
+
import itertools
|
|
5
|
+
from ..geochem import *
|
|
6
|
+
from ..geochem import __common_elements__, __common_oxides__
|
|
7
|
+
from ..comp.codata import *
|
|
8
|
+
from ..comp.aggregate import *
|
|
9
|
+
from .plot import *
|
|
10
|
+
|
|
11
|
+
import matplotlib.colors as mplc
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
|
|
15
|
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from sklearn.base import TransformerMixin, BaseEstimator
|
|
20
|
+
from sklearn.metrics import confusion_matrix
|
|
21
|
+
except ImportError:
|
|
22
|
+
msg = "scikit-learn not installed"
|
|
23
|
+
logger.warning(msg)
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
from fancyimpute import IterativeImputer, SoftImpute
|
|
27
|
+
except ImportError:
|
|
28
|
+
msg = "fancyimpute not installed"
|
|
29
|
+
logger.warning(msg)
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
from imblearn.over_sampling import RandomOverSampler
|
|
33
|
+
except ImportError:
|
|
34
|
+
msg = "imbalanced-learn not installed"
|
|
35
|
+
logger.warning(msg)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_confusion_matrix(clf, test_X, test_y):
|
|
39
|
+
y_true = test_y
|
|
40
|
+
y_pred = clf.predict(test_X)
|
|
41
|
+
return confusion_matrix(y_true, y_pred)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def plot_confusion_matrix(
|
|
45
|
+
*args,
|
|
46
|
+
classes=[],
|
|
47
|
+
normalize=False,
|
|
48
|
+
title="Confusion Matrix",
|
|
49
|
+
cmap=plt.cm.Blues,
|
|
50
|
+
norm=mplc.Normalize(vmin=0, vmax=1.0),
|
|
51
|
+
ax=None
|
|
52
|
+
):
|
|
53
|
+
"""
|
|
54
|
+
This function prints and plots the confusion matrix.
|
|
55
|
+
Normalization can be applied by setting `normalize=True`.
|
|
56
|
+
"""
|
|
57
|
+
if len(args) == 1:
|
|
58
|
+
cm = args[0]
|
|
59
|
+
else:
|
|
60
|
+
cm = get_confusion_matrix(*args)
|
|
61
|
+
if not classes:
|
|
62
|
+
if hasattr(args[0], "classes_"):
|
|
63
|
+
classes = list(args[0].classes_)
|
|
64
|
+
|
|
65
|
+
if not classes:
|
|
66
|
+
classes = np.arange(cm.shape[0])
|
|
67
|
+
|
|
68
|
+
if normalize:
|
|
69
|
+
cm = cm.astype("float") / cm.sum(axis=1)[:, np.newaxis]
|
|
70
|
+
|
|
71
|
+
if ax is None:
|
|
72
|
+
fig, ax = plt.subplots(1)
|
|
73
|
+
|
|
74
|
+
im = ax.imshow(cm, interpolation="nearest", cmap=cmap, norm=norm)
|
|
75
|
+
ax.set_title(title)
|
|
76
|
+
plt.colorbar(im, ax=ax)
|
|
77
|
+
tick_marks = np.arange(len(classes))
|
|
78
|
+
|
|
79
|
+
fmt = ".2f" if normalize else "d"
|
|
80
|
+
thresh = cm.max() / 2.0
|
|
81
|
+
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
|
|
82
|
+
ax.text(
|
|
83
|
+
j,
|
|
84
|
+
i,
|
|
85
|
+
format(cm[i, j], fmt),
|
|
86
|
+
horizontalalignment="center",
|
|
87
|
+
color="white" if cm[i, j] > thresh else "black",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
ax.set(
|
|
91
|
+
ylabel="True",
|
|
92
|
+
xlabel="Predicted",
|
|
93
|
+
xticks=tick_marks,
|
|
94
|
+
yticks=tick_marks,
|
|
95
|
+
xticklabels=classes,
|
|
96
|
+
yticklabels=classes,
|
|
97
|
+
)
|
|
98
|
+
plt.tight_layout()
|
|
99
|
+
return ax
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def plot_gs_results(gs, xvar=None, yvar=None):
|
|
103
|
+
"""Plots the results from a GridSearch showing location of optimum in 2D."""
|
|
104
|
+
labels = gs.param_grid.keys()
|
|
105
|
+
grid_items = list(gs.param_grid.items())
|
|
106
|
+
no_items = len(grid_items)
|
|
107
|
+
if (
|
|
108
|
+
len(grid_items) == 1
|
|
109
|
+
): # if there's only one item, there's only one way to plot it.
|
|
110
|
+
(xvar, xx) = grid_items[0]
|
|
111
|
+
(yvar, yy) = "", np.array([0])
|
|
112
|
+
else:
|
|
113
|
+
if xvar is None and yvar is None:
|
|
114
|
+
(yvar, yy), (xvar, xx) = [(k, v) for (k, v) in grid_items][:3]
|
|
115
|
+
elif xvar is not None and yvar is not None:
|
|
116
|
+
yy, xx = gs.param_grid[yvar], gs.param_grid[xvar]
|
|
117
|
+
else:
|
|
118
|
+
if xvar is not None:
|
|
119
|
+
xx = gs.param_grid[xvar]
|
|
120
|
+
(yvar, yy) = [(k, v) for (k, v) in grid_items if not k == xvar][0]
|
|
121
|
+
else:
|
|
122
|
+
yy = gs.param_grid[yvar]
|
|
123
|
+
(xvar, xx) = [(k, v) for (k, v) in grid_items if not k == yvar][0]
|
|
124
|
+
xx, yy = np.array(xx), np.array(yy)
|
|
125
|
+
other_keys = [i for i in gs.param_grid.keys() if i not in [xvar, yvar]]
|
|
126
|
+
if other_keys:
|
|
127
|
+
pass
|
|
128
|
+
else:
|
|
129
|
+
results = np.array(gs.cv_results_["mean_test_score"]).reshape(xx.size, yy.size)
|
|
130
|
+
fig, ax = plt.subplots(1)
|
|
131
|
+
ax.imshow(results.T, cmap=plt.cm.Blues)
|
|
132
|
+
|
|
133
|
+
ax.set(
|
|
134
|
+
xlabel=xvar,
|
|
135
|
+
ylabel=yvar,
|
|
136
|
+
xticks=np.arange(len(xx)),
|
|
137
|
+
yticks=np.arange(len(yy)),
|
|
138
|
+
xticklabels=["{:01.2g}".format(i) for i in xx],
|
|
139
|
+
yticklabels=["{:01.2g}".format(i) for i in yy],
|
|
140
|
+
)
|
|
141
|
+
ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
|
|
142
|
+
ax.invert_yaxis()
|
|
143
|
+
|
|
144
|
+
max = np.nanmax(results)
|
|
145
|
+
locmax = np.where(results == max)
|
|
146
|
+
x, y = locmax
|
|
147
|
+
ax.scatter(x, y, marker="D", s=100, c="k")
|
|
148
|
+
return ax
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def plot_cooccurence(
|
|
152
|
+
df,
|
|
153
|
+
ax=None,
|
|
154
|
+
normalize=True,
|
|
155
|
+
log=False,
|
|
156
|
+
norm=mplc.Normalize(vmin=0, vmax=1.0),
|
|
157
|
+
**kwargs
|
|
158
|
+
):
|
|
159
|
+
if ax is None:
|
|
160
|
+
fig, ax = plt.subplots(1, figsize=(4.2, 4))
|
|
161
|
+
co_occur = df.fillna(0)
|
|
162
|
+
co_occur[co_occur > 0] = 1
|
|
163
|
+
co_occur = co_occur.T.dot(co_occur).astype(int)
|
|
164
|
+
if normalize:
|
|
165
|
+
diags = np.diagonal(co_occur)
|
|
166
|
+
for i in range(diags.shape[0]):
|
|
167
|
+
for j in range(diags.shape[0]):
|
|
168
|
+
co_occur.iloc[i, j] = co_occur.iloc[i, j] / np.max([diags[i], diags[j]])
|
|
169
|
+
if log:
|
|
170
|
+
co_occur = co_occur.applymap(np.log)
|
|
171
|
+
heatmap = ax.pcolor(co_occur, norm=norm, **kwargs)
|
|
172
|
+
ax.set_yticks(np.arange(co_occur.shape[0]) + 0.5, minor=False)
|
|
173
|
+
ax.set_xticks(np.arange(co_occur.shape[1]) + 0.5, minor=False)
|
|
174
|
+
ax.invert_yaxis()
|
|
175
|
+
ax.xaxis.tick_top()
|
|
176
|
+
ax.set_xticklabels(df.columns, minor=False, rotation=90)
|
|
177
|
+
ax.set_yticklabels(df.columns, minor=False)
|
|
178
|
+
add_colorbar(heatmap)
|
|
179
|
+
return ax
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class DropBelowZero(BaseEstimator, TransformerMixin):
|
|
183
|
+
"""
|
|
184
|
+
Transformer for scikit-learn like use.
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
def __init__(self, **kwargs):
|
|
188
|
+
self.kpairs = kwargs
|
|
189
|
+
self.label = "Feedthrough"
|
|
190
|
+
|
|
191
|
+
def transform(self, X, *args, **kwargs):
|
|
192
|
+
if isinstance(X, pd.DataFrame) or isinstance(X, pd.Series):
|
|
193
|
+
out = X.where(X > 0, np.nan)
|
|
194
|
+
else:
|
|
195
|
+
out = np.where(X > 0, X, np.nan)
|
|
196
|
+
return out
|
|
197
|
+
|
|
198
|
+
def fit(self, X, *args):
|
|
199
|
+
return self
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class LinearTransform(BaseEstimator, TransformerMixin):
|
|
203
|
+
"""
|
|
204
|
+
Linear Transformer for scikit-learn like use.
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
def __init__(self, **kwargs):
|
|
208
|
+
self.kpairs = kwargs
|
|
209
|
+
self.label = "Feedthrough"
|
|
210
|
+
self.forward = lambda x: x
|
|
211
|
+
self.inverse = lambda x: x
|
|
212
|
+
|
|
213
|
+
def transform(self, X, *args, **kwargs):
|
|
214
|
+
if isinstance(X, pd.DataFrame):
|
|
215
|
+
out = X.copy(deep=True)
|
|
216
|
+
out.loc[:, :] = self.forward(X.values, *args, **kwargs)
|
|
217
|
+
elif isinstance(X, pd.Series):
|
|
218
|
+
out = X.copy(deep=True)
|
|
219
|
+
out.loc[:] = self.forward(X.values, *args, **kwargs)
|
|
220
|
+
else:
|
|
221
|
+
out = self.forward(np.array(X), *args, **kwargs)
|
|
222
|
+
return out
|
|
223
|
+
|
|
224
|
+
def inverse_transform(self, Y, *args, **kwargs):
|
|
225
|
+
if isinstance(Y, pd.DataFrame):
|
|
226
|
+
out = Y.copy(deep=True)
|
|
227
|
+
out.loc[:, :] = self.inverse(Y.values, *args, **kwargs)
|
|
228
|
+
elif isinstance(Y, pd.Series):
|
|
229
|
+
out = Y.copy(deep=True)
|
|
230
|
+
out.loc[:] = self.inverse(Y.values, *args, **kwargs)
|
|
231
|
+
else:
|
|
232
|
+
out = self.inverse(np.array(Y), *args, **kwargs)
|
|
233
|
+
return out
|
|
234
|
+
|
|
235
|
+
def fit(self, X, *args):
|
|
236
|
+
return self
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class ExpTransform(BaseEstimator, TransformerMixin):
|
|
240
|
+
"""
|
|
241
|
+
Exponential Transformer for scikit-learn like use.
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
def __init__(self, **kwargs):
|
|
245
|
+
self.kpairs = kwargs
|
|
246
|
+
self.label = "Feedthrough"
|
|
247
|
+
self.forward = np.exp
|
|
248
|
+
self.inverse = np.log
|
|
249
|
+
|
|
250
|
+
def transform(self, X, *args, **kwargs):
|
|
251
|
+
if isinstance(X, pd.DataFrame):
|
|
252
|
+
out = X.applymap(self.forward)
|
|
253
|
+
elif isinstance(X, pd.Series):
|
|
254
|
+
out = X.apply(self.forward)
|
|
255
|
+
else:
|
|
256
|
+
out = self.forward(np.array(X), *args, **kwargs)
|
|
257
|
+
return out
|
|
258
|
+
|
|
259
|
+
def inverse_transform(self, Y, *args, **kwargs):
|
|
260
|
+
if isinstance(Y, pd.DataFrame):
|
|
261
|
+
out = Y.applymap(self.inverse)
|
|
262
|
+
elif isinstance(Y, pd.Series):
|
|
263
|
+
out = Y.apply(self.inverse)
|
|
264
|
+
else:
|
|
265
|
+
out = self.inverse(np.array(Y), *args, **kwargs)
|
|
266
|
+
return out
|
|
267
|
+
|
|
268
|
+
def fit(self, X, *args):
|
|
269
|
+
return self
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class LogTransform(BaseEstimator, TransformerMixin):
|
|
273
|
+
"""
|
|
274
|
+
Log Transformer for scikit-learn like use.
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
def __init__(self, **kwargs):
|
|
278
|
+
self.kpairs = kwargs
|
|
279
|
+
self.label = "Feedthrough"
|
|
280
|
+
self.forward = np.log
|
|
281
|
+
self.inverse = np.exp
|
|
282
|
+
|
|
283
|
+
def transform(self, X, *args, **kwargs):
|
|
284
|
+
if isinstance(X, pd.DataFrame):
|
|
285
|
+
out = X.copy(deep=True)
|
|
286
|
+
out.loc[:, :] = self.forward(X.values, *args, **kwargs)
|
|
287
|
+
elif isinstance(X, pd.Series):
|
|
288
|
+
out = X.copy(deep=True)
|
|
289
|
+
out.loc[:] = self.forward(X.values, *args, **kwargs)
|
|
290
|
+
else:
|
|
291
|
+
out = self.forward(np.array(X), *args, **kwargs)
|
|
292
|
+
return out
|
|
293
|
+
|
|
294
|
+
def inverse_transform(self, Y, *args, **kwargs):
|
|
295
|
+
if isinstance(Y, pd.DataFrame):
|
|
296
|
+
out = Y.copy(deep=True)
|
|
297
|
+
out.loc[:, :] = self.inverse(Y.values, *args, **kwargs)
|
|
298
|
+
elif isinstance(Y, pd.Series):
|
|
299
|
+
out = Y.copy(deep=True)
|
|
300
|
+
out.loc[:] = self.inverse(Y.values, *args, **kwargs)
|
|
301
|
+
else:
|
|
302
|
+
out = self.inverse(np.array(Y), *args, **kwargs)
|
|
303
|
+
return out
|
|
304
|
+
|
|
305
|
+
def fit(self, X, *args):
|
|
306
|
+
return self
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class ALRTransform(BaseEstimator, TransformerMixin):
|
|
310
|
+
"""
|
|
311
|
+
Additive Log Ratio Transformer for scikit-learn like use.
|
|
312
|
+
"""
|
|
313
|
+
|
|
314
|
+
def __init__(self, **kwargs):
|
|
315
|
+
self.kpairs = kwargs
|
|
316
|
+
self.label = "ALR"
|
|
317
|
+
self.forward = alr
|
|
318
|
+
self.inverse = inv_alr
|
|
319
|
+
|
|
320
|
+
def transform(self, X, *args, **kwargs):
|
|
321
|
+
if isinstance(X, pd.DataFrame):
|
|
322
|
+
out = pd.DataFrame(
|
|
323
|
+
index=X.index, data=self.forward(X.values, *args, **kwargs)
|
|
324
|
+
)
|
|
325
|
+
elif isinstance(X, pd.Series):
|
|
326
|
+
out = pd.Series(index=X.index, data=self.forward(X.values, *args, **kwargs))
|
|
327
|
+
else:
|
|
328
|
+
out = self.forward(np.array(X), *args, **kwargs)
|
|
329
|
+
return out
|
|
330
|
+
|
|
331
|
+
def inverse_transform(self, Y, *args, **kwargs):
|
|
332
|
+
if isinstance(Y, pd.DataFrame):
|
|
333
|
+
out = pd.DataFrame(
|
|
334
|
+
index=Y.index, data=self.inverse(Y.values, *args, **kwargs)
|
|
335
|
+
)
|
|
336
|
+
elif isinstance(Y, pd.Series):
|
|
337
|
+
out = pd.Series(index=Y.index, data=self.inverse(Y.values, *args, **kwargs))
|
|
338
|
+
else:
|
|
339
|
+
out = self.inverse(np.array(Y), *args, **kwargs)
|
|
340
|
+
return out
|
|
341
|
+
|
|
342
|
+
def fit(self, X, *args, **kwargs):
|
|
343
|
+
return self
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
class CLRTransform(BaseEstimator, TransformerMixin):
|
|
347
|
+
"""
|
|
348
|
+
Centred Log Ratio Transformer for scikit-learn like use.
|
|
349
|
+
"""
|
|
350
|
+
|
|
351
|
+
def __init__(self, **kwargs):
|
|
352
|
+
self.kpairs = kwargs
|
|
353
|
+
self.label = "CLR"
|
|
354
|
+
self.forward = clr
|
|
355
|
+
self.inverse = inv_clr
|
|
356
|
+
|
|
357
|
+
def transform(self, X, *args, **kwargs):
|
|
358
|
+
if isinstance(X, pd.DataFrame):
|
|
359
|
+
out = X.copy(deep=True)
|
|
360
|
+
out.loc[:, :] = self.forward(X.values, *args, **kwargs)
|
|
361
|
+
elif isinstance(X, pd.Series):
|
|
362
|
+
out = X.copy(deep=True)
|
|
363
|
+
out.loc[:] = self.forward(X.values, *args, **kwargs)
|
|
364
|
+
else:
|
|
365
|
+
out = self.forward(np.array(X), *args, **kwargs)
|
|
366
|
+
return out
|
|
367
|
+
|
|
368
|
+
def inverse_transform(self, Y, *args, **kwargs):
|
|
369
|
+
if isinstance(Y, pd.DataFrame):
|
|
370
|
+
out = Y.copy(deep=True)
|
|
371
|
+
out.loc[:, :] = self.inverse(Y.values, *args, **kwargs)
|
|
372
|
+
elif isinstance(Y, pd.Series):
|
|
373
|
+
out = Y.copy(deep=True)
|
|
374
|
+
out.loc[:] = self.inverse(Y.values, *args, **kwargs)
|
|
375
|
+
else:
|
|
376
|
+
out = self.inverse(np.array(Y), *args, **kwargs)
|
|
377
|
+
return out
|
|
378
|
+
|
|
379
|
+
def fit(self, X, *args, **kwargs):
|
|
380
|
+
return self
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
class ILRTransform(BaseEstimator, TransformerMixin):
|
|
384
|
+
"""
|
|
385
|
+
Isometric Log Ratio Transformer for scikit-learn like use.
|
|
386
|
+
"""
|
|
387
|
+
|
|
388
|
+
def __init__(self, **kwargs):
|
|
389
|
+
self.kpairs = kwargs
|
|
390
|
+
self.label = "ILR"
|
|
391
|
+
self.forward = ilr
|
|
392
|
+
self.inverse = inv_ilr
|
|
393
|
+
|
|
394
|
+
def transform(self, X, *args, **kwargs):
|
|
395
|
+
self.X = np.array(X)
|
|
396
|
+
if isinstance(X, pd.DataFrame):
|
|
397
|
+
out = pd.DataFrame(
|
|
398
|
+
index=X.index, data=self.forward(X.values, *args, **kwargs)
|
|
399
|
+
)
|
|
400
|
+
elif isinstance(X, pd.Series):
|
|
401
|
+
out = X.copy(deep=True)
|
|
402
|
+
out.loc[:] = self.forward(X.values, *args, **kwargs)
|
|
403
|
+
else:
|
|
404
|
+
out = self.forward(np.array(X), *args, **kwargs)
|
|
405
|
+
return out
|
|
406
|
+
|
|
407
|
+
def inverse_transform(self, Y, *args, **kwargs):
|
|
408
|
+
if "X" not in kwargs:
|
|
409
|
+
kwargs.update(dict(X=self.X))
|
|
410
|
+
if isinstance(Y, pd.DataFrame):
|
|
411
|
+
out = pd.DataFrame(
|
|
412
|
+
index=Y.index, data=self.inverse(Y.values, *args, **kwargs)
|
|
413
|
+
)
|
|
414
|
+
elif isinstance(Y, pd.Series):
|
|
415
|
+
out = pd.Series(index=Y.index, data=self.inverse(Y.values, *args, **kwargs))
|
|
416
|
+
else:
|
|
417
|
+
out = self.inverse(np.array(Y), *args, **kwargs)
|
|
418
|
+
return out
|
|
419
|
+
|
|
420
|
+
def fit(self, X, *args, **kwargs):
|
|
421
|
+
return self
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
class BoxCoxTransform(BaseEstimator, TransformerMixin):
|
|
425
|
+
"""
|
|
426
|
+
BoxCox Transformer for scikit-learn like use.
|
|
427
|
+
"""
|
|
428
|
+
|
|
429
|
+
def __init__(self, **kwargs):
|
|
430
|
+
self.kpairs = kwargs
|
|
431
|
+
self.label = "BoxCox"
|
|
432
|
+
self.forward = boxcox
|
|
433
|
+
self.inverse = inv_boxcox
|
|
434
|
+
self.lmbda = None
|
|
435
|
+
|
|
436
|
+
def transform(self, X, *args, **kwargs):
|
|
437
|
+
self.X = np.array(X)
|
|
438
|
+
if "lmbda" not in kwargs:
|
|
439
|
+
if not (self.lmbda is None):
|
|
440
|
+
kwargs.update(dict(lmbda=self.lmbda))
|
|
441
|
+
data = self.forward(X, *args, **kwargs)
|
|
442
|
+
else:
|
|
443
|
+
kwargs.update(dict(return_lmbda=True))
|
|
444
|
+
data, lmbda = self.forward(X, *args, **kwargs)
|
|
445
|
+
self.lmbda = lmbda
|
|
446
|
+
return data
|
|
447
|
+
|
|
448
|
+
def inverse_transform(self, Y, *args, **kwargs):
|
|
449
|
+
if "lmbda" not in kwargs:
|
|
450
|
+
kwargs.update(dict(lmbda=self.lmbda))
|
|
451
|
+
return self.inverse(Y, *args, **kwargs)
|
|
452
|
+
|
|
453
|
+
def fit(self, X, *args, **kwargs):
|
|
454
|
+
bc_data, lmbda = boxcox(X, *args, **kwargs)
|
|
455
|
+
self.lmbda = lmbda
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
class TypeSelector(BaseEstimator, TransformerMixin):
|
|
459
|
+
def __init__(self, dtype):
|
|
460
|
+
self.dtype = dtype
|
|
461
|
+
|
|
462
|
+
def fit(self, X, y=None):
|
|
463
|
+
return self
|
|
464
|
+
|
|
465
|
+
def transform(self, X):
|
|
466
|
+
assert isinstance(X, pd.DataFrame)
|
|
467
|
+
return X.select_dtypes(include=[self.dtype])
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
class ColumnSelector(BaseEstimator, TransformerMixin):
|
|
471
|
+
def __init__(self, columns):
|
|
472
|
+
self.columns = columns
|
|
473
|
+
|
|
474
|
+
def fit(self, X, y=None):
|
|
475
|
+
return self
|
|
476
|
+
|
|
477
|
+
def transform(self, X):
|
|
478
|
+
assert isinstance(X, pd.DataFrame)
|
|
479
|
+
|
|
480
|
+
try:
|
|
481
|
+
return X.loc[:, self.columns]
|
|
482
|
+
except KeyError:
|
|
483
|
+
cols_error = list(set(self.columns) - set(X.columns))
|
|
484
|
+
raise KeyError(
|
|
485
|
+
"The DataFrame does not include the columns: %s" % cols_error
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
class CompositionalSelector(BaseEstimator, TransformerMixin):
|
|
490
|
+
def __init__(
|
|
491
|
+
self, components=__common_elements__ | __common_oxides__, inverse=False
|
|
492
|
+
):
|
|
493
|
+
self.columns = components
|
|
494
|
+
self.inverse = inverse
|
|
495
|
+
|
|
496
|
+
def fit(self, X, y=None):
|
|
497
|
+
return self
|
|
498
|
+
|
|
499
|
+
def transform(self, X):
|
|
500
|
+
assert isinstance(X, pd.DataFrame)
|
|
501
|
+
if self.inverse:
|
|
502
|
+
out_cols = [i for i in X.columns if i not in self.columns]
|
|
503
|
+
else:
|
|
504
|
+
out_cols = [i for i in X.columns if i in self.columns]
|
|
505
|
+
out = X.loc[:, out_cols]
|
|
506
|
+
return out
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
class MajorsSelector(BaseEstimator, TransformerMixin):
|
|
510
|
+
def __init__(self, components=common_oxides()):
|
|
511
|
+
self.columns = components
|
|
512
|
+
|
|
513
|
+
def fit(self, X, y=None):
|
|
514
|
+
return self
|
|
515
|
+
|
|
516
|
+
def transform(self, X):
|
|
517
|
+
assert isinstance(X, pd.DataFrame)
|
|
518
|
+
out_cols = [i for i in X.columns if i in self.columns]
|
|
519
|
+
out = X.loc[:, out_cols]
|
|
520
|
+
return out
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
class ElementSelector(BaseEstimator, TransformerMixin):
|
|
524
|
+
def __init__(self, components=common_elements()):
|
|
525
|
+
self.columns = components
|
|
526
|
+
|
|
527
|
+
def fit(self, X, y=None):
|
|
528
|
+
return self
|
|
529
|
+
|
|
530
|
+
def transform(self, X):
|
|
531
|
+
assert isinstance(X, pd.DataFrame)
|
|
532
|
+
out_cols = [i for i in X.columns if i in self.columns]
|
|
533
|
+
out = X.loc[:, out_cols]
|
|
534
|
+
return out
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
class REESelector(BaseEstimator, TransformerMixin):
|
|
538
|
+
def __init__(self, components=REE()):
|
|
539
|
+
components = [i for i in components if not i == "Pm"]
|
|
540
|
+
self.columns = components
|
|
541
|
+
|
|
542
|
+
def fit(self, X, y=None):
|
|
543
|
+
return self
|
|
544
|
+
|
|
545
|
+
def transform(self, X):
|
|
546
|
+
assert isinstance(X, pd.DataFrame)
|
|
547
|
+
out_cols = [i for i in self.columns if i in X.columns]
|
|
548
|
+
out = X.loc[:, out_cols]
|
|
549
|
+
return out
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
class Devolatilizer(BaseEstimator, TransformerMixin):
|
|
553
|
+
def __init__(
|
|
554
|
+
self, exclude=["H2O", "H2O_PLUS", "H2O_MINUS", "CO2", "LOI"], renorm=True
|
|
555
|
+
):
|
|
556
|
+
self.exclude = [i.upper() for i in exclude]
|
|
557
|
+
self.renorm = renorm
|
|
558
|
+
|
|
559
|
+
def fit(self, X, y=None):
|
|
560
|
+
return self
|
|
561
|
+
|
|
562
|
+
def transform(self, X):
|
|
563
|
+
assert isinstance(X, pd.DataFrame)
|
|
564
|
+
exclude = [i for i in X.columns if i.upper() in self.exclude]
|
|
565
|
+
return devolatilise(X, exclude=exclude, renorm=self.renorm)
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
class RedoxAggregator(BaseEstimator, TransformerMixin):
|
|
569
|
+
def __init__(self, to_oxidised=False, renorm=True, total_suffix="T"):
|
|
570
|
+
self.to_oxidised = to_oxidised
|
|
571
|
+
self.renorm = renorm
|
|
572
|
+
self.total_suffix = total_suffix
|
|
573
|
+
|
|
574
|
+
def fit(self, X, y=None):
|
|
575
|
+
return self
|
|
576
|
+
|
|
577
|
+
def transform(self, X):
|
|
578
|
+
assert isinstance(X, pd.DataFrame)
|
|
579
|
+
return recalculate_redox(
|
|
580
|
+
X,
|
|
581
|
+
to_oxidised=self.to_oxidised,
|
|
582
|
+
renorm=self.renorm,
|
|
583
|
+
total_suffix=self.total_suffix,
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
class ElementAggregator(BaseEstimator, TransformerMixin):
|
|
588
|
+
def __init__(self, renorm=True, form="oxide"):
|
|
589
|
+
self.renorm = renorm
|
|
590
|
+
self.form = form
|
|
591
|
+
|
|
592
|
+
def fit(self, X, y=None):
|
|
593
|
+
return self
|
|
594
|
+
|
|
595
|
+
def transform(self, X):
|
|
596
|
+
assert isinstance(X, pd.DataFrame)
|
|
597
|
+
multiple_entries = check_multiple_cation_inclusion(X)
|
|
598
|
+
|
|
599
|
+
for el in multiple_entries:
|
|
600
|
+
X = aggregate_cation(X, el, form=self.form)
|
|
601
|
+
return X
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
class PdUnion(BaseEstimator, TransformerMixin):
|
|
605
|
+
def __init__(self, estimators: list = []):
|
|
606
|
+
self.estimators = estimators
|
|
607
|
+
|
|
608
|
+
def fit(self, X, y=None):
|
|
609
|
+
return self
|
|
610
|
+
|
|
611
|
+
def transform(self, X):
|
|
612
|
+
assert isinstance(X, pd.DataFrame)
|
|
613
|
+
parts = []
|
|
614
|
+
for est in self.estimators:
|
|
615
|
+
if isinstance(est, pd.DataFrame):
|
|
616
|
+
parts.append(est)
|
|
617
|
+
elif isinstance(est, TransformerMixin) or isinstance(est, BaseEstimator):
|
|
618
|
+
if hasattr(est, "fit"):
|
|
619
|
+
parts.append(est.fit_transform(X))
|
|
620
|
+
else:
|
|
621
|
+
parts.append(est.transform(X))
|
|
622
|
+
else: # e.g. Numpy array, try to convert to dataframe
|
|
623
|
+
parts.append(pd.DataFrame(est))
|
|
624
|
+
|
|
625
|
+
columns = []
|
|
626
|
+
idxs = []
|
|
627
|
+
for p in parts:
|
|
628
|
+
columns += [i for i in p.columns if not i in columns]
|
|
629
|
+
idxs.append(p.index.size)
|
|
630
|
+
|
|
631
|
+
# check the indexes are all the same length
|
|
632
|
+
assert all([idx == idxs[0] for idx in idxs])
|
|
633
|
+
|
|
634
|
+
out = pd.DataFrame(columns=columns)
|
|
635
|
+
for p in parts:
|
|
636
|
+
out[p.columns] = p
|
|
637
|
+
|
|
638
|
+
return out
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
class LambdaTransformer(BaseEstimator, TransformerMixin):
|
|
642
|
+
def __init__(
|
|
643
|
+
self, norm_to="Chondrite_PON", exclude=["Pm", "Eu", "Ce"], params=None, degree=5
|
|
644
|
+
):
|
|
645
|
+
self.norm_to = norm_to
|
|
646
|
+
self.ree = [i for i in REE() if not i in exclude]
|
|
647
|
+
self.radii = np.array(get_radii(self.ree))
|
|
648
|
+
self.exclude = exclude
|
|
649
|
+
if params is None:
|
|
650
|
+
self.degree = degree
|
|
651
|
+
self.params = OP_constants(self.radii, degree=self.degree)
|
|
652
|
+
else:
|
|
653
|
+
self.params = params
|
|
654
|
+
self.degree = len(params)
|
|
655
|
+
|
|
656
|
+
def fit(self, X, y=None):
|
|
657
|
+
return self
|
|
658
|
+
|
|
659
|
+
def transform(self, X):
|
|
660
|
+
assert isinstance(X, pd.DataFrame)
|
|
661
|
+
ree_present = [i in X.columns for i in self.ree]
|
|
662
|
+
if not all(ree_present):
|
|
663
|
+
self.ree = [i for i in self.ree if i in X.columns]
|
|
664
|
+
self.radii = self.radii[ree_present]
|
|
665
|
+
self.params = OP_constants(self.radii, degree=self.degree)
|
|
666
|
+
|
|
667
|
+
return lambda_lnREE(
|
|
668
|
+
X,
|
|
669
|
+
norm_to=self.norm_to,
|
|
670
|
+
params=self.params,
|
|
671
|
+
degree=self.degree,
|
|
672
|
+
exclude=self.exclude,
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
class MultipleImputer(BaseEstimator, TransformerMixin):
|
|
677
|
+
"""
|
|
678
|
+
Multiple Imputation via fancyimpute.IterativeImputer.
|
|
679
|
+
"""
|
|
680
|
+
|
|
681
|
+
def __init__(self, multiple=5, n_iter=10, groupby=None, *args, **kwargs):
|
|
682
|
+
self.multiple = multiple
|
|
683
|
+
self.n_iter = n_iter
|
|
684
|
+
self.args = args
|
|
685
|
+
self.kwargs = kwargs
|
|
686
|
+
self.groupby = groupby
|
|
687
|
+
|
|
688
|
+
def transform(self, X, *args, **kwargs):
|
|
689
|
+
assert isinstance(X, pd.DataFrame)
|
|
690
|
+
df = pd.DataFrame(columns=X.columns, index=X.index)
|
|
691
|
+
if isinstance(self.imputers, dict):
|
|
692
|
+
for c, d in self.imputers.items():
|
|
693
|
+
mask = d["mask"]
|
|
694
|
+
imputers = d["impute"]
|
|
695
|
+
imputed_data = np.array([imp.transform(X[mask, :]) for imp in imputers])
|
|
696
|
+
mean = np.mean(imputed_data, axis=0)
|
|
697
|
+
df.loc[mask, ~pd.isnull(X[mask, :]).all(axis=0)] = mean
|
|
698
|
+
return df
|
|
699
|
+
else:
|
|
700
|
+
imputed_data = np.array([imp.transform(X) for imp in self.imputers])
|
|
701
|
+
mean = np.mean(imputed_data, axis=0)
|
|
702
|
+
df.loc[:, ~pd.isnull(X).all(axis=0)] = mean
|
|
703
|
+
return df
|
|
704
|
+
|
|
705
|
+
"""
|
|
706
|
+
def inverse_transform(self, Y, *args, **kwargs):
|
|
707
|
+
# For non-compositional data, take the mask and reverting to nan
|
|
708
|
+
# for compositional data, renormalisation would be needed
|
|
709
|
+
pass
|
|
710
|
+
"""
|
|
711
|
+
|
|
712
|
+
def fit(self, X, y=None):
|
|
713
|
+
assert isinstance(X, pd.DataFrame)
|
|
714
|
+
start = X
|
|
715
|
+
y_present = y is not None
|
|
716
|
+
groupby_present = self.groupby is not None
|
|
717
|
+
self.imputers = []
|
|
718
|
+
if y_present or groupby_present:
|
|
719
|
+
assert not (groupby_present and y_present)
|
|
720
|
+
if y_present:
|
|
721
|
+
classes = np.unique(y)
|
|
722
|
+
gen_mask = lambda c: y == c
|
|
723
|
+
if groupby_present:
|
|
724
|
+
classes = X[self.groupby].unique()
|
|
725
|
+
gen_mask = lambda c: X[self.groupby] == c
|
|
726
|
+
self.imputers = {
|
|
727
|
+
c: {
|
|
728
|
+
"impute": [
|
|
729
|
+
IterativeImputer(
|
|
730
|
+
n_iter=self.n_iter,
|
|
731
|
+
sample_posterior=True,
|
|
732
|
+
random_state=ix,
|
|
733
|
+
**self.kwargs
|
|
734
|
+
)
|
|
735
|
+
for ix in range(self.multiple)
|
|
736
|
+
],
|
|
737
|
+
"mask": gen_mask(c),
|
|
738
|
+
}
|
|
739
|
+
for c in classes
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
msg = """Imputation transformer: {} imputers x {} classes""".format(
|
|
743
|
+
self.multiple, len(classes)
|
|
744
|
+
)
|
|
745
|
+
logger.info(msg)
|
|
746
|
+
|
|
747
|
+
for c, d in self.imputers.items():
|
|
748
|
+
for imp in d["impute"]:
|
|
749
|
+
imp.fit(X[d["mask"], :])
|
|
750
|
+
|
|
751
|
+
else:
|
|
752
|
+
for ix in range(self.multiple):
|
|
753
|
+
self.imputers.append(
|
|
754
|
+
IterativeImputer(
|
|
755
|
+
n_iter=self.n_iter,
|
|
756
|
+
sample_posterior=True,
|
|
757
|
+
random_state=ix,
|
|
758
|
+
**self.kwargs
|
|
759
|
+
)
|
|
760
|
+
)
|
|
761
|
+
msg = """Imputation transformer: {} imputers""".format(self.multiple)
|
|
762
|
+
logger.info(msg)
|
|
763
|
+
for ix in range(self.multiple):
|
|
764
|
+
self.imputers[ix].fit(X)
|
|
765
|
+
|
|
766
|
+
return self
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
class PdSoftImputer(BaseEstimator, TransformerMixin):
|
|
770
|
+
"""
|
|
771
|
+
Multiple Imputation via fancyimpute.SoftImpute.
|
|
772
|
+
"""
|
|
773
|
+
|
|
774
|
+
def __init__(self, max_iters=100, groupby=None, donotimpute=[], *args, **kwargs):
|
|
775
|
+
self.args = args
|
|
776
|
+
self.kwargs = kwargs
|
|
777
|
+
self.max_iters = max_iters
|
|
778
|
+
self.groupby = groupby
|
|
779
|
+
self.donotimpute = donotimpute
|
|
780
|
+
|
|
781
|
+
def transform(self, X, *args, **kwargs):
|
|
782
|
+
"""
|
|
783
|
+
Impute Missing Values
|
|
784
|
+
|
|
785
|
+
Need to use masks to avoid SoftImpute returning 0. where it cannot impute.
|
|
786
|
+
"""
|
|
787
|
+
assert isinstance(X, pd.DataFrame)
|
|
788
|
+
df = pd.DataFrame(columns=X.columns, index=X.index) # df of nans
|
|
789
|
+
df.loc[:, self.donotimpute] = X.loc[:, self.donotimpute]
|
|
790
|
+
to_impute = [i for i in X.columns if not i in self.donotimpute]
|
|
791
|
+
imputable = ~pd.isnull(X.loc[:, to_impute]).all(axis=1)
|
|
792
|
+
if isinstance(self.imputer, dict):
|
|
793
|
+
for c, d in self.imputer.items():
|
|
794
|
+
mask = d["mask"]
|
|
795
|
+
mask = mask & imputable
|
|
796
|
+
imputer = d["impute"]
|
|
797
|
+
imputed_data = imputer.fit_transform(X.loc[mask, to_impute])
|
|
798
|
+
assert imputed_data.shape[0] == X.loc[mask, :].index.size
|
|
799
|
+
df.loc[mask, to_impute] = imputed_data
|
|
800
|
+
|
|
801
|
+
return df
|
|
802
|
+
else:
|
|
803
|
+
imputed_data = self.imputer.fit_transform(X.loc[imputable, to_impute])
|
|
804
|
+
assert imputed_data.shape[0] == X.loc[imputable, :].index.size
|
|
805
|
+
df.loc[imputable, to_impute] = imputed_data
|
|
806
|
+
return df
|
|
807
|
+
|
|
808
|
+
"""
|
|
809
|
+
def inverse_transform(self, Y, *args, **kwargs):
|
|
810
|
+
# For non-compositional data, take the mask and reverting to nan
|
|
811
|
+
# for compositional data, renormalisation would be needed
|
|
812
|
+
pass
|
|
813
|
+
"""
|
|
814
|
+
|
|
815
|
+
def fit(self, X, y=None):
|
|
816
|
+
assert isinstance(X, pd.DataFrame)
|
|
817
|
+
start = X
|
|
818
|
+
y_present = y is not None
|
|
819
|
+
groupby_present = self.groupby is not None
|
|
820
|
+
self.imputer = []
|
|
821
|
+
if y_present or groupby_present:
|
|
822
|
+
assert not (groupby_present and y_present)
|
|
823
|
+
if y_present:
|
|
824
|
+
classes = np.unique(y)
|
|
825
|
+
gen_mask = lambda c: y == c
|
|
826
|
+
if groupby_present:
|
|
827
|
+
classes = X[self.groupby].unique()
|
|
828
|
+
gen_mask = lambda c: X[self.groupby] == c
|
|
829
|
+
self.imputer = {
|
|
830
|
+
c: {
|
|
831
|
+
"impute": SoftImpute(max_iters=self.max_iters, **self.kwargs),
|
|
832
|
+
"mask": gen_mask(c),
|
|
833
|
+
}
|
|
834
|
+
for c in classes
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
msg = """Building Soft Imputation Transformers for {} classes""".format(
|
|
838
|
+
len(classes)
|
|
839
|
+
)
|
|
840
|
+
logger.info(msg)
|
|
841
|
+
|
|
842
|
+
else:
|
|
843
|
+
self.imputer = SoftImpute(max_iters=self.max_iters, **self.kwargs)
|
|
844
|
+
msg = """Building Soft Imputation Transformer"""
|
|
845
|
+
logger.info(msg)
|
|
846
|
+
|
|
847
|
+
return self
|